在osx上使用MySQL native driver for PHP

昨天处理摄影频道的产品样片时,发现自己osx上的php5没有启用exif,哎,以前的linux的脚本都有的,不知道怎么回事,port到mac时遗漏了。原以为没什么问题,结果问题来了。编译到mysql ext的时候总是报错,大概意思是说mysqlclient(libmysql)的zlib和php编译的动态库版本不一致。奇怪啊,以前好好的。想了半天,原来之前用的是mysql4.1后来升级到mysql5,好像没有重新编译php。怎么解决呢?我以为是macports的问题,就重新把fink的zlib使用,还是无用。调整了可能的编译参数,没用。这下郁闷大了。搜了下,有人说mysql5.0.27的osx版本无法编译php,据说解决了,但是看我的情况还是不行。我也不能降级到mysql4,要么自己重新编译mysql5,要么想别的方法。我受不了那漫长的编译时间,突然想起上次在mysql.com上看到的mysql native driver for php,既然是native,那么就不依赖mysql的库,应该就不会有问题了。

看了看mysqlnd,发现好处是不少的,已经checkin到php6中了,而且php-5.3的特性投票中,它是排在第三,据一些用户的反馈,mysqlnd的速度要比libmysql的速度提升最多2倍,最令人兴奋的是persisten connection能用了,不知道效果如何,但如果真能用我也许可以不使用我的jdba中间件,至少有这可能性吧;此外内存的使用也少了很多。我的要求不高了,能马上用就好了。

编译的还是比较简单的,毕竟咱也轻车熟路这么多回了。

1.首先,要使用php 5.2.5的开发版,从snaps.php.net下,昨天的更新。

2.checkout 最新的mysqlnd的svn代码:

svn co http://svn.mysql.com/svnpublic/php-mysqlnd

3.将mysqlnd的代码合并到php source:

cd /usr/local/src/php-5.2.dev

rm -rf ext/mysql ext/mysqli

cp -R ../php-mysqlnd/trunk/php5/ext/mysql ext/mysql

cp -R ../php-mysqlnd/trunk/php5/ext/mysqli ext/mysqli

cp -R ../php-mysqlnd/trunk/mysqlnd ext/mysqlnd

rm ext/mysql/tests

rm ext/mysqli/tests

cp -R ../php-mysqlnd/trunk/tests/ext/mysql ext/mysql/tests

cp -R ../php-mysqlnd/trunk/tests/ext/mysqli ext/mysqli/tests

4../buildconf –force

5.修改compile.sh,增加mysqlnd的选项:


PATH=/opt/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/mysql/bin:/opt/Ice/bin ./configure \
--prefix=/usr/local/php5  \
--enable-force-cgi-redirect \
--enable-fastcgi \
--enable-ftp \
--enable-calendar \
--enable-gd-native-ttf \
--enable-mbstring \
--enable-mbstr-enc-trans \
--enable-mbregex \
--enable-shmod \
--enable-sockets \
--enable-sysvmsg \
--enable-sysvsem \
--enable-sysvshm \
--enable-inline-optimization \
--disable-ipv6 \
--disable-debug \
--with-config-file-path=/usr/local/php5/etc \
--with-config-file-scan-dir=/usr/local/php5/etc/php.d \
--with-zlib \
--with-curl \
--with-dom \
--with-dom-xslt \
--with-gd=/opt/local \
--enable-gd-native-ttf \
--with-jpeg-dir=/opt/local \
--with-png-dir=/opt/local \
--with-gettext \
--with-openssl=shared \
--with-mysql=mysqlnd \
--with-mysqli=mysqlnd \
--with-freetype-dir=/usr/X11R6 \
--with-iconv  \
--with-gettext=/opt/local \
--with-xml \
--with-kerberos \
--with-pcre-regex \
--enable-exif \
--with-mime-magic=/usr/share/file/magic.mime
make clean
make

4.make test

5.make install

6./usr/local/sbin/spawn-php5.sh restart

正如mysqlnd所描述的,它不是一个新的扩展,而是内部的,替换libmysql的,因此对于使用mysql php代码来说没有什么改变,
但是如果使用mysqli,则可以使用一些增强的函数,获得更好的特性,比如mysqli_fetch_all。我准备马上更新doggy,
增加一个mysqlnd_dba,这样可以充分享用这些新的特性。

关于PHP5 Static的实现 引发的一些问题,使用时要注意

这几天在将我的doggy框架移植到PHP5的时候发现了一些小问题,主要是PHP5的static的实现上和其他的OO语言有很大的不同。
先看一部分代码


class A{
    protected static $v='A';
    public static function getV(){
         return self::$v;
    }
    public static function setV($v){
         self::$v=$v;
    }
}
class B extends A{
    protected static $v='B';
}
class C extends B{
    protected static $v='C';
}
echo 'A::getV '.A::getV();
echo 'B::getV '.B::getV();
echo 'C::getV '.C::getV(); 


按通常的理解,应该是:


A::getV A
B::getV B
C::getV C

但输出的结果是:

A::getV A
B::getV A
C::getV A

再做个实验:

class A {
    protected static $v='A';
    public static function getV(){
         return self::$v;
    }
    public static function setV($v){
         self::$v=$v;
    }
}
class B extends A{
    protected static $v='B';
    public static function getV(){
         return self::$v;
    }
}
class C extends B{
    protected static $v='C';
}
echo 'A::getV '.A::getV();
echo 'B::getV '.B::getV();
echo 'C::getV '.C::getV(); 

猜猜结果是什么?

A::getV A
B::getV B
C::getV B

最后一个例子:



class A{
    protected static $v='A';
    public static function getV(){
         return self::$v;
    }
    public static function setV($v){
         self::$v=$v;
    }
}
class B extends A{
    protected static $v='B';
    public static function getV(){
         return self::$v;
    }
    public static function setV($v){
         self::$v=$v;
    }
}
class C extends B{
    protected static $v='C';
}
A::setV('C');
B::setV('D');
C::setV('E');

echo 'A::getV '.A::getV();
echo 'B::getV '.B::getV();
echo 'C::getV '.C::getV();

输出结果:


A::getV C
B::getV E
C::getV E


ok

看到这里应该清楚了,PHP5的static的实现比较“特别”,从手册里面也能看到说明。
static方法是编译时确定的,而不是按照调用时的继承关系来确定。
简单的说,当调用static方法时,其起始的范围是实现这个static方法(包括重载)的类范围,
而不是按照调用的继承关系的类。比如调B::getV(),如果B类中定义或者重载了getV,那么
此时确定的当前类就是B,否则向上追溯到其父类假设是A,如果A扔没有,继续向上查找,
一旦找到,那么当前类就是这个定义getV的类。此时self指向的就是这个确定的类,而不是
起始调用getMethod的那个class,因此,如果此时这个类假设为A没有定义static $v,则会引发一个错误。

PHP5的这种方式导致了很多困惑,尤其希望实现static重载的时候,你无法通过在父类定义通用
的方法,而试图通过子类override一些static field来实现static级别的继承。

我在用PHP5实现Active Record模式的时候遇到了这些问题,最后只能通过一些hack的手法来实现。

不知道PHP6是否能够改变这种方式,希望如此。

New:

PHP6中通过引入static::来实现late static binding,从而解决了这个问题。

