apache的RewriteMap使用心得

在apache的环境下,rewrite还真是生活之友啊,时不时就得用上。前些日子有个需求,要将url重新转一转。

什么情况?

原来的url
http://www.xxx.com/demo/oldpage.php?param1=1&param2=2

转换后的url
http://www.xxx.com/newpage.php?url=%2Fdemo%2Fmypage.php%3Fparam1%3D1&param2%3D2

需要把粗体部分的url进行urlencode,能看出上面的字符”?&=”都分别转义过,作为参数发给另外一个url。那么这时候请出rewrite还真是最合适不过了。

坎坷的Rewrite经历

查查rewrite手册,俺这才知道,转义这活,非得派出RewriteMap的map function才能做的比较漂亮。现在只有四个内部map function可供差遣:

  • toupper: Converts the key to all upper case.
  • tolower: Converts the key to all lower case.
  • escape: Translates special characters in the key to hex-encodings.
  • unescape: Translates hex-encodings in the key back to special characters.

那么很快就有了第一个rewrite出现:


RewriteMap escape int:escape
RewriteRule ^/([^/]*)$ /newpage.php?mi_url_suffix=${escape:$1?%{QUERY_STRING}} [L,PT]

注:这里的int不是intger的意思,它是internal的缩写,表示调用内部函数。

看上去非常简单,跑起来貌似也正….常?且慢,俺打开RewriteLog一瞅,形式不容乐观啊,”&”字符通通没有转义。看来是失败了,爬到狗狗上翻了一下,貌似escape对”?=”之类的特殊字符是不做转义的,晕。

RewriteMap到底

接着细看apache的rewrite手册,发现RewriteMap还支持自定义脚本,那么还得使出俺的看家绝技——php了。首先弄一个能转义的php,必须非常简单,复杂了apache容易挂掉,写出来发现想复杂都挺难啊:

/usr/local/bin/escape.php

#!/usr/bin/php -f
<?php
while($in = trim(fgets(STDIN)))
        fputs(STDOUT, urlencode($in) . "\r\n");
?>

在这个脚本里可别使用php:://stdin之类的,具体原因查php手册。相应的,rewrite规则如下:


RewriteMap escape prg:/usr/local/bin/escape.php
RewriteRule ^/([^/]*)$ /newpage.php?mi_url_suffix=${escape:$1?%{QUERY_STRING}} [L,PT]

rewrite规则没有太大的改变,prg表示使用自定义脚本。现在这个版本总算正常运作了。

ubuntu下安装php5 + pdo

这几天尝试把工作机迁到ubuntu上来做开发,系统安装好之后的首要任务是安装php+mysql的开发环境. 我打算直接安装php5, pdo_mysql, 下面是安装过程的记录

首先我直接用apt-get安装了apache2,php5,pear以及mysql5, 为了方便后续的安装,还加上了make和libmysqlclient

  • sudo apt-get install apache2-mpm-prefork
  • sudo apt-get install php5
  • sudo apt-get install php5-dev
  • sudo apt-get install php5-pear
  • sudo apt-get install mysql-server-5.0
  • sudo apt-get install make
  • sudo apt-get install libmysqlclient15-dev

pdo在ubuntu的apt里头似乎还找不到安装源,所以通过pecl来安装这个扩展,非常简单 —- 如果海底光纤能连通的话:

pecl install pdo

增加一行:

extension=pdo.so

到文件:

/etc/php/apache2/php.ini
/etc/php/cli/php.ini

接下来安装pdo_mysql碰到一些问题, 直接跑pecl install pecl_mysql会出现一些错误,搜索了一下发现是pecl本身的问题,下面是个比较简单的解决办法:

wget http://pecl.php.net/get/PDO_MYSQL-1.0.2.tgz
tar xzvf PDO_MYSQL-1.0.2.tgz
cd PDO_MYSQL-1.0.2

注释掉configure里头判断是否已经安装pdo扩展的代码片段,继续跑:

phpize
./configure
make
make install

然后再次添加下面一行到前面提到的两个php.ini

extension=pdo_mysql.so

重启apache之后, php5 + pdo_mysql就在ubuntu上安装好了, documentroot是/var/www

