【问题标题】:URL rewriting with PHP使用 PHP 重写 URL
【发布时间】:2013-04-29 15:08:19
【问题描述】:

我有一个如下所示的 URL:

url.com/picture.php?id=51

我将如何将该 URL 转换为:

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

我认为 WordPress 也是如此。

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

【问题讨论】:

  • 您需要在 Apache 文件的配置中进行大量调整...举一个您实际需要的示例?你如何插入这个文本?它是预定义的还是动态创建的?提供尽可能多的信息以获得正确的答案......是的,网址可能更具描述性:)
  • 为什么选择 PHP? Apache 的mod_rewrite 就是你所需要的,在 SO 上有很多关于这个的问题。如果你“认为”wordpress 也一样,why don't you simply look it up? ;)
  • 阅读mod_rewrite
  • 你为什么要这样做?目标是重写 URL,如果是这样,请使用 .htaccess 或类似的东西。如果目标只是改变字符串,$_GET 只获取查询字符串?
  • 文本将是图像的标题,然后是斜线后的 id :) 我将不得不研究 apache 的 mod_rewrite 提供的内容。希望这不是太难:D

标签: php .htaccess url mod-rewrite url-rewriting


【解决方案1】:

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

带有 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 中的硬编码重写规则会很好。

【讨论】:

  • 您可以使用正则表达式完全忽略字符串,而不是对其进行硬编码。换句话说,唯一重要的是 ID 部分。转到picture.php/invalid-text/51 也会重定向到同一位置。您还可以添加检查以查看字符串是否正确,如果不正确,请再次重定向到正确的位置。这就是我在我的一个网站上使用 htaccess 的方式。
  • 对于较小的站点很方便,但如果您必须解析 /blog/25 以及 /picture/51/download/684,则不太实用。此外,如果不是所有随机生成的 URL 都正确返回 404,那么它被认为是非常糟糕的做法(并且会让您受到 Google PR 的惩罚!)。
  • 至少在我的系统上是FallbackResource /index.php(注意前导斜杠)
  • @olli:不好的做法评论具体指的是“不为不存在的 URL 返回 404”,这是通过答案本身的解决方案解决的。至于第一个问题 - FallbackResource 仅适用于文件系统上实际不存在的文件,因此 fallback。因此,如果您有一个文件 /static/styles.css 并将其称为 http://mydomain.tld/static/styles.css,则代码永远不会执行,从而使其按预期和透明的方式工作。
  • 您应该改用if($elements[0] === NULL),因为$elements 仍然会返回一个计数,即使它是空的。
【解决方案2】:

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

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

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

【讨论】:

  • 我需要知道我们必须在href中写什么URL?因为我得到 404
【解决方案3】:

如果您只想更改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

index.php

因为现在一切都重定向到index.php,所以会判断url是否正确,所有参数是否存在,参数类型是否正确。

要测试 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' );

【讨论】:

  • 如何读取参数?它不适用于 $post_id = htmlentities($_GET['post']);
  • @Danijel 能给我一个完整的源代码吗?我尝试了上面的代码,但只输出文本,CSS没有效果。谢谢。
【解决方案4】:

这是一个 .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 或其他什么

【讨论】:

  • Apache 在几个主要版本之前引入了FallbackResource 指令,现在这是以较低性能成本实现此行为的首选方式,因为它不需要启动整个重写引擎。 Documentation here。您的规则也有缺陷,因为您没有引用目录 (!-d) 并且所有扩展过滤器都已过时 - -f 应该已经捕获它们。
【解决方案5】:

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

【讨论】:

  • @Jazerix 这取决于您定义的规则。
猜你喜欢
  • 2010-11-04
  • 2015-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多