149

我有一个如下所示的 URL:

url.com/picture.php?id=51

我将如何将该 URL 转换为:

picture.php/Some-text-goes-here/51

我认为 WordPress 也是如此。

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

4

5 回答 5

203

您基本上可以通过两种方式做到这一点:

带有 mod_rewrite 的 .htaccess 路由

.htaccess在根文件夹中添加一个名为的文件,然后添加如下内容:

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

这将告诉 Apache 为该文件夹启用 mod_rewrite,如果它被询问与正则表达式匹配的 URL,它会在内部将其重写为您想要的内容,而最终用户不会看到它。简单但不灵活,因此如果您需要更多功能:

PHP 路线

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

FallbackResource /index.php

这将告诉它运行您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();
}

这就是大型网站和 CMS 系统的做法,因为它在解析 URL、配置和数据库相关 URL 等方面提供了更大的灵活性。对于零星使用,硬编码的重写规则.htaccess会很好。

于 2013-05-05T20:53:24.583 回答
59

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

文件夹结构

根文件夹中需要两个文件,.htaccessindex.php,最好将其余.php文件放在单独的文件夹中,例如inc/.

root/
  inc/
  .htaccess
  index.php

.htaccess

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

该文件有四个指令:

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

索引.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'      => "/"                                      // '/'
);

接下来是准备请求uri。

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

现在我们有了请求 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 )
         */
    }
}

由于我们在正则表达式中使用命名子模式,成功的匹配将填充$params数组,几乎与 PHP 填充$_GET数组一样。但是,当使用动态 url 时,$_GET会填充数组而不检查任何参数。

    /图片/一些+文字/51

    大批
    (
        [0] => /图片/一些文字/51
        [文本] => 一些文本
        [1] => 一些文字
        [id] => 51
        [2] => 51
    )

    图片.php?text=some+text&id=51

    大批
    (
        [文本] => 一些文本
        [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' );
于 2013-05-06T14:25:46.067 回答
7

这是一个 .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

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

于 2013-05-05T21:01:45.597 回答
6

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

于 2013-05-05T20:47:09.967 回答
2

虽然已经回答,并且作者的意图是创建一个前端控制器类型的应用程序,但我发布了针对问题的文字规则。如果有人有同样的问题。

RewriteEngine On
RewriteRule ^([^/]+)/([^/]+)/([\d]+)$ $1?id=$3 [L]

以上应该适用于 url picture.php/Some-text-goes-here/51。不使用 index.php 作为重定向应用程序。

于 2017-04-27T06:44:23.123 回答