标签存档: php

PHP 5.4 新特性

精简数组用法

//old
$num = array('one', 'two', 'three');
//new
$num = ['one', 'two', 'three'];
$num = [
    '1'=>'one',
    '2'=>'two',
    '3'=>'three'
];

数组成员访问

$name = explode(",", "David, Beckham")[0];

function test()
{
    return [
        'key'  => [ 'hello'  =>  'world' ]
    ];
}
echo  test()[ 'key' ][ 'hello' ];

Trait
Traits 是一种轻量级的方法复用。

trait cURL
{
    public function curl($url)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($ch);
        curl_close($ch);

        return $output;
    }
}

/*
 * Twitter API Class
 */
class Twitter_API
{
    use cURL;

    public function get($url)
    {
        return json_decode($this->curl("http://api.twitter.com/".$url));
    }
}

/*
 * Facebook API Class
 */
class Facebook_API
{
    use cURL;

    public function get($url)
    {
        return json_decode($this->curl("http://graph.facebook.com/".$url));
    }
}

PHP扩展Coreseek API

Coreseek API下载地址http://www.coreseek.cn/products-install/api-list/

$ wget http://pecl.php.net/get/sphinx-1.2.0.tgz
$ tar -zxvf sphinx-1.2.0.tgz
$ cd sphinx-1.2.0
$ /usr/local/php/bin/phpize
$ ./configure --with-php-config=/usr/local/php/bin/php-config
$ make && make install
#安装PHP扩展之前需要安装libsphinxclient
#报错信息:configure: error: Cannot find libsphinxclient headers
$ cd coreseek-3.2.14/csft-3.2.14/api/libsphinxclient
$ ./configure
$ make && make install
$ /usr/local/apache2/bin/apachectl restart

为phpMyAdmin 增加安全口令

由于phpMyAdmin没有设置口令,任何人都可以控制数据库,所以增加一个安全口令,提高安全性。

$ vim /usr/local/apache2/conf/http.conf
#增加以下配置
<Directory "/var/www/html/phpMyAdmin">
    Options Includes FollowSymLinks
    AllowOverride all
    Allow from all
        AuthName "Administrator Auth"
        AuthType Basic
        AuthUserFile /etc/superzc.pwd
        require valid-user
    Order allow,deny
</Directory>
#增加用户以及密码
$ /usr/local/apache2/bin/htpasswd -c /etc/superzc.pwd superzc
password:  #输入安全口令的密码
$ /usr/local/apache2/bin/apachectl restart

重启apache之后,访问phpMyAdmin,搞定~已经需要安全验证。

Xdebug 安装与应用

之前,一直在用Xdebug,但是自己还没有尝试过安装,也没尝试过对Xdebug的应用提升,今天正好有空尝试了下。

Xdebug:是一个开放源代码的PHP程序调试器(即一个Debug工具),可以用来跟踪,调试和分析PHP程序的运行状况。

安装:

$ wget http://xdebug.org/files/xdebug-2.1.3.tgz
$ tar -zxvf xdebug-2.1.3.tgz
$ cd xdebug-2.1.3/
$ /usr/local/php/bin/phpize
$ ./configure --enable-xdebug --with-php-config=/usr/local/php/bin/php-config
$ make
$ make install
$ cd /usr/local/php/lib
$ vim php.ini
[Xdebug]
extension="xdebug.so"
xdebug.auto_trace=0
xdebug.collect_params=4
xdebug.collect_return=on
xdebug.show_mem_delta=1  #查看内存使用量
xdebug.profiler_enable=0  #只对指定的页面调试,和‍xdebug.profiler_enable_trigger连用
xdebug.profiler_output_dir="/tmp/"
xdebug.profiler_enable_trigger=1  #通过XDEBUG_PROFILE的get/post请求触发页面调试
$ /usr/local/apache2/bin/apachectl restart

安装成功后,显示如下截图:

应用

随便写了个php,测试下报错信息是否已经是应用Xdebug,截图如下:

