php 异步执行脚本

2013年8月1日 没有评论

这里说的异步执行是让php脚本在后台挂起一个执行具体操作的脚本,主脚本退出后,挂起的脚本还能继续执行。比如执行某些耗时操作或可以并行执行的操作,可以采用php异步执行的方式。主脚本和子脚本的通讯可以采用外部文件或memcached的方式。原理就是通过exec或system来执行一个外部命令。注意:本文所述的是针对Linux环境。

在Linux下要让一个脚本挂在后台执行可以在命令的结尾加上一个 “&” 符号,有时候这还不够,需要借助nohup命令,关于nohup,可以参考http://www.netingcn.com/linux-nohup.html

CLI环境和Web环境执行的操作还不太一样。先来说CLI环境,这里需要用上nohup和&,同时还要把指定输出,如果不想要输出结果,可以把输出定向到/dev/null中。现在来做一个测试,假设在一个目录中有main.php、sub1.php和sub2.php,其中sub1和sub2内容一样都让sleep函数暂停一段时间。代码如下:

//main.php
<?php
    $cmd = 'nohup php ./sub.php >./tmp.log  &';
    exec($cmd);
    $cmd = 'nohup php ./sub1.php >/dev/null  &';
    exec($cmd);
?>

//sub1.php sub2.php
<?php
    sleep(100000);
?>

上述文件中main.php是作为主脚本,在命令行中执行php main.php,可以看到main.php脚本很快就执行完并退出。在使用ps aux | grep sub命令搜索进程,应该可以在后台看到上述的两个子脚本,说明成功挂起了子脚本。

在Web环境下,执行php脚本都是Web服务器开启的cgi进程来处理,只要脚本不退出,就会一直占有该cgi进程,当启动的所有cgi进程都被占用完后就不能在处理新的请求。所以对那些可能会很费时的脚本,可以采用异步的方式。启动子脚本的方式和CLI差不多,必须要使用&和指定输出(只好是定向到/dev/null),但是不能使用nohup。例如:

<?php
    $cmd = 'php PATH_TO_SUB1/sub1.php >/dev/null  &';
    exec($cmd);
    $cmd = 'php PATH_TO_SUB1/sub2.php >/dev/null  &';
    exec($cmd);
?>

当在浏览器中访问该脚本文件,可以看到浏览器里面响应完成,同时使用ps命令查看后台可以看到sub1和sub2脚本。

注意上述例子中如果php命令不在PATH中,需要指定命令完整的路径。推荐使用完整路径,特别是在Web下。

Strict Standards: Only variables should be passed by reference in

2013年7月28日 没有评论

php中使用内置的reset函数可以获取array的第一个元素的值。例如:

$arr = array('one', 'two', 'three');

echo reset($arr);   // 输出的结果为 one

对于下述代码,如果php开启了“Strict Standards”,将会看到“Strict Standards: Only variables should be passed by reference in”的提示。

$str = 'netingcn.com';

echo reset(explode('.', $str));

为什么会这样呢?可以先看看reset函数的定义:

function reset (array &$array) {}

从定义中可以看到,reset接受的参数是一个array的引用。而上述代码中explode返回值不是任何array的引用,所以在“Strict Standards”下会有上述提示。解决办法很简单,只需要把reset(explode(‘.’, $str))分两步写即可。第一步先把explode的返回值赋给一个变量,第二步把这个变量作为reset参数。

出现上面的提示的不只是reset函数,只要参数接受的是对象引用,而传值直接使用function返回值都会看到那样的提示。例如内置的array_pop、shuffle、curent、next、prev、next等等。

分类: PHP 标签:

也谈empty与isset区别

2013年7月19日 没有评论

empty是判断变量值是非空或非零的值。对应空定义包括:“”(空字符串)、0、“0”、NULL、FALSE、array()和$var(只声明但未赋值)。也就是说当变量值为上述这些,empty返回TRUE,其他的都返回FALSE。

