PHP - Запуск shell_exec () НЕ возвращает весь вывод - PullRequest
6 голосов
/ 08 мая 2019

Я использую pdfgrep для поиска всех появлений ключевого слова в документе PDF.

Теперь я хочу сделать это через PHP, чтобы использовать его на своем веб-сайте.

Однако, когда я запускаю:

$output = shell_exec("pdfgrep -i $keyword $file");
$var_dump($output);

Где $keyword - ключевое слово, а $file - файл, я не получаю весь вывод.

Файл PDFсостоит из таблицы кодов продуктов, названий продуктов и цен на продукты.

Когда я выполняю команду через терминал, я вижу всю строку данных:

product code 1    product name with keyword substring    corresponding price
product code 2    product name with keyword substring    corresponding price
product code 3    product name with keyword substring    corresponding price

Однако, когда я запустил его через PHP, я получил что-то вроде:

name with keyword substring with keyword substring product code 1 
product name with keyword substring product name with keyword substring 
corresponding price

Он просто не получает все данные.Он не всегда получает код продукта и цену, и было много случаев, когда он не может получить также полное название продукта.

Я просматриваю вывод через браузер и вставляю header('Content-Type: text/plain'); но это только предварительно выводит выходные данные, данные по-прежнему неполные.

Я попытался запустить точно такой же сценарий оболочки через Python3.6, и это дало мне желаемый результат.

Теперь я попытался запустить тот же сценарий Python через PHP, но я все еще получаю тот же неправильный вывод.

Я пытался запустить ключевое слово, которое, как я знаю, вернет более короткий вывод, но я все ещене получить всю нужную строку данных.

Есть ли способ надежно получить все данные, выдаваемые командой shell_exec()?

Существуют ли альтернативы, такие как другойкоманда или запуск сценария Python с сервера (поскольку сценарий Python в любом случае не имеет проблем).

Ответы [ 3 ]

5 голосов
/ 13 мая 2019

Я не знаю, как работает pdfgrep, но, возможно, он смешивает stdout и stderr? В любом случае, вы можете использовать такую ​​конструкцию, где вы записываете выходной поток в выходной буфер, а также дополнительно можете смешивать stderr с stdout:

$mixStdErrIntoStdOut = false;

ob_start();
$exitCode = 0;
if ($mixStdErrIntoStdOut) 
{
    system("pdfgrep -i $keyword $file 2>&1", &$exitCode);
} else {
    system("pdfgrep -i $keyword $file", &$exitCode);
}
$output = ob_get_clean();

var_dump($output);
1 голос
/ 18 мая 2019

У меня была точно такая же проблема, в PDF-хранилище оцифрованных контрактов.

Выводы функций "exec", "shell_exec" и "passthru" работали настолько случайно, что мне пришлось выбрать творческое решение: использовать ssh2_connect и ssh2_exec для подключения к собственной машине.

Отсутствует часть соединения SSH (https://www.php.net/manual/es/function.ssh2-connect.php), код:

// command execution
$stream     = ssh2_exec($connection, "pdfgrep -i {$keyword} {$file}");
// set stream block: queue executions to avoid overlapping
stream_set_blocking($stream, true);
// catch stream block
$stream_out = ssh2_fetch_stream($stream, SSH2_STREAM_STDIO);
// output
return stream_get_contents($stream_out);

Сначала это может быть немного сложнее, но в долгосрочной перспективе есть и другие преимущества:

  1. Каждое выполнение ограничено разрешениями пользователя, а не разрешения www-data
  2. Если вы хотите создать «кеш извлечения» с содержимым PDF, новый файлы будут созданы правильным пользователем
  3. Если хранилище PDF растет настолько, что его необходимо перенести в CDN, с помощью этого метода достаточно подключиться к хосту, на котором он находится собираюсь искать.
  4. И самое главное, вы получите полный поток_от

Увидимся!

1 голос
/ 17 мая 2019

Есть несколько способов, как вы можете выполнить процесс и собрать вывод. Если вы можете последовательно повторить проблему, вы можете попробовать другие методы выполнения процесса:

1) exec ($ command, & $ output)

$output = [];
exec($command, $output);

это должно вытолкнуть все выходные данные, строка за строкой, в массиве $ output, который должен быть создан перед вызовом этого метода.

2) passthru ($ command)

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

ob_start();
passthru($command);
$contents = ob_get_contents();
ob_end_clean();

3) popen ($ command, "r");

$output = "";
$handle = open($command, "r");
while (!feof($handle)){
    $output .= fread($handle, 4096);
}

Дайте мне знать, что вы получите, вызвав каждый из методов.

Кроме того, обязательно проверьте stderror на наличие ошибок.

...