89

I have a PHP file that is needed to be run from the command line (via crontab). I need to pass type=daily to the file, but I don't know how. I tried:

php myfile.php?type=daily

but this error was returned:

Could not open input file: myfile.php?type=daily

What can I do?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
hd.
  • 17,596
  • 46
  • 115
  • 165

14 Answers14

141

The ?type=daily argument (ending up in the $_GET array) is only valid for web-accessed pages.

You'll need to call it like php myfile.php daily and retrieve that argument from the $argv array (which would be $argv[1], since $argv[0] would be myfile.php).

If the page is used as a webpage as well, there are two options you could consider. Either accessing it with a shell script and Wget, and call that from cron:

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

Or check in the PHP file whether it's called from the command line or not:

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

(Note: You'll probably need/want to check if $argv actually contains enough variables and such)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
PtPazuzu
  • 2,497
  • 1
  • 17
  • 10
76

Just pass it as normal parameters and access it in PHP using the $argv array.

php myfile.php daily

and in myfile.php

$type = $argv[1];
Christoph Fink
  • 22,727
  • 9
  • 68
  • 113
24

These lines will convert the arguments of a CLI call like php myfile.php "type=daily&foo=bar" into the well known $_GET-array:

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

Though it is rather messy to overwrite the global $_GET-array, it converts all your scripts quickly to accept CLI arguments.

See parse_str for details.


If you want the more traditional CLI style like php myfile.php type=daily foo=bar a small function can convert this into an associative array compatible with a $_GET-array:

// 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);
}
fboes
  • 2,149
  • 16
  • 17
16

Using the getopt() function, we can also read a parameter from the command line. Just pass a value with the php running command:

php abc.php --name=xyz

File abc.php

$val = getopt(null, ["name:"]);
print_r($val); // Output: ['name' => 'xyz'];
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rupesh Wankhede
  • 457
  • 5
  • 16
6

Parameters send by index like other applications:

php myfile.php type=daily

And then you can get them like this:

<?php
    if (count($argv) == 0) 
        exit;

    foreach ($argv as $arg)
        echo $arg;
?>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Subdigger
  • 2,166
  • 3
  • 20
  • 42
  • 3
    this isn't really that convenient, it doesn't separate out the key and value, it just passes the value "type=daily" – spybart Feb 26 '16 at 22:15
5

Save this code in file myfile.php and run as 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;  
    }
}
?>

If you add var_dump($b); before the ?> tag, you will see that the array $b contains type => daily.

Shardj
  • 1,800
  • 2
  • 17
  • 43
easyaspi
  • 51
  • 1
  • 1
  • 1
    While this may answer the question, consider adding details on how this solution solves the issue. Kindly refer to http://stackoverflow.com/help/how-to-answer . – J. Chomel Jul 15 '16 at 14:44
  • Save this code in file myfile.php and run as 'php myfile.php type=daily' if you add var_dump($b); before the ?> tag, you will see that the array $b contains type => daily. – easyaspi Jul 15 '16 at 15:35
4

You can use the following code to both work with the command line and a web browser. Put this code above your PHP code. It creates a $_GET variable for each command line parameter.

In your code you only need to check for $_GET variables then, not worrying about if the script is called from the web browser or command line.

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

Edited. Using this I found a Small bug. If your parameter value contains an = it fails. I'm using this code now:

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;
   }
Hamboy75
  • 938
  • 1
  • 11
  • 22
3

I strongly recommend the use of getopt.

If you want help to print out for your options then take a look at GetOptionKit.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Francisco Luz
  • 2,775
  • 2
  • 25
  • 35
3

You could use what sep16 on php.net recommends:

<?php

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

?>

It behaves exactly like you'd expect with cgi-php.

$ php -f myfile.php type=daily a=1 b[]=2 b[]=3

will set $_GET['type'] to 'daily', $_GET['a'] to '1' and $_GET['b'] to array('2', '3').

K3---rnc
  • 6,717
  • 3
  • 31
  • 46
3

Just pass it as parameters as follows:

php test.php one two three

And inside file test.php:

<?php
    if(isset($argv))
    {
        foreach ($argv as $arg)
        {
            echo $arg;
            echo "\r\n";
        }
    }
?>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sam Prasad
  • 31
  • 3
1

There are four main alternatives. Both have their quirks, but Method 4 has many advantages from my view.


./script is a shell script starting by #!/usr/bin/php


Method 1: $argv

./script hello wo8844rld
// $argv[0] = "script", $argv[1] = "hello", $argv[2] = "wo8844rld"

⚠️ Using $argv, the parameter order is critical.


Method 2: getopt()

./script -p7 -e3
// getopt("p::")["p"] = "7", getopt("e::")["e"] = "3"

It's hard to use in conjunction of $argv, because:

⚠️ The parsing of options will end at the first non-option found, anything that follows is discarded.

⚠️ Only 26 parameters as the alphabet.


Method 3: Bash Global variable

P9="xptdr" ./script
// getenv("P9") = "xptdr"
// $_SERVER["P9"] = "xptdr"

Those variables can be used by other programs running in the same shell.

They are blown when the shell is closed, but not when the PHP program is terminated. We can set them permanent in file ~/.bashrc!


Method 4: STDIN pipe and stream_get_contents()

Some piping examples:


Feed a string:

./script <<< "hello wo8844rld"
// stream_get_contents(STDIN) = "hello wo8844rld"

Feed a string using bash echo:

echo "hello wo8844rld" | ./script
// explode(" ",stream_get_contents(STDIN)) ...

Feed a file content:

./script < ~/folder/Special_params.txt
// explode("\n",stream_get_contents(STDIN)) ...

Feed an array of values:

./script <<< '["array entry","lol"]'
// var_dump( json_decode(trim(stream_get_contents(STDIN))) );

Feed JSON content from a file:

echo params.json | ./script
// json_decode(stream_get_contents(STDIN)) ...

It might work similarly to fread() or fgets(), by reading the STDIN.


Bash-Scripting Guide

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
NVRM
  • 11,480
  • 1
  • 88
  • 87
0
if (isset($argv) && is_array($argv)) {
    $param = array();
    for ($x=1; $x<sizeof($argv);$x++) {
        $pattern = '#\/(.+)=(.+)#i';
        if (preg_match($pattern, $argv[$x])) {
            $key =  preg_replace($pattern, '$1', $argv[$x]);
            $val =  preg_replace($pattern, '$2', $argv[$x]);
            $_REQUEST[$key] = $val;
            $$key = $val;
        }
    }
}

I put parameters in $_REQUEST:

$_REQUEST[$key] = $val;

And it is also usable directly:

$$key = $val

Use it like this:

myFile.php /key=val
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
emmanuel
  • 133
  • 3
0

I found this vanilla/garden-cli on github. I think it answers all the needs for PHP CLI.

Fandi Susanto
  • 2,272
  • 1
  • 26
  • 25
0

To bypass the complexity of passing to the file, it sounds like you could use sed to insert the line directly into the php file.

sed -i "i (backslash)type=daily myfile.php

or as I use it with variables:

sed -i "i (backslash)$type = "(backslash)"${daily}(backslash)"(backslash); ${path}"/myfile.php"

Bill Craig
  • 21
  • 5