详解PHP伪静态的实现方法
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">概述</a></li><li><a href="#_label1">什么是伪静态</a></li><li><a href="#_label2">动态、静态、伪静态之间的利与弊</a></li><li><a href="#_label3">PHP 伪静态实现方法</a></li><ul class="second_class_ul"><li><a href="#_lab2_3_0">方法一:手动解析 URL</a></li><li><a href="#_lab2_3_1">方法二:基于路径解析</a></li><li><a href="#_lab2_3_2">方法三:使用正则表达式</a></li><li><a href="#_lab2_3_3">方法四:利用 PATH_INFO</a></li></ul><li><a href="#_label4">使用 Apache 进行 URL 重写</a></li><ul class="second_class_ul"></ul><li><a href="#_label5">总结</a></li><ul class="second_class_ul"></ul></ul></div><p class="maodian"><a name="_label0"></a></p><h2>概述</h2><p>在现代 Web 开发中,URL 的设计对用户体验和搜索引擎优化(SEO)至关重要。动态 URL 虽然功能强大,但往往显得冗长且不友好。伪静态(URL 重写)技术通过将动态 URL 转换为静态样式,不仅提高了用户体验,也增强了搜索引擎的抓取效率。本文将详细介绍什么是伪静态,以及如何在 PHP 中实现伪静态。</p>
<p class="maodian"><a name="_label1"></a></p><h2>什么是伪静态</h2>
<p>伪静态又名 URL 重写,是将动态的网址(如 abc.php?lang=cn&class=1&id=2)通过重写技术转换为静态样式的网址(如 abc-cn-class1-id2.html)。实际上,这些静态样式的网址在服务器上并不存在,而是通过服务器配置和脚本处理来实现的。</p>
<p class="maodian"><a name="_label2"></a></p><h2>动态、静态、伪静态之间的利与弊</h2>
<p>1.动态网址</p>
<p>优点:</p>
<ul><li>动态网址能够告诉搜索引擎更多的参数信息,有助于内容的识别和处理。</li><li>参数可以灵活变化,适应不同的请求。</li></ul>
<p>缺点:</p>
<ul><li>过长的 URL 可能会影响用户体验和 SEO。</li><li>大量相同的参数可能会导致重复页面,影响搜索引擎的抓取效率。</li></ul>
<p>2.静态网址</p>
<p>优点:</p>
<ul><li>清晰明了,易于理解和记忆。</li><li>对搜索引擎友好,提高点击率。</li></ul>
<p>缺点:</p>
<ul><li>静态文件生成和更新较为耗时,尤其是在内容频繁变化的情况下。</li><li>静态文件占用硬盘空间,可能影响服务器性能。</li></ul>
<p>3.伪静态网址</p>
<p>优点:</p>
<ul><li>结合了动态和静态的优点,既保持了动态 URL 的灵活性,又具有静态 URL 的友好性。</li><li>不需要生成大量的静态文件,节省硬盘空间。</li></ul>
<p>缺点:</p>
<ul><li>伪静态依赖于服务器配置和脚本处理,增加了 服务器的 CPU 负载。</li><li>如果配置不当,可能会导致重复页面,影响 SEO。</li></ul>
<p class="maodian"><a name="_label3"></a></p><h2>PHP 伪静态实现方法</h2>
<p class="maodian"><a name="_lab2_3_0"></a></p><h3>方法一:手动解析 URL</h3>
<div class="jb51code"><pre class="brush:php;"><?php
// 伪静态方法一
// localhost/php100/test.php?id|1@action|2
$Php2Html_FileUrl = $_SERVER["REQUEST_URI"];
echo $Php2Html_FileUrl . "<br>"; // /php100/test.php?id|1@action|2
$Php2Html_UrlString = str_replace("?", "", str_replace("/", "", strrchr(strrchr($Php2Html_FileUrl, "/"), "?")));
echo $Php2Html_UrlString . "<br>"; // id|1@action|2
$Php2Html_UrlQueryStrList = explode("@", $Php2Html_UrlString);
print_r($Php2Html_UrlQueryStrList); // Array ( => id|1 => action|2 )
echo "<br>";
foreach ($Php2Html_UrlQueryStrList as $Php2Html_UrlQueryStr) {
$Php2Html_TmpArray = explode("|", $Php2Html_UrlQueryStr);
print_r($Php2Html_TmpArray); // Array ( => id => 1 ) ; Array ( => action => 2 )
echo "<br>";
$_GET[$Php2Html_TmpArray] = $Php2Html_TmpArray;
}
//echo '假静态:$_GET变量<br />';
print_r($_GET); // Array ( => => 1 => 2 )
echo "<br>";
echo "<hr>";
echo $_GET['id'] . "<br>"; // 1
echo $_GET['action']; // 2
?>
</pre></div>
<p class="maodian"><a name="_lab2_3_1"></a></p><h3>方法二:基于路径解析</h3>
<div class="jb51code"><pre class="brush:php;"><?php
// 伪静态方法二
// localhost/php100/test.php/1/2
$filename = basename($_SERVER['SCRIPT_NAME']);
echo $_SERVER['SCRIPT_NAME'] . "<br>"; // /php100/test.php
echo $filename . "<br>"; // test.php
if (strtolower($filename) == 'test.php') {
if (!empty($_GET['id'])) {
$id = intval($_GET['id']);
echo $id . "<br>";
$action = intval($_GET['action']);
echo $action . "<br>";
} else {
$nav = $_SERVER['REQUEST_URI'];
echo "1:" . $nav . "<br>"; // /php100/test.php/1/2
$script = $_SERVER['SCRIPT_NAME'];
echo "2:" . $script . "<br>"; // /php100/test.php
$nav = ereg_replace("^$script", "", urldecode($nav));
echo $nav . "<br>"; // /1/2
$vars = explode("/", $nav);
print_r($vars); // Array ( => => 1 => 2 )
echo "<br>";
$id = intval($vars);
$action = intval($vars);
}
echo $id . '&' . $action;
}
?>
</pre></div>
<p class="maodian"><a name="_lab2_3_2"></a></p><h3>方法三:使用正则表达式</h3>
<div class="jb51code"><pre class="brush:php;"><?php
// 伪静态方法三
function mod_rewrite() {
global $_GET;
$nav = $_SERVER["REQUEST_URI"];
echo $nav . "<br>";
$script_name = $_SERVER["SCRIPT_NAME"];
echo $script_name . "<br>";
$nav = substr(ereg_replace("^$script_name", "", urldecode($nav)), 1);
echo $nav . "<br>";
$nav = preg_replace("/^.ht(m){1}(l){0,1}$/", "", $nav); // 这句是去掉尾部的.html或.htm
echo $nav . "<br>";
$vars = explode("/", $nav);
print_r($vars);
echo "<br>";
for ($i = 0; $i < count($vars); $i += 2) {
$_GET["$vars[$i]"] = $vars[$i + 1];
}
return $_GET;
}
mod_rewrite();
$year = $_GET["year"]; // 结果为'2006'
echo $year . "<br>";
$action = $_GET["action"]; // 结果为'_add'
echo $action;
?>
</pre></div>
<p class="maodian"><a name="_lab2_3_3"></a></p><h3>方法四:利用 PATH_INFO</h3>
<div class="jb51code"><pre class="brush:php;"><?php
// 伪静态方法四
// 利用 server 变量 取得 PATH_INFO 信息 该例中为 /1,100,8630.html 也就是执行脚本名后面的部分
if (@$path_info = $_SERVER["PATH_INFO"]) {
// 正则匹配一下参数
if (preg_match("/\/(\d+),(\d+),(\d+)\.html/si", $path_info, $arr_path)) {
$gid = intval($arr_path); // 取得值 1
$sid = intval($arr_path); // 取得值 100
$softid = intval($arr_path); // 取得值 8630
} else {
die("Path:Error!");
}
// 相当于 soft.php?gid=1&sid=100&softid=8630
} else {
die('Path:Nothing!');
}
?>
</pre></div>
<p class="maodian"><a name="_label4"></a></p><h2>使用 Apache 进行 URL 重写</h2>
<p>1. 检测 Apache 是否支持 mod_rewrite</p>
<p>通过 PHP 提供的 phpinfo() 函数查看环境配置,通过 Ctrl+F 查找到“Loaded Modules”,其中列出了所有 Apache2Handler 已经开启的模块,如果里面包括“mod_rewrite”,则已经支持,不再需要继续设置。</p>
<p>如果没有开启“mod_rewrite”,则打开目录 您的 Apache 安装目录 /apache/conf/ 下的 httpd.conf 文件,通过 Ctrl+F 查找到“LoadModule rewrite_module”,将前面的“#”号删除即可。</p>
<p>如果没有查找到,则到“LoadModule” 区域,在最后一行加入 LoadModule rewrite_module modules/mod_rewrite.so(必选独占一行),然后重启 Apache 服务器即可。</p>
<p>2. 让 Apache 服务器支持 .htaccess</p>
<p>如何让自己的本地 Apache 服务器支持 .htaccess 呢?其实只要简单修改一下 Apache 的 httpd.conf 设置就可以让 Apache 支持 .htaccess。</p>
<p>打开 httpd.conf 文件(在哪里?Apache 目录的 CONF 目录里面),用文本编辑器打开后,查找:</p>
<div class="jb51code"><pre class="brush:plain;"><Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
</pre></div>
<p>改为:</p>
<div class="jb51code"><pre class="brush:plain;"><Directory />
Options FollowSymLinks
AllowOverride All
</Directory>
</pre></div>
<p>就可以了。</p>
<p>3. 建立 .htaccess 文件</p>
<p>如果是在 Windows 平台下,刚开始还真不知道怎么建立 .htaccess 文件,因为这个文件实际上没有文件名,仅仅只有扩展名,通过普通方式是无法建立这个文件的,别着急,马上告诉你三种方法:</p>
<ul><li>用记事本:打开,点击文件–另存为,在文件名窗口输入 .htaccess,注意是整个绿色部分,也就是包含英文引号,然后点击保存就行了。</li><li>进入 cmd 命令窗口:通过 cd 切换到刚建立 htaccess.txt 文件的文件夹,然后输入命令 rename htaccess.txt .htaccess,然后点击键盘 Enter 键即可。</li><li>通过 FTP 连接: htaccess.txt 所在文件夹,通过 FTP 软件重命名。</li></ul>
<p>4. Rewrite 规则学习</p>
<p>我们新建一个 .htaccess 文件之后,就在里面写入以下内容:</p>
<div class="jb51code"><pre class="brush:plain;">RewriteEngine on
# RewriteEngine 为重写引擎开关,on 为开启,off 为关闭
RewriteRule ({1,})$ index.php?id=$1
# ({1,}) 是指由数字组成的,$ 是结束标志,说明是以数字结束!
# 好吧,现在我们可以实现伪静态页面了,写下一个规则:
RewriteEngine on
RewriteRule ({1,})-({1,})\.html$ index.php?action=$1&id=$2
# ({1,})-({1,})\.html$ 是规则,index.php?action=$1&id=$2 是要替换的格式,
# $1 代表第一个括号匹配的值,$2 代表第二个,如此类推!
</pre></div>
<p class="maodian"><a name="_label5"></a></p><h2>总结</h2>
<p>本文详细介绍了 PHP 伪静态的概念及其多种实现方法,并通过具体的代码示例展示了每个步骤。通过理解这些基本概念和技术,我们可以更加灵活地在 Web 开发中应用伪静态技术,提升用户体验和搜索引擎优化效果。</p> 楼主这篇整理得太及时了!最近刚好在折腾老项目重构,URL优化这块确实让人头疼,伪静态对SEO和用户体验的提升是实打实的。结合自己踩过的坑,补充几点实战建议供大伙参考:
[]现在生产环境基本都上Nginx了,Apache的.htaccess虽然配置灵活,但高并发下会有额外开销,建议直接把rewrite规则写进server块里,性能更稳。
[]用PATH_INFO方案时,千万记得在php.ini里把cgi.fix_pathinfo设为0,否则恶意构造的路径可能导致任意文件读取漏洞。
[*]如果是从零写正则解析,建议加上缓存机制或者优先匹配路由前缀,避免每次请求都重新跑一遍preg_match拖慢响应速度。
楼主的分类讲解逻辑很清晰,新手照着步骤走基本能避开大部分配置雷区。有兄弟在.htaccess转Nginx规则时遇到404或者死循环的,欢迎把配置贴出来一起排查。期待楼主后续能出一期Nginx环境下的实战对比教程,先给大佬递茶! 好帖,收藏了!楼主总结得挺全面的,这几种PHP伪静态的方法基本覆盖了日常开发的需求。我补充几点实际使用中的经验,希望能帮到其他坛友:
方法一里面用的ereg_replace和strrchr这些函数,在PHP7之后基本都被废弃或者移除了,生产环境建议换成preg_replace和strrpos配合substr来处理,不然代码跑不起来。
另外方法二和方法三里面对URL的解析,其实可以考虑直接用parse_url和parse_str函数组合,比自己手工split要稳妥一些,尤其是遇到参数值里面带斜杠或者特殊符号的时候。
关于Apache的.htaccess配置,个人建议能不用尽量不用,毕竟每次请求都要遍历目录去读这个文件,访问量大的站点直接写在httpd.conf或者vhost配置里性能会好很多。Nginx的话就用try_files配合rewrite指令,规则写法和Apache不太一样,楼主如果有空可以补一个Nginx版本的。
PATH_INFO那个方法(方法四)现在用的人少了,主要是很多框架比如Laravel、ThinkPHP都自带路由分发,底层已经帮处理好了,不过理解原理对排查问题还是有帮助的。
最后提醒一下新手,伪静态做完记得在程序里做好canonical标签或者301跳转,不然带参数的原生URL和伪静态URL都能访问的话,搜索引擎会判定重复内容,反而影响SEO效果。
期待楼主后续能出个Nginx环境下的配置教程! 楼上补充得很到位,parse_url和parse_str确实比手动拆分稳得多,尤其是碰上参数里带特殊字符的场景。我再聊聊实际开发中容易翻车的几个点:
一个是伪静态之后,别忘了同步处理好前端的分页、筛选和搜索表单的提交地址,很多人只改了入口链接,结果用户一点“下一页”又蹦回动态参数串,体验掉一档。另一个是使用 PATH_INFO 方式时,如果服务器环境不对(比如某些一键环境里 php.ini 没开 cgi.fix_pathinfo,或者 Nginx 里漏写 fastcgi_split_path_info),会直接报 404 或者把整段路径当成脚本名,排查得很头疼。
另外现在不少项目直接用的框架自带路由,像 ThinkPHP、Laravel 都是内部统一解析,省了不少力气,但对于老项目手动改写的,建议在入口做一个统一的 URL 标准化 301 跳转,把带 index.php 的请求重定向到伪静态地址,避免搜索引擎同时收录两种版本,分散权重。
新手朋友可以多注意一下日志,刚开始调试伪静态规则时,打开 rewrite 日志能省下好多瞎猜的时间~
頁:
[1]