后记

更简单的解决办法是运行:

PHP_PDO_SHARED=1 pecl install pdo_mysql

http_load的使用

记得前些天介绍了一个幻灯——Getting Rich with PHP 5(IE之外的浏览器可看,见用php5来赚大钱),这个幻灯向我们展示了php程序优化的一些技巧,其中命令行工具http_load给我留下很深的印象,这工具看上去和apache的ab很相似,用来做网站的压力测试。昨天在服务器上安装http_load并试用了一段时间,下面是我的一点学习心得。

测试网站每秒所能承受的平均访问量

http_load -parallel 5 -fetches 1000 urls.txt

这段命令行是同时使用5个进程,随机访问urls.txt中的网址列表,总共访问1000次。运行之后的结果:

1000 fetches, 5 max parallel, 6e+06 bytes, in 58.1026 seconds
6000 mean bytes/connection
17.2109 fetches/sec, 103266 bytes/sec
msecs/connect: 0.403263 mean, 68.603 max, 0.194 min
msecs/first-response: 284.133 mean, 5410.13 max, 55.735 min
HTTP response codes:
code 200 — 1000

从上面的运行结果来看,目标网站仅仅能够承受每秒17次访问,不够强壮。

测试网站是否能承受住预期的访问压力

http_load -rate 2 -seconds 300 urls.txt

在300秒内保持一定的频率访问目标url。

注:

  • urls.txt保存要访问的url列表,每行一个
  • 不要测试上线之后的网站,压垮了可不好玩

用php简单实现Search Engine Friendly的URL

上次写了Search Engine Friendly的URL设计 – 俺在这个事上面折腾,要实现这个 http://www.myhost.com/foo.php?a=A&b=B&c=C -> http://www.myhost.com/foo.php/a/A/b/B/c/C的url转换,实际上还有不同的办法.

比如说我用的是虚拟主机,也想实现url优化,但是我没有服务器权限,这时候可以从PATH_INFO来下手.

访问http://www.myhost.com/foo.php/a/A/b/B/c/C这个url的时候,如果apache的AllowPathinfo已经打开,用php访问$_SERVER[‘PATH_INFO’]可以获得a/A/b/B/c/C这串字符 这时候再用php加以解析:

if(!empty($_SERVER['PATH_INFO'])) {
 $paths = explode('/', substr($_SERVER['PATH_INFO'], 1));
 for($i = 0, $cnt = count($paths); $i < $cnt; $i++)
  $_GET[$paths[$i]] = @(string)$paths[++$i];
}

