搭建前后端web生产环境(Apache + Nginx + PHP + Memcached)

前言:谈到Linux下的web生产环境,大家就会想到apache这个开源服务器软件.apache可以整合 大多数应用,比如jsp,php,cgi,python等等,但是apache过于臃肿以及对静态文件响应过于缓慢让很多使用者感到头疼.而nginx作 为新崛起的服务器软件,在很多方面超出apache,定位也很明确:高性能的 HTTP 和反向代理服务器.因而,本篇主要讲的是nginx作为前端,apache作为后端的应用环境搭建过程.

 

为什么使用nginx+php(fastcgi)作为生产环境?

  1. php(fastcgi)不够稳定,容易出现50x错误,在生成相对复杂的页面时没有优势,长时间占用也会使php-cgi进程死去.
  2. 在安全性,多用户多站点的权限问题比较严重.php(fastcgi)在应对多用户多站点往往捉襟见肘,不易于实施.
  3. 整合其他语言,apache表现得游刃有余.资源利用恰到好处.

 

为 什么采用nginx做前端,apache作为后端的方案?nginx在处理静态内容上较apache是几倍或几十倍的差异,因而放在前面过滤静态内容是最 为恰当的.同时nginx也是一个负载均衡器,低资源消耗,高性能转发是它的特点.经过nginx在前面的过滤,后端的apache需要处理的内容相对就 比较少了.只需负责处理动态内容就可以了.在性能与稳定性的权衡下,使用nginx+apache搭配会让它们在各自擅长的领域展现自身的价值.
 

本教程以CentOS 5.4 32bit为环境.其他Linux发行版本暂未测试.nginx,php,apache,mysql,pureftpd均为最新稳定版.

 

获取操作系统源更新.

yum update
yum -y install gcc gcc-c++ bison patch unzip mlocate flex wget automake autoconf gd cpp gettext readline-devel libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel curl curl-devel e2fsprogs e2fsprogs-devel libidn libidn-devel openldap openldap-devel openldap-clients openldap-servers nss_ldap expat-devel libtool libtool-ltdl-devel

 

如果系统默认安装了apache,请先卸载.执行:

yum remove httpd

 

下载最新稳定版的程序源码包,以下都是到官方网站或sourceforge下载的源码包.

cd /usr/local/src
wget http://dev.mysql.com/get/Downloads/MySQL-5.1/mysql-5.1.45.tar.gz/from/http://mysql.he.net/
wget http://www.apache.org/dist/httpd/httpd-2.2.15.tar.gz
wget http://stderr.net/apache/rpaf/download/mod_rpaf-0.6.tar.gz
wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.13.1.tar.gz
wget http://sourceforge.net/projects/mcrypt/files/Libmcrypt/2.5.8/libmcrypt-2.5.8.tar.bz2/download
wget http://sourceforge.net/projects/mcrypt/files/MCrypt/2.6.8/mcrypt-2.6.8.tar.gz/download
wget http://sourceforge.net/projects/mhash/files/mhash/0.9.9.9/mhash-0.9.9.9.tar.bz2/download
wget http://www.php.net/get/php-5.2.13.tar.gz/from/this/mirror
wget http://www.lancs.ac.uk/~steveb/patches/php-mail-header-patch/php5-mail-header.patch
wget http://pecl.php.net/get/memcache-2.2.5.tgz
wget http://bart.eaccelerator.net/source/0.9.6/eaccelerator-0.9.6.tar.bz2
wget ftp://ftp.imagemagick.org/pub/ImageMagick/ImageMagick.tar.gz
wget http://pecl.php.net/get/imagick-2.3.0.tgz
wget http://download.suhosin.org/suhosin-0.9.29.tgz
wget http://downloads2.ioncube.com/loader_downloads/ioncube_loaders_lin_x86.tar.gz
wget http://downloads.zend.com/optimizer/3.3.9/ZendOptimizer-3.3.9-linux-glibc23-i386.tar.gz
wget http://monkey.org/~provos/libevent-1.4.13-stable.tar.gz
wget http://memcached.googlecode.com/files/memcached-1.4.4.tar.gz
wget http://sourceforge.net/projects/pcre/files/pcre/8.01/pcre-8.01.tar.gz/download
wget http://nginx.org/download/nginx-0.7.65.tar.gz
wget http://download.pureftpd.org/pub/pure-ftpd/releases/pure-ftpd-1.0.28.tar.gz

 
 

一.安装Mysql.安装最新稳定版5.1.45版本,并没有采用最新开发版.

groupadd mysql -g 27
useradd mysql -u 27 -g 27 -c “MySQL Server” -d /var/lib/mysql -m
cd /usr/local/src
tar -zxf mysql-5.1.45.tar.gz
cd mysql-5.1.45
./configure –prefix=/usr/local/mysql –localstatedir=/var/lib/mysql –with-unix-socket-path=/var/lib/mysql/mysql.sock –with-mysqld-user=mysql –enable-assembler –enable-thread-safe-client –with-extra-charsets=all –with-big-tables –with-readline –with-ssl –with-embedded-server –enable-local-infile –with-plugins=partition,innodb_plugin,myisam,myisammrg
make && make install
cd ../

cp /usr/local/mysql/share/mysql/my-medium.cnf /etc/my.cnf
/usr/local/mysql/bin/mysql_install_db –user=mysql
chown -R mysql.mysql /var/lib/mysql
chgrp -R mysql /usr/local/mysql/.
cp /usr/local/mysql/share/mysql/mysql.server /etc/init.d/mysql
chmod u+x /etc/init.d/mysql
chkconfig –level 345 mysql on
echo “/usr/local/mysql/lib/mysql” >> /etc/ld.so.conf
echo “/usr/local/lib” >>/etc/ld.so.conf
ldconfig
ln -s /usr/local/mysql/lib/mysql /usr/lib/mysql
ln -s /usr/local/mysql/include/mysql /usr/include/mysql
ln -s /usr/local/mysql/bin/mysql_config /usr/bin/mysql_config
service mysql start
/usr/local/mysql/bin/mysqladmin -u root password root
service mysql restart
service mysql stop

 
 

二.编译安装apache(httpd).apache的执行用户为nobody.

cd /usr/local/src
tar -zxf httpd-2.2.15.tar.gz
cd httpd-2.2.15
./configure –prefix=/usr/local/apache –enable-headers –enable-mime-magic –enable-proxy –enable-rewrite –enable-ssl –enable-suexec  –disable-userdir –with-included-apr –with-mpm=prefork –with-ssl=/usr –with-suexec-caller=nobody –with-suexec-docroot=/ –with-suexec-gidmin=100 –with-suexec-logfile=/usr/local/apache/logs/suexec_log –with-suexec-uidmin=100 –with-suexec-userdir=public_html
make
make install
mkdir /usr/local/apache/domlogs
cp /usr/local/apache/bin/apachectl /etc/init.d/httpd

 

1.编辑/etc/init.d/httpd,在首行#!/bin/sh下添加:

# Startup script for the Apache Web Server
#
# chkconfig: – 85 15
# description: Apache is a World Wide Web server.  It is used to serve \
#              HTML files and CGI.
# processname: httpd
# pidfile: /usr/local/apache/logs/httpd.pid
# config: /usr/local/apache/conf/httpd.conf

ulimit -n 1024
ulimit -n 4096
ulimit -n 8192
ulimit -n 16384
ulimit -n 32768

保存退出.

 

2.配置apache配置参数文件httpd.conf,位于/usr/local/apache/conf/目录

cd /usr/local/apache/conf/
mv httpd.conf httpd.conf.bak
mkdir vhosts
vi httpd.conf

输入以下内容:

上述虚拟主机配置中出现的127.0.0.1请改为你本机公网IP.

 
 

三.编译安装php(mod_php)

1.编译安装相关支持库

cd /usr/local/src
tar -zxf libiconv-1.13.1.tar.gz
cd libiconv-1.13.1/
./configure
make
make install

cd /usr/local/src
tar -jxf libmcrypt-2.5.8.tar.bz2
cd libmcrypt-2.5.8/
./configure
make
make install
/sbin/ldconfig
cd libltdl/
./configure –enable-ltdl-install
make
make install

cd /usr/local/src
tar -jxf mhash-0.9.9.9.tar.bz2
cd mhash-0.9.9.9/
./configure
make
make install

ln -s /usr/local/lib/libmcrypt.la /usr/lib/libmcrypt.la
ln -s /usr/local/lib/libmcrypt.so /usr/lib/libmcrypt.so
ln -s /usr/local/lib/libmcrypt.so.4 /usr/lib/libmcrypt.so.4
ln -s /usr/local/lib/libmcrypt.so.4.4.8 /usr/lib/libmcrypt.so.4.4.8
ln -s /usr/local/lib/libmhash.a /usr/lib/libmhash.a
ln -s /usr/local/lib/libmhash.la /usr/lib/libmhash.la
ln -s /usr/local/lib/libmhash.so /usr/lib/libmhash.so
ln -s /usr/local/lib/libmhash.so.2 /usr/lib/libmhash.so.2
ln -s /usr/local/lib/libmhash.so.2.0.1 /usr/lib/libmhash.so.2.0.1

cd /usr/local/src
tar -zxf mcrypt-2.6.8.tar.gz
cd mcrypt-2.6.8/
/sbin/ldconfig
./configure
make
make install

 

2.编译php,这里为php打入补丁.有助于防止邮件发送被滥用(多用户)以及在邮件中提供有价值的信息.补丁介绍信息请访问:http://www.lancs.ac.uk/~steveb/patches/php-mail-header-patch/

cd /usr/local/src
tar -zxf php-5.2.13.tar.gz
patch -d php-5.2.13 -p1 < php5-mail-header.patch
cd php-5.2.13
./configure –prefix=/usr/local –with-config-file-path=/etc –with-apxs2=/usr/local/apache/bin/apxs –enable-bcmath –enable-calendar –enable-exif –enable-ftp –enable-gd-native-ttf –enable-libxml –enable-magic-quotes –enable-mbstring –enable-pdo=shared –enable-soap –enable-sockets –enable-zip –with-bz2 –with-curl –with-curlwrappers –with-freetype-dir –with-gd –with-gettext –with-jpeg-dir –with-kerberos –with-libexpat-dir=/usr –with-libxml-dir=/usr –with-mcrypt=/usr –with-mhash=/usr –with-mysql=/usr –with-mysql-sock=/var/lib/mysql/mysql.sock –with-mysqli=/usr/bin/mysql_config –with-openssl=/usr –with-openssl-dir=/usr –with-pdo-mysql=shared –with-pdo-sqlite=shared –with-png-dir=/usr –with-sqlite=shared –with-ttf –with-xmlrpc –with-zlib -with-zlib-dir=/usr
make ZEND_EXTRA_LIBS=’-liconv’
make install
cp php.ini-dist /etc/php.ini

 

3.安装php扩展模块

cd /usr/local/src
tar -zxf memcache-2.2.5.tgz
cd memcache-2.2.5/
phpize
./configure –with-php-config=/usr/local/bin/php-config –with-zlib-dir –enable-memcache
make
make install

cd /usr/local/src
tar -jxf eaccelerator-0.9.6.tar.bz2
cd eaccelerator-0.9.6/
phpize
./configure –enable-eaccelerator=shared –with-php-config=/usr/local/bin/php-config
make
make install
mkdir -p /tmp/eaccelerator
chmod 777 /tmp/eaccelerator
echo “mkdir -p /tmp/eaccelerator” >> /etc/rc.local
echo “chmod 777 /tmp/eaccelerator” >> /etc/rc.local

cd /usr/local/src
tar -zxf ImageMagick.tar.gz
cd ImageMagick-*
./configure
make
make install

cd /usr/local/src
tar -zxf imagick-2.3.0.tgz
cd imagick-2.3.0/
phpize
./configure –with-php-config=/usr/local/bin/php-config
make
make install

cd /usr/local/src
tar -zxf suhosin-0.9.29.tgz
cd suhosin-0.9.29
phpize
./configure
make
make install

cd /usr/local/src
tar -zxf ioncube_loaders_lin_x86.tar.gz
cd ioncube
mkdir /usr/local/ioncube
mv ioncube_loader_lin_5.2.so /usr/local/ioncube/

cd /usr/local/src
tar -zxf ZendOptimizer-3.3.9-linux-glibc23-i386.tar.gz
mkdir -p /usr/local/Zend/lib/Optimizer-3.3.9/php-5.2.x
cp ZendOptimizer-3.3.9-linux-glibc23-i386/data/5_2_x_comp/ZendOptimizer.so /usr/local/Zend/lib/Optimizer-3.3.9/php-5.2.x/ZendOptimizer.so

 

3.1.修改php.ini.

查找/etc/php.ini中的extension_dir = “./”.将其修改为extension_dir = “/usr/local/lib/php/extensions/no-debug-non-zts-20060613/”
查找;include_path = “.:/php/includes”,删除前面的分号,并修改为include_path = “.:/usr/lib/php:/usr/local/lib/php”
跳到最后一行,然后添加以下内容:

extension = “memcache.so”
extension = “pdo.so”
extension = “pdo_mysql.so”
extension = “pdo_sqlite.so”
extension = “sqlite.so”
extension = “eaccelerator.so”
eaccelerator.shm_size = 32
eaccelerator.cache_dir = “/tmp/eaccelerator”
eaccelerator.enable = 1
eaccelerator.optimizer = 0
eaccelerator.debug = 0
eaccelerator.name_space = “”
eaccelerator.check_mtime = 1
eaccelerator.filter = “”
eaccelerator.shm_max = 0
eaccelerator.shm_ttl = 3600
eaccelerator.shm_prune_period = 3600
eaccelerator.shm_only = 0
eaccelerator.compress = 0
eaccelerator.compress_level = 9
eaccelerator.keys = shm
eaccelerator.sessions = shm
eaccelerator.content = shm

