存档

‘php’ 分类的存档

PHP中错误处理

2012年2月9日 effect 没有评论

PHP提供了很多的错误等级,这里不一一罗列出来,有兴趣可以翻翻PHP的手册获取。本文主要是讲述在生产环境和开发环境中,错误的处理方式。

1 错误等级

在生产环境中建议 error_reporting(E_ALL ^ E_NOTICE) ,意义是除了notice,其他错误都会记录在案。

在开发环境中如果想严格控制错误,那么可以这样:error_reporting(E_ALL | E_STRICT); 这里几乎所有的错误都会记录,其实也可以和生产环境一致,notice不记录。

2 错误相关的配置(php.ini)

display_errors   是否展示错误,建议开发环境On,生产环境一定要Off,

log_errors  是否记录错误到日志文件中,建议开发环境On,如果你生产环境并发请求比较大,建议Off,当你生产环境出现莫名其妙的问题可以打开几分钟记录一下。

error_log   错误日志的文件路径,当log_errors为On的时候,出现错误的时候,会把错误记录到此文件中。

综上所述,建议在开发环境中如下配置

display_errors = On

log_errors = On

error_log = “/path/to/php/log/file”

生产环境中这样配置:

display_errors=Off

log_errors=Off   #当需要定位问题的时候,可以改为On

error_log = “/path/to/php/log/file”

3 自定义错误处理方式

