Background:
I'm in a position where I'm placing data into the command line and I need a php loop (what will become a server of sorts) to read STDIN and just echo what it reads to the shell its running in.
The following terrible code works when the process is running in the same shell as the content echoed:
<?php
echo getmypid();
$string = "/proc/" . getmypid() . "/fd/0";
while (true) {
fwrite(STDOUT, fgets(fopen($string, 'r'), 4096) . " worked\n");
}
?>
I've tried many variants:
<?php
echo getmypid();
$string = "/proc/" . getmypid() . "/fd/0";
while (true) {
$fo = fread(STDIN, 1024);
fwrite(STDOUT, $fo);
}
?>
The problem is that whenever I write to this loop from a separate terminal, the output appears in the other terminal but is not processed by the loop.
When I enter text in the same terminal, the text is echoed right back.
I need a way to get command line data into this loop from any source.
Related
I used PHP to call python script successfully and got the result . But I have to wait for the end of script running without anything output. It looks not friendly to my customer.
How can I return the script results to the PHP web in realtime ?
For instance ,for code below , I want to the PHP web will show output message in realtime instead of show them together at the end . How can I change my code?
Thank you .
PHP Code:
<?php
$k = $_REQUEST['k'];
if (!empty($k))
{
$k = trim($k);
$a = array();
exec('python ./some.py '.$k, $a);
echo $a[0];
}
?>
Python Code:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import sys
def do_some(a):
print 'test1'
time.sleep(30)
print 'test2'
if __name__ == '__main__':
print 'Now the python scritp running'
time.sleep(20)
a = sys.argv[1]
if a:
print 'Now print something'
T = do_some(a)
By specification, exec stop the calling program until the end of the callee. After that, you get back the output in a variable.
If you want to send data as soon as they are produced, you should use popen. It will fork a new process, but will not block the caller. So you can perform other tasks, like looping to read the sub-process output line by line to send it to your client. Something like that:
$handle = popen("python ./some.py ", 'r');
while(!feof($handle)) {
$buffer = fgets($handle);
echo "$buffer<br/>\n";
ob_flush();
}
pclose($handle)
There might already be questions like this, but none of them answer my question. I have a script that loads a Python script in the directory and then displays a output with PHP:
<?php
$param1 = "first";
$param2 = "second";
$param3 = "third";
$command = "scripts/sg.py";
$command .= " $param1 $param2 $param3 2>&1";
header('Content-Type: text/html; charset=utf-8');
echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
echo "<style type='text/css'>
</style>";
$pid = popen( $command,"r");
echo "<body><pre>";
while( !feof( $pid ) )
{
echo fread($pid, 256);
flush();
ob_flush();
echo "<script>window.scrollTo(0,99999);</script>";
usleep(100000);
}
pclose($pid);
echo "</pre><script>window.scrollTo(0,99999);</script>";
echo "<br /><br />Script finalizado<br /><br />";
?>
And is the Python code it should run, that is located in the directory:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Script Python Example
import time
import sys
print "Initializing Python Script"
secret = 1337
guess = 0
count = 0
#Help the user give number range.
print 'Guess s number it`s between 0 <-> 2000 '
while guess != secret:
guess = input("Guess: ")
if guess < secret:
print "to small"
elif guess > secret:
print "to big"
count += 1
print 'You guessed the number in %s try' % count
The Python actually works! However it seems that Python's inputs don't work, they create a EOF error (end of file error).
Can anybody help me and suggest a way to create a Python interpreter that runs the Python file found in the directory. Just like, skuplt.org, but instead of running code a client users, it runs a Python file located in a directory, like stated above.
popen opens a pipe that is one-way only; you can read from it or write to it, but not both.
You want to use proc_open instead - see http://php.net/manual/en/function.proc-open.php
As a simple proof of concept, I tried to share a string between forked processes from node to node or from node to php.
Take this simple php code that should log the output of stdin according to the php docs:
echo 'test' | php -r 'echo trim(fgets(STDIN));'
Working fine, but when I'm spawning the process from nodejs:
spawner.js
var fs = require('fs'); var spawn = require('child_process').spawn;
//dummy stdin file
var stdin = fs.openSync('stdin_file', 'w+');
//write the string
fs.writeSync(stdin, 'test');
spawn('php', ['stdin_test.php'], {
cwd: __dirname,
detached: true,
//to fully detach the process nothing should be piped from or to the parent process
stdio: [stdin, fs.openSync('out.log', 'a'), fs.openSync('err.log', 'a')]
})
stdin_test.php
<?php
error_log('php://stdin');
//this should log 'test' but outputs a newline
error_log(trim(fgets(STDIN)));
$t = fopen('/dev/stdin', 'r');
error_log('/dev/stdin:');
//this is working as expected
error_log(trim(fgets($t)));
Why is php://stdin empty? Is it safe to use /dev/stdin? What is the difference between /dev/stdin and php://stdin anyway?
Note that I have this behavior between 2 node processes too: process.stdin is empty but /dev/stdin has the expected result.
Gist available here
stdin man reference
I tested with the following script ( stdin_test.php ) using:
> echo test | php stdin_test.php
stdin_test.php
<?
echo 'STDIN :' ;
echo trim(fgets(STDIN)) ;
echo PHP_EOL;
$stdin_stream = fopen('php://stdin', 'r');
echo 'php://stdin :';
echo trim(fgets($stdin_stream));
echo PHP_EOL;
fclose($stdin_stream);
$stdin_file = fopen('/dev/stdin', 'r');
echo '/dev/stdin :';
echo trim(fgets($stdin_file));
echo PHP_EOL;
fclose($stdin_file);
I get back :
STDIN :test
php://stdin :
/dev/stdin :
If I then comment out the line:
//echo trim(fgets(STDIN));
I get back:
STDIN :
php://stdin :test
/dev/stdin :
If I comment out both of the first stdin echoes (and the file handler pointers), I get:
STDIN :
php://stdin :
/dev/stdin : test
Looking at documentation on php://input and how it is one-time usable unless (after 5.6) "the request body is saved" which is typical for POST requests but not PUT requests (apparently). This has me thinking that they are called "streams" because you get to walk in them once.
Rewind your stdin stream in JS before spawning PHP, else the file pointer will sit at the end of what you just wrote.
I have a php script that is called and it executes a shell command through shell_exec(). This shell command requires multiple user inputs at different stages. I am stuck with getting the interactivity piece working at each input stage.
This is just an example of how I imagine it working...
<?php
$return = shell_exec('runcmd');
//Let runcmd run until first break
echo $return;
$userinput1 = 'foo';
//Let runcmd run until next break
echo $return;
$userinput2 = 'bar';
//Let runcmd run until nth break
echo $return;
$userinputNth = 'nth';
To feed input to a shell command, use popen.
$handle = popen('runcmd', 'w');
fputs($handle, 'foo
bar
nth
');
pclose($handle);
Since output is not captured, we needn't echo it.
So I've got my PHP script to bind to a socket and write incoming data to a text file, as new information comes down the stream. This is working well. What I'd like to do is have another, separate PHP script run each time that text file is updated.
I've tried to make this happen by using an 'include' command, but it's not working. I've tested that my 'include' method works by mocking up a very simple script with that command. Maybe I'm putting the line of code in the wrong place? I have it in the do-while loop (see code below).
Maybe the script/socket needs to be restarted or reset for my changes to take place?
Any help would be appreciated. Thank you!
Here's the gist of my code:
[socket create, bind, and listen stuff goes here]
do {
$input = socket_read($spawn, 4096, 1) or die("Could not read input\n");
$trimmed = trim($input);
if ($trimmed != "") {
echo date($dateformat) . ": Received input: $trimmed\n";
if ($trimmed == "END") {
socket_close($spawn);
break;
}
else {
// write content
$fhp = fopen($textFile, 'w') or die("can't open file");
fwrite($fhp, $trimmed);
fclose($fhp);
echo date($date) . ": Wrote: " . $trimmed ."\n";
// run my other PHP script - the crux of my issue - this is not working
include '/home/public_html/update.php';
}
echo date($dateformat) . ": updated \n";
}
}
} while (true);
socket_close($socket);
echo "Socket term\n";
the logic in the script in your question is
Start Loop
Read Socket
Open File Handle
Write To file
Close File
require '/home/public_html/update.php';
echo
Close Socket
End Loop
i can't understand why the script doesn't work as the way you say because the file gets written and closed before the include() line.
the following line of code is outside of if/else, and might cause some confusion since if the IF condition is TRUE then it will still output that's updated..
echo date($dateformat) . ": updated \n";
if problem continues can you paste the update.php script, maybe the problem is located there.
-- Edited
to include the update.php IF the file has content apply this code after the close of the file.
if(filesize($textFile) != 0){
include '/home/public_html/update.php';
}
the code above checks if $textFile doesn't equal to zero, in order to include the update.php file.