【问题标题】:Can't execute external process with PHP无法使用 PHP 执行外部进程
【发布时间】:2012-04-09 00:41:18
【问题描述】:

我有以下代码

function generate_pdf() {

        $fdf_data_strings = $this->get_hash_for_pdf();
        #$fdf_data_names   = array('49a' => "yes");
        $fdf_data_names = array();
        $fields_hidden    = array();
        $fields_readonly  = array();
        $hud_pdf = ABSPATH.'../pdf/HUD3.pdf';

        $fdf= forge_fdf( '',
                 $fdf_data_strings,
                 $fdf_data_names,
                 $fields_hidden,
                 $fields_readonly );

        /*  echo "<pre>";
            print_r($fdf);
            echo "</pre>";
            die('');
        */

        $fdf_fn= tempnam( '.', 'fdf' );
        $fp= fopen( $fdf_fn, 'w' );
        if( $fp ) {
          fwrite( $fp, $fdf );
            //$data=fread( $fp, $fdf );
         // echo $data;
          fclose( $fp );


          header( 'Content-type: application/pdf' );
          header( 'Content-disposition: attachment; filename=settlement.pdf' ); // prompt to save to disk

          passthru( 'pdftk HUD3.pdf fill_form '. $fdf_fn.' output - flatten');

          unlink( $fdf_fn ); // delete temp file

        }
        else { // error
          echo 'Error: unable to open temp file for writing fdf data: '. $fdf_fn;
        }
    }
}

有什么问题吗?

问题是,我已经安装了pdftk

运行whereis pdftk给我'/usr/local/bin/pdftk'

物理检查了位置,pdftk在所述位置..

使用终端,如果我运行pdftk --version 或任何其他命令,它就会运行

如果我使用像passthru('/usr/local/bin/pdftk --version') 这样的php,则不会显示任何内容

如果我使用像system("PATH=/usr/local/bin &amp;&amp; pdftk --version"); 这样的php,它会说'/usr/local/bin /pdftk :there is no directory of file '

当我运行这个函数脚本时,弹出文件下载提示,但是当我保存它时,没有保存,

我已经检查了这个文件夹的权限并更改了它0755, 0766, 0777, 0666我已经尝试了所有,没有任何工作

3天来,我一直在努力克服它,我也问过这个问题,但不知道我到底是怎么回事。

在我用墙撞头之前有人可以帮我吗?

【问题讨论】:

  • 怎么样:system("PATH=/usr/local/bin/ pdftk --version");
  • 至于:/usr/local/bin/pdftk --version,有可能版本输出到stderr,而不是stdout,这就是为什么你什么也得不到。并查看网络服务器 error.log。
  • 如果你要求的是system("PATH=/usr/local/bin/ pdftk --version 2>&1 "),那么结果是sh: pdftk: command not found
  • whereis 给出 /user 或 /usr ?我认为这是问题中的错字,但也许您有一些特定的设置。
  • 你能尝试在命令行上运行php -r "passthru('/usr/local/bin/pdftk --version');"吗?

标签: php linux pdftk


【解决方案1】:

pastru 函数不通过 shell 执行程序。

将确切的路径传递给 passthru 命令。

例如

passthru( '/usr/local/bin/pdftk HUD3.pdf fill_form '. $fdf_fn.' output - flatten');

或 passthru( '/usr/local/bin/pdftk' . $hud_pdf . 'fill_form '. $fdf_fn.' output - flatten');

如果这仍然不起作用测试使用 &lt;?php passthru("/path/to/pdftk --help"); ?&gt; 其中 /path/to/pdftk 是您返回的路径 which 或 where 是,以确保路径正确。

如果路径正确,则问题可能与您告诉 pdftk 使用的临时目录上的权限或 pdftk 二进制文件中关于 apache 用户的权限有关。

如果这些权限没问题,您可以验证 pdftk 从 php 启动但在运行您的命令时挂起,那么也许可以尝试列出的解决方法here

更多关于 passthru 的文档是可用的passthru PHP Manual

附带说明,putenv php 函数用于设置环境变量。

例如putenv('PATH='.getenv('PATH').':.');

所有 3 个 PHP 函数:exec()、system() 和 passthru() 都执行外部命令,但区别在于:

  • exec():返回命令的最后一行输出并且不刷新任何内容。
  • shell_exec():从命令返回整个输出并且不刷新任何内容。
  • system():返回命令的最后一行输出,并尝试在输出的每一行之后刷新输出缓冲区。
  • passthru():不返回任何内容并将结果输出传递给浏览器,不会干扰浏览器,特别是在输出为二进制格式时非常有用。

另见PHP exec vs-system vs passthru SO Question

这些函数的实现位于exec.c,使用popen。

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,经过大量实验后,这正在起作用:

    function InvokePDFtk($pdf_tpl, $xfdf,$output){
    
            $params=" $pdf_tpl fill_form $xfdf output $output flatten 2>&1";
    
            $pdftk_path=exec('/usr/bin/which /usr/local/bin/pdftk');
    
            $have_pdftk= $pdftk_path=='/usr/local/bin/pdftk' ;
    
            $pdftk_path=$have_pdftk  ? $pdftk_path  : 'pdftk ';
    
            exec($pdftk_path.$params,$return_var);
    
            return  array('status'=> $have_pdftk,
                         'command' =>$pdftk_path.$params, 'output'=>$return_var);
        }
    

    希望这能给你一些见解。 (根据你的需要改变)

    【讨论】:

      【解决方案3】:

      完成 Appleman 的回答后,这 3 个函数可以被认为是危险的,因为它们允许您使用 php 执行程序,因此如果您不小心,攻击者就会利用您的脚本之一。因此,在许多想要安全的 php 配置中,它们被禁用。

      所以你应该检查你的 php.ini(和任何 php 配置文件)中的 disable_functions 指令,看看你使用的功能是否被禁用。

      【讨论】:

        【解决方案4】:

        也许您应该将 fclose 排除在 if 语句之外,确保将其定向到正确的文件! :)

        【讨论】:

          【解决方案5】:

          您的 Web 服务器是否已 chroot?尝试将可执行文件放入服务器可以查看的目录中。

          【讨论】:

            【解决方案6】:

            玩转安全模式,一定要检查你的网络服务器日志文件,通常在:

            /var/log/apache2/error.log
            

            【讨论】:

              最近更新 更多