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?
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)
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];
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);
}
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'];
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;
?>
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.
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;
}
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').
I strongly recommend the use of getopt.
If you want help to print out for your options then take a look at GetOptionKit.
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";
}
}
?>
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
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
I found this vanilla/garden-cli on github. I think it answers all the needs for PHP CLI.
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"
Firstly, We have a shell script say ifelsesh.sh having the following code
a=20
b=20
if [ $a == $b ]
then
echo "a is equal to b"
else
echo "a is not equal to b"
fi
Now, we want to execute this file by php say execSh.php as
<?php
// $contents = file_get_contents('ifelsesh.sh');
try
{
exec('ifelsesh.sh',$output);
echo $output;
}
catch(Exception $e)
{
echo $e;
}
when we run the file through the command line works fine
>php execSh.php
but when we run the execSh.php file through the browser nothing works,why and let us know the exact reason to sort it out.Thanks in advance.
Make sure in php.ini function shell_exec, exec are enabled.
You can use the exec to execute the shell script through PHP , make sure exec is enable on your machine
<?php
exec(dirname(__FILE__) . '/ifelsesh.sh');
?>
I'm new to this, and I did some searching, but most of the answers have the same results: the MAC address output is shown as "Found."
My code is below:
$ip = $_SERVER['REMOTE_ADDR'];
$mac=shell_exec("arp -a ".$ip);
$mac_string = shell_exec("arp -a $ip");
$mac_array = explode(" ",$mac_string);
$mac = $mac_array[3];
if(empty($mac)) {
die("No mac address for $ip not found");
}
echo($ip." - ".$mac);
Ah, the old exec() vs shell_exec() vs passthru() question.
To see what command is actually being run, and what the system is actually returning, use exec(), and pass it an int and an array as its 2nd and 3rd params respectively, then var_dump() them both after running the command.
For example:
$cmd = "arp -a " . $ip;
$status = 0;
$return = [];
exec($cmd, $return, $status);
var_dump($status, $return);
die;
If everything went OK, then $status should be zero and $return may or may not be empty. However if $status is non-zero then pay attention to what the value of $return is, as this will be what your system is telling you is happening when it tries to run your command.
Protip: Pass exec() the full path to arp as-in:
#> which arp
/usr/sbin/arp
$cmd = "/usr/sbin/arp -a" . $ip;
Also, bear in mind, depending on where the command is being run, REMOTE_ADDR may not return anything useful. There are several other ways of obtaining an IP address, which are especially useful if the IP address you need is behind some sort of proxy.
Guess I could take this script a step further.. remember, only works on your local network. will return false if not able to get.
function GetMAC() {
$cmd = "arp -a " . $_SERVER["REMOTE_ADDR"];
$status = 0;
$return = [];
exec($cmd, $return, $status);
if(isset($return[3])) return strtoupper(str_replace("-",":",substr($return[3],24,17)));
return false;
}
I am using PHP exec to run a Powershell script to create a new user that is being submitted via a HTML form. What I am looking to do is output only errors from this command on the webpage so any IT team member can see if anything went wrong. Here is what I have:
$psPath = 'c:\\Windows\\System32\WindowsPowerShell\v1.0\\powershell.exe -version 5';
$psDIR = "d:\\wamp64\\www\\includes\\";
$psScript = "NewHire.ps1";
$runCMD = $psPath. ' -ExecutionPolicy RemoteSigned '.$psDIR.$psScript
$createuser = exec($runCMD.' 2>&1', $out);
When I do a var_dump($out), it shows both the output and errors. I tried changing it to exec($runCMD.' &1', $out) but it shows output only. If I try exec($runCMD.' 2>', $out), it doesn't run my command. Is there a way I can display errors only in the $out varible?
Try this,
exec($runCMD."2>&1 1>/dev/null ",$out);
maybe this might help
public static function exec_alt($cmd)
{
exec($cmd, $output);
if (!$output) {
/**
* FIXME: for some reason exec() returns empty output array #mine,'s machine.
* Somehow proc_open() approach (below) works, but doesn't work at
* test machines - same empty output with both pipes and temporary
* files (not we bypass shell wrapper). So use it as a fallback.
*/
$output = array();
$handle = proc_open($cmd, array(1 => array('pipe', 'w')), $pipes, null, null, array('bypass_shell' => true));
if (is_resource($handle)) {
$output = explode("\n", stream_get_contents($pipes[1]));
fclose($pipes[1]);
proc_close($handle);
}
}
return $output;
}
if you on windows 7, you might need to:
Disabling User Account Control (UAC)
run
UserAccountControlSettings.exe
at
C:\Windows\System32\UserAccountControlSettings.exe
and select "Never notify"
Found out this works for stderr only:
exec($runCMD.' >&2' , $out);
I am in a need of running the PHP parser for PHP code inside PHP. I am on Windows, and I have tried
system("C:\\Program Files (x86)\\PHP\\php.exe -l \"C:/Program Files (x86)/Apache/htdocs/a.php\"", $output);
var_dump($output);
without luck. The parameter -l should check for correct PHP syntax, and throw errors if some problems exist. Basically, I want to do something similar to this picture:
(source: mpsoftware.dk)
That is, to be able to detect errors in code.
This seems to work:
<?php
$file = dirname(__FILE__) . '/test.php';
//$output will be filled with output from the command
//$ret will be the return code
exec('php -l ' . escapeshellarg($file), $output, $ret);
//return code should be zero if it was ok
if ($ret != 0) {
echo 'error:';
var_dump($output);
} else {
echo 'ok';
}
The runkit extension provides a function to do that:
runkit_lint_file()
If you can not use runkit then you only other way is to do what you already tried:
echo passthru("php -l ".__FILE__);
Try fixing your path with realpath() if it does not work.