[转] 奇虎360的PHP程序跟踪和分析工具:phptrace

介绍
phptrace 是一个追踪(trace)PHP执行流程的工具,你如果用过strace的话,则可能很容易想到phptrace到底实现了什么样的功能。其实,phptrace是类strace的一个实现,不同的是,strace用来追踪系统调用,而phptrace用来追踪PHP函数调用。无论是开发测试还是线上追查问题,代码执行流程往往会提供许多有用的信息,大大提高了开发人员的工作效率;对于系统函数,我们可以用strace 来观察其调用信息,然而PHP却长久以来缺少这么一个行之有效的工具,因此我们开发了phptrace。
phptrace 目前包括两部分功能:1.打印当前PHP调用栈,2.实时追踪PHP调用
回到顶部
1. 打印当前PHP进程调用栈
C程序的调用栈,我们通过pstack或gdb可以很容易获取到。PHP作为一种非编译型的语言,实际运行在C编写的PHP虚拟机之上。当我们用pstack 或 gdb来打印PHP的调用栈时,实际是打印的虚拟机的执行信息。比如:
?
$ pstack 3130
#0 0x00000035ee6accc0 in __nanosleep_nocancel () from /lib64/libc.so.6
#1 0x00000035ee6acb50 in sleep () from /lib64/libc.so.6
#2 0x0000000000714f23 in zif_sleep ()
#3 0x00000000008e36cd in execute_internal ()
#4 0x00007f27b38b2b77 in phptrace_execute_core () from /home/renyongquan/opt/php5.4.35/lib/php/extensions/debug-non-zts-20100525/phptrace.so
#5 0x00007f27b38b2c04 in phptrace_execute_internal () from /home/renyongquan/opt/php5.4.35/lib/php/extensions/debug-non-zts-20100525/phptrace.so
#6 0x00000000008e44bc in zend_do_fcall_common_helper_SPEC ()
3130 为php-fpm的进程ID,通过pstack我们看到了PHP虚拟机调用栈,然而对于一个PHP开发者来说,更感兴趣的是PHP的调用栈,你可以通过phptrace获取:
?
1
2
3
4
5
6
7 $ ./phptrace -p 3130 -s
phptrace 0.1 demo, published by infra webcore team
process id = 3130
script_filename = /home/renyongquan/opt/nginx//webapp/block.php
[0x7f27b9a99dc8] sleep /home/renyongquan/opt/nginx/webapp/block.php:6
[0x7f27b9a99d08] say /home/renyongquan/opt/nginx/webapp/block.php:3
[0x7f27b9a99c50] run /home/renyongquan/opt/nginx/webapp/block.php:10
-p 参数指定进程pid, -s表示我们需要获取stack信息; -p参数是必需的,并且只能是PHP相关进程(php,php-cli,php-fpm)的pid,这很好理解,因为我们获取的是PHP的调用信息。-s 如果省略,则phptrace不会打印调用栈,而是实时获取PHP函数执行流程,即phptrace 的第二个功能,也是其主要功能。现在我们仍然回到stack上来。
程序输出的第一行,是版本信息,第二行显示了其进程PID,第三行是当前执行的PHP脚本,从第四行开始就是调用栈信息,从打印的信息可以看出,最外层run函数调用了say函数,最终调用了sleep函数。
这时我们curl访问以下这个php脚本,显然会被堵塞住:
?
1 curl http://localhost:8804/block.php
我们知道,block.php在sleep,但是我们却不知道其到底要sleep多长时间,如果能获取到sleep的参数,问题便迎刃而解了,这时,就需要用到我们的第二个功能:实施追踪PHP调用。
回到顶部
2. 实时追踪PHP调用(trace)
trace功能依赖于我们实现的PHP模块,模块作为后端实时获取PHP调用信息,前端程序phptrace则解析并打印调用信息,因此,在使用这个功能之前需要先安装phptrace扩展。
安装扩展后,重启fpm,并打开trace,在php.ini添加配置如下
?
1
2
3 [phptrace]
extension=phptrace.so
phptrace.enabled = 1
?
1 $ phptrace -p 3130
重新访问block.php
?
1 curl http://localhost:8804/block.php
phptrace 打印:
?
1
2
3 1417486170.247324 run()
1417486170.247336 say($msg = “hello world”)
1417486170.247356 sleep($seconds = “3600”)
可以看到-p执行PID后,默认执行的就是trace功能,输出的第一列为函数调用的时间,后面则是调用信息,phptrace按照PHP调用顺序,依此打出run, say, sleep;此时,我们可以看到sleep的参数为3600s,因此curl请求要在1小时后才能返回。
实际上phptrace还可以打印函数返回值及调用耗时,,由于run,say,sleep函数都没有返回,在上面的例子中无法看到这个效果,我们改一下代码,使其sleep 1s :
$ ./phptrace -p 2459
1417506346.727223 run()
1417506346.727232 say($msg = “hello world”)
1417506346.727241 sleep($seconds = “1”)
1417506347.727341 sleep => 0 1.000100
1417506347.727354 say => hello world 1.000122
1417506347.727358 run => nil 1.000135
输出的前三行跟上面的例子相同,仍然是PHP函数的调用信息,后三行则表明了对应函数的返回值以及调用耗时: sleep 返回0 ,耗时1.000100s, say 返回 “hello world”,耗时1.000122s,之所以这么长时间,是因为其调用了sleep函数,同样run 返回nil,及没有返回值,耗时1.000135s。
回到顶部
最后
这里举得例子很简单,因为我们的主要目的是展示phptrace的使用方法,以及phptrace可以为我们提供的信息。后面,我们也会结合实际场景,分别展示phptrace,在开发,测试,以及线上排查问题时如何最大发挥其作用。
phptrace仅仅是一个工具,具体可以用在什么场景,我们考虑的也许不全面,如果你有任何使用心得或改进建议,欢迎向我们反馈。
项目主页:http://www.open-open.com/lib/view/home/1419946294703