zend_extension = “/usr/local/ioncube/ioncube_loader_lin_5.2.so”
zend_extension = “/usr/local/Zend/lib/Optimizer-3.3.9/php-5.2.x/ZendOptimizer.so”

 

4,安装Memcached(可选)

cd /usr/local/src
tar -xzf libevent-1.4.13-stable.tar.gz
cd libevent-1.4.13-stable
./configure
make
make install
echo “/usr/local/lib/” > /etc/ld.so.conf.d/libevent.conf
ldconfig -v

cd /usr/local/src
tar -xzf memcached-1.4.4.tar.gz
cd memcached-1.4.4
./configure
make
make install

基本使用方法:

启动:/usr/local/bin/memcached -d -m 64 -p 11211 -u nobody -l localhost
关闭:killall -9 memcached

 
 

四.安装nginx

1.安装pcre库

cd /usr/local/src
tar -zxf pcre-8.01.tar.gz
cd pcre-8.01
./configure
make
make install

 

2.安装nginx

cd /usr/local/src
tar -zxf nginx-0.7.65.tar.gz
cd nginx-0.7.65
./configure –user=nobody –group=nobody –prefix=/usr/local/nginx –pid-path=/usr/local/nginx/logs/nginx.pid –error-log-path=/usr/local/nginx/logs/error.log –http-log-path=/usr/local/nginx/logs/access.log –http-client-body-temp-path=/tmp/nginx_client –http-proxy-temp-path=/tmp/nginx_proxy –http-fastcgi-temp-path=/tmp/nginx_fastcgi –with-http_stub_status_module
make
make install

 

2.1.添加init控制脚本

保存退出,给该文件赋予执行权限并设置开机启动

chmod 755 /etc/init.d/nginx
chkconfig –level 345 nginx on

 

2.2.修改nginx配置文件,位于:/usr/local/nginx/conf/目录

mkdir -p /var/cache/nginx/cached
chmod 600 /var/cache/nginx/cached
cd /usr/local/nginx/conf/
mv nginx.conf nginx.conf.bak
mkdir vhosts
vi nginx.conf

输入以下内容:

保存退出.

 
 

五.为apache安装rpaf模块,该模块用于apache做后端时获取访客真实的IP.

1.使用apxs安装模块.这里要使用此前apache编译安装后的apxs

cd /usr/local/src/
tar -zxf mod_rpaf-0.6.tar.gz
cd mod_rpaf-0.6
/usr/local/apache/bin/apxs -i -c -n mod_rpaf-2.0.so mod_rpaf-2.0.c

 

2.编辑/usr/local/apache/conf/httpd.conf,添加模块参数,查找LoadModule php5_module modules/libphp5.so,在下方添加:

LoadModule rpaf_module modules/mod_rpaf-2.0.so
#Mod_rpaf settings
RPAFenable On
RPAFproxy_ips 127.0.0.1 [your_ips]
RPAFsethostname On
RPAFheader X-Forwarded-For

上面出现的[your_ips]请修改为你本机所监听web服务的ip.多个IP用空格空开.

 
 

六.安装ftp服务器:pure-ftpd

1.编译安装

cd /usr/local/src/
tar -zxf pure-ftpd-1.0.28.tar.gz
cd pure-ftpd-1.0.28
./configure –prefix=/usr/local/pureftpd –with-language=simplified-chinese –with-everything
make
make install
chmod 755 configuration-file/pure-config.pl
cp configuration-file/pure-config.pl /usr/local/pureftpd/sbin/
mkdir /usr/local/pureftpd/etc/
cp configuration-file/pure-ftpd.conf /usr/local/pureftpd/etc/
ln -s /usr/local/pureftpd/bin/pure-pw /usr/local/bin/

 

2.配置pure-ftpd,这里采用PureDB的验证方式.

vi /usr/local/pureftpd/etc/pure-ftpd.conf

查找 PureDB /etc/pureftpd.pdb 取消前面的#号并设置成PureDB/usr/local/pureftpd/etc/pureftpd.pdb
查找 PassivePortRange 取消前面的#号
其他参数根据需要进行修改

 

3.添加自启动.这里不创建init脚本.直接放在/etc/rc.local启动即可

echo “/usr/local/pureftpd/sbin/pure-config.pl /usr/local/pureftpd/etc/pure-ftpd.conf –daemonize” >> /etc/rc.local

至此.所有安装工作结束.

 
 

如何使用这套系统

一,做好必要的安全工作

设置用户家目录/home/user,相关配置参数文件,以及访问日志等目录的权限.

chmod 711 /home
chmod 711 /usr/local/pureftpd/etc
chmod 711 /usr/local/apache/conf/vhosts
chmod 711 /usr/local/nginx/conf/vhosts
chmod 711 /usr/local/apache/domlogs
chmod 711 /usr/local/apache/logs
chmod 600 /var/cache/nginx/cached

 

二,如何创建用户

创建用户分两个步骤.第一步创建系统用户.该命令直接创建用户家目录.第二步创建ftp用户.创建该用户依赖系统用户的创建.步骤如下(以创建用户名为admin为例):

useradd admin -m -s /sbin/nologin
pure-pw useradd admin -u admin -g admin -d /home/admin -m[第一次执行不可用]
pure-pw mkdb[仅限第一次执行]

注意.通过上述方法安装的ftp服务器在第一次创建用户的时候不可以在pure-pw useradd …后直接添加参数-m更新ftp用户数据库.需要分两步执行.以后可以直接在创建用户时在后面添加参数-m,执行之后会提示让你输入密码.需要重复输入两次.

 

三.如何绑定域名

由于采用前后端操作.因此需要修改两个服务器软件的虚拟主机参数.实例如下(以admin.com为例,用户目录承接上文的/home/admin):

1.创建nginx虚拟主机参数

首先先把公共cache参数和proxy参数写进文件中

cd /usr/local/nginx/conf
touch cache.inc proxy.inc

然后分别编辑者两个文件。

vi cache.inc

proxy_cache       global;
proxy_cache_key   $host$uri$is_args$args;
#proxy_cache_valid 200 302 10m;
#proxy_cache_valid 301 1h;
#proxy_cache_valid any 1m;
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
proxy_temp_file_write_size 64k;
proxy_max_temp_file_size   56m;

vi proxy.inc

proxy_connect_timeout 30s;
proxy_send_timeout   300;
proxy_read_timeout   300;
proxy_buffer_size    64k;
proxy_buffers     16 32k;
proxy_busy_buffers_size 64k;
#proxy_pass http://127.0.0.1:81;
proxy_redirect  off;
proxy_hide_header  Vary;
proxy_set_header   Host   $host;
proxy_set_header   X-Real-IP  $remote_addr;
proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;

然后再编辑虚拟主机文件就会很清晰了

cd /usr/local/nginx/conf/vhosts
touch admin.com.conf
vi admin.com.conf
输入以下内容:

保存退出,注意将上述出现的127.0.0.1替换本机监听web服务的IP

 

2.创建apache虚拟主机配置文件

cd /usr/local/apache/conf/vhosts
touch admin.com.conf
vi admin.com.conf
输入以下内容:

保存退出,注意将上述出现的127.0.0.1替换本机监听web服务的IP,用户名admin改为虚拟主机用户的名称.

 
 

四.如何管理MySQL数据库

1.下载最新版PhpMyAdmin源码包

mkdir -p /var/www/html
chmod -R 711 /var/www
cd /var/www/html
wget http://sourceforge.net/projects/phpmyadmin/files/phpMyAdmin/3.3.3/phpMyAdmin-3.3.3-all-languages.zip/download
unzip phpMyAdmin-3.3.3-all-languages.zip
mv phpMyAdmin-3.3.3-all-languages phpmyadmin

 

2.增加apache配置,编辑httpd.conf,转到最后一行

cd /usr/local/apache/conf
vi httpd.conf /* shift+g转到最后一行 */
#Managed Tools
<VirtualHost 127.0.0.1:81 *>
ServerName localhost
ServerAlias pma.*
DocumentRoot /var/www/html/phpmyadmin
ServerAdmin admin@localhost
UseCanonicalName Off
</VirtualHost>

同样,修改上述出现的127.0.0.1为你提供web服务的IP.重启apache后.我们打开绑定到服务器IP的pma.yourdomain.com即可访问到phpmyadmin.第一次使用.需要进行配置.具体配置请善用Google.

其他没有照顾到的地方自行添加即可.如perl,sendmail等.

为方便管理员添加用户及绑定域名.我编写了一个脚本.

wget http://icodex.org/vhosts
chmod 755 vhosts
./vhosts

三大WEB服务器对比分析(Apache – Lighttpd – Nginx)

一.软件介绍(apache lighttpd nginx)

1. lighttpd

Lighttpd 是一个具有非常低的内存开销,cpu占用率低,效能好,以及丰富的模块等特点。lighttpd是众多OpenSource轻量级的web server中较为优秀的一个。支持FastCGI, CGI, Auth, 输出压缩(output compress), URL重写, Alias等重要功能。

Lighttpd使用fastcgi方式运行php,它会使用很少的PHP进程响应很大的并发量。

Fastcgi的优点在于:

· 从稳定性上看, fastcgi是以独立的进程池运行来cgi,单独一个进程死掉,系统可以很轻易的丢弃,然后重新分配新的进程来运行逻辑.

· 从安全性上看, fastcgi和宿主的server完全独立, fastcgi怎么down也不会把server搞垮,

· 从性能上看, fastcgi把动态逻辑的处理从server中分离出来, 大负荷的IO处理还是留给宿主server, 这样宿主server可以一心一意作IO,对于一个普通的动态网页来说, 逻辑处理可能只有一小部分, 大量的图片等静态IO处理完全不需要逻辑程序的参与(注1)

· 从扩展性上讲, fastcgi是一个中立的技术标准, 完全可以支持任何语言写的处理程序(php,java,python…)

 

2.apache

apache是世界排名第一的web服务器, 根据netcraft(www.netsraft.co.uk)所作的调查,世界上百分之五十以上的web服务器在使用apache.

1995 年4月, 最早的apache(0.6.2版)由apache group公布发行. apache group 是一个完全通过internet进行运作的非盈利机构, 由它来决定apache web服务器的标准发行版中应该包含哪些内容. 准许任何人修改隐错, 提供新的特征和将它移植到新的平台上, 以及其它的工作. 当新的代码被提交给apache group时, 该团体审核它的具体内容, 进行测试, 如果认为满意, 该代码就会被集成到apache的主要发行版中.

apache 的特性:

1) 几乎可以运行在所有的计算机平台上.

2) 支持最新的http/1.1协议

3) 简单而且强有力的基于文件的配置(httpd.conf).

4) 支持通用网关接口(cgi)

5) 支持虚拟主机.

6) 支持http认证.

7) 集成perl.

8) 集成的代理服务器

9) 可以通过web浏览器监视服务器的状态, 可以自定义日志.

10) 支持服务器端包含命令(ssi).

11) 支持安全socket层(ssl).

12) 具有用户会话过程的跟踪能力.

13) 支持fastcgi

14) 支持java servlets

 

3.nginx

Nginx 是俄罗斯人编写的十分轻量级的HTTP服务器,Nginx,它的发音为“engine X”, 是一个高性能的HTTP和反向代理服务器,同时也是一个IMAP/POP3/SMTP 代理服务器.Nginx是由俄罗斯人 Igor Sysoev为俄罗斯访问量第二的 Rambler.ru站点开发.

Nginx以事件驱动的方式编写,所以有非常好的性能,同时也是一个非 常高效的反向代理、负载平衡。其拥有匹配 Lighttpd的性能,同时还没有Lighttpd的内存泄漏问题,而且Lighttpd的mod_proxy也有一些问题并且很久没有更新。但是 Nginx并不支持cgi方式运行,原因是可以减少因此带来的一些程序上的漏洞。所以必须使用FastCGI方式来执行PHP程序。

nginx做为HTTP服务器,有以下几项基本特性:

处理静态文件,索引文件以及自动索引;打开文件描述符缓冲.

无缓存的反向代理加速,简单的负载均衡和容错.

FastCGI,简单的负载均衡和容错.

模块化的结构。包括gzipping, byte ranges, chunked responses,以及 SSI-filter等filter。如果由FastCGI或其它代理服务器处理单页中存在的多个SSI,则这项处理可以并行运行,而不需要相互等待。

Nginx专为性能优化而开发,性能是其最重要的考量,实现上非常注重效率。它支持内核Poll模型,能经受高负载的考验,有报告表明能支持高达 50,000个并发连接数。

Nginx 具有很高的稳定性。其它HTTP服务器,当遇到访问的峰值,或者有人恶意发起慢速连接时,也很可能会导致服务器物理内存耗尽频繁交换,失去响应,只能重启 服务器。例如当前apache一旦上到200个以上进程,web响应速度就明显非常缓慢了。而Nginx采取了分阶段资源分配技术,使得它的CPU与内存 占用率非常低。nginx官方表示保持10,000个没有活动的连接,它只占2.5M内存,所以类似DOS这样的攻击对nginx来说基本上是毫无用处 的。就稳定性而言,nginx比lighthttpd更胜一筹。

Nginx支持热部署。它的启动特别容易, 并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动。你还能够在不间断服务的情况下,对软件版本进行进行升级。

