PHP CLI: How to read from keyboard STDIN when using pipe? - php

I am making a script that accepts data input both via:
filename (it opens a .txt file for reading)
pipe (reading via "php://stdin")
In both cases, I need to get controls from keyboard, stdin;
1. When opening the file not using pipe(stdin) I can read the keyboard from
./myscript.php --file filename.txt
then
<?php
$DATA = file_get_contents("filename.txt");
// etc loop
$input = fopen("php://stdin", "r"); // works
stream_set_blocking($input, false);
$key = fgetc($input); // get input from keyboard
echo $key;
?>
2. But when using pipe, this does not work, example:
cat filename.txt | ./myscript.php
then
<?php
$DATA = file_get_contents("php://stdin");
// etc loop
$input = fopen("php://stdin", "r"); // does not works
stream_set_blocking($input, false);
$key = fgetc($input); // get input from keyboard
echo $key;
?>
Why can't I read from keyboard in the second case? Thanks.

I was able to do it reading directly from /dev/tty
<?php
$DATA = file_get_contents("php://stdin");
// etc loop
$input = fopen("/dev/tty", "r"); // this works, as stdin == pipe
stream_set_blocking($input, false);
$key = fgetc($input); // get input from keyboard
echo $key;
?>
I found the answer here:
How to make Perl use different handles for pipe input and keyboard input?
Also:
Can I prompt for user input after reading piped input on STDIN in Perl?

Related

PHP write to flat text file. New to PHP, learning. I have the read working. Need to write back updates

I have a flat file, TestFile.txt, that contains about 200 lines. Each item is a separate row. I show a partial of the contents of the TestFile.txt file below. I have PHP code working that reads TestFile.txt exactly as I need. The PHP read code searches the TestFile.txt, locates the line I wish to read, and places the result into an html input box. It parses the text after the = in the line, and only displays the data found after the =. Just as I need. Now I need to change the data in the html input box, and write the change back to TestFile.txt, and only update the text after the =. I show the PHP read code below. I have not a clue how to do what I need. I am a little over a week studying PHP. Any help with writing is much appreciated.
Thanks,
Mitch
Partial TestFile.txt:
RXFrequency=432675000
TXFrequency=432675000
RXOffset=260
TXOffset=120
Network=mnet.hopto.org
Password=9Yg81prqL0363zt
Latitude=34.657783
Longitude=-3.784595
Port=62021
Part of the PHP:
<!DOCTYPE html>
<html>
<body>
<?php
// Place text to look for in string $Search_String.
// The $Search_String will remain hard coded in my production
// code. The users will not be able to select $Search_String.
$Search_String_1 = "RXOff";
// Identify Text File, open File and Read the File.
$MyFile = fopen("TestFile.txt", "r") or die("Unable to open file!");
$found= "False";
// Create the while loop. Test each line with the if statement,
// looking for $Search_String, and place the result into string $line.
// Next, echo string $line which containes the found line in the
// flat text file. It will return the entire line even from a
// partial $Search_String, which is what I want.
/*...*/
// Next, let us build the array.
$lines = [];
while ( $line = fgets( $MyFile ) ) {
if ( str_contains( $line, $Search_String_1 ) ) {
//here you are keeping track of each line matching the criteria.
$lines[] = $line;
// This explode function will split the string contained
// in the $line variable at the =. Text left of the = is
// placed into the $key variable. Text right of the = is
// placed into the $value variable.
[$key, $value] = explode("=", "$line");
// echo $key; // RXOffset;
// echo $value; // 260;
//echo $line;
//echo $Search_String_1;
}
}
?>
<?php foreach($lines as $line): ?>
<?php endforeach;
// Properly close the text file.
fclose($MyFile);
// Get string $value from the explode code above.
?>
<label>RXOffset: <input type="text" id="message" value="<?php echo $value;?>"/></label>
<?php
</body>
<html>
Hope this gives enough information. Feel free to comment questions.
Thanks,
Mitch
This is what appears on the browser when I execute this PHP:
RXOffset: 269
Label Data

PHP Piping Data with f_open

I have a piece of code, the issue is the file "data" is over 8GB. This is very memory intensive. I want to reduce the usage of RAM and saw the f_load would be ideal, however, how could i explode this data?
This is my current code:
$data = file_get_contents("data");
$data = explode("|", $data);
foreach ($data as $d) { // rest of code
theoretically, i need to open a pipe, stream and close a pipe How would i go about this?
I've tried using f_open rather than file_get_contents but errors started popping up so i'm doing something wrong and would really like to learn.
You can use stream_get_line to read your data block per block (with | as the delimiter character) : PHP stream_get_line()
$fh = fopen('data', 'r'); // open the file in read-only mode
while( $d = stream_get_line($fh, 1000, '|') ) // read the file until the next |
{
echo $d . PHP_EOL ; // display one block of data
}
fclose($fh); // close the file

How can I pass a text file created by php to my python script for processing?

I have a php code that is writing the user input on the webpage into a text file. I wish to pass the text file into my python script that looks like follows:
PHP Script (getfile.php)
<?php
function writetofile($file, $content, $writeType){
$fo = fopen($file, $writeType);
if($fo){
fwrite($fo,$content);
fclose($fo);
}
}
?>
Python Script (predict.py)
clf=joblib.load('model.pkl')
def run(command):
output = subprocess.check_output(command, shell=True)
return output
row = run('cat '+'/Users/minks/Documents/X-test.txt'+" | wc -l").split()[0]
print("Test row size:")
print(row)
matrix_tmp_test = np.zeros((int(row),col), dtype=np.int64)
print("Test matrix size:")
print(matrix_tmp_test.size)
What I am asking is, after writing to a file : $file in php, how can I then pass this file to replace:
row = run('cat '+'/Users/minks/Documents/X-test.txt'+" | wc -l").split()[0]
where the path gets replace by $file and the processing continues? Also, is it possible to pass $file directly to the python code via command line? I am little confused on how this entire passing and processing can be carried out.
Dow you want something like this?
PHP:
$path = "my.txt";
system("python predict.py $path");
Python:
row = run("cat %s | wc -l" % sys.argv[1]).split()[0]

Trying to understand the difference between /dev/stdin and php://stdin

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.

Execute User Input at breaks from PHP to Shell

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.

Categories