有时候需要对错误进行更加高级的处理,那么可以使用函数set_error_handler。如set_error_handler(‘my_error_handler’),出现错误的时候会调用函数my_error_handler来处理,也可以这样set_error_handler(array(‘eobj’,'emethod’)),这样的话,出现错误会调用eobj对象中的emethod方法。这里要注意的是,如果你这样声明了自定义错误处理,那么如果你设置了日志记录的配置都不起错用,就是说出现错误了也不会记录到配置文件中的error_log中,当然如果错误是致命错误,编译都没通过,那就会记录到error_log中。

有时候需要自己主动抛出错误的时候可以使用trigger_error。想象某个场景,你提供的某个接口需要一个关键的参数,而调用人确没有给或者给的参数不符合要求,那么可以trigger_error(‘param $obj is not valid’);  更加详细的使用方法请参看手册

分类: php 标签:

为什么要用安全模式?

2011年8月1日 effect 没有评论

什么是安全模式?

为了解决一些共享服务器上的安全问题而设立的模式,有一些文件操作的属主检查和一些函数的限制等等。在一些ISP供应商提供的服务器上面,一台服务器往往运行了N个web site,所以为了保证每个站点以及操作系统的安全,这些服务器往往启用了安全模式。

有什么影响?

安全模式才初衷是为了保证操作系统的安全性以及各个web site的安全性。操作系统的安全性可以防止用户恶意的调用一些系统命令以及限制一些文件的访问,所以会限制了exec、system等函数有一个目录检查,如果执行的命令在safe_mode_exec_dir 下面才可以被允许执行。其次会限制一些文件操作的相关函数,比如fopen、mkdir、copy、unlink、link、rename、chown等,这里会检查被操作的目录或者文件是否与被执行的脚本有相同的 UID(所有者)。其他的影响请参看手册/安全/安全模式。

真的有用吗?

正如手册所说:在PHP这一层解决服务器的安全性问题,似乎不太靠谱。对于ISP提供商来说,启用安全模式是必须的,但是还需要其他的安全性限制,比如限制配置disable_functions、disable_classes,每个用户建立自己的执行账户等。而对于公司的服务器来说,没必要启用安全模式,但是代码的安全要严格查询,尤其是一些根据用户的输入来处理对应的文件,这一步要检查是否有漏掉导致引入了一个系统文件等。

分类: php 标签: ,

ini_set知多少

2011年7月20日 effect 没有评论

想必大家都用过这个函数,可以动态的修改php的配置项。但是是不是所有的配置项都可以用ini_set来修改呢?答案肯定是否定的!因为如果都可以修改,那么有些ISP的disable_functions等安全性配置可以轻松被突破,那么哪些是可以修改的呢?本文就来寻找一下答案。

打开你的PHP手册,找到附录中的php.ini配置选项列表,每个配置选项都有一个可修改范围,范围有下面几种值:

PHP_INI_PERDIR 可以在php.ini    .htaccess   http.conf中设置。.htaccess和http.conf只能适用于apache的web server,并且是模块安装的才可以。手册中看到upload_max_filesize的配置范围就是PHP_INI_PERDIR,那么在.htaccess或者http.conf中这样配置:

php_value upload_max_filesize 180M

。这样你的上传文件的最大文件大小是180M了。

PHP_INI_SYSTEM 只能在php.ini和http.conf中配置。http.conf中的配置方法参看上面实例。

PHP_INI_ALL 可以在任何地方配置,所以只有访问是这个的才能在脚本中配置,所以ini_set可配置的选项只能是这个范围之内的

PHP_INI_USER 手册上说是可以在用户的脚本中可以配置,但是没有找到一个范围是这个的配置选项。

分类: php 标签:

给你的PHP加速

2011年7月19日 effect 没有评论

PHP作为一种解释性的语言,可以快速的构建各种WEB服务,并且有着良好的扩展性和维护性。然而每次请求时候,都会把PHP源码解释编译成操作系统可识别的机器码然后再执行,这样下来每次请求都会重复的进行解释编译,那有没有什么方法可以不重复解释编译呢?本文就介绍几种常用的PHP加速器。

什么是PHP加速器?

通过前面的了解,每次HTTP的请求都会进行一个过程:把编译解释成操作系统可以直接运行的机器码。这是一个重复的工作,加速器的功能就是把这一过程缓存起来重复使用。常用的加速器有:Alternative PHP Cache (APC)、XCache、eAccelerator。

Xcache

安装方式无非就是标准的PECL的按照方式,下面就说一下关键的配置文件和查看统计信息的方法。

配置

xcache.cacher = On    开启opcode 缓存器  当size为0时候无效

xcache.size  = 64M 缓存大小一般的网站64M足够,如果此台WEB SERVER有多个vhosts,那么可以适当的增加到256M或者512M等

xcache.count  CPU个数,如果是双核算2,8核的是8

xcache.var_size 同xcache.size

xcache.var_count 同xcache.count

xcache.ttl  缓存项目的ttl(Time To Live) 生命周期,0是永远

xcache.gc_interval  扫描过期项目的时间间隔, 0不扫描,

xcache.coverager  是否启用代码覆盖,测试时候发现关闭次选项加速效果更好

统计信息

拷贝源码中的admin目录下的文件到你的网站的目光目录下(比如是xcacheadmin),那么输入http://yourdomain/xcacheadmin/,这里会有验证框弹出,输入配置中的admin和pass即可。

eaccelerator

安装方式也是标准的PECL安装方式

配置

eaccelerator.shm_size = “8″     eAccelerator 可以使用的共享内存的数量 (以兆为单位) . “0″ 是指操作系统的默认值. 默认值是 “0″.
eaccelerator.cache_dir = “/tmp/eaccelerator”
eaccelerator.enable = “1″  是否开启 1打开 0关闭
eaccelerator.optimizer = “1″    是否开启内部优化 1打开
eaccelerator.check_mtime = “1″  是否开启文件修改的检测 1开启 0关闭
eaccelerator.debug = 0  是否打开日志记录。”1″ 为开启,”0″ 为关闭。默认值为 “0″。会将缓存命中得记录写入日志。
eaccelerator.filter = “”   判断缓存的文件,如果以叹号!开头,那么匹配的将不缓存,否则匹配的加入缓存,默认是空,表示所有的都缓存
eaccelerator.shm_max = “0″
eaccelerator.shm_ttl = 0
eaccelerator.prune_period = 0
eaccelerator.shm_only = 0
eaccelerator.compress = 1  是否压缩缓存内容  1允许
eacceleratorcompress_level = 9  压缩内容的等级 9是最高级

其他加速方法

编译

尽可能的只编译你需要的模块、很少用的模块编译成共享模式,执行时动态加载

配置

禁用register_globals

关闭magic_quotes_*

关闭expose_php

后记

加速PHP只是给PHP编译解析这一重复的过程进行优化,而一个WEB服务本身的执行速度还是取决于是否合理的使用了数据库、是否很好的使用了一些缓存系统(比如memcached)、整个架构是否是最优的。当然在这些条件都一致的情况下,使用这些加速软件还是能有一些效果。

APC一直没有实验,对比了一下xcache和eaccelerator,eacce稍微占优,而且配置文件也相对简单一点,所以个人倾向于使用eacce,当然每个项目可能结果不太一样,大家可以对比后再取舍。

分类: php 标签: ,

kohana3在nginx中的重写配置

2011年7月18日 effect 没有评论

在公司内部推广过kohana3,反应还算可以。不过有好几次同事来咨询在nginx下的重写配置,下面作为备忘:

 location / {
         root   /data/vhosts/k3.com/public_html;#这里改为你对应的目录
         index  index.php index.html index.htm;
          if (!-e $request_filename) {
                rewrite ^/(.*)$ /index.php/$1 last;
          }
        }
 
        location ~ ^(.+\.php)(.*)$  {
                root /data/vhosts/k3.com/public_html;#这里改为你对应的目录
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_index index.php;
                set $script $fastcgi_script_name;
            if ($uri ~ "^/index.php(/.+)$") {  ###这个if语句表示如果是如果是以/index.php开头的URL,那么设置sectip为index.php path_info为后面部分
                set $script 'index.php';
                set $path_info  $1;<span style="color: #800000;">###这一行很重要</span>
            }
                fastcgi_param SCRIPT_FILENAME /data/vhosts/k3.com/public_html/$fastcgi_script_name;#这里改为你对应的目录
                fastcgi_param  PATH_INFO $path_info;<span style="color: #800000;">###这一行也很重要 在kohana3中是使用path_info来做route</span>
                include fastcgi_params;
        }

kohana3是一个简单高效的PHP5框架,拥有良好的OO特性,很强的扩展性(非修改源码方式来扩展,在这里小小的BS一下总是想通过修改源码来达到扩展目的的同学),强烈推荐!

分类: php 标签:

真的了解memcached吗?

2011年7月18日 effect 没有评论

1 什么是memcached?

Memcached 是一个高性能的分布式内存对象缓存系统,基于一个存储键/值对的hashmap,也就是常说的Key-Value。主要特性是分布式和内存存储,所以读写速度是非常神速的,1.5W/s没问题的。

2 memecached启动参数

memcached -d -m 2048  -p 11211 -P /tmp/memcached.pid

-d 守护模式

-m 分配最大的内存单位MB

-p 监听端口

-P 保存pid的文件,只有-d的时候才有效果

其他的参数见memcached -h

结合上面的启动参数,关闭memcached的命令是:kill `cat /tmp/memcached.pid`   ,需要注意的是:memcached是存储在内存中,所以kill之后,存储的数据全部没了。

3 服务器状态

使用命令:telnet memcached-server-address port,这样就可以连接上memcached服务器,然后输入stats 即可得到服务器各项状态数据,主要状态说明:

pid 服务器进程id

uptime 服务器运行秒数

time 服务器当前时间锉

version 服务器版本

pointer_size 操作系统指针大小(32位的就是32)

rusage_user 进程累计用户时间

rusage_system 进程累计系统时间

curr_connections  当前打开的连接数

total_connections 系统启动后的连接总数

cmd_get   get请求总数

cmd_set  set请求总数

cmd_flush  flush请求总数

get_hits  get请求命中次数

get_misses  get未命中次数

delete_misses   delete未命中次数

delete_hits delete命中次数

threads  线程数

bytes 存储的item占用的 字节数

curr_items 当前item数目

total_items  系统启动后的总字节数目

evictions  为获取空闲内存而删除的items数(分配给memcache的空间用满后需要删除旧的items来得到空间分配给新的items)

limit_maxbytes   分配的内存大小

bytes_read  读取字节数目

bytes_written  发送字节数目

缓存命中率 = get_hits/cmd_get * 100%

4  php-client

有三种php-client:

1)MemcachedClient.php   使用的是php socket和服务器交互,不推荐 。

2)pecl的memcache扩展 推荐

