使用PHP重写URL

Jaz*_*rix 135 php url .htaccess mod-rewrite url-rewriting

我有一个看起来像这样的网址:

url.com/picture.php?id=51
Run Code Online (Sandbox Code Playgroud)

我如何将该URL转换为:

picture.php/Some-text-goes-here/51
Run Code Online (Sandbox Code Playgroud)

我认为WordPress做同样的事情.

如何在PHP中创建友好的URL?

Nie*_*jes 185

你基本上可以这两种方式:

带有mod_rewrite的.htaccess路由

添加.htaccess在根文件夹中调用的文件,并添加如下内容:

RewriteEngine on
RewriteRule ^/?Some-text-goes-here/([0-9]+)$ /picture.php?id=$1
Run Code Online (Sandbox Code Playgroud)

这将告诉Apache为此文件夹启用mod_rewrite,如果它被问到匹配正则表达式的URL,它会在内部将其重写为您想要的内容,而不会让最终用户看到它.简单但不灵活,所以如果你需要更多的力量:

PHP路由

将以下内容放在.htaccess中:(注意前导斜杠)

FallbackResource /index.php
Run Code Online (Sandbox Code Playgroud)

这将告诉它运行您index.php在网站中通常无法找到的所有文件.在那里你可以举例如:

$path = ltrim($_SERVER['REQUEST_URI'], '/');    // Trim leading slash(es)
$elements = explode('/', $path);                // Split path on slashes
if(empty($elements[0])) {                       // No path elements means home
    ShowHomepage();
} else switch(array_shift($elements))             // Pop off first item and switch
{
    case 'Some-text-goes-here':
        ShowPicture($elements); // passes rest of parameters to internal function
        break;
    case 'more':
        ...
    default:
        header('HTTP/1.1 404 Not Found');
        Show404Error();
}
Run Code Online (Sandbox Code Playgroud)

这就是大型网站和CMS系统如何做到这一点,因为它在解析URL,配置和数据库相关的URL等方面具有更大的灵活性.对于零星的使用,硬编码的重写规则.htaccess将会很好.

  • 方便较小的网站,但如果您必须解析`/ blog/25`以及`/ picture/51`和`/ download/684`,则不太实用.此外,如果并非所有随机生成的网址都正确返回404,那么它被认为是非常糟糕的做法(并且会让Google PR受到惩罚!) (7认同)
  • 至少在我的系统上,那就是`FallbackResource/index.php`(注意前导斜线) (5认同)
  • @olli:不良做法评论特指"不为不存在的URL返回404",这是由答案本身的解决方案解决的.至于第一个问题 - "FallbackResource"只针对文件系统中实际不存在的文件,因此*fallback*.因此,如果您有一个文件`/ static/styles.css`并将其称为`http:// mydomain.tld/static/styles.css`,则代码永远不会执行,从而使其按预期工作并透明地工作. (3认同)

Dan*_*jel 57

如果您只想更改路由,picture.php那么添加重写规则.htaccess将满足您的需求,但是,如果您希望在Wordpress中重写URL,那么PHP就是这样.这是一个简单的例子.

文件夹结构

但是也有一些需要在根文件夹中的两个文件,.htaccess并且index.php,这将是很好的放置的其余部分.php在不同的文件夹中的文件一样inc/.

root/
  inc/
  .htaccess
  index.php
Run Code Online (Sandbox Code Playgroud)

的.htaccess

RewriteEngine On
RewriteRule ^inc/.*$ index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
Run Code Online (Sandbox Code Playgroud)

该文件有四个指令:

  1. RewriteEngine - 启用重写引擎
  2. RewriteRule- 拒绝访问文件inc/夹中的所有文件,将对该文件夹的任何调用重定向到index.php
  3. RewriteCond - 允许直接访问所有其他文件(如图像,CSS或脚本)
  4. RewriteRule - 重定向任何其他内容 index.php

的index.php

因为现在所有内容都被重定向到index.php,所以将确定url是否正确,所有参数是否存在以及参数类型是否正确.

要测试网址,我们需要有一套规则,最好的工具是正则表达式.通过使用正则表达式,我们将一击就杀死两只苍蝇.要通过此测试的Url必须具有在允许的字符上测试的所有必需参数.以下是一些规则示例.

