PHP does not show output [duplicate] - php

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"

Related

How to assign SplFileObject::fpassthru output to variable

I'm currently writing some data to an SplFileObject like this:
$fileObj = new SplFileObject('php://text/plain,', "w+");
foreach($data as $row) {
$fileObj->fputcsv($row);
}
Now, I want to dump the whole output (string) to a variable.
I know that SplFileObject::fgets gets the output line by line (which requires a loop) but I want to get it in one go, ideally something like this:
$fileObj->rewind();
$output = $fileObj->fpassthru();
However, this does not work as it simply prints to standard output.
There's a solution for what I'm trying to achieve using stream_get_contents():
pass fpassthru contents to variable
However, that method requires you to have direct access to the file handle.
SplFileObject hides the file handle in a private property and therefore not accessible.
Is there anything else I can try?
After writing, do a rewind() then you can read everything. The example is for understanding:
$fileObj = new SplFileObject('php://memory', "w+");
$row = [1,2,'test']; //Test Data
$fileObj->fputcsv($row);
$fileObj->rewind();
//now Read
$rowCopy = $fileObj->fgetcsv();
var_dump($row == $rowCopy);//bool(true)
$fileObj->rewind();
$strLine = $fileObj->fgets(); //read as string
$expected = "1,2,test\n";
var_dump($strLine === $expected); //bool(true)
//several lines
$fileObj->rewind();
$fileObj->fputcsv(['test2',3,4]);
$fileObj->fputcsv(['test3',5,6]);
$fileObj->rewind();
for($content = ""; $row = $fileObj->fgets(); $content .= $row);
var_dump($content === "test2,3,4\ntest3,5,6\n"); //bool(true)
If you absolutely have to fetch your content with only one command then you can do this too
// :
$length = $fileObj->ftell();
$fileObj->rewind();
$content = $fileObj->fread($length);
getSize() doesn't work here.
In the absence of an inbuilt function I've decided to do php output buffering as #CBroe had suggested.
...
$fileObj->rewind();
ob_start();
$fileObj->fpassthru();
$buffer = ob_get_clean();
See #jsplit's answer for a better method using SplFileObjects inbuilt functions

PHP exec() function windows 7 IIS 7.5

I am trying to run an a command line util using exec() but it doesnt return anything. I have read on php.net that the permissions on cmd.exe need to be set to allow the iis user to run it. I have not been able to do this using any method I can think of. cacls icacls and the standard security screen dont work. I am logging the output to a mysql database.
my code looks like this:
$Ret = array();
$err = "";
exec("dir", $Ret, $err);
in the db I get array for $Ret
Either something is wrong with the command, I doubt it, or I need to set the permissions somehow.
Please help.
Change the line:
exec("dir", $Ret, $err);
to:
$r = exec("dir", $Ret, $err);
echo $r;
You need to capture the return value of exec into a variable then render that.
Or try running this:
<?php
$a = array();
$e = "";
echo "exec'ing<br/>";
$r = exec("dir", $a, $e);
echo "var_dumping<br/>";
var_dump($a);
echo "=====================\n";
var_dump($e);
echo "=====================\n";
var_dump($r);
?>
If you're running this in a browser with xdebug turned off then you might need to view-source to see the results.

How to get include contents as a string? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Execute a PHP file, and return the result as a string
PHP capture print/require output in variable
I am trying to get the contents of an include to a string. Is that possible?
For example, if I have a test.php file:
echo 'a is equal to '.$a;
I need a function, say include_to_string to include the test.php and return what would be output by in in a string.
Something like:
$a = 4;
$string = include_to_string(test.php); // $string = "a is equal to 4"
ob_start();
include 'test.php';
$string = ob_get_clean();
I think is what you want. See output buffering.
ob_start();
include($file);
$contents = ob_get_contents(); // data is now in here
ob_end_clean();
You can do this with output buffering:
function include2string($file) {
ob_start();
include($file);
return ob_get_clean();
}
#DaveRandom points out (correctly) that the issue with wrapping this in a function is that your script ($file) will not have access to variable defined globally. That might not be an issue for many scripts included dynamically, but if it is an issue for you then this technique can be used (as others have shown) outside of a function wrapper.
** Importing variables
One thing you can do is to add a set of data you would like to expose to your script as variables. Think of it like passing data to a template.
function include2string($file, array $vars = array()) {
extract($vars);
ob_start();
include($file);
return ob_get_clean();
}
You would call it this way:
include2string('foo.php', array('key' => 'value', 'varibleName' => $variableName));
and now $key and $variableName would be visible inside your foo.php file.
You could also provide a list of global variables to "import" for your script if that seems clearer to you.
function include2string($file, array $import = array()) {
extract(array_intersect_key($GLOBALS, array_fill_keys($import, 1)));
ob_start();
include($file);
return ob_get_clean();
}
And you would call it, providing a list of the globals you would like exposed to the script:
$foo='bar';
$boo='far';
include2string('foo.php', array('foo'));
foo.php should be able to see foo, but not boo.
You could also use this below but I recommend the above answer.
// How 1th
$File = 'filepath';
$Content = file_get_contents($File);
echo $Content;
// How 2th
function FileGetContents($File){
if(!file_exists($File)){
return null;
}
$Content = file_get_contents($File);
return $Content;
}
$FileContent = FileGetContents('filepath');
echo $FileContent;
Function in PHP manual : file_get_contents

