如何从单独的PHP脚本执行PHP脚本而不会丢失第二个脚本的输出?

时间:2016-06-02 15:32:32

标签: javascript php jquery html excel

我目前正在开发一个使用HTML和PHP的项目,允许用户在Web表单中输入信息以生成Excel文件。提交时,表单运行一个PHP文件main.php:

<?php
    // output headers so that the file is downloaded rather than displayed
    $order = $_POST["order"];
    header('Content-Type: text/plain; charset=utf-8');
    header('Content-Disposition: attachment; filename="'.$_POST['order'].'.xls"');
    exec('php xl.php');
    sleep(2);
    readfile('xl_template.xls');
    error_reporting(E_ALL);
    ini_set("display_errors", 1);
?>

其中&#34; xl.php&#34;是另一个PHP文件&#34; xl_template&#34;是我想要修改的Excel工作表的模板。 main.php的目的是获取修改后的模板并将其下载到用户的计算机,而xl.php实际修改Excel模板并将其保存到服务器计算机(使用PHPExcel库):

<?php
    // this file will be called by main.php
    // after execution, there should be a newfile.xls
    // for the main.php to read from
    error_reporting(E_ALL);
    require('Classes/PHPExcel.php');

    // variable definitions
    $template = "xl_template.xls";

    $objPHPExcel = PHPExcel_IOFactory::load($template);
    $objWorksheet = $objPHPExcel->getActiveSheet();
    $objWorksheet->getCell('A2')->setValue('123400000000000000000001');
    $objWorksheet->getCell('B2')->setValue('it worked!');
    $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
    $objWriter->save($template);
?>

当从终端调用xl.php文件然后填写表单时,这可以正常工作。但是,当通过exec('php xl.php')方法从main.php调用xl.php时,Excel文件不会更新,我认为这意味着xl.php未成功执行。

除了exec()之外,我还尝试了system()shell_exec,反引号运算符和passthru(),结果相同。此外,我尝试了Javascript和JQuery方法,使用$.get('xl.php')$.ajax({url: 'xl.php'})调用xl.php文件,但没有运气。

对于这个问题的任何见解将不胜感激,因为我仍然是使用PHP的新手。感谢。

2 个答案:

答案 0 :(得分:1)

我建议制作两个单独的函数,并按照您需要的顺序调用它们以防止错误发生。这是最有效的方法。

如果你真的想要使用不同的页面,你可以使用php中的header()函数重定向到第二个php页面,并包含你需要传递的任何变量并使用$ _GET检索它们()。

答案 1 :(得分:0)

问题1

您正在使用非常奇怪的方式加载第二个PHP文件。虽然exec("php xl.php")确实会执行xl.php,但它会像从命令行执行它一样。您的xl.php将无法访问外部脚本中的任何变量或其他信息,并且无法将任何内容写入发送给用户的输出。此外,以这种方式调试第二个脚本中发生的任何错误要困难得多。

您应该使用require("xl.php");来运行xl.php文件,就好像它的内容直接属于您的外部脚本一样。

问题2

您正在写入服务器上的文件。除非绝对必要,否则您应该避免这样做(例如,对于用户上传)。

  • 在您的情况下,写入可能首先失败,因为您将其写入PHP文件所在的同一目录中。通常,PHP没有权限在那里写入 - 这是有充分理由的,因为如果你的网络服务器(例如Apache)只在这个目录中运行PHP文件,并且PHP没有权限写入它,那么攻击者就很难将自己的恶意PHP代码放在那里,运行它,或者修改你的一个脚本以向其添加恶意代码。
  • 假设您已解决了权限问题(应该通过使用PHP脚本目录之外的单独目录来完成,可能只是临时目录 - 而不是通过更改权限以允许写入脚本目录!),然后您有另一个问题:你的文件名是不变的。现在假设有两个用户同时下载一个Excel文件......所有内容都会搞砸,因为两个会话将尝试写入/读取同一个文件。
  • 假设您通过使用随机临时名称(然后在最后再次删除文件)来修复此问题,那么在您不需要时仍然存在访问硬盘的问题。您只需将Excel文件的内容直接从内存流式传输到用户的浏览器即可。

因此,最好的解决方案是根本不使用文件,而是直接将数据发送给用户。这可以使用伪文件名php://output来完成,它基本上将写入它的所有数据直接发送给用户。

问题3

您的内容类型标头指定text/plain和UTF-8为charset,但您发送的是Excel文件。由于Excel文件不是纯文本(也可能不是UTF-8),因此应使用正确的MIME类型,即application/vnd.ms-excel

问题4

只有在所有操作都已发生后,才会启用错误报告。这意味着如果发生错误,则不会按预期方式报告,因为它是在启用报告之前发生的。

最后的例子

结合上面提到的修补程序,您的代码可能如下所示:

<强> main.php:

<?php

    error_reporting(E_ALL);
    ini_set("display_errors", 1);

    // output headers so that the file is downloaded rather than displayed
    $order = $_POST["order"];
    header('Content-Type: application/vnd.ms-excel');
    header('Content-Disposition: attachment; filename="'.$_POST['order'].'.xls"');

    require("xl.php");
?>

<强> xl.php:

<?php
    // this file will be called by main.php
    require('Classes/PHPExcel.php');

    $objPHPExcel = PHPExcel_IOFactory::load($template);
    $objWorksheet = $objPHPExcel->getActiveSheet();
    $objWorksheet->getCell('A2')->setValue('123400000000000000000001');
    $objWorksheet->getCell('B2')->setValue('it worked!');
    $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
    $objWriter->save("php://output");
?>

最后的想法

现在您更改了这样的代码,最好考虑是否需要这样构造第二个PHP文件,如果是这样,是否可能要将代码包装在函数中并且从外部脚本调用它,这样你也可以很好地传递参数,因为我认为你并不总是静态地写#34;它有效!&#34;在那里。