$rules = array( 
    'picture'   => "/picture/(?'text'[^/]+)/(?'id'\d+)",    // '/picture/some-text/51'
    'album'     => "/album/(?'album'[\w\-]+)",              // '/album/album-slug'
    'category'  => "/category/(?'category'[\w\-]+)",        // '/category/category-slug'
    'page'      => "/page/(?'page'about|contact)",          // '/page/about', '/page/contact'
    'post'      => "/(?'post'[\w\-]+)",                     // '/post-slug'
    'home'      => "/"                                      // '/'
);
Run Code Online (Sandbox Code Playgroud)

接下来是准备请求uri.

$uri = rtrim( dirname($_SERVER["SCRIPT_NAME"]), '/' );
$uri = '/' . trim( str_replace( $uri, '', $_SERVER['REQUEST_URI'] ), '/' );
$uri = urldecode( $uri );
Run Code Online (Sandbox Code Playgroud)

现在我们有了uri请求,最后一步是测试uri的正则表达式规则.

foreach ( $rules as $action => $rule ) {
    if ( preg_match( '~^'.$rule.'$~i', $uri, $params ) ) {
        /* now you know the action and parameters so you can 
         * include appropriate template file ( or proceed in some other way )
         */
    }
}
Run Code Online (Sandbox Code Playgroud)

由于我们在正则表达式中使用命名子模式,因此填充$params数组几乎与PHP填充$_GET数组相同.但是,在使用动态URL时,$_GET将填充数组而不检查任何参数.

    /picture/some+text/51

    Array
    (
        [0] => /picture/some text/51
        [text] => some text
        [1] => some text
        [id] => 51
        [2] => 51
    )

    picture.php?text=some+text&id=51

    Array
    (
        [text] => some text
        [id] => 51
    )

这几行代码和正则表达式的基本知识足以开始构建可靠的路由系统.

完整的来源

define( 'INCLUDE_DIR', dirname( __FILE__ ) . '/inc/' );

$rules = array( 
    'picture'   => "/picture/(?'text'[^/]+)/(?'id'\d+)",    // '/picture/some-text/51'
    'album'     => "/album/(?'album'[\w\-]+)",              // '/album/album-slug'
    'category'  => "/category/(?'category'[\w\-]+)",        // '/category/category-slug'
    'page'      => "/page/(?'page'about|contact)",          // '/page/about', '/page/contact'
    'post'      => "/(?'post'[\w\-]+)",                     // '/post-slug'
    'home'      => "/"                                      // '/'
);

$uri = rtrim( dirname($_SERVER["SCRIPT_NAME"]), '/' );
$uri = '/' . trim( str_replace( $uri, '', $_SERVER['REQUEST_URI'] ), '/' );
$uri = urldecode( $uri );

foreach ( $rules as $action => $rule ) {
    if ( preg_match( '~^'.$rule.'$~i', $uri, $params ) ) {
        /* now you know the action and parameters so you can 
         * include appropriate template file ( or proceed in some other way )
         */
        include( INCLUDE_DIR . $action . '.php' );

        // exit to avoid the 404 message 
        exit();
    }
}

// nothing is found so handle the 404 error
include( INCLUDE_DIR . '404.php' );
Run Code Online (Sandbox Code Playgroud)

  • 你怎么看参数?它不适用于$ post_id = htmlentities($ _ GET ['post']); (2认同)

小智 7

PHP 不是您要找的,请查看mod_rewrite


Luc*_*chi 6

这是一个.htaccess文件,几乎全部转发到index.php

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_URI} !-l
RewriteCond %{REQUEST_FILENAME} !\.(ico|css|png|jpg|gif|js)$ [NC]
# otherwise forward it to index.php
RewriteRule . index.php
Run Code Online (Sandbox Code Playgroud)

然后由您解析$ _SERVER ["REQUEST_URI"]并路由到picture.php或其他

  • Apache在几个主要版本之前引入了`FallbackResource`指令,现在这是以较低的性能成本实现此行为的首选方法,因为它不需要启动整个重写引擎.[此处的文档](http://httpd.apache.org/docs/trunk/mod/mod_dir.html#fallbackresource).您的规则也存在缺陷,因为您没有引用目录(`!-d`)并且所有扩展过滤器都已过时 - `-f`应该已经捕获它们了. (7认同)