3) pecl的memcached扩展 基于libmemcached的扩展,相比memcache多了很多方法,而且效率各方面也优于memcache扩展。强烈推荐

5 推荐的分布式方式

memcached服务器本身没有分布式的功能,分布式都是通过客户端根据key值算出对应的服务器节点。比较常规的分布式是求余法,但是这个方法有个致命的硬伤:当要增加或者删减一个服务器节点的时候,当时的缓存命中率大大降低。推荐的方法是一致性hash模式。

如果你使用的是memcache扩展,那么想要使用一致性hash模式,请在php.ini中增加或者修改配置:

Memcache.hash_strategy =consistent
Memcache.hash_function =crc32

如果使用的是memcached,那么在代码中使用:
$mem->setOption(Memcached::OPT_DISTRIBUTION,Memcached::DISTRIBUTION_CONSISTENT);
$mem->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE,true);

6 参考资料

memcached api文档翻译:http://blog.csdn.net/lgg201/article/details/6002928

memcached 安装方式:http://www.9enjoy.com/php-memcached/

一致性hash: http://baike.baidu.com/view/1588037.htm

分类: php, 服务器 标签:

httpsqs配置记录&php client

2011年7月13日 effect 没有评论

什么是httpsqs?

基于http的开源队列服务,使用Tokyo Cabinet 的 B+Tree Key/Value来做持久化存储。

