PDFTK с php: // памятью - PullRequest
       22

PDFTK с php: // памятью

4 голосов
/ 24 января 2012

Вопрос: Можно ли использовать php: // memory для команды exec или passthru ?

Я могу использовать phpПеременные в exec или passthru без проблем, но у меня проблемы с фоном php: // memory

: я пытаюсь удалить все мои временные записи в pdf файл с помощью PDFTK.1) Я пишу временный файл PDF2) заполнить временный файл PDF, используя # 13) повторить № 1 и № 2 для всех PDF-файлов4) объединить все PDF-файлы вместе.

В настоящее время это работает, но создает много файлов и является узким местом.

Я бы хотел ускорить работу с помощью pdftk, используявиртуальный файл php: // memory

Во-первых, я пытаюсь виртуализировать файл PDF, используемый в # 1.Одного ответа достаточно для «правильного ответа».:)

Код выглядит следующим образом:

$fdf = 'fdf file contents here';
$tempFdfVirtual= fopen("php://memory", 'r+');
if(  $tempFdfVirtual ) {
  fwrite(  $tempFdfVirtual, $fdf);
} else {
    echo "Failure to open temporary fdf file";
    exit;
}
rewind( $tempFdfVirtual);
$url = "unfilled.pdf";
$temppdf_fn = "output.pdf"; 
$command = "pdftk $url fill_form  $tempFdfVirtual output $temppdf_fn flatten"; 
$error="";   
exec( $command, $error );
if ($error!="") {
    $_SESSION['err'] = $error;       
} else {
    $_SESSION['err'] = 0;
}

Я получаю код ошибки # 1.Если я выполняю stream_get_contents ($ tempFdfVirtual), он показывает содержимое.

Спасибо за просмотр!

Ответы [ 2 ]

4 голосов
/ 24 января 2012

php://memory и php://temp (и фактически любой дескриптор файла) доступны только для запущенного в настоящее время процесса php. Кроме того, $tempFdfVirtual является дескриптором ресурса, поэтому нет смысла помещать его в строку.

Вы должны передать данные из вашего дескриптора ресурса в процесс через его стандартный вход. Вы можете сделать это с помощью proc-open, что дает вам больший контроль над вводом и выводом дочернего процесса, чем exec.

Обратите внимание, что по какой-то причине вы не можете передать дескриптор файла 'php: // memory' процессу. PHP будет жаловаться:

Предупреждение: proc_open (): не может представлять поток типа MEMORY в качестве дескриптора файла

Вместо этого используйте php://temp, который должен быть точно таким же, за исключением того, что он будет использовать временный файл, как только поток станет достаточно большим.

Это проверенный пример, который иллюстрирует общий шаблон кода, который использует proc_open(). Это должно быть заключено в функцию или другую абстракцию:

$testinput = "THIS IS A TEST STRING\n";

$fp = fopen('php://temp', 'r+');
fwrite($fp, $testinput);
rewind($fp);

$cmd = 'cat';
$dspec = array(
    0 => $fp,
    1 => array('pipe', 'w'),
);
$pp = proc_open($cmd, $dspec, $pipes);

// busywait until process is finished running.
do {
    usleep(10000);
    $stat = proc_get_status($pp);
} while($stat and $stat['running']);

if ($stat['exitcode']===0) {
    // index in $pipes will match index in $dspec
    // note only descriptors created by proc_open will be in $pipes
    // i.e. $dspec indexes with an array value.
    $output = stream_get_contents($pipes[1]);
    if ($output == $testinput) {
        echo "TEST PASSED!!";
    } else {
        echo "TEST FAILED!! Output does not match input.";
    }
} else {
    echo "TEST FAILED!! Process has non-zero exit status.";
}

// cleanup
// close pipes first, THEN close process handle.
foreach ($pipes as $pipe) {
    fclose($pipe);
}
// Only file descriptors created by proc_open() will be in $pipes.
// We still need to close file descriptors we created ourselves and
// passed to it.
// We can do this before or after proc_close().
fclose($fp);
proc_close($pp);

Непроверенный пример, специфичный для вашего использования PDFTK:

// Command takes input from STDIN
$command = "pdftk unfilled.pdf fill_form - output tempfile.pdf flatten"; 
$descriptorspec = array(
    0 => $tempFdfVirtual, // feed stdin of process from this file descriptor
//    1 => array('pipe', 'w'), // Note you can also grab stdout from a pipe, no need for temp file
);
$prochandle = proc_open($command, $descriptorspec, $pipes);
// busy-wait until it finishes running
do {
    usleep(10000);
    $stat = proc_get_status($prochandle);
} while ($stat and $stat['running']);

if ($stat['exitcode']===0) {
    // ran successfully
    // output is in that filename
    // or in the file handle in $pipes if you told the command to write to stdout.
}

// cleanup
foreach ($pipes as $pipe) {
   fclose($pipe);
}
proc_close($prochandle);
1 голос
/ 24 января 2012

Это не просто то, что вы используете php://memory, это любой дескриптор файла.Файловые дескрипторы существуют только для текущего процесса.В любом случае, дескриптор, который вы получаете из fopen, не может быть перенесен в любое другое место за пределами вашего скрипта.

Пока вы работаете с внешним приложением, вы в значительной степени застряли с помощьювременные файлы.Единственный другой вариант - попытаться передать данные в pdftk на stdin и получить выходные данные на stdout (если он это поддерживает).Насколько мне известно, единственный способ вызвать внешний процесс с таким доступом к его дескрипторам (stdin / stdout) - это использовать семейство функций proc_, в частности proc_open .

...