3

经过一番挣扎,我发现了一些我无法解释/解决的行为,所以在这里寻求帮助。在我们的服务器(带有 PHP 7.0.30 的 Ubuntu 16.04.5 LTS)上,我们正在使用“httpdocs”之外的一些工具,这些工具被称为 usingexec()来获取它们的输出。在这种情况下,它是一个二维码生成器。

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

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

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

示例二维码

我发现使用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()但这直接输出内容,这是不希望的。在实际代码中不可能像下面的示例中那样输出缓冲...

<?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()-function 对我们来说总是工作得很好,导致 $return_var AND $output,但现在我正在丢失字节。我已经尝试了 PHP_EOL 的一些变体,我们现在将其用作胶水(\n、\r 和 \n\r),但是对于前 2 个行尾,我仍然只有 239 个字节,而最后一个,我最终得到 241 个字节,所以 1 个字节太多了。

为什么我在这里丢失一个字节?将 $output-array 转换回字符串的正确方法是什么?有没有办法通过内爆数组来取回 240 字节的输出?或者还有其他我还没有找到的函数来执行一个可以给我输出和return_var的命令?

4

1 回答 1

2

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

但更重要的是手册指出:

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

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

如果一行以F\t\n(大写 F,或任何其他非空白字符,制表符,然后是换行符)结尾,则两个空白字符都将从末尾删除。在进行implode手术时,您可能会在\n背部放置,但您永远不会知道\t被剥离的东西。

这里要实现的关键exec是期望处理纯文本而不是原始二进制数据

我建议不要使用cat qr.png,而是使用base64 qr.png将二进制数据编码为 ASCII 字符串,然后在 PHP 中使用base64_decode. 如果您不打算cat在现实中使用,您仍然可以base64像这样通过管道输出 QR 生成命令的输出generate-qr-png |base64:在那种情况下不应该有任何重要的空白,所以不会有任何东西被exec.

于 2018-07-30T21:46:45.533 回答