isset是检测变量是否设置,并且不是 NULL。变量设置可以从几个方面来说。1:最简单的就是变量是否先声明和赋值;2:array中是否存在对应的index或key;3:object中是否存在对应的属性。

从上面的两个function定义可以看到,在某些情况下,两者可以公用,但其区别还是很大的。另外它们都只能检测变量,检测任何非变量的东西都将导致解析错误。例如直接检查另一个function的返回值(empty(otherFunction())),你将看到“Fatal error: Can’t use function return value in write context in”这样的错误。

另外isset可以一次检查多个变量,例如:isset($var1, $var2, $var3),当这三个值分别的isset都为TRUE结果为TRUE,否则结果为FALSE。

测试代码:

$sep = "<br />";

echo 'test undeclared var empty : ';
var_dump(empty($var));	// TRUE
echo $sep . 'test undeclared var isset : ';
var_dump(isset($var));	// FALSE

$var;
echo $sep . 'test declared var but no set value empty : ';
var_dump(empty($var));	// TRUE
echo $sep . 'test declared var but no set value isset : ';
var_dump(isset($var));	// FALSE, 变量申明未赋值,默认值为NULL

$var = NULL;
echo $sep . 'test declared var and set value NULL empty : ';
var_dump(empty($var));	// TRUE
echo $sep . 'test declared var and set value NULL isset : ';
var_dump(isset($var));	// FALSE, 变量申明赋值为NULL

$var1 = ''; $var2 = '0'; $var3 = 0; $var4 = FALSE; $var5 = array();

echo $sep . 'test \'\' empty : ';
var_dump(empty($var1));	// TRUE
echo $sep . 'test \'0\' empty : ';
var_dump(empty($var2));	// TRUE
echo $sep . 'test 0 empty : ';
var_dump(empty($var3));	// TRUE
echo $sep . 'test FALSE empty : ';
var_dump(empty($var4));	// TRUE
echo $sep . 'test array() empty : ';
var_dump(empty($var5));	// TRUE
echo $sep . 'test \'\', \'0\', 0, FALSE, array() isset : ';
var_dump(isset($var1, $var2, $var3, $var4, $var5));	// TRUE,  变量申明并赋值为空字符串

输出的结果为:

test undeclared var empty : bool(true)
test undeclared var isset : bool(false)
test declared var but no set value empty : bool(true)
test declared var but no set value isset : bool(false)
test declared var and set value NULL empty : bool(true)
test declared var and set value NULL isset : bool(false)
test '' empty : bool(true)
test '0' empty : bool(true)
test 0 empty : bool(true)
test FALSE empty : bool(true)
test array() empty : bool(true)
test '', '0', 0, FALSE, array() isset : bool(true)
分类: PHP 标签:

PHP 下查看memcached使用情况的工具

2013年7月14日 没有评论

在php官网上提供了一个工具可以查看memcached的使用情况,提供的信息还是比较全面的。下载地址:http://pecl.php.net/package/memcache。下载解压后找到一个名为memcache.php的文件,拷贝此文件到项目中,同时修改文件中一下几个地方。

//设置能访问此页面的用户名和密码
define('ADMIN_USERNAME','memcache'); 
define('ADMIN_PASSWORD','password');

//设置memcached服务器的IP和端口,如果有多个memcached服务器,配置多行
$MEMCACHE_SERVERS[] = 'mymemcache-server1:11211'; 
$MEMCACHE_SERVERS[] = 'mymemcache-server2:11211';

通过上述操作,就可以通过访问http://your domain/memcache.php来查看memcached的使用情况了,结果如下图。

分类: PHP 标签:

php curl 分离header和body信息

2013年7月9日 没有评论

php中可以通过curl来模拟http请求,同时可以获取http response header和body,当然也设置参数可以只获取其中的某一个。当设置同时获取response header和body时候,它们会一同作为结果返回。这时需要我们自己来分离它们。

下面代码是模拟向google一个http GET请求

