PHP readline() when STDIN other than keyboard - php

I'm writing an script that is able to read from stdin and then request for confirmation.
<?php
$stream = fopen('php://stdin', 'r');
$input = fgets($stream, 1024);
$confirmation = readline('Are you sure?');
if ( $confirmation == 'y' )
/* Do dangerous stuff */
When I run it directly:
$ php script.php
inputdata
^D
Are you sure?
But I'm trying to run it using a file as STDIN. In that case, readline() returns false and no confirmation is prompted.
$ php script.php < data.txt
or
$ echo "foobar" | php script.php
How can I read both from the STDIN and keyboard when invoking this script in this way?
Thanks.

Use fgetc function with STDIN. See example bellow.
$input = fgets(STDIN, 1024);
echo "\nAre you sure?\n";
$conf = fgetc(STDIN);
if($conf=='y'){
echo "Great! Lets go ahead\n";
}else{
echo "Okay, May be next time\n";
}
Console output
Sample 1
$ echo 'data
> y
> ' | php php_readline.php
Are you sure?
Great! Lets go ahead
Sample 2
$ php php_readline.php
Some data
Are you sure?
n
Okay, May be next time

According to a commenter ont he PHP page ( http://php.net/manual/en/book.readline.php ):
When readline is enabled, php switches the terminal mode to accept
line-buffered input. This means that the proper way to use the cli
when you pipe to an interactive command is to explicitly specify that
php is not using the terminal for input:
php somescript.php < /dev/null | less
I believe the point is to append | less. Not knowing the structure of your data, presumably something might need to be done within your script to handle the transition from data to confirmation.
One might add a mechanism to detect when terminal line-buffered input is enabled.

Related

Linux output of cronjob handled by php script

Is it possible to let the output of a cronjab be handled by a PHP script? The default is cron sending an email, an alternative is to write it to a log file. But I would like the output being caught by a PHP script doing something with the output (for example store it in a database or send through the Facebook messenger to someone).
Yes, you could do that by piping the output to a php script.
Consider the following example.
test.php:
<?php
while (false !== ($line = fgets(STDIN))) {
var_dump($line);
}
Testing it:
# echo "this is a random text" | php test.php
/Users/nikola/test.php:4:
string(22) "this is a random text
"
The last portion of a line in crontab is the shell script that is run.
The STDOUT of that script is sent to the user's email.
Like any other shell script, you can redirect STDOUT somewhere else using the pipe character.
* * * * * do_something_a_lot | php /path/to/your/script.php

php exec in the background with WAMP on Windows

with the following code i can call a php script and pass some variables into it
$cmd = 'php -f C:/wamp/www/np/myphpscript.php '.$var1;
exec($cmd);
this way my called script works, but , i need that process to be in the background , i dont want to wait for the script to finish, is there any way of doing that using wamp on windows ?
been doing some reading and some add a & at the end of the command, or a > NUL , now i noticed some of them are for linux , is there such a command for wamp on windows ? if there is please share it
EDIT: Due to the way the exec() command waits for the program to finish executing, it's very difficult to do this with vanilla exec(). I came across these solutions, and this one should work:
$rshell = new COM("WScript.Shell");
$rexec = $rshell->Run("php -f C:/wamp/www/np/myphpscript.php ".$var1, 0, false);
The WScript.Shell->Run command takes 3 arguments: the command (you can optionally add output redirection), window mode (0 = hidden), and wait it should wait to finish. Because the 3rd argument is false, this PHP should return immediately.
Original Solution: As this post suggests, you should try START /B cmd. It is virtually the Linux equivalent of cmd & in that it runs the command asynchronously, in the background, without user interaction or opening a new shell.
Because this will return immediately, PHP won't wait for it to finish, and the exec() command will not receive any output. Instead, try using shell output redirection. Your PHP given code would look like this:
$cmd = 'start /b "" php -f C:/wamp/www/np/myphpscript.php '.$var1.' >C:/wamp/www/np/output.txt';
exec($cmd);
Don't know what you are running and if you get a response to your command. But maybe it helps if you open a tab for each command. So you can see responses of each running script and at the end you can call javascript to close the tab.
You must set the variable php on windows environment !
If you have already done so skip the tutorials steps:
1. Open:
My Computer => Properties => Change Settings
2. Select the tab: Advanced
3. Click Environment Variables: Variable system
4. Click the button New
Add the name of the environment variable. Example = php
Add the path to executable php.exe. Example = D:\xampp\php\php.exe
Create a file myscript.php
The variariaveis $argc and $argv are native php.
You will notice that $ argc always carries the same value as the
result of calling count ($argv) in any case $argc is the standard
used and is a few milliseconds faster by being in memory (if that
makes any difference in performance your script).
//\n skip line
echo "\n\n";
//echo test debug
echo "Print Total Args : ";
//Print return variavel $argc
print_r($argc);
//\n skip line
echo "\n\n";
//echo test debug
echo "Print Array Args : \n\n";
//Print return variavel $argv
print_r($argv);
echo "\n";
// You can retrieve the arguments in the normal way.
$myvar_count = $argc;
$myvar_array_args = $argv;
Or if you want to set is not the environment variable, simply can call the path
Example: D:\xampp\php\php.exe myscript.php argument1 2 3 4 5
Retorn the Prompt in Windows
Total Args : 5
Array Args :
Array
(
[0] => test.php
[1] => argumento1
[2] => 2
[3] => 3
[4] => 4
)
I hope this helps! See you later!

Get PHP to update with every line returned from a shell command

Background:
I'm trying to write a shell script using php that will automatically checkout a couple of large SVN repos. I am also using the PEAR console progress bar class to display the progress of the checkout (not totally necessary, but the thing that prompted my question).
Question:
Is there a way to run a loop that will update with every line output to STDIN on the commandline?
If I do
<?php shell_exec("svn co svn://my.repo.com/repo/trunk"); ?>
I get back all of the output from the command in a giant string.
Trying a loop like
<?php $bar = new Console_ProgressBar('%fraction% [%bar%] %percent% | %elapsed% :: %estimate%', '=>', ' ', 80, $total);
$bar->display(0);
stream_set_blocking(STDIN, 0);
$output = array();
$return = '';
exec("svn co $svnUrl $folder", $output, $return);
while (!isset($return))
{
$bar->update(count($output));
}
$bar->erase(); ?>
will display the bar but not update.
Any solutions?
========================= UPDATE =======================================
Here's the working code I came up with based on the answer (for future reference):
<?php
$bar = new Console_ProgressBar('%fraction% [%bar%] %percent% | %elapsed% :: %estimate%', '=>', ' ', 80, $total);
$handle = popen("/usr/bin/svn co $svnUrl $folder", 'r');
$elapsed = 0;
$bar->display($elapsed);
while ($line = fgets($handle))
{
$elapsed++;
$bar->update($elapsed);
}
pclose($handle);
?>
PHP is not multi-threaded. exec() and company will block your script until the exec'd task completes. There's no point in using the while() loop, because the loop will not even start running until the svn call has completed.
If you want to run multiple parallel svn's, you'll need to use popen() (or proc_open()), which gives you a filehandle from which you can read the external command's output, and have multiple such external commands at the same time.
Use Output Buffering
see:
http://php.net/manual/en/function.ob-start.php
http://php.net/manual/en/function.ob-flush.php
http://php.net/manual/en/function.ob-end-clean.php
and see some related:
PHP Output buffering on the command line
Kohana 3 Command line output buffering?
AS I understand your problem that php execute script synchronously. Thats mean cycle will be run only after exec command and output will not be changed because it already done. Try to use fork.

Continually running PHP script using Bash

I have a long running PHP script that has a memory leak which causes it to fail part way through. The script uses a 3rd party library and I haven't been able to find the source of the leak.
What I would like to do is create a bash script that continually runs the PHP script, processing 1000 records at a time, until the script returns an exit code saying it has finished processing all records. I figure this should help me get around the memory leak because the script would run for 1000 records, exit, and then a new process would be started for another 1000 records.
I'm not that familiar with Bash. Is this possible to do? How do I get the output from the PHP script?
In pseudocode, I was thinking of something along the lines of:
do:
code = exec('.../script.php')
# PHP script would print 0 if all records are processed or 1 if there is more to do
while (code != 0)
$? gives you the exit code of a program in bash
You can do something ilke
while /bin/true; do
php script.php
if [ $? != 0 ]; then
echo "Error!";
exit 1;
fi
done
You can probably even do:
while php script.php; do
echo "script returned success"
done
Do you have to use bash? You could probably do this with PHP:
while (true) {
$output = exec('php otherscript.php', $out, $ret);
}
The $ret variable will contain the exit code of the script.
Use a simple until loop to automatically test the exit status of the PHP script.
#!/bin/sh
until script.php
do
:
done
The colon is merely a null operator, since you don't actually want to do anything else in the loop.
until while execute the command script.php until it returns zero (aka true). If the script returned 0 to indicate not done instead of 1, you could use while instead of until.
The output of the PHP script would go to standard out and standard error, so you could wrap the invocation of the shell script with some I/O re-direction to stash the output in a file. For example, if the script is called loop.sh, you'd just run:
./loop.sh > output.txt
though of course you can control the output file directly in the PHP script; you just have to remember to open the file for append.
You might want to ask a separate question about how to debug the PHP memory leak though :-)
You can write:
#!/bin/bash
/usr/bin/php prg.php # run the script.
while [ $? != 0 ]; do # if ret val is non-zero => err occurred. So rerun.
/usr/bin/php prg.php
done
Implemented solution in PHP instead as:
do {
$code = 1;
$output = array();
$file = realpath(dirname(__FILE__)) . "/script.php";
exec("/usr/bin/php {$file}", $output, $code);
$error = false;
foreach ($output as $line) {
if (stripos($line, 'error') !== false) {
$error = true;
}
echo $line . "\n";
}
} while ($code != 0 && !$error);

