php使用exec导致结果叠加的坑

关于php在使用exec函数时结果叠加的坑

今天用php在后台跑一些常规任务的时候使用到了exec函数,用来执行系统函数进行相关统计,但是却发生了很诡异的问题,,真的是特别诡异的问题,首先看下面这段代码

$shell = 'date';

exec($shell, $result);
var_dump($result);

//结果如下:
array(1) {
  [0]=>
  string(42) "2016年 09月 29日 星期四 21:44:20 CST"
}

$shell = 'echo "1\n2\n3"';

exec($shell, $result);
var_dump($result);

// 按理说结果应该应该如下啊,exec会把shell执行的结果每一行作为一个数组元素复值给result:
array(3) {
  [0]=>
  string(1) "1"
  [1]=>
  string(1) "2"
  [2]=>
  string(1) "3"
}

// 但最终结果却是下面的结果:
array(4) {
  [0]=>
  string(42) "2016年 09月 29日 星期四 21:44:20 CST"
  [1]=>
  string(1) "1"
  [2]=>
  string(1) "2"
  [3]=>
  string(1) "3"
}

所以你大概能够看明白发生什么了吧,对,exec会将结果追加$result中去!!!

所以最终result的结果并不是你想要的单纯的123,而是在之前date的基础上追加了123!!!

因为单独执行下面的代码是符合预期的


$shell = 'echo "1\n2\n3"';

exec($shell, $result);
var_dump($result);

array(3) {
  [0]=>
  string(1) "1"
  [1]=>
  string(1) "2"
  [2]=>
  string(1) "3"
}


所以,当我有这么一种预期:依赖exec执行结果进行逻辑处理时,下面的代码是会出坑的

$shell = 'date';

for ($i = 0; $i < 3; $i++) {
    exec($shell, $result);
    sleep(1); // 模拟每次时间不同,shell结果不同

    // 这里是我们对输出结果进行处理和使用
    // 假设我们的shell会把结果输出为一行,打印到屏幕上
    // 那么 $result 数组应该就只包含一个元素,就是输出的数据行
    // 我们取 $result[0] 就是需要的结果

    var_dump($result[0]); // 假设这里是对结果的应用
}

你知道结果是啥么?竟然是这个:


string(42) "2016年 09月 29日 星期四 22:02:26 CST"
string(42) "2016年 09月 29日 星期四 22:02:26 CST"
string(42) "2016年 09月 29日 星期四 22:02:26 CST"

对啊,为啥是一样的呢!!至少每个结果应该多一秒才对吧!!

分析一下,就是因为exec每次将结果追加到 $result 中导致的:

循环执行第一次时, $result是

array(3) {
  [0]=>
  string(42) "2016年 09月 29日 星期四 22:02:26 CST"
}

第二次时

array(3) {
  [0]=>
  string(42) "2016年 09月 29日 星期四 22:02:26 CST"
  [1]=>
  string(42) "2016年 09月 29日 星期四 22:02:27 CST"
}

第三次时

array(3) {
  [0]=>
  string(42) "2016年 09月 29日 星期四 22:02:26 CST"
  [1]=>
  string(42) "2016年 09月 29日 星期四 22:02:27 CST"
  [12=>
  string(42) "2016年 09月 29日 星期四 22:02:28 CST"
}

结果是追加上去的,每一次shell执行的结果都放在 $result 的尾部,然后我们每次用 $result[0]作为预期数据时,实际上每次取的永远是第一次exec的结果,而不是我们想要的后面执行的而结果 囧


实际上php.net上官方已经明显的标注了

如果提供了 output 参数, 那么会用命令执行的输出填充此数组, 每行输出填充数组中的一个元素。 数组中的数据不包含行尾的空白字符,例如 \n 字符。 请注意,如果数组中已经包含了部分元素,exec() 函数会在数组末尾追加内容。如果你不想在数组末尾进行追加, 请在传入 exec() 函数之前 对数组使用 unset() 函数进行重置。

呵呵,还是没认真读文档的锅,所以如果要多次使用exec的值,那么每次在exec($shell, $result) 之前,要先 unset($result)清空即可

但其实还有更简单的方法,,,直接用 $result = shell_exec($shell) 也行,shell_exec不会有类似追加问题,直接将标准输出复制到$result中


觉得不错? 哈哈 感谢赏个键盘磨损钱~(左微信 右支付宝)

wechat 8.8 alipay 8.8