How do I pass parameters into a PHP script through a webpage?

I am calling a PHP script whenever a webpage loads. However, there is a parameter that the PHP script needs to run (which I normally pass through the command line when I am testing the script).
How can I pass this argument every time the script is run when the page loads?
Presumably you're passing the arguments in on the command line as follows:
php /path/to/wwwpublic/path/to/script.php arg1 arg2
... and then accessing them in the script thusly:
<?php
// $argv[0] is '/path/to/wwwpublic/path/to/script.php'
$argument1 = $argv[1];
$argument2 = $argv[2];
?>
What you need to be doing when passing arguments through HTTP (accessing the script over the web) is using the query string and access them through the $_GET superglobal:
Go to http://yourdomain.example/path/to/script.php?argument1=arg1&argument2=arg2
... and access:
<?php
$argument1 = $_GET['argument1'];
$argument2 = $_GET['argument2'];
?>
If you want the script to run regardless of where you call it from (command line or from the browser) you'll want something like the following:
as pointed out by Cthulhu in the comments, the most direct way to test which environment you're executing in is to use the PHP_SAPI constant. I've updated the code accordingly:
<?php
if (PHP_SAPI === 'cli') {
$argument1 = $argv[1];
$argument2 = $argv[2];
}
else {
$argument1 = $_GET['argument1'];
$argument2 = $_GET['argument2'];
}
?>
$argv[0]; // the script name
$argv[1]; // the first parameter
$argv[2]; // the second parameter
If you want to all the script to run regardless of where you call it from (command line or from the browser) you'll want something like the following:
<?php
if ($_GET) {
$argument1 = $_GET['argument1'];
$argument2 = $_GET['argument2'];
} else {
$argument1 = $argv[1];
$argument2 = $argv[2];
}
?>
To call from command line chmod 755 /var/www/webroot/index.php and use
/usr/bin/php /var/www/webroot/index.php arg1 arg2
To call from the browser, use
http://www.mydomain.example/index.php?argument1=arg1&argument2=arg2

getenv() vs. $_ENV in PHP

