1

So I have this really weird issue where I have the following dummy.php script:

<?php
declare(strict_types=1);

$prompt = "Hello there!".
    PHP_EOL . "What do you want to know?" .
    PHP_EOL . "Proceed by specifying what you want to know:" .
    PHP_EOL .":  " . PHP_EOL;

readline($prompt);

When I execute the script via php, I get the correct output.

When I place a zsh / bash script in the same directory as the PHP script above, with the contents:

php "./dummy.php";

I get the same output.

When I change the contents of dummy.php to:

<?php
declare(strict_types=1);

$prompt = "Hello there!".
    PHP_EOL . "What do you want to know?" .
    PHP_EOL . "Proceed by specifying what you want to know:" .
    PHP_EOL . "Proceed by specifying what you want to know:" .
    PHP_EOL . "Proceed by specifying what you want to know:" .
    PHP_EOL .":  " . PHP_EOL;

readline($prompt);

I still get the same for both.

When changing it to (added on line of Proceed by specifying what you want to know:):

<?php
declare(strict_types=1);

$prompt = "Hello there!".
    PHP_EOL . "What do you want to know?" .
    PHP_EOL . "Proceed by specifying what you want to know:" .
    PHP_EOL . "Proceed by specifying what you want to know:" .
    PHP_EOL . "Proceed by specifying what you want to know:" .
    PHP_EOL . "Proceed by specifying what you want to know:" .
    PHP_EOL .":  " . PHP_EOL;

readline($prompt);

I get the following when executing it via PHP:

Hello there!
What do you want to know?
Proceed by specifying what you want to know:
Proceed by specifying what you want to know:
Proceed by specifying what you want to know:
Proceed by specifying what you want to know:
: 

And the following when executing with the shell script:

Hello there!
What do you want to know?
Proceed by specifying what you want to know:
Proceed by specifying what you want to know:
Proceed by specifying what you want to know:
ying what you want to know:
:  

What I've tried so far (none of them solved the issue):

  • check the $prompt for unexpected characters like carriage returns, etc.
  • run the script via require -r in the zsh.
  • run the script via bash instead of zsh.
  • check the readline docs for some maxlength constraints (the docs do not mention any).

If relevant, I am trying this on a mac on the latest software state, where zsh is the default shell, on PHP 8.2.

Why is this happening? It is essential because I am writing multiple interactive CLI automations in PHP using readline, and this issue seems to randomly modify the $prompt provided to readline(), which breaks the whole purpose.

Of course the alternative is to execute all scripts via php in the automations, but doing so via zsh / bash is preferred, as all the other processes of the system are also shell scripts.

3
  • My current workaround is to simply do echo $prompt; readline() instead of readline($prompt);, but I'd still be interested in knowing why this happens. Commented Oct 14 at 22:32
  • 2
    From the source code, it can be seen that the expected value for this prompt string should be at most 2 lines. Commented Oct 15 at 6:00
  • 1
    Yes, as it's name, readline is to catch a single line, thus the second line acts as a submit, so the ENTER key is effective. Traditionally it helps to understand how works legacy modal editors, such as ed and vim. The line in a text is edited outside of the flow, and pressing ENTER does actually replace the line. The greatest achievement of a programmer with a lot of time is definitely to make his own text editor, and this is how it starts! Commented Oct 15 at 19:13

1 Answer 1

2

Yes, this is one of the old bug that makes readline hard to use for complex CLI programs (not only PHP).

If you are catching user keys in your program, using readline might breaks the STDIN flow., and has it's own logic for new lines.

So, either, use only readline for simple user inputs, or use another PHP built-in function to catch the STDIN, such as stream_get_line().

The following is not exactly a readline replacement, however it won't break the STDIN pipe, won't have the new line issue you shown, so that logic could be used from within really complex CLI programs. In any cases, It's great to play around.

In this example only one character is expected.


// $user = readline();
stream_set_blocking(STDIN, true);
$user = stream_get_line(STDIN, 1, PHP_EOL);

if ($user === "y") {
    doSomething();
}
if ($user === "n") {
    break;
}
if ($user === "q") {
    exit;
}
Sign up to request clarification or add additional context in comments.

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.