4

質問:execまたはpassthruコマンドでphp:// memoryを使用することは可能ですか?

execまたはpassthruでphp変数を問題なく使用できますが、php://memoryに問題があります。

背景:PDFTKで書いている一時的なPDFファイルをすべて削除しようとしています。
1)一時的なfdfファイルを作成しています
2)#1を使用して一時的なpdfファイルをフォーム入力します
3)すべてのpdfに対して#1と#2を繰り返します
4)すべてのpdfをマージします。

これは現在機能していますが、多くのファイルが作成され、ボトルネックになっています。

仮想ファイルphp://memoryを利用してpdftkでスピードアップしたい

まず、#1で使用したfdfファイルを仮想化しようとしています。
「正解」には、これだけで答えるだけで十分です。:)

コードは次のとおりです。

$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)を実行すると、コンテンツが表示されます。

見てくれてありがとう!

4

2 に答える 2

4

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);
于 2012-01-23T22:28:00.910 に答える
1

を使用しているだけではなくphp://memory、任意のファイル ハンドルです。ファイル ハンドルは、現在のプロセスに対してのみ存在します。すべての意図と目的において、fopen から返されたハンドルは、スクリプト外の他の場所に転送することはできません。

外部のアプリケーションで作業している限り、一時ファイルの使用はほとんど行き詰まります。他の唯一のオプションは、stdin でデータを pdftk に渡して、stdout で出力を取得することです (サポートされている場合)。私が知る限り、そのような記述子 (stdin/stdout) へのアクセスで外部プロセスを呼び出す唯一の方法は、一連proc_の関数、特にproc_openを使用することです。

于 2012-01-23T22:17:20.683 に答える