这样就可以简单的将PATH_INFO转换为全局的$_GET数组,这样还有个好处

  • http://www.myhost.com/foo.php?a=A&b=B&c=C
  • http://www.myhost.com/foo.php/a/A/b/B/c/C
  • 上面的url同时可以访问,保证了通用性 

    php + xapian extension的安装

    版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明

    xapian是啥玩意?

    xapian 是一个“Xapian 是一个开源概率论信息检索库,基于GPL发布。它是用C++编写的,提供的绑定可以支持其它语言(支持Perl, Python, PHP, Java, and TCL )的开发。 Xapian 设计为一个高度可适应的工具集,可以让开发人员方便地为他们自己的应用程序增加高级索引和搜索功能。”

    在网上找到这段介绍后,俺手痒痒就想试试xapian —- 一定要给php整个这东东上去.参考了若干文档以后,这就开始动手了(我的环境仍然是freebsd + apache 2.2 + php 5.1.2,apache和php原来就已经安装好):

    1.下载xapian

    cd /usr/local/src
    wget http://www.oligarchy.co.uk/xapian/0.9.4/xapian-core-0.9.4.tar.gz
    wget http://www.oligarchy.co.uk/xapian/0.9.4/xapian-bindings-0.9.4.tar.gz

    前者是xapian的核心lib代码,后者是给其它语言调用的接口

    2.安装Xapian-core

    cd /usr/local/src
    tar xzvf xapian-core-0.9.4.tar.gz
    cd xapian-core-0.9.4
    ./configure –prefix=/usr/local/xapian
    make
    make install

    3.安装Xapian-bindings

    cd /usr/local/src
    tar xzvf xapian-bindings-0.9.4.tar.gz
    cd xapian-bindings-0.9.4
    ln -s /usr/local/xapian/bin/xapian-config /usr/local/bin/xapian-config #这里需要做个软连接,编译的时候需要用到
    ./configure –without-python #我没用到python,就不编译了
    make
    make install

    进行到这一步,Xapian-bindings应该算是安装好了,但是不知道为何,编译好的xapian.so没有按说明文档所说的自动复制到php的extension目录,于是我手工完成这一步骤

    cp php/.libs/xapian.so /usr/local/lib/php #/usr/local/lib/php是我在php.ini设置的extension目录

    然后修改php.ini
    extension_dir = “/usr/local/lib/php/” #没有就加上
    extension=xapian.so

    安装全部完成,重启apache看看phpinfo:
    php + xapian extension
    一切ok:)

    php + clucene extension的安装

    版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明

    CLuceneSF上面的一个对Lucene(一个用Java写的全文检索引擎工具包)的移植,做为Lucene的C++的重新实现,以带来更快的检索速度,但是一直还不stable.这里仅仅是尝试php+clucene扩展的安装,具体应用先不管.

    安装环境:
    Freebsd 6.0 + apache 2.2 + php 5.1.2

    apache+php的安装就不说了,网上一抓一大把,注意clucene扩展必须在php5以上才能安装.

    • 首先安装clucene

    1.下载clucene
    直奔它的首页–clucene.sourceforge.net,下载clucene 0.9.10
    2.编译clucene

    tar xzvf clucene-0.9.10.tar.gz
    cd clucene-0.9.10
    ./autogen.sh
    ./configure
    make

    这样clucene就安装好了,为了让其它程序可以调用clucene,这里把编译好的lib放到系统lib目录下

    cp src/.libs/libclucene.* /usr/local/lib
    cp src/CLucene.h /usr/local/include/
    cp -r src/CLucene /usr/local/include/

    • 安装clucene php extension

    1.下载clucene php extension
    在pecl.php.net有下载,拖回来就是
    http://pecl.php.net/package/clucene

    2.编译clucene php extension

    tar xzvf clucene-0.0.9.tgz
    cd clucene-0.0.9
    cp -r /usr/local/include/Clucene include/  #编译时要把clucene的include文件弄一份
    cp -r /usr/local/include/Clucene.h include/ 
    phpize
    ./configure
    make

    编译完成,这里会生成一个clucene.so,我们把它放在php的extension目录下(没有就建一个),然后修改php.ini

    加入
    extension=clucene.so

    重启apache之后看phpinfo

    php+clucene

    至此安装就算完成了,demo嘛在examples目录下有一个,命令行调用方式(根据已有的index检索):
    php clucene.php “Your query”

    BTW:新出的zend framework也有lucene模块,但是功能还不完善,现在0.1.2好像只能建立索引,检索功能尚在开发中

    Search Engine Friendly的URL设计 – 俺在这个事上面折腾

    最近的某个项目需要配合seo,改进php动态页面的url,这里首先参考了车东的
    如何提高在Google中的排名(3) —— Search Engine Friendly的URL设计

    其中有一段url rewrite的例子比较符合要求且改动最少:

    一个更通用的能够将所有的动态页面进行参数映射的表达式是:
    http://www.myhost.com/foo.php?a=A&b=B&c=C
    表现成
    http://www.myhost.com/foo.php/a/A/b/B/c/C
    RewriteRule (.*?\.php)(\?[^/]*)?/([^/]*)/([^/]*)(.+?)? $1(?2$2&:\?)$3=$4?5$5: [N,I]

    这段例子我在自家的apache上操练了很久,反复的调试,修改httpd.conf,查看error.log,rewrite.log,失败的一塌糊涂,几乎让我产生巨大的挫败感.后来查看了apache手册的rewrite指南,发觉里面根本没有[N,I]这个I flag,这下终于明白,这个rewrite规则8成是在IIS上面适用,IIS和apache向来是世仇,通用就甭考虑了.这里又去麻烦网管大哥,讨得下面这段rewrite规则,基本满足需求:

    RewriteEngine on
    RewriteMap quux-map prg:/root/t.sh
    RewriteRule ^/(.*)\.php/(.*) /$1.php?${quux-map:$2}

    cat t.sh

    #!/bin/sh

    LOGFILE=/tmp/percent_rewrite.log
    cat /dev/null > $LOGFILE

    while read URL
    do
    NEWURL=$(echo “$URL” | sed -e ‘s/\([^/]*\)\/\([^/]*\)\//\1=\2\&/g’ | sed ‘s/[/&]$//’ | sed ‘s/\//=/’ )
    echo “Changing $URL to $NEWURL” >> $LOGFILE
    echo $NEWURL

    apache的rewrite – 代理吞吐(Proxy Throughput)功能

    今天尝试使用apache的rewrite作为ajax跨域调用代理,要用到rewrite的Proxy Throughput功能.翻看apache手册,看上去不算太复杂,只要用flag

    [P]就可以

    映射远程页面甚至整个远程网络区域到自己的名称空间.照着手册上写了个配置:

    RewriteEngine On
    RewriteRule ^/proxy/(.*)$ http://$1 [P,L]

    我想通过上面的url重写达到这样的效果,使用代理功能访问http://www.mysite.com/proxy/www.destsite.com,自动使用代理访问www.destsite.com, url不改变.重启apache后,进行测试,始终是无法访问,于是开启rewrite日志:

    RewriteLogLevel 9
    RewriteLog logs/rewrite.log

    日志中显示已经正确转向到www.destsite.com,但是仍然无法访问.郁闷的很,找这边的网管大哥讨教,被告知要开启proxy功能,否则rewrite的Proxy Throughput功能无法使用.于是修改httpd.conf,加入两行:

    LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_http_module modules/mod_proxy_http.so

    重启apache测试,一切ok

    apache的rotatelogs使用手记

    今天妄图使用apache的rotatelogs来回卷Apache日志,翻看手册,很简单

    CustomLog “|bin/rotatelogs /var/logs/logfile 86400” common

    我需要两个小时生成一个apache日志,并以时间命名,于是依样画葫芦修改httpd.conf

    CustomLog “|bin/rotatelogs /var/logs/%Y%m%d%H.logfile 7200” common

    重启apache失败,说明葫芦不能照着画:

    CustomLog “|/usr/local/httpd/bin/rotatelogs /var/logs/%Y%m%d%H.logfile 7200” common

    修改后apache成功启动,但是生成的日志文件名(以小时命名)有些问题,与服务器时间相差8小时,仔细查看手册,原来是rotatelogs的使用有些机关(有个offset参数,单位是分钟)

    CustomLog “|/usr/local/httpd/bin/rotatelogs /var/logs/%Y%m%d%H.logfile 7200 480” common

    重启后收工

    附rotatelogs说明

    rotatelogs logfile [ rotationtime [ offset ]] | [ filesizeM ]

    选项
    logfile
    它加上基准名就是日志文件名。如果logfile中包含’%’,则它会被视为用于的strftime(3)的格式字串;否则,它会被自动加上以秒为单位的.nnnnnnnnnn后缀。这两种格式都表示新的日志开始使用的时间。
    rotationtime
    日志文件回卷的以秒为单位的间隔时间
    offset
    相对于UTC的时差的分钟数。如果省略,则假定为0,并使用UTC时间。比如,要指定UTC时差为-5小时的地区的当地时间,则此参数应为-300。
    filesizeM
    指定回卷时以兆字节为单位的后缀字母M的文件大小,而不是指定回卷时间或时差。

    fedora 4下面安装apache+php5无法启动

    今天在fedora 4下面安装按常规步骤安装apache+php5,无法启动。

    输入apacheclt start后显示:

    modules/libphp5.so: cannot restore segment prot after reloc: Permission denied

    google之,找到了原因:
    https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=153146

    That error is from selinux which was apparently supposed to be fixed to complain
    like that (rh#147806#). Though the real problem is that libicudata is supposed
    to be compiled with -fpic, which was also supposed to be fixed. I see now that
    the upsteam patch is b0rked.

    原来是selinux安装包惹的祸,升级后apache正常启动:
    yum update selinux-policy-targeted