适用于什么应用场景?

比较适合于比较慢而又没有特别高的时效性的应用。比如发送邮件(用户进行了某个操作,需要发送邮件给他的email账户通知。)、图片裁剪、视频转换、日志记录等。这些时效性要求不怎么高,这样就可以采用异步方式 ,让后台来集中处理,可以降低前台的服务压力。

具有什么特点?

支持http GET/POST协议,所以支持HTTP协议的都可以和他通信。

非常快速

高并发

更加详细的内容见官方网站:http://blog.s135.com/httpsqs/

官方提供了两种php client。1)php扩展(门槛高、不使用于win下的用户) 2)httpsqs_client.php (这个代码真不敢恭维)。所以自己写了一个httpsqs的类,供大家使用。

<!--?php class Httpsqs{ 	private $host; 	private $port; 	private $auth; 	private $charset; 	private static $sockets=array(); 	public function __construct($host,$port,$auth='',$charset='utf-8'){ 		$this--->host = $host;
		$this-&gt;port = $port;
		$this-&gt;auth = $auth;
		$this-&gt;charset = $charset;
	}
 
	public function get($name,$kt=0){
		$query  = $this-&gt;build_query($name,'get');
		return $this-&gt;execute($query,'GET','',$kt);
	}
 
	public function put($name,$body,$kt=0){
		$query = $this-&gt;build_query($name,'put');
		return $this-&gt;execute($query,'POST',$body,$kt);
	}
 
	public function reset($name){
		$query = $this-&gt;build_query($name,'reset');
		$r = $this-&gt;execute($query);
		if($r &amp;&amp; $r['data'] == "HTTPSQS_RESET_OK"){
			return true;
		}
		else return false;
	}
 
	public function status($name,$type='text'){
		if($type=='json'){
			$cmd = 'status_json';
		}
		else{
			$cmd = 'status';
		}
		$query = $this-&gt;build_query($name,$cmd);
		$r = $this-&gt;execute($query);
		if($r== false || $r['data']==false || $r['data']=='HTTPSQS_ERROR'){
			return false;
		}
		return $r['data'];
	}
 
	public function view($name,$pos){
		$query = $this-&gt;build_query($name,'view',array("pos=".$pos));
		$r = $this-&gt;execute($query);
		if($r==false || $r['data']==false || $r['data']=='HTTPSQS_ERROR'){
			return false;
		}
		else return $r['data'];
	}
 
	private function build_query($name,$cmd,$extra=array()){
		$tmp  = array("name=".$name,"opt=".$cmd);
		if($this-&gt;auth){
			$tmp[]="auth=".$this-&gt;auth;
		}
		$tmp[]="charset=".$this-&gt;charset;
		$tmp = array_merge($tmp , $extra);
		return '/?'.implode('&amp;',$tmp);
	}
 
	private function execute($query,$type='GET',$body='',$kt=0){
		if($kt==1){
			$key = md5($this-&gt;host.':'.$this-&gt;port);
			if(!isset(self::$sockets[$key])){
				self::$sockets[$key] = fsockopen($this-&gt;host,$this-&gt;port,$error,$errstr,5);
			}
			$socket = self::$sockets[$key];
		}
		else{
			$socket = fsockopen($this-&gt;host,$this-&gt;port,$error,$errstr,5);
		}
		if(!$socket){
			return false;
		}
		$out = "{$type} {$query} HTTP/1.1\r\n";
		$out .="Host: {$this-&gt;host}\r\n";
		if($type=='POST'){
			$out.="Content-Length: ".strlen($body)."\r\n";
		}
		if($kt==0){
			$out .="Connection: close\r\n";
		}
		else{
			$out .="Connection: Keep-Alive\r\n";
		}
		$out .="\r\n";
		if($type=='POST' &amp;&amp; $body){
			$out .=$body;
		}
		fwrite($socket,$out);
		$line = trim(fgets($socket));
		list($proto,$rcode,$result) = explode(" ",$line);
		$len = -1;
		$pos_value = 0;
		while(($line = trim(fgets($socket)))!=""){
			if(strstr($line,'Content-Length:')){
				list($cl,$len) = explode(" ",$line);
			}
			elseif(strstr($line,"Pos:")){
				list($pos_key,$pos_value) = explode(" ",$line);
			}
		}
		if($len&lt;0){ 			return false; 		} 		$body = @fread($socket,$len); 		if($kt==0){ 			fclose($socket); 		} 		return array( 			'pos'=&gt;intval($pos_value),
			'data'=&gt;$body
		);
	}
}