[http://www.php.net/~derick/meeting-notes.html#late-static-binding-using-this-without-or-perhaps-with-a-different-name](http://www.php.net/~derick/meeting-notes.html#late-static-binding-using-this-without-or-perhaps-with-a-different-name)

BTW,Javascript/AS都是prototype-based,和php class-based是不一样的,
[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Class-Based_vs._Prototype-Based_Languages](http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Class-Based_vs._Prototype-Based_Languages)

Spawn PHP5/4 fastcgi on mac osx

下面是我使用的脚本,用于启动php5/4的fastcgi daemon,和linux 上使用的版本基本一样:


#!/bin/bash
#PID for SPAWN Process
PID=/tmp/php5-fcgi.pid
## ABSOLUTE path to the spawn-fcgi binary
SPAWNFCGI="/usr/local/bin/spawn-fcgi"

## ABSOLUTE path to the PHP binary
FCGIPROGRAM="/usr/local/php5/bin/php5"
#FCGIPROGRAM="/usr/local/bin/php"

## TCP port to which to bind on localhost
FCGIPORT="1026"
FCGISOCKET=/tmp/php5.socket
## number of PHP children to spawn
PHP_FCGI_CHILDREN=2

## maximum number of requests a single PHP process can serve before it is restarted
PHP_FCGI_MAX_REQUESTS=1000

## IP addresses from which PHP should access server connections
FCGI_WEB_SERVER_ADDRS="127.0.0.1,192.168.2.10,192.168.80.108"

# php.ini
PHPRC=/usr/local/php5/etc/php.ini

# allowed environment variables, separated by spaces
ALLOWED_ENV="ORACLE_HOME PATH USER"

## if this script is run as root, switch to the following user
USERID=www
GROUPID=www

ICE_HOME=/opt/Ice-3.2.0
export ICE_HOME
export DYLD_LIBRARY_PATH=$ICE_HOME/lib:$DYLD_LIBRARY_PATH
################## no config below this line

if test x$PHP_FCGI_CHILDREN = x; then
  PHP_FCGI_CHILDREN=5
fi

export PHP_FCGI_MAX_REQUESTS
export FCGI_WEB_SERVER_ADDRS
export PHPRC

ALLOWED_ENV="$ALLOWED_ENV PHP_FCGI_MAX_REQUESTS FCGI_WEB_SERVER_ADDRS PHPRC ICE_HOME DYLD_LIBRARY_PATH"

if test x$UID = x0; then
  if test x$FCGISOCKET = x; then
  EX="$SPAWNFCGI -p $FCGIPORT -f $FCGIPROGRAM -u $USERID -g $GROUPID -C $PHP_FCGI_CHILDREN -P $PID"
  else
  EX="$SPAWNFCGI -s $FCGISOCKET -f $FCGIPROGRAM -u $USERID -g $GROUPID -C $PHP_FCGI_CHILDREN -P $PID "
  fi
else
  if test x$FCGISOCKET = x; then
  EX="$SPAWNFCGI -p $FCGIPORT -f $FCGIPROGRAM -C $PHP_FCGI_CHILDREN -P $PID "
  else
  EX="$SPAWNFCGI  -s $FCGISOCKET -f $FCGIPROGRAM -C $PHP_FCGI_CHILDREN -P $PID"
  fi
fi

# copy the allowed environment variables
E=

for i in $ALLOWED_ENV; do
  E="$E $i=${!i}"
done

# clean the environment and set up a new one
start(){
    if [ -f $PID ];then
        echo "PHP is running already.";
        exit 1;
    fi
   env - $E $EX
}
stop(){
    if test -f $PID;then
        killall `basename $FCGIPROGRAM`
        rm -f $PID
    else
        echo "PHP is not running"
    fi
}

#Main################
case "$1" in
    'start')
    start
    ;;
    'stop')
    stop
    ;;
    'restart')
    stop
    start
    ;;
    *)
    echo "usage: $0 {start|stop|restart}"
    ;;
esac
exit 1

IcePHP导致PHP5 Crash

IcePHP3.2编译成功后就没有仔细看,昨天才发现,PHP5 FastCGI daemon不能启动,crash记录中显示:


Library not loaded: ../../lib/libIce.3.2.0.dylib
  Referenced from: /opt/IcePHP-3.2.0/lib/IcePHP.so
  Reason: image not found

应该是Ice的动态库无法找到,但是在bashrc中指定了libpath了。
今天又仔细看了一下,发现是在spawn-php5.sh中的问题,我使用了一个脚本来启动php5,
但是其中环境变量没有传递给php,虽然spawn-fcgi可以获得,但是php无法知道。
修改了一下这几行:

 ICE_HOME=/opt/Ice-3.2.0
 export ICE_HOME
 export DYLD_LIBRARY_PATH=$ICE_HOME/lib:$DYLD_LIBRARY_PATH
ALLOWED_ENV="$ALLOWED_ENV PHP_FCGI_MAX_REQUESTS FCGI_WEB_SERVER_ADDRS PHPRC ICE_HOME DYLD_LIBRARY_PATH"

重新启动Php5,正常。

Compile IcePHP 3.2 with PHP 5.2.3 on Mac Osx

IcePHP在Linux和Windows上似乎都很好编译,但是非常不幸,我用的是Macbook Pro :(
按照帮助配置了config/Make.rules, make 立刻报错,缺少Make.rules.Darwin, 晕啊,Zeroc似乎
不喜欢osx啊,还好发现Ice的源码中有Make.rules.Darwin,在Zeroc的forum上,有人直接复制了
过来,成功编译了IceRuby。以为可以,但是不幸的是,link的时候仍然报了一大堆错误。
看来没戏了,我想去forum发个贴问问,因为3.1还支持osx呢,3.2怎么就突然不支持了呢?
而且奇怪的是,3.1用phpize来autoconf的,但是3.2,则用了手写的Makefile。
ZeroC的forum真是难注册,竟然还需要人工审核才能发言。我等了1天,结果告知我没有被通过,
说是关于本人和使用项目的描述不清,让我重新注册。要被气死,求人不如求己,一气之下
自己写了一个compile.sh,直接用g++编译,管他什么Makefile,竟然link成功,嗯。
看来问题不大,应该是Make.rules.Darwin的问题。既然能用了,就不那么郁闷了,重新审视了
这个配置,嗯,由于是编译Ice使用的,直接用来编译PHP的shared module的确有问题,改了
几处地方,一切都ok了。

你可以在这里下载Makefile.rules.Darwin.

If you want build IcePHP 3.2 with PHP 5.2.x on Mac osx, you should need this file Make.rules.Darwin,
save into config dir under IcePHP source direcotry, then make again.

Make.rules.Darwin (compile IcePHP-3.2 on mac osx)

Icc 9 compile script for PHP5.2.3 on x86_64

默认的php脚本是无法在x86_64上面编译的。
此脚本适用于php5.2.x.

flags="-cxxlib-icc -i-static -unroll2 -O3 -no-prec-div -xP " \
CC=icc \
CXX=icpc \
CFLAGS="$flags" \
CXXFLAGS="$flags" \
./configure \
--prefix=/usr/local/php5  \
--with-libdir=lib64 \
--enable-force-cgi-redirect \
--enable-fastcgi \
--enable-ftp \
--enable-calendar \
--enable-gd-native-ttf \
--enable-mbstring \
--enable-mbstr-enc-trans \
--enable-mbregex \
--enable-shmod \
--enable-sockets \
--enable-sysvmsg \
--enable-sysvsem \
--enable-sysvshm \
--enable-inline-optimization \
--disable-ipv6 \
--disable-debug \
--with-config-file-path=/usr/local/php5/etc \
--with-config-file-scan-dir=/usr/local/php5/etc/php.d \
--with-zlib \
--with-curl \
--with-dom \
--with-dom-xslt \
--with-gd=/usr \
--enable-gd-native-ttf \
--with-jpeg-dir=/usr \
--with-png-dir=/usr \
--with-gettext \
--with-openssl=shared \
--with-mysql \
--with-freetype-dir=/usr \
--with-mysqli \
--with-iconv  \
--with-gettext \
--with-xml \
--with-kerberos \
--with-pcre-regex \
--with-mime-magic=/usr/share/file/magic.mime
make clean
make

Php4/Php5 compile script on mac osx

我的编译脚本:

PHP4:

PATH=/usr/local/bin:/sw/bin:/usr/local/mysql/bin:/usr/bin:/bin ./configure \
--prefix=/usr/local/php4  \
--enable-force-cgi-redirect \
--enable-fastcgi \
--enable-ftp \
--enable-calendar \
--enable-gd-native-ttf \
--enable-mbstring \
--enable-mbstr-enc-trans \
--enable-mbregex \
--enable-shmod \
--enable-sockets \
--enable-sysvmsg \
--enable-sysvsem \
--enable-sysvshm \
--enable-inline-optimization \
--disable-ipv6 \
--disable-debug \
--with-config-file-path=/usr/local/php4/etc \
--with-config-file-scan-dir=/usr/local/php4/etc/php.d \
--with-zlib \
--with-curl \
--with-dom \
--with-dom-xslt \
--with-gd=/sw \
--enable-gd-native-ttf \
--with-jpeg-dir=/sw \
--with-png-dir=/sw \
--with-gettext \
--with-openssl=shared \
--with-mysql=/usr/local/mysql \
--with-freetype-dir=/usr/X11R6 \
--with-iconv=/usr  \
--with-gettext=/sw \
--with-xml \
--with-kerberos \
--with-pcre-regex \
--with-mime-magic=/usr/share/file/magic.mime
make clean
make
make test && make install

PHP5:

PATH=/usr/local/bin:/sw/bin:/usr/local/mysql/bin:/usr/bin:/bin ./configure \
--prefix=/usr/local/php5  \
--enable-force-cgi-redirect \
--enable-fastcgi \
--enable-ftp \
--enable-calendar \
--enable-gd-native-ttf \
--enable-mbstring \
--enable-mbstr-enc-trans \
--enable-mbregex \
--enable-shmod \
--enable-sockets \
--enable-sysvmsg \
--enable-sysvsem \
--enable-sysvshm \
--enable-inline-optimization \
--disable-ipv6 \
--disable-debug \
--with-config-file-path=/usr/local/php5/etc \
--with-config-file-scan-dir=/usr/local/php5/etc/php.d \
--with-zlib \
--with-curl \
--with-dom \
--with-dom-xslt \
--with-gd=/sw \
--enable-gd-native-ttf \
--with-jpeg-dir=/sw \
--with-png-dir=/sw \
--with-gettext \
--with-openssl=shared \
--with-mysql=/usr/local/mysql \
--with-mysqli \
--with-freetype-dir=/usr/X11R6 \
--with-iconv=/usr  \
--with-gettext=/sw \
--with-xml \
--with-kerberos \
--with-pcre-regex \
--with-mime-magic=/usr/share/file/magic.mime 

make clean
make test && make install

Lighttpd php4/php5 conf:


$HTTP["url"] =~ "\.php$" {
    proxy-core.balancer = "round-robin"
    proxy-core.protocol = "fastcgi"
    proxy-core.allow-x-sendfile = "enable"
  #  proxy-core.backends = ( "unix:/tmp/php4.socket" )
    proxy-core.backends = ( "unix:/tmp/php5.socket" )
    proxy-core.max-pool-size = 2
    proxy-core.rewrite-request=(
            "_pathinfo"=>("\.php(/.*)" =>"$1" )
    )
}

note:如果没有rewrite则无法支持path_info

xcache导致php segfault

郁闷了n天的php segfault,今天终于让我抓到了元凶: xcache.
不论是s1还是s8,php的fastcgi始终会segfault。在blog上的频率最高。
今天查看xcahce的tickets,发现有xcache导致segault的例子。我突然想,
俺们是不是也一样呢。
关键是要重现segfault,嗯,如果是xcache的问题,那么在高负载下应该能够重现,
因为它就是用于缓冲opcode的。
用ab测试,很快segfault频频出现,又把xcache禁用,ab再次测试,没有segfault。
ok,原因找到了,这个错误在xcache的1.2dev中曾经被closed,但是最近又被reopen了,
看来要等作者修复完了再重新考虑xcache了。
现在的替代就是使用zend optimizer,测试了一下,没有什么问题。

Firefox Extension for PHP Development

一个Firefox plugin,可以查看当前php运行的信息,可以把一些调试,profile信息发送的firebug的终端,这样即可以输出一些调试信息又可以不用影响页面,套用apple的宣传语:

**firephp,firebug,天生一对**

看来为此,我需要为这个写一个logger的adpater了呵呵

* [在这里下载FirePHP:http://www.firephp.org/](http://www.firephp.org/)
* [Terry的一篇文章,介绍了FirePHP到底是什么](http://terrychay.com/blog/article/clever-http.shtml) 说实话,我看firephp的那些screenshot还真不知道到底是做什么的

支持ETag的PHP的SendFile

在动态生成缩略图的时候,需要用PHP把生成缩略图的文件输出,此外,很多时候把文件放在browser不能直接访问的地方,用php代理,最常见的做法是read文件,echo出去,但是这样会白白浪费带宽,此外,也无法使用squid的负载缓存。昨晚实现了一个判断ETag的方法,本来还想实现断点续传,太困就没有继续,原理也简单,只要判断一下IF-RANGE,然后fseek到指定位置,读出,echo出去就ok了,等有空了再完善,现在这个是用于缩略图的,不支持多点续传也无所谓了。
Read more

« Previous PageNext Page »