Почему exec () молча отбрасывает байты?

После долгих попыток я обнаружил поведение, которое не могу объяснить / решить, поэтому попросил помощи здесь. На нашем сервере (Ubuntu 16.04.5 LTS с PHP 7.0.30), мы используем некоторые инструменты вне «httpdocs», которые называются с помощью exec() чтобы получить их результаты. В данном случае это QRCode-генератор.

Однако некоторые QR-коды отображаться не будут. Мы получили вывод из инструмента (вывод данных PNG), но когда мы показываем его как изображение, по какой-то причине оно кажется сломанным.

После многих отладок я обнаружил, что результат иногда отличается на 1 или 2 байта от выходных данных инструмента.

Я сделал свою последнюю отладку с помощью QR-кода ниже (12345), который представляет собой файл размером 240 байт. Однако при его окончательном выводе длина оказывается равной 239 байтам, так что мы где-то потеряли байт?

Пример QR-кода

Я узнал, используя 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()-функция всегда работала довольно хорошо для нас, в результате чего $ return_var А ТАКЖЕ $ output, но теперь я теряю байты. Я уже попробовал несколько вариантов PHP_EOL, теперь мы используем как клей (\ n, \ r и \ n \ r), но с первыми двумя окончаниями строки я все еще получил только 239 байт, а с последним я получаю 241 байт, так что 1 байт — много.

Почему я теряю байт здесь? Как правильно преобразовать массив $ output обратно в строку? Есть ли способ вернуть 240-байтовый вывод обратно, взорвав массив? Или есть другие функции, которые я еще не нашел, чтобы выполнить команду, которая выдаст мне выходные данные, а также return_var?

3

Решение

Согласно ручной записи для exec, функция возвращает последнюю строку вывода. Включена ли последняя строка в качестве последнего элемента $output неясно.

Но что более важно, в руководстве говорится:

Конечные пробелы, такие как \ n, не включены в этот массив.

Я бы предположил, что это для каждого элемента массива (т.е. для каждой строки вашего вывода), но в любом случае ваш пробел здесь будет значительным, потому что вы не имеете дело с текстом — здесь все байты важны и значимы , Помните, что пробел не только означает \n, Это также может означать \t или же (пробел), например.

Если строка заканчивается F\t\n (заглавная буква F или любой другой непробельный символ, табуляция, затем символ новой строки), оба пробельных символа будут удалены с конца. Когда вы делаете implode операция, вы можете положить \n назад, но вы никогда не узнаете о \t это было раздето.

Главное, что нужно осознать здесь, это exec ожидает иметь дело с простым текстом, а не необработанными двоичными данными.

Я бы предложил, чтобы вместо использования cat qr.png, ты используешь base64 qr.png кодировать двоичные данные в строку ASCII, а затем декодировать их в PHP с base64_decode, Если вы не собираетесь использовать cat на самом деле вы все еще можете направить вывод команды QR-генерации через base64 как это: generate-qr-png |base64, В этой ситуации не должно быть значительных пробелов, поэтому ничто не может быть exec,

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]