url重写后的路径问题

以前用FleaPHP的url_rewrite模式一直有一个很头痛的问题, 就是页面上相关资源的路径问题.

问题大概是这样的, 为了让url更加友好我们使用apache的mod_rewrite将类似

http://localhost/?controller=default&action=index&a=1

这样的路径重写成

http://localhost/default/index/a/1

或者

http://localhost/default/index/a/1.html

这样, 但是如果是这样那么浏览器请求页面相关资源的基地址就发生了改变, 从原来的documentroot下变成了documentroot/default/index/a, 如果你要在页面上显示一个图片 1.jpg, 那么原来本来应该在documentroot/1.jpg下找到的文件却变成了documentroot/default/index/a/1.jpg, 那结果肯定是找不到的.

为了解决这个问题以前用过很多方法, 用的最多的就是使用绝对路径来解决这个问题, 这是有一个前提的, 就是程序一定要放在虚拟机的根目录下, 这样在html中要将所有的资源都是用/开头, /的意思是从根目录下开始寻找, 在localhost下的任何一个程序在任何目录中使用/1.jpg都会被指向documentroot/1.jpg, 这里再强调一个概念, “./“是当前目录, “../“是上级目录, “/“是根目录.

上面这个方法实际上已经可以解决这个问题了, 但是有局限, 就是程序的目录是固定的, 一定要在虚拟机根目录下, 这样或多或少会带来一些麻烦, 至少我觉得调试不方便. 于是又有了第二个解决方案, 也就是上面方案的升级版. 我们在全局定义一个常量 define('PRE_DIR', '/'); 这样的话要将程序中所有的资源路径都写成类似 <?php echo PRE_DIR;?>dir/filename.jpg, 这样的话资源会被定为到 /dir/filename.jpg, 如果要将程序放在二级目录 test/下的话, 只要将PRE_DIR的值改成'/test/'就可以了.

其实在这之后又有了升级版, 但是不打算介绍太多, 因为这不是重点, 在手动改目录之后大家就想到要程序自动检测当前目录, 这个以前有做过, 是个不错的想法, 代码不少, 但是找不到了.

还有个东西我觉得比较神奇的, smarty有一个自动替换的插件, 可以自动在所有模板的资源链接前面加前缀, 当然前提是你已经定义了这个前缀, 插件名不记得了, 太久不用找不到了.

还是说重点吧, 昨天bobhero给我提供了一个新的思路, 利用mod_rewrite重新对资源进行定向, 后来到网上找相关的资料, 没有找到, 只找到了一些mod_rewrite的教程什么的. 研究了一下午也没研究出来, 因为url太复杂了, 很多情况都要考虑进去, 正则说什么就写不明白了, 今天早上终于搞定了.

1
2
3
4
5
6
7
8
9
#.htaccess

RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^.]*)(\.html)?$ index.php/$1 [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]*)/(.*\..*)$ $2

起作用的其实就这些东西, 可能还会有错误, 不过的确生效了.简单解释一下, RewriteCond %{REQUEST_FILENAME} !-f是条件语句, 意思是说如果请求的文件不存在下面的规则才生效. 第一条规则RewriteRule ^([^.]*)(.html)?$ index.php/$1 [L]是FLEAPHP的重写规则.

下面两条才是为了解决路径问题的, RewriteRule ^([^/])/(...*)$ $2的作用大概是这样, 比如url是这样controller/action/page/1,那么该页的style/css.css可能变成了controller/action/page/style/css.css, 这条语句就是要将controller/action/page/style/css.css指向action/page/style/css.css, 而由于某种机制请求每更换一次目录就会再执行一次根目录下的.htaccess中的重写规则, 由于action/page/style/css.css也不存在所以又被定向到page/style/css.css, 同理page/style/css.css也不存在, 再向上 style/css.css, 由于文件存在而不再执行重写规则, 向用户返回style/css.css的内容.

总的来说最后的这个方法除了apache受点累还是很完美的, 这样大概可能每个资源请求都会被重定向4次以上, 目前还不清楚对执行效率有多大的影响.

参考资料:

竹笋炒肉:Apache的Mod_rewrite学习