function httpGet() {
    $url = 'http://www.google.com.hk';
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, TRUE);    //表示需要response header
    curl_setopt($ch, CURLOPT_NOBODY, FALSE); //表示需要response body
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, FALSE);
    curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE);
    curl_setopt($ch, CURLOPT_TIMEOUT, 120);
    
    $result = curl_exec($ch);
    
    if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == '200') {
        return $result;
    }
    
    return NULL;
}

调用上述方法后看到如下类似输出:

HTTP/1.1 200 OK
Date: Tue, 09 Jul 2013 14:21:08 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=UTF-8
Set-Cookie: PREF=ID=75e996a7ad21f47b:FF=0:NW=1:TM=1373379668:LM=1373379668:S=TTLQQN-jwGDYnkkY; expires=Thu, 09-Jul-2015 14:21:08 GMT; path=/; domain=.google.com.hk
Set-Cookie: NID=67=PPu7FfFeuZqwfsrUifgzjidX4JZxxCPLe9xFHjdXhfHpzs3gaykFSH5uGXy2esWTlp_rdqIYkjFDMollzI_sA-8owxD3mDh6KCRwdMa9-g5VChj0E5XAGNjo9d-sZfLN; expires=Wed, 08-Jan-2014 14:21:08 GMT; path=/; domain=.google.com.hk; HttpOnly
P3P: CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info."
Server: gws
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Transfer-Encoding: chunked

