PHP用proc_open新建子进程使用管道通信非阻塞执行PHP脚本

PHP用proc_open新建子进程使用管道通信非阻塞执行PHP脚本.
脚本结束时register_shutdown_function回调函数访问管道获取子进程输出的数据.

例子1(popen):
<?php
function foo() {
	echo date('Y-m-d H:i:s')."\n";
	echo shell_exec('php -r \'sleep(1); echo date("Y-m-d H:i:s")." by shell_exec:blocking\n";\'');       //阻塞
	$pipe1 =  popen('php -r \'sleep(2); echo date("Y-m-d H:i:s")." by popen1:non-blocking\n";\'', 'r');  //非阻塞(管道)
	$pipe2 =  popen('php -r \'sleep(1); echo date("Y-m-d H:i:s")." by popen2:non-blocking\n";\'', 'r');  //非阻塞(管道)
	echo date('Y-m-d H:i:s')."\n";
	register_shutdown_function(function() use ($pipe1, $pipe2) { //事件驱动(脚本结束事件),异步回调
		echo stream_get_contents($pipe1); //输出子进程返回的数据
		echo stream_get_contents($pipe2); //输出子进程返回的数据
		pclose($pipe1);
		pclose($pipe2);
	});
}
foo();
//输出
2016-09-11 20:25:30
2016-09-11 20:25:31 by shell_exec:blocking
2016-09-11 20:25:31
2016-09-11 20:25:33 by popen1:non-blocking
2016-09-11 20:25:32 by popen2:non-blocking

例子2(proc_open):
<?php
function foo() {
	$proc = proc_open(
		//task.php 内容为 $arr = unserialize(stream_get_contents(STDIN)); $arr['time'] = date('Y-m-d H:i:s', $arr['time']); echo serialize($arr);
		'/png/php/5.4.45/bin/php /home/eechen/task.php', 
		array(
			0 => array('pipe','r'), //stdin (用fwrite写入数据给管道)
			1 => array('pipe','w'), //stdout(用stream_get_contents获取管道输出)
			2 => array('pipe','w'), //stderr(用stream_get_contents获取管道输出)
			//2 => array('file','/tmp/err.txt','a') //stderr(写入到文件)
		), 
		$pipes, //管道(stdin/stdout/stderr)
		'/tmp', //当前PHP进程的工作目录
		array('foo' => 'bar') //php.ini 配置 variables_order = "EGPCS" 其中E表示$_ENV,否则$_ENV输出为空
	);
	//var_dump($pipes); //resource of type (stream)
	if(is_resource($proc)) {
		//stdin
		$stdin = serialize(array('time' => time()));
		fwrite($pipes[0], $stdin); //把参数传给脚本task.php
		fclose($pipes[0]); //fclose关闭管道后proc_close才能退出子进程,否则会发生死锁
		register_shutdown_function(function() use($pipes, $proc) { //事件驱动(脚本结束事件),异步回调
			//stdout
			$stdout = stream_get_contents($pipes[1]);
			fclose($pipes[1]);
			//stderr
			$stderr = stream_get_contents($pipes[2]);
			fclose($pipes[2]);
			//exit code (返回进程的终止状态码,如果发生错则返回-1)
			$status = proc_close($proc);
			$data = array(
				'stdout' => $stdout,
				'stderr' => $stderr,
				'status' => $status,
			);
			var_export($data); //echo json_encode($data);
		});
	}
}
foo();
//输出:
array (
  'stdout' => 'a:1:{s:4:"time";s:19:"2016-09-11 21:26:29";}',
  'stderr' => '',
  'status' => 0,
)

 

转载于:https://my.oschina.net/eechen/blog/745504

proc_open()是PHP的一个函数,用于创建一个新的进程并与它进行通信。以下是一个示例: ``` $descriptorspec = array( 0 => array("pipe", "r"), // 标准输入 1 => array("pipe", "w"), // 标准输出 2 => array("pipe", "w") // 标准错误输出 ); $process = proc_open('ls -la', $descriptorspec, $pipes, '/tmp'); if (is_resource($process)) { fwrite($pipes[0], "input\n"); fclose($pipes[0]); echo stream_get_contents($pipes[1]); fclose($pipes[1]); echo stream_get_contents($pipes[2]); fclose($pipes[2]); $returnValue = proc_close($process); } ``` 该示例中,我们运行了一个shell命令`ls -la`,并在`/tmp`目录下执行。`$descriptorspec`是一个数组,指定了标准输入、标准输出和标准错误输出的管道。 我们使用`proc_open()`函数创建了一个新的进程。如果此函数成功执行,它将返回一个进程资源。我们可以使用`is_resource()`函数来检查此进程资源是否有效。 接下来,我们向标准输入管道中写入了一个字符串`input`,并通过`fclose()`关闭了该管道。然后我们使用`stream_get_contents()`函数读取了标准输出和标准错误输出的管道,并通过`fclose()`函数关闭了它们。 最后,我们使用`proc_close()`函数关闭进程并获取该进程的退出代码。 请注意:使用`proc_open()`函数时需要谨慎,因为它允许执行任意的shell命令。为了避免安全问题,请确保在执行时正确地过滤和验证输入。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值