应用提升:

register_shutdown_function('xdebug_stop_trace');

xdebug_start_trace("/tmp/xLog_test");

/*此处省略过程代码*/

xdebug_stop_trace();

生成的Xdebug日志文件/tmp/xLog_test.xt,部分内容截图如下:

通过Xdebug的日志,我们可以了解到时间和内存的使用情况,也可以了解陌生产品架构的方式,还可以通过执行时间快速的定位问题。

运用WinCacheGrind.exe:
1.WinCacheGrind.exe,下载地址:http://sourceforge.net/projects/wincachegrind/
2.如果xdebug.profiler_enable_trigger = 1开启状态,可以用游览器+调试参数XDEBUG_PROFILE来生成cachegrind.out.xxxx的文件,比如用游览器访问:http://www.superzc.com/index.php?id=1&XDEBUG_PROFILE。然后在xdebug.profiler_output_dir=”/tmp/”设置的目录下就生成了一个cachegrind.out.xxxx的文件;
3.最后用WinCacheGrind来解读这个文件,点击菜单栏的”File” –> “Open…”,选择cachegrind.out.xxxx文件,然后打开,如下图:

PHP APC 安装与应用

APC:Alternative PHP Cache (APC)是一种对PHP有效的开放源高速缓冲储存器工具,他能够缓存opcode的php中间码。

PHP APC提供两种缓存功能,即缓存Opcode(目标文件),我们称之为apc_compiler_cache。同时它还提供一些接口用于PHP开发人员将用户数据驻留在内存中,我们称之为apc_user_cache。

安装:

$ wget http://pecl.php.net/get/APC-3.1.9.tgz
$ tar -zxvf APC-3.1.9.tgz
$ cd APC-3.1.9/
$ /usr/local/php/bin/phpize
$ ./configure --enable-apc --enable-mmap --enable-apc-spinlocks --disable-apc-pthreadmutex --with-php-config=/usr/local/php/bin/php-config
$ make
$ make install
$ vim php.ini
#增加以下APC配置
[apc]
extension="apc.so"
apc.enabled=1
apc.cache_by_default=on  #对所有文件启用缓冲
apc.shm_segments=1  #apc.shm_segments指定了使用共享内存块数
apc.shm_size=64  #apc.shm_size指定一块共享内存空间大小,单位是M
apc.ttl=7200  #缓存条目在缓冲区中允许逗留的秒数
apc.user_ttl=7200
apc.num_files_hint=0
apc.write_lock=on  #启用写入锁
$ cd /home/super/APC-3.1.9/
$ cp apc.php /var/www/html/
$ /usr/local/apache2/bin/apachectl restart

调用phpinfo(),安装完成了,显示如下图:

访问apc.php,显示如下图:

PS:APC提供了apc.php,用于监控与管理APC缓存。不要忘记修改管理员名和密码:

defaults('ADMIN_USERNAME','super');
defaults('ADMIN_PASSWORD','123456');

应用:
1.函数说明:
apc_clear_cache() 清除apc缓存内容
默认(无参数)时,只清除系统缓存,要清除用户缓存,需用’user’参数

apc_define_constants ( string key, array constants [, bool case_sensitive] )
将数组constants以常量加入缓存

apc_load_constants (string Key)
取出常量缓存

apc_store ( string key, mixed var [, int ttl] )
在缓存中保存数据

apc_fetch ( string key )
获得apc_store保存的缓存内容

apc_delete ( string key )
删除apc_store保存的内容

<?php
$test=array(
'abc'=>'super',
'def'=>'hello world'
);

apc_define_constants('test_const',$test);

apc_load_constants('test_const');

echo 'test_const:'.abc;  //注意abc前面没有$
?>

输出:test_const:super

<?php
$bar = 'BAR';
apc_store('foo', $bar);
var_dump(apc_fetch('foo'));
?>

Python SocketServer

