将变量传递给从命令行运行的PHP脚本

89

我有一个PHP文件需要从命令行运行(通过crontab)。我需要传递type=daily到该文件,但我不知道如何做。我尝试了:

php myfile.php?type=daily

但是返回了以下错误:

无法打开输入文件:myfile.php?type=daily

我该怎么办?

14个回答

141

?type=daily参数(最终在$_GET数组中)仅适用于通过网络访问的页面。

您需要像这样调用它:php myfile.php daily 并从$argv数组检索该参数(在这种情况下,$argv[1]将是该参数,因为$argv[0]myfile.php)。

如果该页面也用作网页,则有两个选项可供考虑。要么使用shell脚本和Wget访问它,并从cron中调用它:

#!/bin/sh
wget http://location.to/myfile.php?type=daily

或者在 PHP 文件中检查它是否是从命令行调用的:

if (defined('STDIN')) {
  $type = $argv[1];
} else {
  $type = $_GET['type'];
}

(注意:你可能需要/想要检查$argv是否实际包含足够的变量等)


2
推荐的方式是使用getopt()函数。 - ViliusL
2
defined('STDIN') 是什么意思? - CodeForGood
正是我在寻找的东西! - wHiTeHaT

77

将它作为普通参数传递,然后在PHP中使用$argv数组访问它。

php myfile.php daily

并且在myfile.php中

$type = $argv[1];

5
使用:if (isset($argv[1])) { echo $argv[1]; } else { die('no !'); } 该代码段的功能是,如果在命令行中传递了一个参数,则输出该参数。否则,显示错误信息并终止程序执行。 - demenvil

24

这些代码将把CLI调用的参数(例如php myfile.php "type=daily&foo=bar")转换为众所周知的$_GET数组:

$query = parse_url($argv[1], PHP_URL_QUERY);
parse_str($query, $_GET);
if (!empty($argv[1])) {
    parse_str($argv[1], $_GET);
}

虽然覆盖全局变量$_GET数组可能会比较混乱,但它可以快速转换所有脚本以接受CLI参数。

有关详细信息,请参见parse_str


如果您想要更传统的CLI样式,例如php myfile.php type=daily foo=bar,则可以使用一个小型函数将其转换为与$_GET兼容的关联数组:

// Convert $argv into associative array
function parse_argv(array $argv): array
{
    $request = [];
    foreach ($argv as $i => $a) {
        if (!$i) {
            continue;
        }

        if (preg_match('/^-*(.+?)=(.+)$/', $a, $matches)) {
            $request[$matches[1]] = $matches[2];
        } else {
            $request[$a] = true;
        }
    }

    return $request;
}

if (!empty($argv[1])) {
    $_GET = parse_argv($argv);
}

1
完美的答案!谢谢! - Reado
是的,我认为这就是原帖作者实际上正在寻找的(在命令行环境中运行几乎相同的(Web)PHP脚本)。 - Peter Mortensen

16

通过使用getopt()函数,我们可以从命令行读取参数。只需在php运行命令时传递一个值:

php abc.php --name=xyz

文件abc.php

$val = getopt(null, ["name:"]);
print_r($val); // Output: ['name' => 'xyz'];

6

像其他应用程序一样,可以按索引发送参数:

php myfile.php type=daily

然后你可以像这样获取它们:
<?php
    if (count($argv) == 0) 
        exit;

    foreach ($argv as $arg)
        echo $arg;
?>

3
这并不是很方便,它没有将键和值分开,只是传递了值 "type=daily"。 - spybart

5

将此代码保存在文件myfile.php中,并运行php myfile.php type=daily

<?php
$a = $argv;
$b = array();
if (count($a) === 1) exit;
foreach ($a as $key => $arg) {
    if ($key > 0) {
        list($x,$y) = explode('=', $arg);
        $b["$x"] = $y;  
    }
}
?>

如果您在?>标记之前添加var_dump($b);,您将看到数组$b包含type => daily

1
虽然这可能回答了问题,但请考虑添加有关此解决方案如何解决问题的详细信息。请参考 http://stackoverflow.com/help/how-to-answer 。 - J. Chomel
将此代码保存在名为myfile.php的文件中,并运行命令'php myfile.php type=daily'。如果您在?>标记之前添加var_dump($b);,您将看到数组$b包含type => daily。 - easyaspi

4

您可以使用以下代码来同时处理命令行和Web浏览器。将此代码放置在PHP代码之上。它为每个命令行参数创建一个$ _GET变量。

在您的代码中,您只需要检查 $ _GET 变量,而不必担心脚本是从Web浏览器还是命令行调用的。

if(isset($argv))
    foreach ($argv as $arg) {
        $e=explode("=",$arg);
        if(count($e)==2)
            $_GET[$e[0]]=$e[1];
        else
            $_GET[$e[0]]=0;
    }

编辑。使用此代码,我发现一个小错误。如果您的参数值包含“=”,则会失败。我现在使用以下代码:

if(isset($argv))
   foreach ($argv as $arg) {
       $e=explode("=",$arg);
       if(count($e)>=2)
           $_GET[$e[0]]=substr($arg,strlen($e[0])+1,strlen($arg));
       else   
           $_GET[$e[0]]=0;
   }

3
我强烈推荐使用getopt。 如果您需要输出选项的帮助信息,请查看GetOptionKit

你能详细阐述一下你的回答吗?例如,提供实际操作的示例代码吗? - Peter Mortensen

3
只需将其作为参数传递,如下所示:
php test.php one two three

在文件test.php内部:

<?php
    if(isset($argv))
    {
        foreach ($argv as $arg)
        {
            echo $arg;
            echo "\r\n";
        }
    }
?>

3
您可以使用php.net上sep16建议的方法来实现:

您可以使用sep16在php.net上推荐的方法

<?php

parse_str(implode('&', array_slice($argv, 1)), $_GET);

?>

它与cgi-php的行为完全一致。
$ php -f myfile.php type=daily a=1 b[]=2 b[]=3

$_GET['type'] 设置为 'daily',将 $_GET['a'] 设置为 '1',将 $_GET['b'] 设置为 array('2', '3')


"sep16" 是谁或什么? - Peter Mortensen
@PeterMortensen是我链接的文章的作者。 - K3---rnc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接