3

我试图让一个脚本启动另一个脚本并将其数据放入会话变量中供另一个脚本使用。问题是,当第二个脚本 data.php 运行时,它似乎无法访问会话变量。它们是空白的,没有任何内容写入 data.txt。如果我自己运行 data.php,它会写入最后一个$_SESSION["data"]正确设置的值,但不是在使用 exec 运行时。我不确定问题是什么。有任何想法吗?

输入.php:

session_start();
$_SESSION["data"] = "Data!";
exec("/usr/bin/php /path/to/data.php > /dev/null 2>&1 &");

数据.php:

session_start();
$fp = fopen('data.txt', 'w');
fwrite($fp, $_SESSION["data"]);
fclose($fp);

编辑:我正在尝试从 input.php 内部启动 data.php,并在 data.php 中访问 input.php 中的变量。

4

2 回答 2

4

您可以将数据作为命令行参数传递给使用 CLI 运行的 PHP 脚本。该数据将可用于$argv数组中的子脚本。

输入.php:

$arg = "Data!";
exec("/usr/bin/php /path/to/data.php ".escapeshellarg($arg)." > /dev/null 2>&1 &");

数据.php

$fp = fopen('data.txt', 'w');
fwrite($fp, $argv[1]);
fclose($fp);

几点注意事项:

  • 传递每个参数 以确保用户无法将命令注入到您的 shell 中,这一点很重要。这也将阻止参数中的特殊 shell 字符破坏您的脚本。escapeshellarg()
  • $argv是一个全局变量,而不是像and这样的超全局变量。它仅在全局范围内可用。如果需要在函数范围内访问它,可以使用. 这是我认为使用可接受的唯一情况,尽管最好在启动时处理全局范围内的参数,并将它们作为参数传递给范围。$_GET$_POST$GLOBALS['argv']$GLOBALS
  • $argv是一个 0 索引数组,但第一个“参数”在$argv[1]. $argv[0]总是包含当前正在执行的脚本的路径,因为$argv它实际上代表了传递给 PHP 二进制文件的参数,其中脚本的路径是第一个。
  • 命令行参数的值始终具有字符串类型。PHP 的输入非常混乱,因此对于标量值这无关紧要,但您(很明显)不能通过命令行传递向量类型(对象、数组、资源)。serialize()可以通过使用例如或编码来传递对象和数组json_encode()。无法通过命令行传递资源。

编辑在传递我更喜欢使用的向量类型时,serialize()因为它带有有关对象所属类的信息。

这是一个例子:

输入.php:

$arg = array(
  'I\'m',
  'a',
  'vector',
  'type'
);
exec("/usr/bin/php /path/to/data.php ".escapeshellarg(serialize($arg))." > /dev/null 2>&1 &");

数据.php

$arg = unserialize($argv[1]);
$fp = fopen('data.txt', 'w');
foreach ($arg as $val) {
  fwrite($fp, "$val\n");
}
fclose($fp);

以下是我用来简化此过程的剪辑集合中的几个函数:

// In the parent script call this to start the child
// This function returns the PID of the forked process as an integer
function exec_php_async ($scriptPath, $args = array()) {
  $cmd = "php ".escapeshellarg($scriptPath);
  foreach ($args as $arg) {
    $cmd .= ' '.escapeshellarg(serialize($arg));
  }
  $cmd .= ' > /dev/null 2>&1 & echo $$';
  return (int) trim(exec($cmd));
}

// At the top of the child script call this function to parse the arguments
// Returns an array of parsed arguments converted to their correct types
function parse_serialized_argv ($argv) {
  $temp = array($argv[0]);
  for ($i = 1; isset($argv[$i]); $i++) {
    $temp[$i] = unserialize($argv[$i]);
  }
  return $temp;
}

If you need to pass a large amount of data (larger than the output of getconf ARG_MAX bytes) you should dump the serialized data to a file and pass the path to the file as a command line argument.

于 2012-08-01T08:10:41.223 回答
0

您可以尝试对 $_SESSION ["data"] 进行 urlencode 并将其作为参数传递给 CLI 脚本:

脚本 1

$URLENCODED = urlencode($_SESSION["data"]);
exec("/usr/bin/php /path/to/data.php " . $URLENCODED . " > /dev/null 2>&1 &")

脚本 2

$args = urldecode($argv[1]);   // thanks for the reminder daverandom ..forgot to do this :)

fwrite($fp, $args);
于 2012-08-01T07:59:00.183 回答