Executing linux commands with PHP

I'm trying to execute a linux command through a PHP command-line script, which is no problem using the exec command.
The problem is, the command I am executing (mysqldump) outputs an error message if something is wrong (for example user/password is incorrect). I can't seem to be able to capture this error in order to log it. It just prints this error to the screen.
How do I cause this error not to be printed to the screen, but instead to put it in a variable for use in my script?
Thanks!
Use popen to run the process. The example #2 on this page shows exactly what you're looking for:
<?php
error_reporting(E_ALL);
/* Add redirection so we can get stderr. */
$handle = popen('/path/to/spooge 2>&1', 'r');
echo "'$handle'; " . gettype($handle) . "\n";
$read = fread($handle, 2096);
echo $read;
pclose($handle);
?>
exec("mysqldump -u user -p passwod database > outputfile.sql 2> error.log");
You need to redirect stderr to stdout, so you can capture it. This example routes stdout to devnull (thus ignoreing it) and routes stderr to you:
exec('ls * 2>&1 1>/dev/null');
I'm not too hot in Unix (New Years Resolution...) but these functions look helpful:
shell_exec - returns result as a string.
passthru - It looks like you can execute this like: passthru('command', $result); and then use $result.
tried using backticks?
$var = `command`;
The following will route stderr messages to the same place as the normal output.
exec("mysql_dump blah 2>&1",$output,$return_val)
if($return_val !== 0)
echo "there was an error"
2>&1 means re-route stderr messages to the same place as stdout, and thus will be loaded into the output array.
Have you looked at the system() command? It's been a while since I did any PHP, but that rings a bell.

Categories