What is the difference between getenv() and $_ENV?
Any trade-offs between using either?
I noticed sometimes getenv() gives me what I need, while $_ENV does not (such as HOME).
According to the php documentation about getenv, they are exactly the same, except that getenv will look for the variable in a case-insensitive manner when running on case-insensitive file systems (like Windows). On Linux hosts it still works as case-sensitive. Most of the time it probably doesn't matter, but one of the comments on the documentation explains:
For example on Windows $_SERVER['Path'] is like you see, with the first letter capitalized, not 'PATH' as you might expect.
Because of that, I would probably opt to use getenv to improve cross-platform behavior, unless you are certain about the casing of the environment variable you are trying to retrieve.
Steve Clay's comment in this answer highlights another difference:
Added getenv() advantage: you don't need to check isset/empty before access. getenv() won't emit notices.
I know that the comment in the docs says that getenv is case-insensitive, but that's not the behaviour I'm seeing:
> env FOO=bar php -r 'print getenv("FOO") . "\n";'
bar
> env FOO=bar php -r 'print getenv("foo") . "\n";'
> env foo=bar php -r 'print getenv("foo") . "\n";'
bar
> env foo=bar php -r 'print getenv("FOO") . "\n";'
> php --version
PHP 5.4.24 (cli) (built: Jan 24 2014 03:51:25)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
Looking at the source code for the getenv function, this is because there are three ways that PHP can fetch the environment variable:
Via sapi_getenv (e.g. if it's getting the environment variable from Apache)
If on Windows, from GetEnvironmentVariableA.
If on non-Windows, from the getenv function provided by libc.
As far as I can tell, the only time when it will behave in a case-insensitive manner is on Windows because that's how the Windows environment variable API behaves. If you're on Linux, BSD, Mac, etc then getenv is still case sensitive.
As mentioned by mario, $_ENV is not always populated due to different configurations of variables_order so it's best if you avoid $_ENV if you don't control the server configuration.
So, for the most portable PHP code:
Use getenv.
Use the correct case for the environment variable name.
Additionally $_ENV is typically empty if variables_order does't have E listed. On many setups it's likely that only $_SERVER is populated, and $_ENV is strictly for CLI usage.
On the other hand getenv() accesses the environment directly.
(Regarding the case-ambiguity, one could more simply employ array_change_key_case().)
I found getenv() useful to avoid a strange PHP bug where sometimes $_SERVER and $_ENV was undefined if auto_globals_jit was enabled (creating the _SERVER and _ENV variables when they're first used). Since then I began to to use it.
Taken from the PHP docs:
This function is useful (compared to $_SERVER, $_ENV) because it searches $varname key in those array case-insensitive manner.
For example on Windows $_SERVER['Path'] is like you see Capitalized, not 'PATH' as you expected.
So just: <?php getenv('path') ?>
I'd add that getenv() is a better choice because, as a function, it can be overloaded for testing purposes. Whereas overwriting your $_SERVER or $_ENV variables might interfere with test frameworks and other libraries and ultimately require a lot more work to carry out safely.
I think the existing answers give a good overview of any differences in usage, but it might also be worth bearing in mind that the maintainers of the popular PHP library for loading environment variables recommend to avoid using getenv
https://github.com/vlucas/phpdotenv
Using getenv() and putenv() is strongly discouraged due to the fact that these functions are not thread safe
read env and create
<?php
namespace neoistone;
class ns_env {
/**
* env to array file storage
*
* #param $envPath
*/
public static function envToArray(string $envPath)
{
$variables = [];
$mread = fopen($envPath, "r");
$content = fread($mread,filesize($envPath));
fclose($mread);
$lines = explode("\n", $content);
if($lines) {
foreach($lines as $line) {
// If not an empty line then parse line
if($line !== "") {
// Find position of first equals symbol
$equalsLocation = strpos($line, '=');
// Pull everything to the left of the first equals
$key = substr($line, 0, $equalsLocation);
// Pull everything to the right from the equals to end of the line
$value = substr($line, ($equalsLocation + 1), strlen($line));
$variables[$key] = $value;
} else {
$variables[] = "";
}
}
}
return $variables;
}
/**
* Array to .env file storage
*
* #param $array
* #param $envPath
*/
public static function arrayToEnv(array $array, string $envPath)
{
$env = "";
$position = 0;
foreach($array as $key => $value) {
$position++;
// If value isn't blank, or key isn't numeric meaning not a blank line, then add entry
if($value !== "" || !is_numeric($key)) {
// If passed in option is a boolean (true or false) this will normally
// save as 1 or 0. But we want to keep the value as words.
if(is_bool($value)) {
if($value === true) {
$value = "true";
} else {
$value = "false";
}
}
// Always convert $key to uppercase
$env .= strtoupper($key) . "=" . $value;
// If isn't last item in array add new line to end
if($position != count($array)) {
$env .= "\n";
}
} else {
$env .= "\n";
}
}
$mwrite = fopen($envPath, "w");
fwrite($mwrite, $env);
fclose($mwrite);
}
/**
* Json to .env file storage
*
* #param $json
* #param $envPath
*/
public static function JsonToEnv(array $json, string $envPath)
{
$env = "";
$position = 0;
$array = json_decode($json,true);
foreach($array as $key => $value) {
$position++;
// If value isn't blank, or key isn't numeric meaning not a blank line, then add entry
if($value !== "" || !is_numeric($key)) {
// If passed in option is a boolean (true or false) this will normally
// save as 1 or 0. But we want to keep the value as words.
if(is_bool($value)) {
if($value === true) {
$value = "true";
} else {
$value = "false";
}
}
// Always convert $key to uppercase
$env .= strtoupper($key) . "=" . $value;
// If isn't last item in array add new line to end
if($position != count($array)) {
$env .= "\n";
}
} else {
$env .= "\n";
}
}
$mwrite = fopen($envPath, "w");
fwrite($mwrite, $env);
fclose($mwrite);
}
/**
* XML to .env file storage
*
* #param $json
* #param $envPath
*/
public static function XmlToEnv(array $xml, string $envPath)
{
$env = "";
$position = 0;
$array = simplexml_load_string($xml);
foreach($array as $key => $value) {
$position++;
// If value isn't blank, or key isn't numeric meaning not a blank line, then add entry
if($value !== "" || !is_numeric($key)) {
// If passed in option is a boolean (true or false) this will normally
// save as 1 or 0. But we want to keep the value as words.
if(is_bool($value)) {
if($value === true) {
$value = "true";
} else {
$value = "false";
}
}
// Always convert $key to uppercase
$env .= strtoupper($key) . "=" . $value;
// If isn't last item in array add new line to end
if($position != count($array)) {
$env .= "\n";
}
} else {
$env .= "\n";
}
}
$mwrite = fopen($envPath, "w");
fwrite($mwrite, $env);
fclose($mwrite);
}
}
?>

Categories