【问题标题】:How to pass a file as an argument to php exec?如何将文件作为参数传递给php exec?
【发布时间】:2011-12-13 14:57:40
【问题描述】:

我想知道如何将文件(在我的情况下为 csv)的内容作为参数传递给 php 中的 exec 调用的命令行可执行文件(在 C 或 Objective C 中)。

这是我所做的:用户从这样的 URL 加载其文件的内容:

http://www.myserver.com/model.php?fileName=test.csv

那么下面的代码就可以让php解析并加载csv文件了:

<?php

$f = $_GET['fileName'];
$handle = fopen("$f", "r"); 

$data = array(); 
while (($line = fgetcsv($handle)) !== FALSE) { 
$data[] = $line;
}

?>

我卡住的地方是如何将此 csv 文件的内容作为参数传递给 exec。即使我可以假设 csv 已知只有两列,它有多少行是用户特定的,所以我不能将所有值作为参数一一传递,例如

exec("/path_to_executable/model -a $data[0][0] -b $data[0][1] .....");

我猜唯一的替代解决方案是写这样的东西:

exec("/path_to_executable/model -fileName test.csv");

并让命令行可执行文件进行 csv 解析,但在这种情况下,我认为我需要将 csv 文件物理写入服务器端。我想知道如果几个人同时使用自己不同的 csv 文件访问网页会发生什么情况,他们是否会相互覆盖?

我想一定有一个非常合适的方法来做到这一点,但我还没有弄清楚。任何想法?谢谢!

【问题讨论】:

  • 什么是有效的参数输入可以提供给可执行文件?
  • 它或多或少可以是任何东西,因为我编写了可执行文件。如果我知道 csv 大小,我认为可能是 csv 文件名或值。
  • by one by one 是否等于line by line
  • 不,不是逐行,而是逐个值。 csv 包含按列组织的两个时间序列。每一行代表不同的年份。我可以传递第一个时间序列,然后传递下一个,或者传递第一年的两个时间序列的值,然后传递第二年,依此类推。命令行可执行文件将妥善处理此问题。

标签: php c exec command-line-arguments


【解决方案1】:

您可以使用popen() 来获取要写入的进程的句柄。如果您需要双向(读/写)并且可能需要更多功能,请查看proc_open()

您也可以将数据写入某个随机文件(以避免多个用户互相踢对方的比赛条件)。类似于

<?php
$csv = file_get_contents('http://www.myserver.com/model.php?fileName=test.csv
');
$filename = '/tmp/' . uniqid(sha1($csv)) . '.csv';
file_put_contents($filename, $csv);
exec('/your/thing < '. escapeshellarg($filename));
unlink($filename);

由于您还负责可执行文件,您可能会弄清楚如何获取传递的参数数量(提示:argc)并将它们读入(提示:argv)。像这样通过基于行的方式传递它们:

<?php

$csvRow = fgetcsv($fh);
if ($csvRow) {
  $escaped = array_map('escapeshellarg', $csvRow);
  exec('/your/thing '. join(' ', $escaped));
}

【讨论】:

  • 谢谢。我想在将文件写入磁盘之前,我需要检查它是否是正确的 csv 文件,而不仅仅是任何具有 csv 扩展名的文件?还是因为在之后立即取消链接而无关紧要?
  • 您是否害怕在您的 /tmp 中临时存储病毒或类似的东西,或者您是否害怕 csv 格式错误?如果是前者,您的可执行文件将失败,并且该文件将立即被删除。如果您害怕格式错误……您应该知道 CSV 有很多丑陋的味道。无论如何,您都需要知道字段和行分隔符、引号和转义字符(以及编码!)。
  • 如果用户可以输入网址,是的,他们可以下载任何他们想要的东西。如果您允许这样做,则由您来检查传入的内容。但是,我会更担心大量数据(例如,每个文件超过 2MB 的任何数据,以及同时超过 100 个文件)。 ;)
【解决方案2】:

我建议将这些数据放在磁盘上,然后在命令行实用程序中加载它——这样就不会那么麻烦了。但是,如果您不能这样做,只需一次将其传入 1(未解析)行:

$command = "/path_to_executable/model";
foreach ($fileData as $line) {
  $command .= ' "'.escapeshellarg($line).'"';
}
exec($command);

然后您可以通过循环argv 将数据提取到您的实用程序中,其中argv[0] 是第一行,argv[1] 是第二行,依此类推。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-20
    • 2020-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多