3

TL;DR -- echo -n abc | bash -c 'read -s x && echo -n \$x' doesn't output abc.

I have a PHP CLI script which needs to read a password from stdin.

<?php

function quiet_read_stdin ()
{
    return shell_exec ("bash -c 'read -s x && echo -n \$x'");
}

print "got: ###".quiet_read_stdin ()."###\n";
?>

If I run this in a terminal and input, say, 'xyz':

$> php /tmp/foo.php
got: ###xyz###

As expected, also this works

$> echo xyz | php /tmp/foo.php
got: ###xyz###

But this doesn't.

$> echo -n xyz | php /tmp/foo.php
got: ######

This is causing problems in my script in the case that the secret key is stored in a file without a newline, equivalent to php /tmp/foo.php < keyfile.

This doesn't work (Inappropriate ioctl for device):

system ('stty -echo');
$password = trim (fgets (STDIN));
system ('stty echo');

I don't want to fudge it by inserting a newline at any stage. How can I modify quiet_read_stdin so that it works whether or not the input has a trailing newline? A Linux-only solution is fine.

2
  • You can't make "read -s" work when the input prematurely ends (before LF). So you need to look for another solution to read from STDIN with local echo disabled. Commented Nov 20, 2016 at 21:52
  • which OS / distribution & shell are you working on? php version? Commented Nov 20, 2016 at 22:00

2 Answers 2

1

For me, this works:

$ cat test.php
<?php
// ignore error message
// stty: standard input: Inappropriate ioctl for device    
shell_exec('stty -echo 2>/dev/null'); 

$io = fopen("php://stdin", "r");
$password = fgets($io);
echo "foo: $password\n";

shell_exec('stty echo 2>/dev/null');

$ echo -n "xyz" | php test.php
foo: xyz

$ php test.php          # typing: abc[ENTER]
foo: abc
Sign up to request clarification or add additional context in comments.

3 Comments

And as my question says, stty -echo doesn't work for me.
anyway, gonna leave this here as it may help others. been using it on all my scripts and it never failed me (so far).
@spraff did you try the example? When piping data to STDIN, you can safely ignore the error message as piped content is not displayed anyways. And when you call the script keyboard interactively (without piping), the stty -echo should work. For me, the error message only appears when piping content and can thus be ignored.
0

This will read a line with or without a newline and always print it with a newline

readslient.sh:

#!/bin/bash

while IFS= read -r -s LINE || [[ -n "$LINE" ]]; do
    echo $LINE
done

PHP can then

$pw = rtrim (shell_exec ("readslient.sh"));

I can't see how to make this a one-liner to shell-exec but it would be nice to not have a separate file for this.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.