为什么exec()默默地丢弃字节?

时间:2018-07-30 21:17:18

标签: php exec shell-exec implode passthru

经过很多努力,我发现了一些我无法解释/解决的行为,因此请寻求帮助。在我们的服务器上(使用PHP 7.0.30的 Ubuntu 16.04.5 LTS ),我们正在使用“ httpdocs”之外的一些工具,这些工具使用exec()进行调用以获取其输出。在这种情况下,它是QRCode生成器。

但是,某些QR码将不会显示。我们从该工具获得了输出(输出PNG数据),但是当我们将其显示为图像时,由于某种原因,它似乎已损坏。

经过大量调试,我发现结果有时与工具的输出相差1或2个字节。

我使用下面的QR码( 12345 )进行了最后一次调试,该QR码是一个240字节的文件。但是,最终输出时,长度似乎是239个字节,所以我们在某个地方丢失了一个字节?

Example QR-code

我发现使用exec(),我们正在创建输出数组。尾随空格(例如\ n)不包含在此数组中,因此implode()可以将数组粘贴回字符串,如下所示:

<?php

$cmd = 'cat qr.png';
$output = array();
$exit_code = 0;

exec($cmd, $output, $exit_code);

if($exit_code === 0)
{
    header ("Content-type: image/png;");
    print implode(PHP_EOL, $output);
}
die();

但是由于某种原因,在此过程中丢失了一个字节吗?我已经使用shell_exec()但这里没有return_var,所以我们无法检查验证过程...

<?php

$command = 'cat qr.png';

$output = shell_exec($command);
if($output !== null)
{
    header ("Content-type: image/png;");
    print $output;
}
die();

...并使用passthru(),但是这会直接输出内容,这是不希望的。在实际代码中无法进行以下示例中的输出缓冲... < / em>)

<?php

$command = 'cat qr.png';
$return_var = 0;

ob_start();
passthru($command, $return_var);

if($return_var === 0)
{
    header ("Content-type: image/png;");
    $output = ob_get_clean();
    print $output;
}
die();

到目前为止,exec()函数对我们而言一直运行良好,导致$ return_var AND $输出,但是现在我丢失了字节。我已经尝试了PHP_EOL的一些变体,我们现在使用的是胶水( \ n,\ r和\ n \ r ),但是在前两个行尾,我仍然只有239个字节,最后一个是241个字节,所以1个字节就占了很多。

为什么我在这里丢失一个字节?将$ output-array转换回字符串的正确方法是什么?有没有办法通过内爆数组来获取240字节的输出?还是还有其他我尚未找到的功能来执行将为我提供输出以及return_var的命令?

1 个答案:

答案 0 :(得分:2)

根据exec的手动输入,该函数返回输出的最后一行。尚不清楚最后一行是否也包含为$output的最后一个元素。

但更重要的是,手册指出:

  

尾随空格,例如\ n,不包含在此数组中。

我猜想这是数组的每个元素(即输出的每行),但是无论哪种方式,您的空格在这里都是重要的,因为您不处理文本-所有字节都是重要的在这里有意义。请记住,空格不仅仅意味着\n。例如,它也可以表示\t(一个空格)。

如果一行以F\t\n结尾(大写F或任何其他非空白字符,制表符,然后换行),则两个空白字符都将从结尾处去除。在执行implode操作时,您可能会将\n放回原处,但是您永远不会知道被剥离的\t

这里要意识到的关键是, exec希望处理纯文本而不是原始二进制数据

我建议不要使用cat qr.png,而是使用base64 qr.png将二进制数据编码为ASCII字符串,然后使用base64_decode在PHP中对其进行解码。如果实际上不打算使用cat,则仍然可以像这样通过base64通过generate-qr-png |base64传递QR生成命令的输出:exec。在这种情况下,不应有任何大的空格,因此.mat-calendar-content { padding: 0px 0px 8px 0px !important; outline: 0; } .mat-calendar-body-cell-content .mat-calendar-body-selected { border-radius: 100% !important; color: orange !important; } 不会让任何东西蒙住。