这几天在搞2台服务器同步文件的问题,由于公司文件传送限制用户权限,导致写好的传送脚本scp.exp用apache用户无法执行脚本同步。所以另外想办法,参照相关文档用python写了一个SocketServer,在后台跑然后接受php的命令去执行脚本($ nohup python server.py > nohup.out &或者$ python server.py &,然后#exit,再ssh登陆,查看后台进程#ps -ef | grep py,能查到server.py的进程就OK了。)
server端:server.py

import os
import SocketServer
class MyHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        while 1:
            dataReceived = self.request.recv(1024)
            if not dataReceived: break
            #self.request.send(dataReceived)
            #print dataReceived
            if dataReceived == 'cmd=1':
                os.system('/home/cgi/scp.exp')
                self.request.send(dataReceived+'&result=1\n')
            else:
                self.request.send(dataReceived+'&result=0\n')
myServer = SocketServer.ThreadingTCPServer(('localhost',6000), MyHandler)
myServer.serve_forever()

client端:client.py

import socket
remote_host = '127.0.0.1'
remote_port = 6000
send_buf = raw_input()
#send_buf = open('test.txt', 'rb').read()
#send_buf = send_buf.replace('\x0D\x0A', '')
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((remote_host, remote_port))
sock.send(send_buf)
response_data = sock.recv(1024)
print response_data
sock.close()

或者用PHP写client端:client.php

$fp = fsockopen("127.0.0.1", 6000, $errno, $errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)<br />\n";exit;
} else {
    $out = "cmd=1";
    fwrite($fp, $out);
    while (!feof($fp)) {
        $str .= fgets($fp, 4096);
    if(strpos($str, "\n") !== FALSE){
        if(strpos($str, "&result=1") != FALSE){
            break;
        }else{
    }
    }
}
fclose($fp);

启动apache 报错:libphp5.so:undefined symbol: zend_parse_parameters

今天在PHP扩展ssh2的时候,重启apache时候,发现报错,网上找了好久资料,一种是关闭selinux,怕安全性问题没这么做,后来又找到了一个解决方案(http://www.linuxforums.org/forum/red-hat-fedora-linux/87975-configuring-php-work-apache.html),如下:

$ /usr/local/apache2/bin/apachectl start
httpd: Syntax error on line 203 of /etc/httpd/conf/httpd.conf: Cannot load /usr/lib/httpd/modules/libphp5.so into server: /usr/lib/httpd/modules/libphp5.so: undefined symbol: zend_parse_parameters

解决方法:
首先,安装bison,bison 是替代yacc的语法分析程序生成器。

$ wget http://ftp.gnu.org/gnu/bison/bison-2.5.tar.gz
$ tar -zxvf bison-2.5.tar.gz
$ cd bison-2.5
$ ./configure
$ make
$ make install

然后,重新编译php

$ make install distclean
$ /usr/local/apache2/bin/apachectl start

[转]利用php调用C语言 扩展函数

第一步. 生成需要调用的so文件

1. 首先做一个简单的so文件:

/** * hello.c
* To compile, use following commands:
*   gcc -O -c -fPIC -o hello.o hello.c
*   gcc -shared -o libhello.so hello.o
*/
int hello_add(int a, int b)
{
return a + b;
}

然后将它编译成.so文件并放到系统中:

$ gcc -O -c -fPIC -o hello.o hello.c #-fPIC:是指生成的动态库与位置无关;假如是c++程序,用g++  -O -c -fPIC -o hello.o hello.c
$ gcc -shared -o libhello.so hello.o #-shared:是指明生成动态链接库;假如需要编译多个文件:g++ a.h b.cpp -fPIC -shared -o libtest.so
$ cp libhello.so /usr/local/lib #把生成的链接库放到指定的地址
$ echo /usr/local/lib > /etc/ld.so.conf.d/local.conf #把库地址写入到配置文件中
$ /sbin/ldconfig #用此命令,使刚才写的配置文件生效

2. 写段小程序来验证其正确性:

/**
* hellotest.c
* To compile, use following commands:
*   gcc -o hellotest -lhello hellotest.c
*/
#include <stdio.h>
int main()
{
int a = 3, b = 4;
printf("%d + %d = %d", a, b, hello_add(a,b));
return 0;
}

编译并执行:

$ gcc -o hellotest -lhello hellotest.c #编译测试文件,生成测试程序
$ ./hellotest #运行测试程序

第二步. 制作PHP模块(外部模块)

请确保你已安装 PHP及APACHE服务器。

$ cd php-5.2.3/ext

1. 然后通过下面的命令用ext_skel脚本建立一个名为 hello 的模块:

$ ./ext_skel --extname=hello

2. 执行该命令之后它会提示你应当用什么命令来编译模块,可惜那是将模块集成到php内部的编译方法。

如果要编译成可动态加载的 php_hello.so,方法要更为简单。

$ cd hello

首先编辑 config.m4 文件,去掉第16行和第18行的注释(注释符号为 dnl 。)

16: PHP_ARG_ENABLE(hello, whether to enable hello support,

17: dnl Make sure that the comment is aligned:

18: [ --enable-hello Enable hello support])

3. 然后执行 phpize 程序,生成configure脚本:

$ phpize

该程序在ubuntu的php5-dev包中

4. 打开 php_hello.h,在 PHP_FUNCTION(confirm_hello_compiled); 之下加入函数声明:

PHP_FUNCTION(confirm_hello_compiled); /* For testing, remove later. */

PHP_FUNCTION(hello_add);

5. 打开 hello.c,在 PHP_FE(confirm_hello_compiled, NULL) 下方加入以下内容。

zend_function_entry hello_functions[] = {

PHP_FE(confirm_hello_compiled, NULL) /* For testing, remove later. */

PHP_FE(hello_add, NULL) /* For testing, remove later. */

{NULL, NULL, NULL} /* Must be the last line in hello_functions[] */};

然后在 hello.c 的最末尾书写hello_add函数的内容:

PHP_FUNCTION(hello_add)

{

long int a, b;

long int result;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “ll”, &a, &b) == FAILURE) {

return;

}

result = hello_add(a, b);

RETURN_LONG(result);}保存退出,编译并安装。

表: zend_parse_parameters() 字母对应的类型

类型 字母 变量类型
Boolean b zend_bool
Long l long
Double d double
String s char *, int
Resource r zval *
Array a zval *
Object o zval*
zval z zval*

6. 编译

$ ./configure
#此处由于php-config的路径问题报错,解决方法:./configure --with-php-config=/usr/local/php/bin/php-config
$ make LDFLAGS=-lhello
$ sudo make install #编译生成了php扩展模块
Installing shared extensions: /usr/lib/php5/20060613
$ cp modules/hello.so /usr/lib/php/modules
$ vim /usr/local/php/lib/php.ini
#enable_dl = Off;允许dl()动态加载so扩展功能enable_dl = On
#增加一条:extension=hello.so
$ /usr/local/apache2/bin/apachectl restart

然后在 /var/www/html 下建立一个 hello.php 文件,内容如下:

<?php
dl("hello.so");
echo hello_add(3, 4);
?>

然后在浏览器中打开hello.php文件,如果显示7,则说明函数调用成功了。

第三步. 制作PHP模块(内部模块)

另外可以在apache重启的时候让我们的so库直接动态编译进php5,就像linux的insmod hello.ko模块一样,不用dl加载也不用重新编译php,就可以直接使用so的函数了,步骤如下:

$ vim /etc/php5/apache2/php.ini
#enable_dl = Off
#增加一条:extension=hello.so
$ /usr/local/apache2/bin/apachectl restart

不能reload而必须restart apache,这样so就像insmod hello.ko一样被融到了php5内核,然后代码就可以忽略掉dl(“hello.so”);了,
[注意,这种方式只适合hello.so库内所有功能代码已经全部调试ok,如果还处在调试期间,那么需要采用上面的dl强制加载的方式]

代码如下:

<?php
echo hello_add(3, 4);
?>

但是该功能不太适合调试,因为每次修改hello.so中代码的话,都需要让service apache restart重启才能让php5内核再次加载新的hello.so扩展.可以这样定义hello.so的实现,这样每次执行.php网页,都会在 /var/www/下建立一个文件夹,所以php扩展实现了

HTTP 协议

HTTP 304

304 的标准解释是:Not Modified 客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。

如果客户端在请求一个文件的时候,发现自己缓存的文件有 Last Modified ,那么在请求中会包含 If Modified Since ,这个时间就是缓存文件的 Last Modified 。因此,如果请求中包含 If Modified Since,就说明已经有缓存在客户端。只要判断这个时间和当前请求的文件的修改时间就可以确定是返回 304 还是 200 。对于静态文件,例如:CSS、图片,服务器会自动完成 Last Modified 和 If Modified Since 的比较,完成缓存或者更新。但是对于动态页面,就是动态产生的页面,往往没有包含 Last Modified 信息,这样浏览器、网关等都不会做缓存,也就是在每次请求的时候都完成一个 200 的请求。

因此,对于动态页面做缓存加速,首先要在 Response 的 HTTP Header 中增加 Last Modified 定义,其次根据 Request 中的 If Modified Since 和被请求内容的更新时间来返回 200 或者 304 。虽然在返回 304 的时候已经做了一次数据库查询,但是可以避免接下来更多的数据库查询,并且没有返回页面内容而只是一个 HTTP Header,从而大大的降低带宽的消耗,对于用户的感觉也是提高。

当这些缓存有效的时候,查看一个请求会得到这样的结果:

第一次访问 200

鼠标点击二次访问 (Cache)

按F5刷新 304

按Ctrl+F5强制刷新 200

HTTP 3xx

301 Moved Permanently:请求的资源已经被赋予一个新的URL

header( "HTTP/1.1 301 Moved Permanently" ) ;
header( "Location:http://www.superzc.com" );

304 Not Modified:如果客户端已经完成一个有条件的请求并且是允许的,但是这个文档并没有改变,服务器应该返回304状态码。304状态码一定不能包含信息主体,从而通常通过一个头字段后的第一个空行结束

HTTP 4xx:客户端错误

400 Bad Request:因为错误的语法导致服务器无法理解请求信息
403 Forbidden:服务器接收请求,但是被拒绝处理
404 Not Found

HTTP 5xx:服务器错误

500 Internal Server Error:服务器遭遇异常阻止了当前请求的执行
502 Bad Gateway

PHP函数 fgetcsv 中文问题

今天使用fgetcsv,打开上传的CSV文件后,发现文件列中包含中文的都为空。

解决方案:
// utf-8
setlocale(LC_ALL, ‘en_US.UTF-8′);
// 简体
setlocale(LC_ALL, ‘zh_CN’);

以下是常用的地区标识:
zh_CN GB2312
en_US.UTF-8 UTF-8
zh_TW BIG5
zh_HK BIG5-HKSCS
zh_TW.EUC-TW EUC-TW
zh_TW.UTF-8 UTF-8
zh_HK.UTF-8 UTF-8
zh_CN.GBK GBK

例子:

setlocale(LC_ALL, 'zh_CN.GBK');

$goods_csv=$_FILES['goods_info']['tmp_name']; //CSV编码为ANSI

$file = fopen($goods_csv,'r');

while ($data = fgetcsv($file)) {
    $goods_list[] = $data;
}

foreach($goods_list as $key=>$value){
    foreach($value as $k=>$v){
        //由于PHP文件编码是UTF-8,把GBK转码成UTF-8
        $goods_list[$key][$k] = mb_convert_encoding($v, "UTF-8", "GBK");
    }
}
print_r($goods_list);

fclose($file);
第 1 页,共 2 页12