使用gzencode对数据进行压缩

对于上一篇博客要存储blob的类型,可以对数据进行压缩后存储
函数如下:http://php.net/manual/zh/function.gzencode.php
简单的例子

        $str = "this is a test string this is a test string this is a test string this is a test string this is a test string";
        var_dump($str);
        $zip   = gzencode($str);
        $unzip = gzdecode($zip);
        var_dump($zip);
        var_dump($unzip);

结果:
string(109) “this is a test string this is a test string this is a test string this is a test string this is a test string” string(44) “-� +��,V�D���� �⒢̼t� ڈ ��� m” string(109) “this is a test string this is a test string this is a test string this is a test string this is a test string”
可以看到明显的数据压缩。
对于存储在KV或者数据库的数据压缩后存储,虽然浪费了CPU性能,但是大大提高了存储空间,在一般的接口速度上也能提高。
this is a benchmark test of gzencode (.txt file)
———————————————-
original file size = 3.29 MB (3,459,978 bytes)
compress lvl 1 = 1.09 MB (1,144,006 bytes)
compress lvl 2 = 1.06 MB (1,119,518 bytes)
compress lvl 3 = 1.03 MB (1,085,567 bytes)
compress lvl 4 = 953 KB (976,538 bytes)
compress lvl 5 = 909 KB (931,486 bytes)
compress lvl 6 = 910 KB (932,516 bytes)
compress lvl 7 = 910 KB (932,608 bytes)
compress lvl 8 = 910 KB (932,646 bytes)
compress lvl 9 = 910 KB (932,652 bytes)

[转]MySql中Blob与Text的区别

BLOB是一个二进制大对象,可以容纳可变数量的数据。有4种BLOB类型:TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB。它们只是可容纳值的最大长度不同。

有4种TEXT类型:TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT。这些对应4种BLOB类型,有相同的最大长度和存储需求。

BLOB 列被视为二进制字符串(字节字符串)。TEXT列被视为非二进制字符串(字符字符串)。BLOB列没有字符集,并且排序和比较基于列值字节的数值值。TEXT列有一个字符集,并且根据字符集的 校对规则对值进行排序和比较。

在TEXT或BLOB列的存储或检索过程中,不存在大小写转换。

当未运行在严格模式时,如果你为BLOB或TEXT列分配一个超过该列类型的最大长度的值值,值被截取以保证适合。如果截掉的字符不是空格,将会产生一条警告。使用严格SQL模式,会产生错误,并且值将被拒绝而不是截取并给出警告。

在大多数方面,可以将BLOB列视为能够足够大的VARBINARY列。同样,可以将TEXT列视为VARCHAR列。BLOB和TEXT在以下几个方面不同于VARBINARY和VARCHAR:

· 当保存或检索BLOB和TEXT列的值时不删除尾部空格。(这与VARBINARY和VARCHAR列相同)。

请注意比较时将用空格对TEXT进行扩充以适合比较的对象,正如CHAR和VARCHAR。

· 对于BLOB和TEXT列的索引,必须指定索引前缀的长度。对于CHAR和VARCHAR,前缀长度是可选的。

· BLOB和TEXT列不能有 默认值。

LONG和LONG VARCHAR对应MEDIUMTEXT数据类型。这是为了保证兼容性。如果TEXT列类型使用BINARY属性,将为列分配列字符集的二元 校对规则。

MySQL连接程序/ODBC将BLOB值定义为LONGVARBINARY,将TEXT值定义为LONGVARCHAR。

由于BLOB和TEXT值可能会非常长,使用它们时可能遇到一些约束:

· 当排序时只使用该列的前max_sort_length个字节。max_sort_length的 默认值是1024;该值可以在启动mysqld服务器时使用–max_sort_length选项进行更改。

运行时增加max_sort_length的值可以在排序或组合时使更多的字节有意义。任何客户端可以更改其会话max_sort_length变量的值:

mysql> SET max_sort_length = 2000;