<!doctype html><html itemscope="itemscope" itemtype="http://schema.org/WebPage"><head><meta itemprop="image" content="/images/google_favicon_128.png"><title>Google</title><script>(function(){
window.google={kEI:"VBzcUdWuHOmtiQf64IHoCw",getEI:function(a){for(var b;a&&(!a.getAttribute||!(b=a.getAttribute("eid")));
……

这里可以看到结果中header和body信息是在一起的,那么如何分离它们呢。方法有二种,一是通过curl自带的curl_getinfo()方法获取头的长度,然后使用substr来分割字符串。示例代码如下:

$response = curl_exec($ch);

if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == '200') {
    $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $header = substr($response, 0, $headerSize);
    $body = substr($response, $headerSize);
}

第二种方法基于header和body是通过两个回车换行来分割的,所以可以通过如下代码实现:

$response = curl_exec($ch);

if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == '200') {
    list($header, $body) = explode("\r\n\r\n", response, 2);
}
分类: PHP 标签:

PHP 执行外部命名获取出错信息

2013年7月7日 没有评论

php中提供了四种方法来执行外部命令,外面命令可以是一个系统命令或自己实现的shell(Linux)、批处理(window)脚本。四种调用方法分别是exec()、passthru()、system()、shell_exec()。关于它们的区别可以参看:http://www.leapsoul.cn/?p=646。

本文主要介绍在linux系统下如何获取命令出错的信息。出错包括命令执行时候出错和命名拼写错误等。上述四种方法只会返回命令执行返回码,没有具体的出错信息。想要获取具体的出错信息,可以把命令执行的输出结果输出到一个文件。利用符号 “>”即可。例如:

$cmd = 'your command >/tmp/test.log 2>&1';
exec($cmd);

命令输出的信息可以在/tmp/test.log中找到。

分类: PHP 标签:

php memcached 扩展 timeout 问题

2013年6月27日 没有评论

php 中使用memcached扩展来访问memcached时,当安装memcached服务的服务器无法正常连接,在默认设置下会造成请求响应变慢。注意:无法正常连接指网络故障,如两台服务器无法进行通信等,只要能ping通,就算memcached服务没有开启或down掉,不会影响响应时间,只是memcached没有启作用。

设置timeout时间通过常量Memcached::OPT_CONNECT_TIMEOUT来控制,默认是4000毫秒(php 官网显示1000,我测试版本1.0.2和2.0.1都是4000)。另外1.0.2和2.0.1还有很大差别。1.0.2在执行addServer时就会连接memcached服务器,而且执行命令时候需要2倍的timeout时间,所有当memcached无法连接时候,花费时间是3倍的timeout时间。

2.0.1在php 5.2中似乎有bug,无法使用,具体参看:https://bugs.php.net/bug.php?id=61283。

分类: PHP 标签:

php urlencode与rawurlencode的区别

2013年1月31日 1 条评论

urlencode的用途就是编码字符串,把原字符串中所有除”-_”以为的非所有字母数字字符替换成百分号(%)后跟两位十六进制数,但是需要注意:由于历史原因会把空格替换+号。rawurlencode其实和urlencode一样,也是用来编码字符串的,唯一的不同是它是使用RFC1738 编码,也就是会把空格替换成%20。

它们对应的解码函数是urldecode和rawurldecode。参考官方网站的说明,urldecode解码给出的已编码字符串中的任何%##,加号(’+')被解码成一个空格字符;rawurldecode解码字符字符串中百分号(%)后跟两位十六进制。有两点区别,一是urldecode解码是对百分号(%)后任意两位字符都去会进行解码,例如%MN也会解码,但是会失败;rawurldecode则只会对百分号(%)后两位是十六进制(0-9A-F)的字符才会解码,二是urldecode会把+号解码为空格。

通过上面对解码函数的描述,可以推论,使用urlencode或rawurlencode编码的都可以使用urldecode进行解码,但是如果原字符串中含有空格,使用urlencode编码后的字符串使用rawurlencode解码后获得的字符串会和原字符串不同。

分类: PHP 标签:

PHP Warning: Call-time pass-by-reference has been deprecated

2013年1月17日 没有评论

今天执行一个php脚本的时候得到如题的警告信息,原因是在调用function的时候在参数前面加了符号”&”,这种做法已经没php遗弃了。参数前加符号”&”,就是相当于传地址,function内部可以修改此变量。那么如何去掉此警告的同时且达到function内部能对参数进行修改呢?答案就是在定义function的时候使用”&”符号。例如:

function foo(&$var) {
	$var = 321;
}

$var = 123;
foo($var);

echo $var;   // 输出为 321
分类: PHP 标签:

php 直接输出图片

2013年1月10日 没有评论

前段时间看 google analytics 移动版,发现可以直接通过php来输出一个1×1像素的图片。以前的我的做法是php中执行了处理逻辑后,然后通过header 进行一个 302 转跳到一个已有的图片上,看来是多此一举了。下面是图片输出的示例代码:

<?php
function writeGifData() {
    $GIF_DATA = array(
        chr(0x47),chr(0x49),chr(0x46),chr(0x38),chr(0x39),chr(0x61),
        chr(0x01),chr(0x00),chr(0x01),chr(0x00),chr(0x80),chr(0xff),
        chr(0x00),chr(0xff),chr(0xff),chr(0xff),chr(0x00),chr(0x00),
        chr(0x00),chr(0x2c),chr(0x00),chr(0x00),chr(0x00),chr(0x00),
        chr(0x01),chr(0x00),chr(0x01),chr(0x00),chr(0x00),chr(0x02),
        chr(0x02),chr(0x44),chr(0x01),chr(0x00),chr(0x3b)
    );

    header("Content-Type: image/gif");
    header("Cache-Control: " . "private, no-cache, no-cache=Set-Cookie, proxy-revalidate");
    header("Pragma: no-cache");
    header("Expires: Wed, 17 Sep 1975 21:32:10 GMT");

    echo join($GIF_DATA);

    exit;
}

writeGifData();
?>

受到启示,也可以通过下面的方式来输出图片

<?php
function writeGifData() {
    //服务器图片真实路径
    $file = dirname(__FILE__) . '/1x1.gif';
    readfile($file);

    exit;
}

writeGifData();
?>

另外,如果觉得.php作为图片的扩展名不好看,可以在服务器上通过urlrewrite来改造一下,这样用户看到的是图片扩展名,但是服务器真是处理的是一个php脚本,既然是php脚本,就可以做很多其他的事,这种方式在网站统计、广告系统等广泛应用。

分类: PHP 标签:

无觅相关文章插件,快速提升流量