.3WEB服务器的比较:

server

Apache

Nginx

Lighttpd

Proxy代理

非常好

非常好

一般

Rewriter

非常好

一般

Fcgi

不好

非常好

热部署

不支持

支持

不支持

系统压力比较

很大

很小

比较小

稳定性

非常好

不好

安全性

一般

一般

技术支持

非常好

很少

一般

静态文件处理

一般

非常好

Vhosts虚拟主机

支持

不支持

支持

反向代理

一般

非常好

一般

Session sticky

支持

不支持

不支持

注: 在相对比较大的网站,节约下来的服务器成本无疑是客观的。而有些小型网站往往服务器不多,如果采用 Apache 这类传统 Web 服务器,似乎也还能撑过去。但有其很明显的弊端: Apache 在处理流量爆发的时候(比如爬虫或者是 Digg 效应) 很容易过载,这样的情况下采用 Nginx 最为合适。

建议方案:

Apache 后台服务器(主要处理php及一些功能请求 如:中文url)

Nginx 前端服务器(利用它占用系统资源少得优势来处理静态页面大量请求)

Lighttpd 图片服务器

总体来说,随着nginx功能得完善将使他成为今后web server得主流。

 

.性能测试

将分别测试3种软件在对动态页面和静态页面请求及并发时的响应时间

l 静态页面 搜狐首页

LIGHTTPD

n/-c(ab参数)

cpu%

Mem

RequestsperSecond

Time taken for tests

100000/100

64

60

462.75

21.6

100000/200

67

60

312.07

32.4

100000/500

83

60

137.24

72.8

100000/1000

出现错误丢包

94

60

126.6

78.9

NGINX

n/-c(ab参数)

cpu%

Mem

RequestsperSecond

Time taken for tests

100000/100

34.6

140

943.66

10.597

100000/200

35.6

110

924.32

10.818

100000/500

34.3

110

912.68

10.956

100000/1000

37

160

832.59

12.106

APACHE

n/-c(ab参数)

cpu%

Mem

RequestsperSecond

Time taken for tests

100000/100

40.6

170

690.72

14.47

100000/200

41.1

180

685.39

14.59

100000/500

42.3

190

633.64

15.78

100000/1000

43.1

200

547.53

18.26

l 动态页面 内部社区首页

LIGHTTPD

n/-c(ab参数)

cpu%

Mem

RequestsperSecond

Time taken for tests

1000/100

50

200

33.54

29.816

1000/200

52

210

30.43

32.858

1000/500

54

230

25.79

38.76

1000/1000

62

250

24.83

40.28

NGINX

n/-c(ab参数)

cpu%

Mem

RequestsperSecond

Time taken for tests

1000/100

53.8

250

83.12

12.305

1000/200

55.8

250

74.05

13.504

1000/500

56

260

58.99

16.951

1000/1000

58

260

43.41

23.347

APACHE

n/-c(ab参数)

cpu%

Mem

RequestsperSecond

Time taken for tests

100000/100

60

200

27.37

36.541

100000/200

61

220

23.82

41.981

100000/500

73

150

20.59

48.562

100000/1000

53

200

27.18

36.796

l PHPINFO函数页

LIGHTTPD

n/-c(ab参数)

cpu%

Mem

RequestsperSecond

Time taken for tests

100000/100

45

20

168.06

59.504

100000/200

47

22

140.64

71.103

100000/500

49

24

52.80

189.386

100000/1000

在请求到4840时测试测试程序死掉

NGINX

n/-c(ab参数)

cpu%

Mem

RequestsperSecond

Time taken for tests

100000/100

70

120

143.46

69.706

100000/200

72

130

140.57

71.140

100000/500

73

150

135.87

73.601

100000/1000

77

160

132.18

75.657

APACHE 出现丢包

n/-c(ab参数)

cpu%

Mem

RequestsperSecond

Time taken for tests

100000/100

70

180

245.73

40.694

100000/200

72

190

245.79

40.684

100000/500

75

200

241.29

41.443

100000/1000

77

220

236.74

42.239

四.各大网站WEB服务器资源列表

网站名 操作系统 web服务器

1.门户网站类:

搜狐 LINUX apache 1.3.37

新浪 LINUX apache 2.0.54

迅雷 LINUX nginx 0.6.31

163 LINUX apache 2.2.6

2.搜索类

百度 unknown BWS 1.0

Google linux gws

Sougou FreeBSD apache 2.2.4

Hao123 linux apache 2.2.4

4. 电子邮箱类

126 linux apache

Hotmail win2003 microsoft-IIS 6.0

新浪邮箱 F5 Big-IP apache 2.2.8

263 linux apache 2.2.6

5. 博客类

新浪博客 linux nginx 0.5.35

搜狐博客 linux nginx

迅雷博客 linux nginx 0.6.32

天涯博客 F5 Big-IP Microsoft-IIS/5.0

6.视频类

优酷 linux apache

土豆 linux apache

Ku6 linux apache

六间房 linux nginx 0.6.14

 
 
 

Lighttpd:单台支持上万并发;请求处理速度是Apache 的3-5 倍;对多CPU 支持不太好;有内存泄漏问题
典型范例-YouTube、Mop、SF、豆瓣
豆瓣如今很多lightty 也改为Nginx 了,留下图片服务器使用lighttpd。

Nginx(Engin X) 处理速度比Lighttpd 快10%-15%;在Proxy 方面,Nginx>Lighttpd;在FastCGI 支持方面,Lighttpd>Nginx;典型范例-六间房,新浪Blog

Apache 使用范围最广;在高负载环境下,性能不突出,单台仅能承受上千个并发数;对DOS(拒绝服务攻
击)抵御能力差;只有Apache 1.3 对FastCGI 有支持,不适合使用3P(PHP、Perl 和Python)的Web2.0 站点

如果是新兴的Web Server 2.0 站点,Lighttpd 和Nginx 凭借对FastCGI 的支持,和高负载下的良好表现,将会是最好的选择;如果是传统站点,Apache 是最通用的选择。

Yahoo!给出的34条网站加速方法

Yahoo给出的包括Yslow规则(22条)的34条 详细说明 ,通过这此规则对自己页面进行一次全面的分析优化,可以提高你网站的加载速度。

 

1.Minimize HTTP Requests 减少HTTP请求
图片、CSS、script、flash等等这些都会增加http请求数,减少这些元素的数量就能减少响应时间。把多个JS、CSS在可能的情况下写进一 个文件,页面里直接写入图片也是不好的做法,应该写进CSS里,利用 CSS sprites 将小图拼合后利用background来定位。

 

2.Use a Content Delivery Network 利用CDN技术
CDN 确实是好东西,8过服务器提供商的这项服务一般是要收费的,我以前买的国内空间是有这个的但是我当时根本不知道啥用,现在没了。。。

 

3.Add an Expires or a Cache-Control Header 设置头文件过期或者静态缓存
浏览器会用缓存来减少http请求数来加快页面加载的时间,如果页面头部加一个很长的过期时间,浏览器就会一直缓存页面里的元素。不过这样如果页面里的东西变动的话就要改名字了,否则用户端不会主动刷新,看自己衡量了~ 这项可以通过修改.htaccess文件来实现。

 

4.Gzip Components Gzip压缩
Gzip格式是一种很普遍的压缩技术,几乎所有的浏览器都有解压Gzip格式的能力,而且它可以压缩的比例非常大,一般压缩率为85%。压缩没压缩,可以到 这里 做下测试。

 

5.Put Stylesheets at the Top 把CSS放顶部
让浏览者能尽早的看到网站的完整样式。

 

6.Put Scripts at the Bottom 把JS放底部
网站呈现完毕后再进行功能设置,当然这些JS要在你的加载过程中不影响内容表现。

 

7.Avoid CSS Expressions 避免CSS Expressions
CSS表达式很可怕,这个只被IE支持的东西执行时候的运算量非常大,你移动一下鼠标它都要进行重计算的,但有时候为了做浏览器的兼容必须要用到这个||| IE6去死去死!~

 

8.Make JavaScript and CSS External 将JS和CSS外链
前面讲到了缓存这个事情,一些较为公用的JS和CSS,我们可以使用外链的形式,譬如我就是从Google外链来的Jquery文件,如果我的浏览者在浏览别的使用了这个外链文件的网站时已经下载并缓存了这个文件,那么他在浏览我的网站的时候就不需要再进行下载了!~

 

9.Reduce DNS Lookups 减少DNS查找
貌似是要减少网站从外部调用资源,我的Google分析和picasa的外链图片都算在里面了。

 

10.Minify JavaScript and CSS 减小JS和CSS的体积
写JS和CSS都是有技巧的,用最少的代码实现同样的功能,减少空白,增强逻辑性,用缩写方式等等,当然也有不少工具也能够帮你实现这一点。

 

11. Avoid Redirects 避免重定向
再写入链接时,虽然“http://www. today-s-ooxx. com”和“http://www. today-s-ooxx. com/” 仅有一个最后的“/”只差,但是结果是不同的,服务器需要花时间把前者重定向为后者然后进行跳转,这个要自己注意,也可以在Apache里用Alias 或者mod_rewrite或者DirectorySlash解决。

 

12. Remove Duplicate Scripts 删除重复脚本
重复调用的代码浏览器并不会识别忽略,而是会再次运算一遍,这当然是大大的浪费。

 

13. Configure ETags 配置ETags
搞不清楚咋回事,总之我是在. htaccess里把它删除了。

 

14. Make Ajax Cacheable 缓存Ajax
Ajax是实时响应的,在浏览器接收到新的数据前,旧的数据被缓存,这样能够更好的提高效率。

 

15. Flush the Buffer Early 尽早的释放缓冲
当用户进行页面请求时,服务器端需要花费200到500毫秒时间来拼合HTML,将写在head与body之间,释放缓冲,这样可以将文件头先发送出去,然后再发送文件内容,提高效率。

 

16. Use GET for AJAX Requests 用GET方式进行AJAX请求
Get 方法和服务器只有一次交互(发送数据),而 Post 要两次(发送头部再发送数据)。

 

17. Post-load Components 延迟加载组件
最先加载必须的组件进行页面初始化,然后再加载其他,YUI Image Loader 是很好的例子。

 

18. Preload components 预加载组件
提前加载以后可能用到的东西,和延迟加载并不冲突,它的目的是为后续请求提供更快的响应,参见Google首页上的CSS sprites应用。

 

19. Reduce the Number of DOM Elements 减少DOM元素数量
复杂的页面结构意味着更长的下载及响应时间,更合理更高效的使用标签来架构页面,是好的前端的必备条件。

 

20. Split Components Across Domains 跨域分离组件
页面组件多个来源可以增大你的平行下载量,但注意不要过多,超过2-4个域名会引起上面说到的DNS查找浪费。

 

21. Minimize the Number of iframes 减少iframe数量
需要更有效的利用 ifames。
iframe 优点:有利于下载缓慢的广告等第三方内容,安全沙箱,并行下载脚本
iframe 缺点:即使为空也会有较大资源消耗,会阻止页面的onload,非语义

 

22. No 404s 不要出现404页面
站点本身里(非搜索结果)出现404页面,无意义的404页面会影响用户体验并且会消耗服务器资源。

 

23. Reduce Cookie Size 减小Cookie
Cookie在服务器及浏览器之间的通过文件头进行交换,尽可能减小Cookie体积,设置合理的过期时间,能够很好的提高效率。

 

24. Use Cookie-free Domains for Components 对组件使用无Cookie的域名
对静态组件的Cookie读取是一种浪费,使用另一个无Cookie的域名来存放你的静态组件式一个好方法,或者也可以在Cookie中只存放带www的域名。

 

25. Minimize DOM Access 减少DOM的访问次数
JS访问DOM是很慢的,尽量不要用JS来设置页面布局。

 

26. Develop Smart Event Handlers 开发灵活的事件处理句柄
DOM树上过多的元素被加入事件句柄的话,反应效率肯定会低,YUI事件工具有一个 onAvailable 方法可以帮助你灵活的设置DOM事件句柄

 

27. Choose < link >over @import 使用< link >而非 @import
在IE中使用@import就和在页面底部用< link >一样,我们前面说要把< link >放顶部的。

 

28. Avoid Filters 避免过滤器的使用
如果需要Alpha透明,不要使用AlphaImageLoader,它效率低下而且只对IE6及以下的版本适用,用PNG8图片。如果你非要使用,加上_filter以免影响IE7+用户。

 

29. Optimize Images 优化图片
将你的GIF转为PNG8会是个减小体积的好办法,另外有很多方法处理你的JPG及PNG图片以达到优化效果。

 

30. Optimize CSS Sprites 优化CSS Sprites
在CSS Sprites中竖直并尽量紧凑的排列图片,尽量将颜色相似的图片排在一起,会减小图片本身的大小及提高页面图片显示速度。

 

31. Don’t Scale Images in HTML 不要在HTML中缩放图片
图片要用多大的就用多大的,1000X1000的图片被width=”100″ height=”100″以后,本身的KB数是不会减少的。

 

32. Make favicon. ico Small and Cacheable 缩小favicon. ico的大小并缓存它
站点的浏览器ICO应该不是经常换吧,那就长时间的缓存它,并且最好控制在1K以下。

 

33. Keep Components under 25K 保证组件在25K以下
iPhone不能缓存25K以上的组件,并且这还是要在被压缩前。

 

34. Pack Components into a Multipart Document 将组件打包进一个多部分的文档中
就好像在邮件中加入附件一样,一个HTTP请求就够了,但是这一技术需要确保你的代理支持,iPhone就不支持。

 
 

原文:http://developer.yahoo.com/performance/rules.html

JS游戏引擎列表

这里有一个网址收集了关于JS游戏引擎开发库的一个列表,转过来。关于使用JS和HTML5做的一些小游戏,可参见《HTML5 小游戏展示

游戏引擎

Name Latest Release License Type Notes
The Render Engine 1.5.3 MIT 跨浏览器; 大规模 API; 开源. 2
gameQuery 0.5.1 CC BY-SA 2.5 和 jQuery 一起使用
gTile 0.0.1 Tile based
Akihabara 1.3 GPL2/MIT Classic Repro 基于JS+HTML5的街机风格的游戏 3
The Javascript 2D Game Engine GPL 注重于重力、物理、碰撞检测方面,使用HTML5 Canvas 和IE的ExplorerCanvas 低CPU消耗. 4
The GMP Javascript Game Engine 1.7.4 (2010-10-31) GPL2/MIT 注重于数度的操作简化,”easy to learn and use” 5
Crafty 0.1 GPL/MIT 轻量级和模块化。 6
Effect Games
PropulsionJS 1.1 MIT 使用 HTML5 Canvas. 7
Flax Apache 2.0 还没有released。使用 GWT 和 HTML5。关注于Linux和Mac OS上的Web游戏开发。8
j5g3 GPLv3 还在开发过程中
cssgameengine 用于初学者。
jsGameSoup v74 LGPLv3
Javascript Gamelib 2.10
Sarien.net interpreter GPL 2D Adventure
jGen Isometric
Isogenic Engine Isometric
GammaJS 1.0 MIT 2.5D Platform
Tom’s Halls 3.0 Platform
Diggy BSD 基于 DHTML, 正在暂停中
Impact Commercial ($99) 2D
Rocket Engine Commercial
Aves Commercial?
Rosewood 2D
Cocos2D BSD 2D
GameJS MIT 2D CommonJs; 可以和 RingoJs server 整合,很像 PyGame; 仅支持Canvas;
xc.js BSD 2D
vegalib LPGL
ClanFX 0.0.1 Tile based
Canvex FPS
bdge Demo
js-verge 2D Demo
FlixelJS 2D Demo Port of Flixel (Flash) to JS. Announcement thread.
Unity3D Commercial (free version too) JS backend


3D 引擎

相比起成熟的游戏引擎来说,这些引擎没有包括诸如AI、声音、游戏逻辑、网络等等功能,不过,你可以使用别的一些JS库来辅助完成这些功能。

Name Latest Release License Notes
Pre3d Demo
three.js MIT
C3DL 2.1 (?) MIT
CopperLicht 1.3.2 (?)
JS3D 0.1a (2007-02-05) GPL
Sandy 3D 由Haxe编辑成 JS
O3D BSD
GLGE 0.5.2
SpiderGL

碰撞检测

动画

Name Latest Release License Notes
sprite.js VIEW Created with goal of having common JS framework for dsktop and web. 1

声音

图形

Canvas

Name Size (KB) License IE SVG Docs Notes
canto.js 56
fabric.js 97 yes yes yes Demo
gury.js 10 yes
CAKE 211
Mootools Canvas Library (MCL) 8
HTML5 Canvas Library 12
Layered Canvas Library (LCL) 21
Artisan.js 17
canvg 78.3 yes no
burst 56 yes 没有维护了
easel.js 33 MIT no no yes 尝试像Flash的DisplayList 一样在 Canvas 上创建图形。
processing.js
toxiclibsjs LPGL2.1 和 processing.js 结合和很好
CAAT MIT
Unveil.js
doodle.js BSD

注意,文件尺寸比较并不一定准确,因为有些lib并没有压缩过。

WebGL

Color

  • color.js – 颜色管理工具。 MIT

Math

其它

  • PlayMyCode – 在线游戏社区。使用 Quby (像Ruby) 编译成JavaScript.
  • Sphere RPG Engine – 为 RPG 游戏设计。使用 JavaScript
  • playtomic – Commercial service providing analytics, leaderboards etc. services for games. Provides HTML5/JS API in addition to AS2/AS3 ones.

(全文完)

公司SVN版本提交钩子post-commit.bat

  1. SET REPOS=%1  
  2. SET REV=%2  
  3. SET SVN_HOME_BIN=C:\svnServer\bin\  
  4. SET SVNUpdatePath=E:\svnupdate\gamebto\update\gamebto_new  
  5. SET VERPath=E:\svnupdate\gamebto\version\%date:~0,4%-%date:~5,2%-%date:~8,2%  
  6. SET WEBPath=E:\web\gamebto  
  7. SET WEBPath2=\\192.168.14.16\web\gamebto  
  8. SET WEBPath3=\\192.168.14.78\web\gamebto  
  9. SET WEBPath4=\\192.168.14.80\web\gamebto  
  10. SET ChangeList=E:\svnupdate\gamebto\logs\%date:~0,4%.%date:~5,2%.%date:~8,2%_%REV%.txt  
  11. %SVN_HOME_BIN%svnlook changed %REPOS% > %ChangeList%  
  12. %SVN_HOME_BIN%svn update %SVNUpdatePath%  
  13. E:  
  14. FOR /F “eol=; tokens=1 delims=” %%a in (%ChangeList%) do (FOR /f “tokens=1,2,* delims= “  %%i in (“%%a”do IF %%i==D (DEL %VERPath%%%~pnxj|DEL %WEBPath%%%~pnxj|DEL %WEBPath2%%%~pnxj) ELSE (echo f| xcopy %SVNUpdatePath%%%~pnxj %VERPath%%%~pnxj /R /Y /C|echo f| xcopy %SVNUpdatePath%%%~pnxj %WEBPath%%%~pnxj /R /Y /C|echo f| xcopy %SVNUpdatePath%%%~pnxj %WEBPath2%%%~pnxj /R /Y /C|echo f| xcopy %SVNUpdatePath%%%~pnxj %WEBPath3%%%~pnxj /R /Y /C|echo f| xcopy %SVNUpdatePath%%%~pnxj %WEBPath4%%%~pnxj /R /Y /C)); 

Subversion服务详细配置

Subversion安装成service

 以前的svnserve要想成为windows服务,必须依赖于svnservice或其他工具。从Subversion1.4开始,Subversion本身就集成Windows服务的工具。

1,安装svnservice

 在Windows NT中(包括Windows XP, Windows 2000, Windows 2003 Server)本身包含了一个安装服务的工具,叫做”Service Control”,也就是sc.exe。

例如我的Subversion安装在”D:\Subversion”,版本库在”D:\svnroot”,而我希望对应的Subversion服务名为svnservice,安装这个svn服务的命令就可以这样写:

sc create svnservice
binpath= “D:\Subversion\bin\svnserve.exe –service -r D:\svnroot”
displayname= “SVNService”
depend= Tcpip

请注意,因为便于察看,上面的命令分为多行,但在实际执行时应该在一行里。另外,在以前启动svnserve时会使用”-d”选项,也就是守护进程模式,在这里不能使用,会导致服务无法启动。同样,”-i”和”-t”选项也不能使用。

在命令行窗口执行完这个命令之后,服务还没有启动,你可以继续运行”net start svnservice”启动这个服务,然后使用”net stop svnservice”停止服务。

另外还有两点需要小心处理。首先,如果路径中包括空格,一定要用“\”处理“””号,例如上面的例子中如果 svnserve.exe在“c:\program files\subversion\”中,则命令应该写为“binpath= “\”c:\program files\subversion\bin\svnserve.exe\””(“”中的内容),整个命令如下,红色部分是改变部分:

sc create svnservice
binpath= “\”D:\program files\Subversion\bin\svnserve.exe\” –service -r D:\svnroot”
displayname= “SVNService”
depend= Tcpip

其次,sc对选项的格式还有要求,例如“depend= Tcpip”不能写为“depend = Tcpip”或“depend=Tcpip”,也就是“=”前不能有空各,而后面必须有空格。

2,删除服务

 如果服务安装的有问题,你可能需要删除服务。要删除前面添加的服务,只需要运行”net start svnservice”,”svnservice”就是我们创建服务时使用的名字。

3,配置服务是自动启动

 默认情况下安装的服务不会随Windows的启动而启动,为了使svn服务能够随Windows启动而启动,需要修改一下”sc create”命令(首先要删除),增加”start= auto”选项:

sc create svnservice
binpath= “D:\Subversion\bin\svnserve.exe –service -r D:\svnroot”
displayname= “SVNService”
depend= Tcpip
start= auto

当然你也可以使用图形化的工具修改服务的属性,你可以在“开始->运行…”中执行”services.msc”,然后在界面中修改。

Subversion的权限控制

 1,认证(Authentication)和授权(Authorization)

 这两个术语经常一起出现。其中认证的意思就是鉴别用户的身份,最常见的方式就是使用用户名和密码,授权就是判断用户是否具备某种操作的权限,在 Subversion里提供了“authz-db”文件,实现了以路径为基础的授权,也就是判断用户是否有操作对应路径的权限,在Subversion 1.3之后,svnserve和Apache一样都可以使用“authz-db”文件。

2. svnserve下的配置文件

 因为本文是以svnserve为例的,所以先介绍一下版本库目录的结构:

D:\SVNROOT\PROJECT1
├─conf
├─dav
├─db
│ ├─revprops
│ ├─revs
│ └─transactions
├─hooks
└─locks

其中conf下面有三个文件:

authz
passwd
svnserve.conf

其中的“svnserve.conf”是这个版本库的配置文件,当使用svnserve时,这个配置文件决定了使用什么认证和授权文件:

password-db = passwd
authz-db = authz

上面的配置说明使用“svnserve.conf”同目录的passwd和authz,其中的password-db指定了用户密码文件,authz-db是我们的授权文件,也就是我们本文主要介绍的文件。

注意:使用Apache作为服务器时,根本就不会参考“svnserve.conf”文件的内容,而是会参考Apache的配置。

3,基于svnserve的版本库文件布局

 使用svnserve时,为了管理的方便,应该使用相同的认证和授权文件,所以应该让所有版本库的配置文件svnserve.conf指向同一个password-db和authz-db文件。下面是一个多版本库的目录:

D:\SVNROOT
├─project1
│ ├─conf
│ ├─dav
│ ├─db
│ │ ├─revprops
│ │ ├─revs
│ │ └─transactions
│ ├─hooks
│ └─locks
└─project2
├─conf
├─dav
├─db
│ ├─revprops
│ ├─revs
│ └─transactions
├─hooks
└─locks

D:\SVNROOT下有两个目录project1和project2,都已经创建了版本库,所以我们修改每个conf目录下的svnserve.conf,使之指向同一个password-db和authz-db文件。

password-db = ..\..\passwd

 authz-db = ..\..\authz这样,D:\SVNROOT\passwd和D:\SVNROOT\authz就控制了所有版本库的svnserve访问。另外在 后面的操作中要关闭匿名访问,应该去掉“anon-access = none”前的“#”号,保证只有认证用户可以访问。

注意:还有一点需要注意,那就是svnserve的“realm”的值,在上面的设置下,应该保证所有的版本库使用相同的realm值,这样,对版本库的密码缓存可以在多个版本库之间共享,更多细节见客户端凭证缓存。

4,测试用户和组说明

 版本库禁止任何匿名用户的访问,只对认证用户有效。

root:配置管理管理员,对版本库有完全的管理权限。

p1_admin1:project1的管理员,对project1有完全权限。
 p1_d1:project1的开发者,对project1的trunk有完全的权限,但是对其中的/trunk/admin目录没有任何权限。
 p1_t1:project1的测试者,对project1的trunk有完全的读权限,但是对其中的/trunk/admin目录没有任何权限。

p2_admin1:project2的管理员,对project2有完全权限。
 p2_d1:project2的开发者,对project2的trunk有完全的权限,但是对其中的/trunk/admin目录没有任何权限。
 p2_t1:project2的测试者,对project2的trunk有完全的读权限,但是对其中的/trunk/admin目录没有任何权限。

对应的组及组的用户:

p1_group_a:p1_admin1
p1_group_d:p1_d1
p1_group_t:p1_t1
p2_group_a:p2_admin1
p2_group_d:p2_d1
p2_group_t:p2_t1

5,修改D:\SVNROOT\passwd文件

前面已经说过了,用户和密码文件应该是在D:\SVNROOT\passwd,所以我们为每一位用户设置权限,文件内容如下:

[users]
p1_admin1 = p1_admin1
p1_d1 = p1_d1
p1_t1 = p1_t1

p2_admin1 = p2_admin1
p2_d1 = p2_d1

p2_t1 = p2_t1为了便于验证,所有密码和用户名一致,如果你使用的是其他认证方式,这一步可能不同,但是用户名应该都是一样的。

6,配置授权,修改D:\SVNROOT\authz

[groups]
# 定义组信息

p1_group_a = p1_admin1
p1_group_d = p1_d1
p1_group_t = p1_t1

p2_group_a = p2_admin1
p2_group_d = p2_d1
p2_group_t = p2_t1

[/]
# 指定所有的版本库默认只读,root可读写
* = r
root = rw

[project1:/]
# 指定对版本库project1根目录的权限
@p1_group_a = rw
@p1_group_d = rw
@p1_group_t = r

[project1:/trunk/admin]
# 指定对版本库project1的/trunk/admin根目录的权限,
# p1_group_a读写,p1_group_d和p1_group_t没有任何权限。
@p1_group_a = rw
@p1_group_d =
@p1_group_t =

[project2:/]
# 指定对版本库project2根目录的权限
@p2_group_a = rw
@p2_group_d = rw
@p2_group_t = r

[project2:/trunk/admin]
# 指定对版本库project1的/trunk/admin根目录的权限
@p2_group_a = rw
@p2_group_d =
@p2_group_t =

经过以上设置以后,你会发现一些有趣的事情。当使用用户“p1_d1”,检出project1的trunk时,目录是空的,好像admin目录根本不存在一样,当使用p1_d1用户浏览版本库时,能够看到admin目录,但是其中的内容却无法看到。

关 于中文目录,也是没有问题的,只是注意要把authz文件转化为UTF-8格式,在我的WINXP的UltraEdit里显示的文件格式为U8-DOS, 具体的做法是用UltraEdit打开authz文件,然后选择“文件->转换->ASCII转UTF-8”,然后保存。

再复杂的情况也不过如此,在实际的工作中要首先规划好权限,只赋给用户最小的权限,保证以最小的配置实现最复杂的权限控制。

Subversion备份

 版本控制最关键的一件事是保证数据的安全性,不能因为磁盘损坏,程序故障造成版本库无可挽回的错误,为此必须制定较完备的备份策略。在Subversion中,我们有三种备份方式:完全备份,增量备份和同步版本库。

1, 完全备份

 最常见和简单的备份就是直接使用拷贝命令,将版本库目录拷贝到备份目录上,就可以了。但是这样不是很安全的方式,因为如果在拷贝时版本库发生变化,将会 造成备份的结果不够准确,失去备份的作用,为此Subversion提供了“svnadmin hotcopy”命令,可以防止这种问题。

还记得我们的版本库目录吗?

D:\SVNROOT
├─project1
│ ├─conf
│ ├─dav
│ ├─db
│ │ ├─revprops
│ │ ├─revs
│ │ └─transactions
│ ├─hooks
│ └─locks
└─project2
├─conf
├─dav
├─db
│ ├─revprops
│ ├─revs
│ └─transactions
├─hooks
└─locks

如果要把project1备份到d:\svnrootbak目录下,只需要运行:

svnadmin hotcopy d:\svnroot\project1 d:\svnrootbak\project1

但是我们作为配置管理员,必须想办法优化这个过程,如果我们这个目录下有许多版本库,需要为每个版本库写这样一条语句备份,为此我写了下面的脚本,实现备份一个目录下的所有版本库。我们在D:\SVNROOT下创建了两个文件,simpleBackup.bat:

@echo 正在备份版本库%1……
 @%SVN_HOME%\bin\svnadmin hotcopy %1 %BACKUP_DIRECTORY%\%2
 @echo 版本库%1成功备份到了%2!

这个文件仅仅是对“svnadmin hotcopy”的包装,然后是backup.bat:

echo off

rem Subversion的安装目录
set SVN_HOME=”D:\Subversion”

rem 所有版本库的父目录
set SVN_ROOT=D:\svnroot

rem 备份的目录
set BACKUP_SVN_ROOT=D:\svnrootbak

set BACKUP_DIRECTORY=%BACKUP_SVN_ROOT%\%date:~0,10%
if exist %BACKUP_DIRECTORY% goto checkBack
echo 建立备份目录%BACKUP_DIRECTORY%>>%SVN_ROOT%/backup.log

mkdir %BACKUP_DIRECTORY%

rem 验证目录是否为版本库,如果是则取出名称备份
for /r %SVN_ROOT% %%I in (.) do @if exist “%%I\conf\svnserve.conf” %SVN_ROOT%\simpleBackup.bat “%%~fI” %%~nI
goto end

:checkBack
echo 备份目录%BACKUP_DIRECTORY%已经存在,请清空。
goto end

:end

你 在使用的时候,只需要修改backup.bat开头的三个路径,将两个脚本拷贝到“SVN_ROOT”下就可以了。根据以上的配置,你只需要运行 backup.bat,就可以把“SVN_ROOT”下的版本库都备份到“BACKUP_SVN_ROOT”里,并且存放在备份所在日的目录里,例如 “D:\svnrootbak\2006-10-22”。

虽然这部分工作很简单,可是必须有人定时地去执行这个操作(例如每周一凌晨),为了避免发生遗忘的情况,我们可以将这个操作加入到系统的at任务当中去,例如还是上面的环境,为了安装at任务,我们运行:

at 1:00 /every:M D:\svnroot\backup.bat这样在每周一凌晨1:00都会执行这个备份过程。当然备份在本机也是不安全的,你也许需要上传到别的机器,这个就要靠你自己去实现了。

2, 增量备份

 尽管完全备份非常简单,但是也是有代价的,当版本库非常巨大时,经常进行完全备份是不现实的,也并不必要,但是一旦版本库在备份之间发生问题,该如何呢,这里我们就用到了增量备份。

增量备份通常要与完全备份结合使用,就像oracle数据库的归档日志,记录着每次Subversion提交的变 化,然后在需要恢复时能够回到最新的可用状态。在我们这个例子中我们使用的是,svnadmin dump命令进行增量的备份,使用方法是:

svnadmin dump project1 –revision 15 –incremental > dumpfile2

上面的命令实现了对修订版本15进行增量的备份,其中的输出文件dumpfile2只保存了修订版本15更改的内容。

为了记录每次提交的结果,我们需要使用一项Subversion的特性–钩子(hook),看看我们的project1目录:

├─project1
│ ├─conf
│ ├─dav
│ ├─db
│ │ ├─revprops
│ │ ├─revs
│ │ └─transactions
│ ├─hooks
│ └─locks

其中的hooks目录里存放的就是钩子脚本,我们在此处只使用post-commit钩子,这个钩子会在每次提交之后执行,为了实现我们的备份功能,我们在hooks下建立一个文件post-commit.bat,内容如下:

echo off
set SVN_HOME=”C:\Program Files\Subversion”
set SVN_ROOT=D:\svnroot
set UNIX_SVN_ROOT=D:/svnroot
set DELTA_BACKUP_SVN_ROOT=D:\svnrootbak\delta
set LOG_FILE=%1\backup.log
echo backup revision %2 >> %LOG_FILE%
for /r %SVN_ROOT% %%I in (.) do if D:/svnroot/%%~nI == %1 %SVN_ROOT%\%%~nI\hooks\deltaBackup.bat %%~nI %2
goto end
:end

通过这个脚本,可以实现D:\svnroot下的版本库提交时自动增量备份到D:\svnrootbak \delta(确定这个目录存在),其中使用的deltaBackup.bat其实可以放在任何地方,只是对脚本的svnadmin dump的包装,内容如下:

@echo 正在备份版本库%2……
 %SVN_HOME%\bin\svnadmin dump %SVN_ROOT%\%1 –incremental –revision %2 >> %DELTA_BACKUP_SVN_ROOT%\%1.dump
 @echo 版本库%2成功备份到了%3!

以上两个脚本可以直接拷贝到project2的hooks目录下,不需要修改就可以实现project2的自动备份。

以上的操作已经OK了,现在需要做的是将完全备份和增量备份结合起来,也就是在完全备份后清理增量备份的结果,使之只保存完全备份后的结果。

当果真出现版本库的故障,就要求我们实现版本库的恢复操作了,这是用要使用svnadmin load命令,同时也需要上次的完全备份例如要把上次完全备份backuprepo,和之后的增量备份dumpfile:

svnadmin load backuprepo < dumpfile

最后的结果,可以下载svnroot.rar,将之解压缩到d:\下,然后修改几个bat文件的SVN_HOME就可以使用了。

3, 版本库同步

Subversion 1.4增加了同步机制,可以实现一个版本库同另一个版本库的同步(但好像只是单向的),我们可以用来实现版本库的备份或镜像。

3.1. 对目标库初始化

 svnsync init svn://localhost/project2 svn://localhost/project1
 其中project2是目标的版本库,而project1是源版本库。其中的目标版本库必须为空,而且必须允许修订版本属性的修改,也就是在目标的版本 库的hooks目录里添加一个文件pre-revprop-change.bat,内容为空即可。

3.2. 同步project2到project1

 svnsync sync svn://localhost/project2
 这时候你update一下你的project2的一个工作拷贝,就会发现有了project1的所有内容。如果project1又有提交,这时候 project2的版本库无法看到最新的变化,还需要再运行一遍sync操作,这样才能将最新的变化同步。需要注意的是,目标版本库只能做成只读的,如果 目标版本库发生了变更,则无法继续同步了。

3.3. 同步历史属性的修改

 因为同步不会更新对历史属性的修改,所以svnsync还有子命令copy-revprops,可以同步某个版本的属性。

3.4. 钩子自动同步

 希望在每次提交时同步,则需要在源版本库增加post-commit脚本,内容如下:

echo off
set SVN_HOME=”D:\Subversion”
%SVN_HOME%\bin\svnsync sync –non-interactive svn://localhost/project2

把以上内容存放为post-commit.bat,然后放到版本库project1下的hooks目录下,这样project1每次提交,都会引起project2的同步。

PHP缓存加速器: eAccelerator

eAccelerator README for Linux 简体中文翻译

eAccelerator 是一个为 PHP 程序加速的免费开源软件,其极速效果绝不输给 Zend Performance Suite。并且支持 Linux, FreeBSD, Solaris,
MacOS X, Windows等系统。

eAccelerator for PHP

什么是 eAccelerator ?

eAccelerator 是一个开源并且免费的 PHP 加速器,优化器,编码器,同时也能够为 PHP提供动态内容缓存。它能够将 PHP 脚本缓存为已编译状态以达到提升 PHP 脚本运行性能的目的,因此传统的预编译几乎被消除。eAccelerator 也能够优化 PHP 脚本以提升 PHP 脚本的执行速度。eAccelerator 可有效降低服务器负载并且提高 PHP 程序速度达 1-10 倍。

TurckMMCache 是 eAccelerator 的前身。
( http://sourceforge.net/project/turckmm-cache/ by Dmitry Stogov )

eAccelerator 包含一个 PHP 编码器和加载器。您可以使用编码器对 .php 脚本进行编码, 从而能够以非源代码方式发布您的 PHP 程序。经过编码的 PHP 程序可以运行在任何安装有 PHP 解析环境和 eAccelerator 的站点上,由于编码后的 PHP 程序存储为已编译代码,并且 已编译版本中不包含程序的源代码,因此,经过 eAccelerator 编码的 PHP 程序是不能被还原 恢复的。当然,一些内部脚本可以被某些不同的反编译引擎工具(如 disassemblers, debuggers等) 进行还原恢复,但这并非是微不足道的。

eAccelerator 与 Zend Optimizer 加载器兼容。在 php.ini 中,Zend Optimizer 必须在 eAccelerator 之后加载。如果您的站点不运行任何经由 Zend 编码器编码的 PHP 脚本,那么 我们并不推荐您在安装 eAccelerator 的服务器上安装 Zend Optimizer。

eAccelerator 不能运行于 CGI 模式下,但它可以运行于像 lighttpd 类似的 Fast-CGI模式。

以下是一些与 eAccelerator 具有相同功能的产品:
– Zend Performance Suite (http://www.zend.com)
– Alternative PHP Cache (http://pecl.php.net/package/APC)

下载

最新版的 eAccelerator 可以在 Sourceforge 下载:
http://sourceforge.net/projects/eaccelerator/
CVS 开发版本快照(snapshots)可以在以下地址下载:
http://snapshots,eaccelerator.net

所需环境

Apache 1.3 或更高版本
mod_php 4.1 或更高版本
autoconf
automake
libtool
m4

兼容性

经过用户的使用和报告,eAccelerator 能够运行在 PHP4 和 PHP5。PHP5.1 目前尚不能完整的
支持。eAccelerator 能够与 Apache 1.3/2.0、lighttpd、和 IIS 在 Linux、FreeBSD、MacOS X、Solaris 和
Windows 上运行。

快速安装

您可以在 eAccelerator 站点获取更多有关安装方面的信息。
http://eaccelerator.sourceforge.net/

注意(1):有关 Microsoft Windows 平台的安装信息,请阅读 README.win32 file。

步骤 1. 编译 eAccelerator

cd /usr/local/src

wget http://internap.dl.sourceforge.n … rator-0.9.4.tar.bz2

tar xjvf eaccelerator-0.9.4.tar.bz2

cd eaccelerator-0.9.4.tar.bz2

export PHP_PREFIX=”/usr/local/php”

$PHP_PREFIX/bin/phpize

./configure \
–enable-eaccelerator=shared \
–with-php-config=$PHP_PREFIX/bin/php-config

make

您必须在 export 命令中指定 PHP 真实的安装目录位置。该目录位置可能是 “/usr” “/usr/local”,或 其他位置。

步骤 2. 安装 eAccelerator

make install

步骤 3. 配置 eAccelerator

eAccelerator 可以安装为 Zend 扩展或者 PHP 扩展。

对于 eAccelerator 0.9.1 及其以上版本,如果您系统中存在 /etc/php.d 目录,则需要将 eaccelerator.ini
文件复制到该目录中,并且根据需要修改其中的默认设置和数值。

如果系统中不存在 /etc/php.d 目录,则编辑 php.ini 文件(通常位于 /etc/php.ini)。

安装为 Zend 扩展:

zend_extension=”/usr/lib/php4/eaccelerator.so”
eaccelerator.shm_size=”16″
eaccelerator.cache_dir=”/tmp/eaccelerator”
eaccelerator.enable=”1″
eaccelerator.optimizer=”1″
eaccelerator.check_mtime=”1″
eaccelerator.debug=”0″
eaccelerator.filter=””
eaccelerator.shm_max=”0″
eaccelerator.shm_ttl=”0″
eaccelerator.shm_prune_period=”0″
eaccelerator.shm_only=”0″
eaccelerator.compress=”1″
eaccelerator.compress_level=”9″

如果您使用 thread safe 编译安装 PHP,则您必须使用 “zend_extension_ts” 代替 “zend_extension”。

安装为 PHP 扩展:

extension=”eaccelerator.so”
eaccelerator.shm_size=”16″
eaccelerator.cache_dir=”/tmp/eaccelerator”
eaccelerator.enable=”1″
eaccelerator.optimizer=”1″
eaccelerator.check_mtime=”1″
eaccelerator.debug=”0″
eaccelerator.filter=””
eaccelerator.shm_max=”0″
eaccelerator.shm_ttl=”0″
eaccelerator.shm_prune_period=”0″
eaccelerator.shm_only=”0″
eaccelerator.compress=”1″
eaccelerator.compress_level=”9″

步骤 4. 创建缓存目录

mkdir /tmp/eaccelerator
chomd 0777 /tmp/eaccelerator

配置选项

eaccelerator.shm_size
指定 eAccelerator 能够使用的共享内存数量,单位:MB。 “0” 代表操作系统默认。默认值为 “0”。

eaccelerator.cache_dir
用户磁盘缓存的目录。eAccelerator 在该目录中存储预编译代码、session 数据、内容等。
相同的数据也可以存储于共享内存中(以获得更快的存取速度)。默认值为 “/tmp/eaccelerator”。

eaccelerator.enable
开启或关闭 eAccelerator。”1″ 为开启,”0″ 为关闭。默认值为 “1”。

eaccelerator.optimizer
开启或关闭内部优化器,可以提升代码执行速度。”1″ 为开启,”0″ 为关闭。默认值为 “1”。

eaccelerator.debug
开启或关闭调试日志记录。”1″ 为开启,”0″ 为关闭。默认值为 “0”。

eaccelerator.check_mtime
开启或关闭 PHP 文件改动检查。”1″ 为开启,”0″ 为关闭。如果您想要在修改后重新编译 PHP程序则需要设置为 “1”。默认值为 “1”。

eaccelerator.filter
判断哪些 PHP 文件必须缓存。您可以指定缓存和不缓存的文件类型(如 “*.php *.phtml”等)如果参数以 “!” 开头,则匹配这些参数的文件被忽略缓存。默认值为 “”,即,所有 PHP 文件都将被缓存。

eaccelerator.shm_max
当使用 ” eaccelerator_put() ” 函数时禁止其向共享内存中存储过大的文件。该参数指定允许存储的最大值,单位:字节 (10240, 10K, 1M)。”0″ 为不限制。默认值为 “0”。

eaccelerator.shm_ttl
当 eAccelerator 获取新脚本的共享内存大小失败时,它将从共享内存中删除所有在最后 “shm_ttl” 秒内无法存取的脚本缓存。默认值为 “0”,即:不从共享内春中删除
任何缓存文件。

eaccelerator.shm_prune_period
当 eAccelerator 获取新脚本的共享内存大小失败时,他将试图从共享内存中删除早于”shm_prune_period” 秒的缓存脚本。默认值为 “0”,即:不从共享内春中删除
任何缓存文件。
eaccelerator.shm_only
允许或禁止将已编译脚本缓存在磁盘上。该选项对 session 数据和内容缓存无效。默认值为 “0”,即:使用磁盘和共享内存进行缓存。

eaccelerator.compress
允许或禁止压缩内容缓存。默认值为 “1”,即:允许压缩。

eaccelerator.compress_level
指定内容缓存的压缩等级。默认值为 “9”,为最高等级。

eaccelerator.name_sapce
一个所有键(keys)的前缀字符串。如果设置该前缀字符串则允许 .htaccess 或者 主配置文件在相同主机上运行两个相同的键名。

eaccelerator.keys
eaccelerator.sessions
eaccelerator.content
判断哪些键(keys)、session 数据和内容将被缓存。可用参数值为:
“shm_and_disk” – 同时在共享内存和磁盘中缓存数据(默认值);
“shm” – 如果共享内存用尽或者数据容量大于 “eaccelerator.shm_max”
则在共享内存或磁盘中缓存数据;
“shm_only” – 仅在共享内存中缓存数据;
“disk_only” – 仅在磁盘中缓存数据;
“none” – 禁止缓存数据。

eAccelerator 应用程序接口(API)

eaccelerator_put($key, $value, $ttl=0)
将 $value 存储在共享内存中,并存储 $tll 秒。

eaccelerator_get($key)
从共享内存中返回 eaccelerator_put() 函数所存储的缓存数值,如果不存在或者已经过期,则返回 null。

eaccelerator_rm($key)
从共享内存中删除 $key。

eaccelerator_gc()
删除所有过期的键(keys)

eaccelerator_lock($lock)
创建一个指定名称的锁(lock)。该锁可以通过 eaccelerator_unlock() 函数解除,在请求结束时也会自动解锁。例如:
<?php
eaccelerator_lock(“count”);
eaccelerator_put(“count”,eaccelerator_get(“count”)+1));
?>

eaccelerator_unlock($lock)
解除指定名称的锁(lock)。

eaccelerator_set_session_handlers()
安装 eAccelerator session 句柄。
从 PHP 4.2.0 以后,您可以通过设置 php.ini 中的 “session.save_handler=eaacelerator”
安装 eAccelerator 句柄。

eaccelerator_cache_output($key, $eval_code, $ttl=0)
在共享内存中缓存 $eval_code 的输出,缓存 $ttl 秒。
可以调用 mmcach_rm() 函数删除相同 $key 的输出。例如:
<?php eaccelerator_cache_output(‘test’, ‘echo time(); phpinfo();’, 30); ?>

eaccelerator_cache_result($key, $eval_code, $ttl=0)
在共享内存中缓存 $eval_code 的结果,缓存 $ttl 秒。
可以调用 mmcach_rm() 函数删除相同 $key 的结果。例如:
<?php eaccelerator_cache_output(‘test’, ‘time().” Hello”;’, 30); ?>

eaccelerator_cache_page($key, $ttl=0)
缓存整个页面,且缓存 $ttl 秒。例如:
<?php
eaccelerator_cache_page($_SERVER[‘PHP_SELF’].’?GET=’.serialize($_GET),30);
echo time();
phpinfo();
?>

eaccelerator_rm_page($key)
从缓存中删除由 eaccelerator_cache_page() 函数创建的相同 $key 的页。

eaccelerator_encode($filename)
返回 $filename 文件经过编译后的编码。

eaccelerator_load($code)
加载被 eaccelerator_encode() 函数编码过的脚本。

WEB 界面

可以通过 eaccelerator.php 进行基于 WEB 界面的管理。当然,您需要将该文件存储于您的 WEB 站点目录中。出于安全原因,建议您对该文件进行安全控制,保证只有本地 IP 才能读取该文件。

从 2.3.18 版本开始,管理界面可以进行密码保护。从终端命令行运行 eaccelerator_password.php 并按照以下步骤生成密码:

$ php -q eaccelerator_password.php
更改 eAccelerator WEB 管理界面密码。(eaccelerator.php)

Enter admin name:admin
New admin password: eaccelerator
Retype new admin password: eaccelerator

在 php.ini 中添加以下内容,并且重新启动 WEB 服务:
eaccelerator.admin.name=”admin”
eaccelerator.admin.password=”$1$0ScD9gkb$nOEmFerNMvQ576hELeLrG0″

如果在受 HTTPD 密码保护的目录中存放 eaccelerator.php,则 eaccelerator 的管理员用户名和密码 必须一致。

PHP中使用XML-RPC构造Web Service简单入门

[  Web Service介绍 ]

Web Service就是为了异构系统的通信而产生的,它基本的思想就是使用基于XML的HTTP的远程调用提供一种标准的机制,而省去建立一种新协议的需求。 目前进行Web Service通信有两种协议标准,一种是XML-RPC,另外一种是SOAP。XML-RPC比较简单,出现时间比较早,SOAP比较复杂,主要是一些 需要稳定、健壮、安全并且复杂交互的时候使用。

PHP中集成了XML-RPC和SOAP两种协议的访问,都是集中在xmlrpc扩展当 中。另外,在PHP的PEAR中,不管是PHP 4还是PHP 5,都已经默认集成了XML-RPC扩展,而且该扩展跟xmlrpc扩展无关,能够独立实现XML-RPC的协议交互,如果没有xmlrpc扩展,建议使 用PEAR::XML-RPC扩展。

我们这里主要是以XML-RPC来简单描述Web Service的交互过程,部分内容来自PHP手册,更详细内容,建议参考手册。

[  安装xmlrpc扩展 ]

如果你的系统中没有安装xmlrpc的php扩展,那么请正确安装。

在 Windows平台下,首先把PHP安装目录下的扩展php_xmlrpc.dll放到C:\Windows或者C:\Winnt目录下,(PHP4的扩 展在C:\php\extensions目录中,PHP5的扩展在C:\php\ext目录中),同时在C:\Windows\php.ini或者C: \Winnt\php.ini中把extension=php_xmlrpc.dll前面的分号”;”去掉,然后重启Web服务器后查看 phpinfo()有没有XML-RPC项目就能够确定是否已经正确安装xmlrpc扩展。

在Unix/Linux平台下,如果没有安装xmlrpc扩展,请在重新编译PHP,在configure的时候请加入 –with-xmlrpc 选项,然后查看phpinfo()看是否正常安装xmlrpc。

(注意:以下操作都是建立在xmlrpc扩张正常安装前提下,请务必正确安装。)

[  XML-RPC工作原理 ]

XML-RPC大致就是整个过程就是使用XML来进行通信。首先构造一个RPC 服务器端用来出来从RPC客户端传递过来的使用XML封装的请求,并且把处理结果通过XML的形式返回给RPC客户端,客户端就去分析XML获取自己需要的数据。

XML-RPC的服务器端必须有现成的函数提供给客户端调用,并且客户端提交的请求中的函数和方法必须和服务器端的一致,否则将无法获取所需要的结果。

下面我进行简单的代码来描述整个过程。


[  XML-RPC实践 ]

服务器端使用xmlrpc_server_create函数产生一个服务器端,然后把需要需要暴露的RPC调用接口进行注册,接受RPC客户端POST过来的XML数据,然后进行处理,处理结果通过XML的形式显示给客户端。

代码如下: rpc_server.php

  1. <?php  
  2. /** 
  3. * 函数:提供给RPC客户端调用的函数 
  4. * 参数: 
  5. * $method 客户端需要调用的函数 
  6. * $params 客户端需要调用的函数的参数数组 
  7. * 返回:返回指定调用结果 
  8. */  
  9. function rpc_server_func($method$params) {  
  10. $parameter = $params[0];  
  11.    if ($parameter == “get”)  
  12.    {  
  13.        $return = This data by get method;  
  14.    }  
  15.    else  
  16.    {  
  17.        $return = Not specify method or params;  
  18.    }  
  19.    return $return;  
  20. }  
  21.   
  22. //产生一个XML-RPC的服务器端  
  23. $xmlrpc_server = xmlrpc_server_create();  
  24.   
  25. //注册一个服务器端调用的方法rpc_server,实际指向的是rpc_server_func函数  
  26. xmlrpc_server_register_method($xmlrpc_server“rpc_server”“rpc_server_func”);  
  27.   
  28. //接受客户端POST过来的XML数据  
  29. $request = $HTTP_RAW_POST_DATA;  
  30.   
  31. //执行调用客户端的XML请求后获取执行结果  
  32. $xmlrpc_response = xmlrpc_server_call_method($xmlrpc_server$request, null);  
  33.   
  34. //把函数处理后的结果XML进行输出  
  35. header(Content-Type: text/xml);  
  36. echo $xmlrpc_response;  
  37.   
  38. //销毁XML-RPC服务器端资源  
  39. xmlrpc_server_destroy($xmlrpc_server);  
  40. ?> 

服务器端构造好了,那么再构造我们的RPC客户端。客户端大致通过Socket访问XML-RPC服务器端的80端口,然后把需要调用的RPC接口封装到XML里,通过POST请求提交给RPC服务器端,最后获取服务器端返回结果。

代码如下:rpc_client.php

  1. <?php  
  2. /** 
  3. * 函数:提供给客户端进行连接XML-RPC服务器端的函数 
  4. * 参数: 
  5. * $host  需要连接的主机 
  6. * $port  连接主机的端口 
  7. * $rpc_server XML-RPC服务器端文件 
  8. * $request  封装的XML请求信息 
  9. * 返回:连接成功成功返回由服务器端返回的XML信息,失败返回false 
  10. */  
  11. function rpc_client_call($host$port$rpc_server$request) {  
  12.   
  13.    //打开指定的服务器端  
  14.    $fp = fsockopen($host$port);  
  15.   
  16.    //构造需要进行通信的XML-RPC服务器端的查询POST请求信息  
  17.    $query = “POST $rpc_server HTTP/1.0\nUser_Agent: XML-RPC Client\nHost: “.$host.“\nContent-Type: text/xml\nContent-Length: “.strlen($request).“\n\n”.$request.“\n”;  
  18.   
  19.    //把构造好的HTTP协议发送给服务器,失败返回false  
  20.    if (!fputs($fp$querystrlen($query)))  
  21.    {  
  22.        $errstr = “Write error”;  
  23.        return false;  
  24.    }  
  25.      
  26.    //获取从服务器端返回的所有信息,包括HTTP头和XML信息  
  27.    $contents = ;  
  28.    while (!feof($fp))  
  29.    {  
  30.        $contents .= fgets($fp);  
  31.    }  
  32.   
  33.    //关闭连接资源后返回获取的内容  
  34.    fclose($fp);  
  35.    return $contents;  
  36. }  
  37.   
  38. //构造连接RPC服务器端的信息  
  39. $host  = localhost;  
  40. $port  = 80;  
  41. $rpc_server = /~heiyeluren/rpc_server.php;  
  42.   
  43. //把需要发送的XML请求进行编码成XML,需要调用的方法是rpc_server,参数是get  
  44. $request = xmlrpc_encode_request(rpc_serverget);  
  45.   
  46. //调用rpc_client_call函数把所有请求发送给XML-RPC服务器端后获取信息  
  47. $response = rpc_client_call($host$port$rpc_server$request);  
  48.   
  49. //分析从服务器端返回的XML,去掉HTTP头信息,并且把XML转为PHP能识别的字符串  
  50. $split = <?xml version=“1.0” encoding=“iso-8859-1”?>;  
  51. $xml =  explode($split$response);  
  52. $xml = $split . array_pop($xml);  
  53. $response = xmlrpc_decode($xml);  
  54.   
  55. //输出从RPC服务器端获取的信息  
  56. print_r($response);  
  57.   
  58. ?>  

大致我们上面的例子就是提交一个叫做rpc_server的方法过去,参数是get,然后获取服务器端的返回,服务器端返回的XML数据是:

  1. <?xml version=“1.0” encoding=“iso-8859-1”?>  
  2. <methodResponse>  
  3. <params>  
  4. <param>  
  5.   <value>  
  6.    <string>This data by get method</string>  
  7.   </value>  
  8. </param>  
  9. </params>  
  10. </methodResponse> 

那么我们再通过xmlrpc_decode函数把这个XML编码为PHP的字符串,我们就能够随意处理了,整个Web Service交互完成。

[  结束语 ]

不 管是XML-RPC也好,SOAP也罢,只要能够让我们稳定、安全的进行远程过程的调用,完成我们的项目,那么就算整个Web Service就是成功的。另外,如果可以的话,也可以尝试使用PEAR中的XML-RPC来实现上面类似的操作,说不定会更简单,更适合你使用。

简单的使用XML-RPC进行Web Service交互就完成了,部分代码参考PHP手册,想获取详细信息建议参考手册,如果文章有不正确,请指正。

PHPRPC for JavaScript

PHPRPC for JavaScript
 
PHPRPC 对 JavaScript 的支持是非常早的,最初协议的设计中对数据的编码方式,返回数据的格式以及回调参数这些内容都充分考虑了 JavaScript 的特性。大部分 PHPRPC 用户最初也是把 PHPRPC 作为一个优秀的 Ajax 方案来使用的。但是 PHPRPC for JavaScript 不同于其它那些专门用于 Ajax 的 RPC 方案(如 DWR、xajax 等),PHPRPC for JavaScript 客户端与服务器是松散耦合的,它不依赖于某种特定语言编写的服务器。并且它还可以同目前许多优秀的 Ajax 框架(如 JQuery、YUI、MooTools 等)一起使用,而不会有任何冲突。并且它还有一个最大的好处,那就是可以让你轻松实现跨域调用。
 
 
PHPRPC for JavaScript 的安装
 

PHPRPC for JavaScript 有 2 个版本的实现,一个是纯 JavaScript 实现的版本(js 版本),另一个是 Flash 与 JavaScript 混合实现的版本(ajs 版本1)。

PHPRPC for JavaScript 两个版本的安装使用方法略有不同,我们下面分别来介绍一下。

js 版本的安装

js 目录下是纯 JavaScript 版本的源代码,其中的 compressed 目录下是压缩后的版本,压缩后的版本有 2 个,直接存放在 compressed 目录下的是不兼容 Windows IE 5.0 的版本(但兼容 Windows IE 5.5 及其以上版本),ie5compat 目录下是兼容 Windows IE 5.0 浏览器的版本。通常情况下,您不需要使用 ie5compat 的版本,这并不是因为 ie5compat 版本更大一些,运行效率更低一些。而是因为现在还在使用 IE 5.0 的用户基本上已经不存在了。另一个更重要的原因是你页面中的 HTML 部分可能根本就无法在 IE 5.0 上正常显示,其它的(除了 PHPRPC 以外的)脚本也无法在 IE 5.0 上面正常运行。因为 IE 5.0 对 HTML 的显示和 JavaScript 的支持实在是相当差劲。

你如果要在你的页面中引用 PHPRPC for JavaScript,只需要把 compressed 下的 phprpc_client.js 复制到你的 Web 目录的脚本目录下,然后在你的页面中像引用其它外部脚本一样引用该脚本文件就可以了,引用的代码看上去像下面这样:

  1. <script type=“text/javascript” src=“scripts/phprpc_client.js”></script> 

上面这句,你可以放在 head 中,也可以放在 body 中,只要放在你创建 PHPRPC_Client 对象之前就可以了。

ajs 版本的安装

ajs 目录下是 JavaScript 和 Flash 混合实现版本的源代码。同样,你只需要关心 compressed 下的文件(如果你不打算修改源代码的话)。你需要做的同样是将 phprpc_client.js 复制到你的 Web 目录的脚本目录下,同时把 phprpc_flash.js 也复制过去,而 flashrequest.swf 文件你可以放到 Web 目录下的任何你觉得合适的目录下。然后你需要将 phprpc_flash.js 中的 flashrequest.swf 路径修改为你实际的 Web 路径,修改后的代码可能会像这样:

  1. document.write([‘<object classid=”clsid:D27CDB6E-AE6D-11cf-96B8-444553540000″ ‘,  
  2.                 ‘type=”application/x-shockwave-flash” ‘,  
  3.                 ‘codebase=”http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0″ ‘,  
  4.                 ‘width=”0″ height=”0″ id=”flashrequest_as3″>’,  
  5.                 ‘<param name=”movie” value=”/scripts/flashrequest.swf” />’,  
  6.                 ‘<param name=”allowScriptAccess” value=”always” />’,  
  7.                 ‘<param name=”quality” value=”high” />’,  
  8.                 ‘<embed src=”/scripts/flashrequest.swf” type=”application/x-shockwave-flash” ‘,  
  9.                 ‘width=”0″ height=”0″ name=”flashrequest_as3″ allowScriptAccess=”always” />’,  
  10.                 ‘</object>’].join()); 

最后,在你的页面中引用这两个脚本,其中 phprpc_client.js 可以放在 head 或者 body 中,而 phproc_flash.js 需要放到 body 中,但不要放到 form 中。这里 ajs 的意思是 Another JavaScript 的意思,你也可以理解为 ActionScript & JavaScript 的意思。

 
 
 
 
PHPRPC for JavaScript 客户端

PHPRPC for JavaScript 的 js 版本和 ajs 版本除了前面安装部分所介绍的引入方法有所不同之外,在用法上基本没有区别。下面我们先来看一下基本用法。

如何调用 PHPRPC 服务

我们先通过一个简单的例子,来介绍如何调用 PHPRPC 服务。

  1. var client = new PHPRPC_Client(‘http://localhost:8080/index.aspx’, [‘add’‘sub’]);  
  2. client.setKeyLength(256);  
  3. client.setEncryptMode(2);  
  4. client.add(1, 2, function (result, args, output, warning) {  
  5.     alert(result);  
  6. });  
  7. client.sub(1, 2, function (result, args, output, warning) {  
  8.     alert(result);  
  9. }); 

PHPRPC_Client 对象的 setKeyLength setEncryptMode 这两个方法是跟加密传输有关的。

setKeyLength 方法用于设置密钥长度

setEncryptMode 方法用于设置加密模式

上面设置密钥长度、加密模式都是可选项,如果你不需要这些功能,可以直接忽略它们。

PHPRPC 3.0 for JavaScript 客户端与 Java、.NET 客户端不同,它不需要使用 useService 来返回指定接口的远程代理对象,JavaScript 客户端本身就是一个代理对象。所以,上面例子中 client.add client.sub 这两个调用实际上调用的就是远程方法,对于 JavaScript 客户端来说,远程方法名虽然可以不事先声明,但这样只能在 client.onready 事件发生后或者 client.getReady() 等于 true 时才能进行调用,但这种做法是为了保持与旧版本兼容而提供的,属于过时的方法,所以不推荐这种做法,而是强烈建议像上面那样直接在客户端代码中指定所需要调用的远程方法名。

回调函数有四个参数,你可以认为它们是服务器端方法执行之后返回的内容。

第一个参数 result 是服务器端方法(函数)的返回值,它可以是任意类型。

第二个参数 args 是方法调用的参数,如果这个调用是一个引用参数传递的调用,参数也有可能被修改,这时候,你可以通过 args 来获得修改后的参数,关于引用参数传递的调用我们后面会做进一步说明。

第三个参数 output 是服务器端输出的内容,它是字符串类型的。

第四个参数 warning 是服务器端发生的警告错误(目前只有 PHP 服务器会产生警告错误),一般只调试过程中可能会用到。

通过这个例子,我想你已经可以掌握 PHPRPC for JavaScript 客户端的基本使用方法了。

如何在调用 PHPRPC 服务时,进行引用参数传递?

引用参数传递实际上非常简单,看下面这个例子,首先来看 PHP 的服务器端:

  1. <?php  
  2. include(‘phprpc_server.php’);  
  3. function inc(&$n) {  
  4.     $n++;  
  5. }  
  6. $phprpc_server = new PHPRPC_Server();  
  7. $phprpc_server->add(‘inc’);  
  8. $phprpc_server->start();  
  9. ?> 

这个服务器发布了一个 inc 方法,该方法是将参数值加一。这个方法是需要引用参数传递的。下面我们来看看如何在 JavaScript 中调用这个远程过程:

  1. var client = new PHPRPC_Client(‘http://localhost/index.php’, [‘inc’]);  
  2. client.inc(1, function (result, args, output, warning) {  
  3.     alert(args[0]);  
  4. }, true); 

其实很简单,只要在回调函数之后跟一个 true 参数就可以了。这个 true 就是表示启用引用参数传递。

如何来得到远程过程执行的错误信息?

PHPRPC 把错误分为两种,一种是致命错误,一种是警告性错误。

当远程过程执行发生致命错误时,远程过程调用的返回值是一个 PHPRPC_Error 类型的对象,它其中包含了远程过程执行时发生的致命错误信息。

当远程过程执行发生警告性错误时,你可以通过回调函数的第四个参数 warning 得到警告错误,warning 的值也是 PHPRPC_Error 类型的对象。如果没有发生警告错误,warning 为 null

 

PHPRPC for PHP

Install PHPRPC for PHP

Uncompress PHPRPC for PHP releases on the fly,

  • bigint.php
  • compat.php
  • phprpc_date.php
  • xxtea.php

These 4 files are common files which are required by both server and client side.

  • phprpc_client.php

This is the client code, if you need PHPRPC for PHP client only, common files and this file are enough for you, include this file in your client code only, common files are included implicitly.

  • dhparams
  • dhparams.php
  • phprpc_server.php

These files are required by PHPRPC server.
dhparams folder includes parameters which will be used to generate private key in encrypted mode, if you need detailed explaination, see Encrypted transfer.

dhparams.php includes a class to access dhparams directory.
phprpc_server.php is PHPRPC for PHP server, if you are going to publish services by PHP, you should include this file, common files and dhparams.php will be included implicitly.

Runtime environmonet

  • PHP 4.3+, PHP 5, PHP 6
  • PHPRPC client requires socket extension
  • PHPRPC server requires HTTP server with PHP support, such as IIS, apache, lighttpd
  • Session must be configured properly, if encrypted mode is enabled

bigint extenstion is recommeneded to enable when encrypt is enabled, gmp, big_int, bcmath are supported by PHPRPC (ordered by performance). If your host doesn’t support these extensions, key exchange will be done by php script, it is a bit slower.

For better encryption performance, xxtea PECL extension should be enabled, it is written in C programming language, this extension can significantly improve encryption performance.

How to compile xxtea extension

There are three popular ways to do this:

  1. Compiled with PHP source code
  2. Use phpize
  3. Use Microsfot Visual C (.net or 6.0) on Windows

1. compile with PHP source code

  1. Create ext/xxtea in PHP source code root path, move all files to this folder
  2. Run ./buildconf to create PHP configure script
  3. Compile PHP with --enable-xxtea flag, this will create a xxtea internal module, using --enable-xxtea=shared flag instead will create a dymanical extension.

2. phpize utility

  1. Uncompress xxtea extension source code achive
  2. Run phpize, this will create configure script and other stuff required
  3. Run ./configure --enable-xxtea=share to generate a proper makefile
  4. Run make to compile xxtea extension
  5. make install, this will install xxtea extension to PHP

3. Use Microsoft Visual C (.net or 6.0)

  1. Create ext/xxtea in PHP source code root path, move all files to this folder
  2. Copy php4ts.lib (for PHP 4) or php5ts.lib (for PHP 5) from current working PHP directory to ext/xxtea.
  3. Open php_xxtea.sln or php_xxtea.dsw, compile Release_php4 or release_php5
  4. Copy php_xxtea.dll from ext/xxtea/Release_php4 or ext/xxtea/Release_php5 to PHP extension directory, the path of extension directory can be found in php.ini
  5. add this line to php.ini: extension=php_xxtea.dll
 
PHPRPC for PHP Server

Publish functions

In Quick start chapter, we already knew how to register a php function, in the following text, we are going to know which functions can be published as PHPRPC services.
Most functions can be published, even php internal functions, except the functions which have resource type parameters or return values (such as mysql_connect, mysql_query).
You can even publish several functions at one time, no matter your own functions or php internal ones. For example:


  1. <?php  
  2. include(‘php/phprpc_server.php’);  
  3. function hello($name) {  
  4.     return ‘Hello ‘ . $name;  
  5. }  
  6. $server = new PHPRPC_Server();  
  7. $server->add(array(‘hello’‘md5’‘sha1’));  
  8. $server->add(‘trim’);  
  9. $server->start();  
  10. ?> 

In this case, we published 4 functions, hello is the one we created, the other three are php internal functions. We can place the function names into an array, add method can accept function names as string and array both.

Publish methods

Class static methods and instance methods are supported as well, for example:

  1. <?php  
  2. include(‘php/phprpc_server.php’);  
  3. class Example1 {  
  4.     static function foo() {  
  5.         return ‘foo’;  
  6.     }  
  7.     function bar() {  
  8.         return ‘bar’;  
  9.     }  
  10. }  
  11. $server = new PHPRPC_Server();  
  12. $server->add(‘foo’‘Example1’);  
  13. $server->add(‘bar’new Example1());  
  14. $server->start();  
  15. ?> 

foo is a class method, the second parameter is the class name. bar is an instance method, so the second parameter should be an instance of class. If you publish an instance method by the way of class method, you will get a warning error when calling. 1

Maybe we want to ask how to publish 2 methods with the names belonging to different classes? Will they conflict? How to avoid conflict?

Alias

It does, this happens usally, In some cases, the functions registered later may overwrite the one registered before, PHPRPC provide alias mechanism to solve this problem, see following code:

  1. <?php  
  2. include(‘php/phprpc_server.php’);  
  3. function hello($name) {  
  4.     return ‘Hello ‘ . $name;  
  5. }  
  6. class Example1 {  
  7.     static function foo() {  
  8.         return ‘foo’;  
  9.     }  
  10.     function bar() {  
  11.         return ‘bar’;  
  12.     }  
  13. }  
  14. class Example2 {  
  15.     function foo() {  
  16.         return ‘foo, too’;  
  17.     }  
  18.     function bar() {  
  19.         return ‘bar, too’;  
  20.     }  
  21. }  
  22. $server = new PHPRPC_Server();  
  23. $server->add(‘hello’, NULL, ‘hi’);  
  24. $server->add(‘foo’‘Example1’‘ex1_foo’);  
  25. $server->add(‘bar’new Example1(), ‘ex1_bar’);  
  26. $server->add(array(‘foo’‘bar’), new Example2(), array(‘ex2_foo’‘ex2_bar’));  
  27. $server->start();  
  28. ?> 

Both functions and methods can be registered with alias. To register a function, the second parameter should be set as NULL. To add several methods/functions at one time, the number and order of alias should match the functions/methods list.

NOTE, the original name of the functions/methods are not callable, only alias can be used.

Use Session

In the above example, we did publish an instance method, but we didn’t use $this to access instance members in code. It is unusual actaully, it looks like a class static method except it will get warning by called as static methods”. You should find it don’t work as expected when trying to access instance members in it, for example:

  1. <?php  
  2. include(‘php/phprpc_server.php’);  
  3. class ExampleCounter {  
  4.     var $_count = 0;  
  5.     function inc() {  
  6.         $this->_count += 1;  
  7.     }  
  8.     function count() {  
  9.         return $this->_count;  
  10.     }  
  11. }  
  12. $server = new PHPRPC_Server();  
  13. $server->add(array(‘inc’‘count’), new ExampleCounter());  
  14. $server->start();  
  15. ?> 

We published two instance methods of ExampleCounter, but no matter how many times inc called by clients, count always returns 0.

It is caused by the way of PHP execution. The server side pages are loaded again everytime you call them. So, a new ExampleCount instance will be created everytime, and destoried with all page content.

If you want to use instances like local resources, you can add instances to sessions, for example:

  1. <?php  
  2. include(‘php/phprpc_server.php’);  
  3. class ExampleCounter {  
  4.     var $_count = 0;  
  5.     function inc() {  
  6.         $this->_count += 1  
  7.     }  
  8.     function count() {  
  9.         return $this->_count;  
  10.     }  
  11. }  
  12. if (!isset($_SESSION[‘counter’])) {  
  13.     $_SESSION[‘counter’] = new ExampleCounter();  
  14. }  
  15. $server = new PHPRPC_Server();  
  16. $server->add(array(‘inc’‘count’), $_SESSION[‘counter’]);  
  17. $server->start();  
  18. ?> 

By this way, you will get expected result when calling from clients, you can operate session in instances as well.

  1. <?php  
  2. include(‘php/phprpc_server.php’);  
  3. class ExampleCounter {  
  4.     function ExampleCounter() {  
  5.         if (!isset($_SESSION[‘count’])) {  
  6.             $_SESSION[‘count’] = 0;  
  7.         }  
  8.     }  
  9.     function inc() {  
  10.         $_SESSION[‘count’] += 1;  
  11.     }  
  12.     function count() {  
  13.         return $_SESSION[‘count’];  
  14.     }  
  15. }  
  16. $server = new PHPRPC_Server();  
  17. $server->add(array(‘inc’‘count’), new ExampleCounter());  
  18. $server->start();  
  19. ?> 

That’s exactly what we do when developing PHP dynamic pages. If you need application scope instead of session scope, database and Memcache can help, they are out of topic, we won’t talk about them here.

Publishment options

Services publishment has several options, in most cases, you don’t need to worry about them, the default values should be the best. Here is an example of options:

  1. <?php  
  2. include(‘php/phprpc_server.php’);  
  3. function hello($name) {  
  4.     return ‘Hello ‘ . $name;  
  5. }  
  6. $server = new PHPRPC_Server();  
  7. $server->add(‘hello’);  
  8. $server->setCharset(‘UTF-8’);  
  9. $server->setDebugMode(true);  
  10. $server->setEnableGZIP(true);  
  11. $server->start();  
  12. ?> 

setCharset is a method used to set charset, the default value is 'UTF-8', if you need other charsets, you need to call this method, UTF-8 is one of the best choice for internationalization.

setDebugMode decide whether your servre is running in debug mode. In debug mode, the published methods will return more detailed information, including filenames, lines. Generally speaking, in production site, this options should be turned off, it is secure for your web server, so the default value is false.

setEnableGZIP is used to turn on/off gzip compression. GZIP compresson can reduce the number of bytes transmitted, but it costs more memory and CPU, so the default value is off. Actually, many web servers (such as Apache, lighttpd, nginx) provide GZIP compression, we don’t need to turn it on in general.
You won’t see the warning error, because it won’t popup like a dialog box, it is visible in programming level only, you will find it when you check the error object.

 
 
 
PHPRPC for PHP Client
 
 

In Quick start chapter, we have got to know how to use PHPRPC client to access PHPRPC services, let us have a look at a more complicated example:

  1. <?php  
  2. include (“php/phprpc_client.php”);  
  3. $client = new PHPRPC_Client();  
  4. $client->setProxy(NULL);  
  5. $client->useService(‘http://127.0.0.1/server.php’);  
  6. $client->setKeyLength(1000);  
  7. $client->setEncryptMode(3);  
  8. $client->setCharset(‘UTF-8’);  
  9. $client->setTimeout(10);  
  10. echo $client->hi(‘PHPRPC’), “\r\n”;  
  11. echo $client->getKeyLength(), “\r\n”;  
  12. echo $client->getEncryptMode(), “\r\n”;  
  13. echo $client->getCharset(), “\r\n”;  
  14. echo $client->getTimeout(), “\r\n”;  
  15. ?> 

This is the hi method we used before, maybe you have found out there are no parameters when we initialize PHPRPC_Client, so we need to call useService to indicate a service URL.

setProxy is provided to set HTTP proxy, proxies willn’t be used if NULL is set. You can set proxies by two ways:

  1. By URL: http://username:password@host:port, username, password and port are optional
  2. Passing 4 parameters, they are host, port, username and password by order, again, port, username and password are optional.

useService is used to set service URL, if it is set when initializing, it is not necessary to call it anymore. But you can change service URL anytime you want by this method .

setKeyLength sets key length.

setEncryptMode sets encrypted mode.

setCharset sets client charset.

setTimeout sets timeout period, use the number of seconds as parameter.

getKeyLength gets key length, it is a negotiated value you got from the first remote call, otherwise, it is the value you set by setkeyLength (or default value 128).

getEncryptMode gets encrypted mode, after the first call, if the server doesn’t support encryption, this method will return 0, otherwise return the value you set.

getCharset return charset, after the first call, this method will return server side charset, otherwise, it will return the charset you set.

getTimeout return timeout period you set or default value 30s.

Reference parameters

When calling PHPRPC service by method names, it is not reference passing, because it is completely different between remote calling and local calling. For local, Reference parameters is actuall passing memory address (pointer), local calling is possible to modify the value of parameters (not modifying pointer). It cost less then passing value. But remote calling will serialize local value, then pass to remote sever, this is passing value, if passing reference is needed, the server side need to serialize parameters, the return to clients. It is costly, that why PHPRPC client don’t use reference parameters by default.

It is not difficult to use reference parameters in PHPRPC, but you need invoke to call remote services. Let use see an example. The server published a PHP internal function: sort, below is how we call it from client:

  1. <?php  
  2. include (“php/phprpc_client.php”);  
  3. $client = new PHPRPC_Client(‘http://127.0.0.1/server.php’);  
  4. $fruits = array(“lemon”“orange”“banana”“apple”);  
  5. $args = array(&$fruits, SORT_STRING);  
  6. print_r($fruits);  
  7. $client->invoke(‘sort’$args, true);  
  8. print_r($fruits);  
  9. ?> 

We will see the result:

Well, success.

Three things need to be aware:

First, the second parameter of invoke is reference parameter, it must be a variable, so we cannot say:

  1. $client->invoke(‘sort’, array(&$fruits, SORT_STRING), true);  

You will get an error like this:

Second, when assigning $args, if $fruits is not a reference, you won’t see the changed value after calling invoke by print_r($fruits);, but if you call print_r($args);, you will find out the first element is changed, it successed.

Third, most important one, the third parameter of invoke decide whether use reference parameters, if it is true, then pass reference, if false, pass value. The default value is false, you are able to use invoke to pass value, but it is more complicated, but if you need string type function name to call remote service, it is a good deal for you.

 

 
PHPRPC for PHP utilities

PHPRPC for PHP Date Class

PHP provides many date and time functions, but they can process string or number format only. In PHP, there is no class to present date and time until PHP 5.2, ~Datetime is shipped with PHP 5.2, but there are no detailed documentation of it.

To exchange date type with the other language, PHPRPC use PHPRPC_Date to present date type. When serializing or unserializing, all date class will be processed by PHPRPC_Date, different languages can exchange date type data directly by this class.

Create PHPRPC_Date object

To get a PHPRPC_Date object, 4 ways are available:

  1. PHPRPC_Date construction function
  2. PHPRPC_Date static method now
  3. PHPRPC_Date static method today
  4. PHPRPC_Date static method parse

They are different and relative, when call PHPRPC_Date constructor without parameters, it returns the same result as now. today returns the same date as now, but time part is fulfilled by 0. PHPRPC_Date constructor takes int and string type parameters, parse supports these two types as well. int type parameter is Unix timestamp, constructor and parse accept it identically. For string parameter, it is different, constructor accepts the same formats as strtotime, but parse accepts the following formats:

short format 2008-10-21
long format 2008-10-21 12:13:34
full format 2008-10-21 12:13:34.167

The full format is not supported by strtotime. parse takes PHPRPC_Date object as parameter, it will return the parameter directly.

PHPRPC_Date instance properties

year Year
month Month
day Day
hour Hour
minute Minute
second Second
millisecond Millisecond

PHPRPC_Date instance methods

addMilliseconds($milliseconds) add $milliseconds milliseconds, $milliseconds is integer, positive or negative number
addSeconds($seconds) add $seconds seconds, $seconds is integer, positive or negative number
addMinutes($minutes) add $minutes minutes, $minutes}}} is integer, positive or negative number
addHours($hours) add $hours hours, $hours is integer, positive or negative number
addDays($days) add $days days, $days is integer, positive or negative number
addMonths($months) add $months months, $months is integer, positive or negative number
addYears($years) add $years years,$years is integer, positive or negative number
after($when) If current object is later than $when, return true, otherwise, return false. $when should be accepted by parse
before($when) If current object is earlier than $when, return true, otherwise return false. $when should be accepted by parse
equals($when) If current object equals $when, return true, otherwise, return false. $when should be accepted by parse
set($year, $month, $day[, $hour, $minute, $second[, $millisecond]]) Set values
time() Return Unix timestamp of this object
toString() Return textual representation of current object, it is full format which is supported by parse
dayOfWeek() Return the day of the week, value, from 0-6, 0 is Sunday, 1 is Monday … 6 is Saturday
dayOfYear() Return the day of the year

PHPRPC_Date static methods

dayOfWeek($year, $month, $day) Return the day of the week, value, from 0-6, 0 is Sunday, 1 is Monday … 6 is Saturday
dayOfYear($year, $month, $day) Return the day of the year
isLeapYear($year) Return if it is leap year
daysInMonth($year, $month) Return how many days in this month
isValidDate($year, $month, $day) Is it a valid date?
isValidTime($hour, $minute, $second) Is it a valid time?