mysql> SELECT id, comment FROM tbl_name

-> ORDER BY comment;

当你想要使超过max_sort_length的字节有意义,对含长值的BLOB或TEXT列使用GROUP BY或ORDER BY的另一种方式是将列值转换为固定长度的对象。标准方法是使用SUBSTRING函数。例如,下面的语句对comment列的2000个字节进行排序:

mysql> SELECT id, SUBSTRING(comment,1,2000) FROM tbl_name

-> ORDER BY SUBSTRING(comment,1,2000);

· BLOB或TEXT对象的最大大小由其类型确定,但在客户端和服务器之间实际可以传递的最大值由可用内存数量和通信缓存区大小确定。你可以通过更改max_allowed_packet变量的值更改消息缓存区的大小,但必须同时修改服务器和客户端程序。例如,可以使用mysql和mysqldump来更改客户端的max_allowed_packet值。

每个BLOB或TEXT值分别由内部分配的对象表示。这与其它列类型形成对比,后者是当打开表时为每1列分配存储引擎。

[php]通过yield方法,批量multi_curl请求接口数据

yield是php5.5以后的新特性,详细可通过之前的博客了解一般的yield概念,这里采用异步的方式,整合所有的curl请求,收集再一起,
最后通过统一的curl_multi_*方法批量获取,代码如下

<?php
class Test {
    
    protected $_mh;
    protected $_ch;
    protected $_doMulti = true;
    
    
    public function mytest() {
       
        $gens = array();
        //test接口 请添加自己的接口
        $url   = array();
        $url[] = "https://www.baidu.com/";
        $url[] = "http://www.haosou.com/";
        $i = 3;
        while($i) {
            $gens[$i] = $this->_asyncQuery($url[1]);
            $i --;
        }
        echo "i am doing same other!";
        $gens[4] = $this->_asyncQuery($url[0]);   
        do {
            $running = false;
            foreach($gens as $id => $gen) {
                if ($gen->valid()) {
                    $running = true;
                    $gen->next();
                    $tmp = $gen->current();
                    if ($tmp !== null) {
                        $ret[$id] = $tmp;
                    }
                }
            }
        }while($running);
        var_dump($ret);
    }
    
    
    protected function _asyncQuery($url, $body = array()) {
    
        yield null; // create a generator
        //{{{产生ch
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);       
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)');
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // 302 redirect
        //产生ch结束
    
        $body = http_build_query($body);
    
        curl_setopt($ch, CURLOPT_POST, (bool) $body);
    
        if($body) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
        }
    
        //一次multi
        if(empty($this->_mh)) {
            $this->_mh = curl_multi_init();
        }
        curl_multi_add_handle($this->_mh, $ch);
        $this->_ch[] = $ch;
        
        yield null;
        //这里需要统一处理,后面的迭代器不需要再次curl_mutlti_exec  
        if($this->_doMulti) {
        do {
            $mrc = curl_multi_exec($this->_mh, $active);
            } while ($active > 0);
            //var_dump("this just do once");
        }
         
        $ch  = array_shift($this->_ch);
        $raw = curl_multi_getcontent($ch);
        curl_multi_remove_handle($this->_mh, $ch);
        //如果为空的话,关掉multi_close
        if(empty($this->_ch)){
            curl_multi_close($this->_mh);
        }
        $this->_doMulti = false;
    
        yield $raw;
    
    } 
}

可以通过microtime(true)计算一下执行时间,和统一的curl_multi方法一致。大约是单个curl循环调用时间的N分之一。N为请求数(前提是每个请求的时间都差不多,否则multi_curl受最长时间影响)

Yii 框架下的权限管理CDbAuthManager中的AuthItemChild

大家都知道Yii可以通过CDbAuthManager进行简单的权限管理,在component下配置

    'components' => array(
        'authManager'=>array(
            'class'=>'CDbAuthManager',
            'connectionID'=>'db',
        ),
)

就可以直接使用。数据库对应的AuthItemChild,`AuthItem,AuthAssignment三张表。
其中AuthItem是有哪些权限,AuthAssignment是给哪些用户分配权限,而AuthItemChild使用中一般为空。
后来经过慢SQL查询,发现总是有SELECT `parent`\nFROM `AuthItemChild`\nWHERE child=:name这样的情况,因为AuthItemChild为空,所以造成速度很慢。
在CDbAuthManager中发现有递归权限验证

	protected function checkAccessRecursive($itemName,$userId,$params,$assignments)
	{
		if(($item=$this->getAuthItem($itemName))===null)
			return false;
		Yii::trace('Checking permission "'.$item->getName().'"','system.web.auth.CDbAuthManager');
		if(!isset($params['userId']))
		    $params['userId'] = $userId;
		if($this->executeBizRule($item->getBizRule(),$params,$item->getData()))
		{
			if(in_array($itemName,$this->defaultRoles))
				return true;
			if(isset($assignments[$itemName]))
			{
				$assignment=$assignments[$itemName];
				if($this->executeBizRule($assignment->getBizRule(),$params,$assignment->getData()))
					return true;
			}
			
			$parents=$this->db->createCommand()
				->select('parent')
				->from($this->itemChildTable)
				->where('child=:name', array(':name'=>$itemName))
				->queryColumn();

			
			foreach($parents as $parent)
			{
				if($this->checkAccessRecursive($parent,$userId,$params,$assignments))
					return true;
			}
		}
		return false;
	}

意思如果没有这个name的权限,就去AuthItemChild找parent,如果parent有权限,
那么自己也有权限。如果不使用,可以注释掉

// 			$parents=$this->db->createCommand()
// 				->select('parent')
// 				->from($this->itemChildTable)
// 				->where('child=:name', array(':name'=>$itemName))
// 				->queryColumn();
			
// 			foreach($parents as $parent)
// 			{
// 				if($this->checkAccessRecursive($parent,$userId,$params,$assignments))
// 					return true;
// 			}

最后可以用redis代替db来进行权限的管理,具体方法见http://www.yuansir-web.com/2013/07/30/%E5%88%A9%E7%94%A8redis-%E5%8A%A0%E9%80%9F-yii-cdbauthmanager/

Nginx 下php5和php7共存的方法

一 准备工作
安装和配置好php5,php7

二 修改php-fpm.conf
监听sock设置不同的文件

listen = /home/work/var/run/php7.sock  
listen = /home/work/var/run/php.sock  

之后启动两个/sbin/下的php-fpm
三 修改nginx

    upstream php {
        server unix:/home/work/var/run/php.sock  weight=1 max_fails=2 fail_timeout=30s;
    }   

    upstream php7 {
        server unix:/home/work/var/run/php7.sock  weight=1 max_fails=2 fail_timeout=30s;
    }

之后 根据不同的需求配置nginx的location,就可以使用不同的php了

    location @php {
        include fastcgi_params;
        fastcgi_param  SCRIPT_FILENAME &quot;$document_root/index.php&quot;;
        fastcgi_pass php7;
    }   

    location ~ /php5 {
        include fastcgi_params;
        fastcgi_param  SCRIPT_FILENAME &quot;$document_root/index.php&quot;;
        fastcgi_pass php;
    }

三 测试结果
/test/php5/和/test/php/下分别有phpinfo()函数,结果是不同的php版本,表示设置成功了
用ab压测下ab -c 5 -n 10 localhost:8080/test/php/


发现结果还是差距挺大的

[转]使用socket方式连接Nginx优化php-fpm性能

原文地址:https://blog.linuxeye.com/364.html
Nginx连接fastcgi的方式有2种:TCP和unix domain socket
什么是Unix domain socket?—— 维基百科
Unix domain socket 或者 IPC socket是一种终端,可以使同一台操作系统上的两个或多个进程进行数据通信。与管道相比,Unix domain sockets 既可以使用字节流和数据队列,而管道通信则只能通过字节流。Unix domain sockets的接口和Internet socket很像,但它不使用网络底层协议来通信。Unix domain socket 的功能是POSIX操作系统里的一种组件。
Unix domain sockets 使用系统文件的地址来作为自己的身份。它可以被系统进程引用。所以两个进程可以同时打开一个Unix domain sockets来进行通信。不过这种通信方式是发生在系统内核里而不会在网络里传播。
TCP和unix domain socket方式对比
TCP是使用TCP端口连接127.0.0.1:9000
Socket是使用unix domain socket连接套接字/dev/shm/php-cgi.sock(很多教程使用路径/tmp,而路径/dev/shm是个tmpfs,速度比磁盘快得多)
测试机是个1核的centos5.4,2用户并发时系统资源消耗50%左右,10用户资源就跑得很满了。
2users 10users
nginx/1.2.9 + PHP 5.2.5 tcp 1060 1294
nginx/1.2.9 + PHP 5.2.5 socket 997 1487
nginx/1.2.9 + PHP 5.3.10 tcp 906 1082
nginx/1.2.9 + PHP 5.3.10 socket 880 1247
结论是在服务器压力不大的情况下,tcp和socket差别不大,但在压力比较满的时候,用套接字方式,效果确实比较好。
下面是php 5.3以上版本将TCP改成socket方式的配置方法:
修改php-fpm.conf(/usr/local/php/etc/php-fpm.conf)
;listen = 127.0.0.1:9000
listen = /dev/shm/php-cgi.sock
修改nginx配置文件server段的配置,将http的方式改为socket方式
location ~ .*\.(php|php5)?$ {
#fastcgi_pass 127.0.0.1:9000;
fastcgi_pass unix:/dev/shm/php-cgi.sock;
fastcgi_index index.php;
include fastcgi.conf;
}
重启php-fpm与nginx
service nginx restart
service php-fpm restart
ls -al /dev/shm
可以看到php-cgi.sock文件unix套接字类型
参考:http://zh.wikipedia.org/wiki/Unix_domain_socket

[转]PHP连接Mysql常用API(mysql,mysqli,pdo)的区别

原文链接:http://my.oschina.net/junn/blog/204594?fromerr=u7hz0qmX
PHP中提供的用于MySQL的主要API是什么?
当考虑连接到MySQL数据库服务器的时候,有三种主要的API可供选择:
PHP的MySQL扩展
PHP的mysqli扩展
PHP数据对象(PDO)
三者都有各自的优缺点。下面的讨论就是为了对每种API的关键方面给出一个简短的介绍。

什么是PHP的MySQL扩展?
这 是设计开发允许PHP应用与MySQL数据库交互的早期扩展。mysql扩展提供了一个面向过程 的接口,并且是针对MySQL4.1.3或更早版本设计的。因此,这个扩展虽然可以与MySQL4.1.3或更新的数据库服务端 进行交互,但并不支持后期MySQL服务端提供的一些特性。
Note:如果你是使用MySQL4.1.3或更新的服务端版本,强烈建议你使用mysqli 扩展替代它。
mysql扩展的源代码在PHP扩展目录ext/mysql下。
对于mysql扩展的更多信息,请参阅MySQL。

什么是PHP的mysqli扩展?
mysqli扩展,我们有时称之为MySQL增强扩展,可以用于使用 MySQL4.1.3或更新版本中新的高级特性。mysqli扩展在PHP 5及以后版本中包含。
mysqli扩展有一系列的优势,相对于mysql扩展的提升主要有:
面向对象接口
prepared语句支持(译注:关于prepare请参阅mysql相关文档)
多语句执行支持
事务支持
增强的调试能力
嵌入式服务支持
Note:如果你使用MySQL4.1.3或更新版本,强烈建议你使用这个扩展。
在提供了面向对象接口的同时也提供了一个面向过程的接口。
mysqli扩展是使用PHP扩展框架构建的,它的源代码在PHP源码目录下的ext/mysqli中。
对于mysqli扩展的更多信息,请参阅Mysqli。

什么是PDO?
PHP 数据对象,是PHP应用中的一个数据库抽象层规范。PDO提供了一个统一的API接口可以使得你的PHP应用不去关心具体要 连接的数据库服务器系统类型。也就是说,如果你使用PDO的API,可以在任何需要的时候无缝切换数据库服务器,比如从Firebird 到MySQL,仅仅需要修改很少的PHP代码。
其他数据库抽象层的例子包括Java应用中的JDBC以及Perl中的DBI。
当然,PDO也有它自己的先进性,比如一个干净的,简单的,可移植的API,它最主要的缺点是会限制让你不能使用 后期MySQL服务端提供所有的数据库高级特性。比如,PDO不允许使用MySQL支持的多语句执行。
PDO是基于PHP扩展框架实现的,它的源码在PHP源码目录的ext/pdo下。
PDO的更多信息,请参阅PDO。

什么是PDO的MySQL驱动器?
PDO 的MySQL驱动并不是一套API,至少从PHP程序员的角度来看是这样的。实际上,PDO的MySQL驱动处于PDO自己的下层, 提供了特定的Mysql功能。程序员直接调用PDO的API,而PDO使用了PDO的MySQL驱动完成与MySQL服务器端的交互。
PDO的MySQL驱动是众多PDO驱动中的一个。其他可用的PDO驱动包括Firebird,PostgreSQL等等。
PDO的MySQL驱动是基于PHP扩展框架实现的。它的源码在PHP源码目录下的ext/pdo_mysql。 它没有向PHP程序员暴露API。
PDO的MySQL扩展的更多信息请参阅MySQL (PDO)。

什么是PHP的MySQL Native 驱动?(mysqlnd)
为了与MySQL数据库服务端进行交互,mysql扩展,mysqli扩展, PDO MySQL驱动都使用了实现了必要的协议的底层库。以前,可用的库只有MySQL客户端库和libmysql。
然而,libmysql包含的接口没有针对与PHP的应用交互进行优化,libmysql 是早期为C应用程序设计的。基于这个原因,MySQL Native驱动mysqlnd,作为libmysql的一个 针对PHP应用的修改版本被开发。
mysql,mysqli以及PDO Mysql驱动都可以各自配置使用 libmysql或者mysqlnd。mysqlnd作为一个专门设计 用于PHP系统的库,它在内存和速度上都比libmysql有很大提升。非常希望你去尝试这些提升。
Note:MySQL Native驱动仅仅可以在MySQL服务端版本为4.1.3及以后版本才可以使用。
MySQL Native驱动是基于PHP扩展框架实现的。源代码位于PHP源码目录的ext/mysqlnd下。 它没有向PHP程序员暴露接口。

&lt;?php
/**
看了很多相关数据库连接和操作后对
php中数据库连接的一个自我小结吧
------------希望有所益处
 
*/
 
//1 连接类型
/**
 
php中link -MySQL数据库服务器时常用的三种主要的API:mysql,mysqli,pdo区别及联系
 
/********基本相关信息*********/
  a.API----------------Application Programming Interface
应用程序接口(Application Programming Interface的缩写),定义了类,方法,函数,
变量等等一切 你的应用程序中为了完成特定任务而需要调用的内容。在PHP应用程序需要
和数据库进行交互的时候所需要的API 通常是通过PHP扩展暴露出来(给终端PHP程序员调用)。
 
API可以是面向过程的,也可以是面向对象的。对于面向过程的API,我们通过调用函数来完
成任务,而对于面向对象的API, 我们实例化类,并在实例化后得到的对象上调用方法。
对于这两种接口而言,后者通常是首选的,因为它更加现代化,并且 给我们带来了良好的
代码结构。
 
 
  b.connector  -----“一段允许你的应用连接到MySQL数据库服务器的软件代码”。 
 在你的PHP应用需要和一个数据库服务器交互的时候,你需要书写PHP代码去完成“连接数据
 库服务器”,“查询数据库“以及其他数据库相关功能 等一系列活动。你的PHP应用将会使用提
 供这些API的软件,或者在需要的时候使用一些中间库,来处理你的应用和数据库服务器之间
 的交互。
 
  c.驱动
  用来于一种特定类型的数据库服务器进行交互的软件代码。驱动可能会调用一些库,
  比如MySQL客户端库或者MySQL Native驱动库。 这些库实现了用于和MySQL数据库服务
  器进行交互的底层协议。
   
  可能大家会不加区分的使用连接器和驱动这两个术语。
  在MySQL相关文档中&quot;driver&quot;术语被作为一个连接器包 
  中提供特定数据库部分的软件代码。
 
  d.什么是扩展?
 
  在PHP文档中你还会发现很多其他的扩展。PHP代码是由一个核心,一些可选扩展组成了核心功能。
  PHP 的MySQL相关扩展,比如mysqli,mysql都是基于PHP扩展框架实现的。
  扩展一个典型的作用就是暴露一个API给PHP程序员,允许扩展自己的功能可以被程序员使用。
  当然,也有一部分基于PHP扩展框架 开发的扩展不会给PHP程序员暴露API接口。
 
比如说PDO MySQL驱动扩展,就没有向PHP程序员暴露API接口,但是向它上层的PDO层提供了一个接口。
 
术语API和扩展描述的不是同一类事物,因为扩展可能并不需要暴露一个API接口给程序员。
 
 
/*********重点*******/
PHP中提供的用于MySQL的主要API:
 
■PHP的MySQL扩展
    (优缺点)
 
    【
 
    设计开发允许PHP应用与MySQL数据库交互的早期扩展。mysql扩展提供了一个面向过程 的接口,
    并且是针对MySQL4.1.3或更早版本设计的。因此,这个扩展虽然可以与MySQL4.1.3或更新的数
    据库服务端 进行交互,但并不支持后期MySQL服务端提供的一些特性。
 
    】
 
 
■PHP的mysqli扩展
    mysqli扩展,我们有时称之为MySQL增强扩展,可以用于使用 MySQL4.1.3或更新版本中新的高级特性。
    mysqli扩展在PHP 5及以后版本中包含。
 
    mysqli扩展有一系列的优势,相对于mysql扩展的提升主要有:
 
    ■面向对象接口
 
    ■prepared语句支持(译注:关于prepare请参阅mysql相关文档)
 
    ■多语句执行支持
 
    ■事务支持
 
    ■增强的调试能力
 
    ■嵌入式服务支持
 
■PHP数据对象(PDO)
 
PHP数据对象,是PHP应用中的一个数据库抽象层规范。PDO提供了一个统一的API接口可以
使得你的PHP应用不去关心具体要 连接的数据库服务器系统类型。也就是说,
如果你使用PDO的API,可以在任何需要的时候无缝切换数据库服务器
 
 
/*******对比***********/
 
PHP-MySQL 是 PHP 操作 MySQL 资料库最原始的 Extension ,PHP-MySQLi 的 i 代表 Improvement ,
提更了相对进阶的功能,就 Extension 而言,本身也增加了安全性。
而 PDO (PHP Data Object) 则是提供了一个 Abstraction Layer 来操作资料库
 
 
详细出处参考:http://www.jb51.net/article/28103.htm
 
1.mysql与mysqli
mysqli是php5提供的新函数库,(i)表示改进,其执行速度更快.当然也更安全 
详细出处参考:http://www.jb51.net/article/28103.htm
 
mysql是非持继连接函数而mysqli是永远连接函数。也就是说 
mysql每次链接都会打开一个连接的进程而mysqli多次运行mysqli将使用同一连接进程,
从而减少了服务器的开销 
有些朋友在编程的时候,使用new mysqli('localhost', usenamer', 'password', 'databasename');总是报 
错,Fatal error: Class 'mysqli' not found in d:\... 
mysqli类不是php自带的吗? 
不是默认开启的,win下要改php.ini,去掉php_mysqli.dll前的;,linux下要把mysqli编译进去。 
一:Mysqli.dll是一个允许以对象的方式或者过程操作数据库的,它的使用方式也很容易。这里就几个常
详细出处参考:http://www.jb51.net/article/28103.htm
 
多做事少说话:
 
*/
&lt;?php 
mysql_connect($db_host, $db_user, $db_password); 
mysql_select_db($dn_name); 
$result = mysql_query(&quot;SELECT `name` FROM `users` WHERE `location` = '$location'&quot;); 
while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) 
{ 
echo $row['name']; 
} 
mysql_free_result($result); 
  
 
/**
其实背后有些学问… 
这种方式不能 Bind Column ,以前例的 SQL 叙述来说,$location 的地方容易被 SQL Injection。
后来于是发展出了 mysql_escape_string() (备注:5.3.0之后弃用) 以及 mysql_real_escape_string()
来解决这个问题,不过这麽一搞,整个叙述会变得複杂且丑陋,而且如果栏位多了,可以想见会是怎样的情形… 
 
详细出处参考:http://www.jb51.net/article/28103.htm
 
*/
 
 
 
 
$query = sprintf(&quot;SELECT * FROM users WHERE user='%s' AND password='%s'&quot;, 
mysql_real_escape_string($user), 
mysql_real_escape_string($password)); 
mysql_query($query); 
 
 
/**
在 PHP-MySQLi 中有了不少进步,除了透过 Bind Column 来解决上述问题,而且也多援 Transaction, Multi Query ,
并且同时提供了 Object oriented style (下面这段 PHP-MySQLi 范例的写法) 和 Procedural style 
(上面 PHP-MySQL 范例的写法)两种写法…等等。 
 
详细出处参考:http://www.jb51.net/article/28103.htm
*/
 
 
 
$mysqli = new mysqli($db_host, $db_user, $db_password, $db_name); 
$sql = &quot;INSERT INTO `users` (id, name, gender, location) VALUES (?, ?, ?, ?)&quot;; 
$stmt = $mysqli-&gt;prepare($sql); 
$stmt-&gt;bind_param('dsss', $source_id, $source_name, $source_gender, $source_location); 
$stmt-&gt;execute(); 
$stmt-&gt;bind_result($id, $name, $gender, $location); 
while ($stmt-&gt;fetch()) 
{ 
echo $id . $name . $gender . $location; 
} 
$stmt-&gt;close(); 
$mysqli-&gt;close(); 
 
/**
但看到这边又发现了一些缺点,例如得 Bind Result,这个就有点多馀,不过这其实无关紧要,
因为最大的问题还是在于这不是一个抽象(Abstraction)的方法,所以当后端更换资料库的时候,就是痛苦的开始… 
于是 PDO 就出现了
详细出处参考:http://www.jb51.net/article/28103.htm
 
*/
 
 
// 2.PDO与mysql
/*
PDO是PHP5.1之后才支持的,他为访问数据库采用了一致性的接口。但是国内众多的开源程序都是
使用MySQL的extension所提供的function连接数据库,进行查询。PDO功能强大为何国内成熟的PHP系统都不使用呢?
问过几个朋友为啥用PDO,答案是“快”,PDO连接数据库会快么?为什么使用PDO?
 
他们两种方式有什么区别?首先还是比较关心的性能问题.写了1个脚本测试向MySQL插入100万条数据。
*/
 
$link = mysql_connect(&quot;localhost&quot;, &quot;root&quot;, &quot;root&quot;) or die('mysql connect error');
$num = 100000;
$dsn = &quot;mysql:host=127.0.0.1;dbname=performace_test&quot;;
$db = new PDO($dsn, 'root', 'root', array(PDO::ATTR_PERSISTENT =&gt; true));
mysql_query('TRUNCATE TABLE `performace_test`.`myquery`',$link);  //Truncate Table
$query = &quot;INSERT INTO `performace_test`.`myquery`(`goods_id`,`cat_id`,`click_count`,`goods_number`,`goods_weight`,`goods_sn`,`goods_name`,`goods_reason`,`brand_name`,`goods_thumb`,`brand_id`,`is_on_sale`,`wap_cod`,`wap_title`,`wap_detail`,`wap_flag`,`wap_onsale`,`shop_price`,`cost_price`,`channel_rate`,`channel_onsale`,`add_time`,`is_main`,`last_update`,`brand_logo`) VALUES ( ’80′,’298′,’65′,’100′,’0.125′,’SMT000080′,’健康′,”,’健康120’,'images/201004/thumb_img/80_thumb_G_1272071721054.jpg’,’1′,’0′,’0′,NULL,NULL,NULL,’0′,’2980.00′,’0.00′,’1.250000′,’1′,’1271612064′,’0′,’1297624384′,’1293649512083026412.jpg’)&quot;;
$start_time = microtime(true);
for($i=0;$i&lt;$num;$i++)
{
mysql_query($query,$link);
}
echo &quot;USE MySQL extension: &quot;. (microtime(true)-$start_time);
mysql_query(‘TRUNCATE TABLE `performace_test`.`myquery`’,$link);  //Truncate Table
$start_time = microtime(true);
for($i=0;$i&lt;$num;$i++)
{
$db-&gt;exec($query);
}
echo &quot;\r\nUSE PDO : &quot;. (microtime(true)-$start_time);
 
/**
USE MySQL extension: 95.233189106s
 
USE PDO : 99.1193888187s
 
在链接MySQL上几乎没有区别。PDO的性能损失完全可以忽略不计。
 
但是却有非常多的操作却是MySQL扩展库所不具备的:
 
1:PDO真正的以底层实现的统一接口数库操作接口
2:PDO支持更高级的DB特性操作,如:存储过程的调度等,mysql原生库是不支持的.
3:PDO是PHP官方的PECL库,兼容性稳定性必然要高于MySQL Extension,可以直接使用 pecl upgrade pdo 命令升级
 
PHP6默认也是使用PDO进行数据库链接,MySQL Extension会作为辅助。
 
所以我们在日常项目中,如果环境允许,尽可能去使用PDO来进行MySQL数据库操作。
 
 
?&gt;

php7安装和使用yaf框架

php7的效率是php5的一倍,而yaf框架又是由C语言写的最快的框架,两者的结合应该是比较理想的架构。这里在自己的环境上安装和使用php7下的yaf
一 安装php7
我已经介绍过php7的安装:http://1.chunwei.sinaapp.com/?p=257
照着步骤安装即可
二 安装yaf
1, 到git上下载鸟哥的php7兼容版本:https://github.com/laruence/yaf/tree/php7
2,执行

/usr/local/php7/bin/phpize
./configure --with-php-config=/usr/local/php7/bin/php-config
make &amp;&amp; make install

3,添加扩展
打开 vim /usr/local/php7/etc/php.ini
添加
[yaf]
extension=yaf.so
4,顺手创建一个例子
在yaf
/yaf-php7/tools/cg
下执行
php yaf_cg web
这里产生了一个web的文件夹实例
三 配置nginx

server {
    listen 8080;
    root /usr/www/web;

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
    }



    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
}

四 测试
最后打开你的浏览器访问http://localhost:8080/index.php就可以看到输出Hello World! I am Stranger的实例了。这就代表了yaf已经安装成功。
压测一下自己的ab -n 50 -c 10 localhost:8080/index.php/

结果还是很赞的
最后 改进
听鸟哥的话:
http://www.laruence.com/2015/12/04/3086.html
添加opcache配置

opcache.enable=1
opcache.enable_cli=1
opcache.huge_code_pages=1
opcache.file_cache=/tmp

使用fastcgi_finish_request提高页面响应速度

原文链接:http://www.laruence.com/2011/04/13/1991.html
Fastcgi_finish_request文档:http://php.net/manual/zh/function.fastcgi-finish-request.php
PHP运行在FastCGI模式时,PHP FPM提供了一个名为fastcgi_finish_request的方法.按照文档上的说法,此方法可以提高请求的处理速度,如果有些处理可以在页面生成完后再进行,就可以使用这个方法.
听起来可能有些茫然,我们通过几个例子来说明一下:
1.
通过浏览器访问此脚本, 结果发现并没有输出相应的字符串,但却生成了相应的文件.由此说明在调用fastcgi_finish_request后,客户端响应就已经结束,但与此同时服务端脚本却继续运行!
合理利用这个特性可以大大提升用户体验,趁热打铁再来一个例子:
1.
代码里用sleep模拟一些耗时的操作,浏览时没有被堵塞,程序却都执行了,具体看日志.
末了给您提个醒,Yahoo在Best Practices for Speeding Up Your Web Site中提到了Flush the Buffer Early,也就是利用PHP中的flush方法把内容尽快发到客户端去,它和本文介绍的fastcgi_finish_request有些许的类似.
转载附言: 我看了下这个方法, 在调用的时候, 会发送响应, 关闭连接. 但是不会结束PHP的运行. 相比调用flush, 或者我之前介绍的加速你的Echo来说, 这个方法能更加干脆一些.
另外, 从代码的可移植性讲的话, 可以在代码中附上如下代码:
1. if (!function_exists(“fastcgi_finish_request”)) {
2. function fastcgi_finish_request() {
3. }
4. }
不会造成代码部署在非fpm环境下造成问题.
总结:之前flush只有在cli模式下运行才有效,这个方法亲测在服务器端FastCGI模式下生效。
封装函数

    public static function FlushJson($msg = ''){
        if (!function_exists(&quot;fastcgi_finish_request&quot;)) {
              function fastcgi_finish_request()  { }
        }
        if (!headers_sent()) {
            header('Content-type: application/json; charset=utf-8', TRUE);
        }
        echo json_encode($msg);
        fastcgi_finish_request();
        return;
    }