使用demo:

//get
$httpsqs = new Httpsqs('192.168.219.128','1218');
$r = $httpsqs-&gt;get('my_query');
 
//put
$httpsqs = new Httpsqs('192.168.219.128','1218');
$r = $httpsqs-&gt;put('my_query',"my_query_value");
 
//其他的请看源码

后感:
这个队列服务真的很实用,以前也有不少类似的应用,可以异步操作,实现方式是通过日志,比如每5分钟创建一个日志文件,然后每隔5分钟来处理,这样的风险很大,很可能造成数据的丢失等。有了这个,居多的应用都可以实现,异步发邮件,异步打日志,异步裁剪图片等等。

分类: php 标签:

多选项的保存

2010年9月10日 effect 没有评论

先贴上代码,稍候来阐述

function selectToDec($select,$all){
	$bin='';
	foreach($all as $s){
		if(in_array($s,$select)){
			$bin.='1';
		}
		else $bin.='0';
	}
	return bindec($bin);
}
function DecToSelect($dec,$all){
	$bin=decbin($dec);
	if(strlen($bin)<count($all)){
		$bin = str_pad($bin, count($all), "0", STR_PAD_LEFT); 
	}
	var_dump($bin);
	$select=array();
	for($i=0;$i<strlen($bin);$i++){
		if($bin[$i]==1) $select[]=$all[$i];
	}
	return $select;
}
分类: php 标签:

kohana3.0之分页

2010年9月2日 effect 没有评论

说实话,如果用route模式的话,真的很难用,建议用query_string

都一点了,困死了,直接上代码吧,在控制器里面:

$view = new View('test');
$this->pagination = new Pagination(array(
								'current_page'   => array('source' => 'query_string', 'key' => 'page'), // source: "query_string" or "route"
							    'total_items'    =>80, // use db count query here of course
							    'items_per_page' =>3, // it may be handy to set defaults for stuff like this in config/pagination.php
							    'view'          => 'pagination/floating',
							));
$view->set('page',$this->pagination);
$this->request->response = $view->render();

上面参数不解释。

在view中:

<?php echo $page->render();?>

不解释,收工睡觉!

分类: php 标签:

Kohana3.0之路由(router)

2010年9月2日 effect 没有评论

废话不多说,先上代码:

Route::set('static', '&lt;page&gt;',array('page'=&gt;'about|faq|location'))
	-&gt;defaults(array(
		'controller' =&gt; 'static',
		'action'     =&gt; 'index',
	));

意义:/about或者/faq或者/location这样的链接就直接路由到控制器:static,action:index。

Route::set('info', 'info/&lt;id&gt;',array('id'=&gt;'\d+'))
	-&gt;defaults(array(
		'controller' =&gt; 'product',
		'action'     =&gt; 'info',
	));

意义:info/123路由到:/product/info/123

Route::set('xiaozu', 'xiaozu/&lt;id&gt;(/&lt;controller&gt;(/&lt;action&gt;))',array('id'=&gt;'\d+'))
	-&gt;defaults(array(
		'directory'  =&gt; 'group',
		'controller' =&gt; 'main',
		'action'     =&gt; 'index',
	));

意义:/xiaozu/123 这样的链接路由到:/group/main/index。

参考文档:http://v3.kohanacn.com/guide/tutorials.urls

分类: php 标签: