Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use unix named pipe instead of stdin/stdout? #638

Closed
t-oster opened this issue May 24, 2020 · 3 comments
Closed

Use unix named pipe instead of stdin/stdout? #638

t-oster opened this issue May 24, 2020 · 3 comments

Comments

@t-oster
Copy link

t-oster commented May 24, 2020

Hi,
I stumbeled on this great project. However since most in-the-wild apps are running on apache any ma not be easily started with PHP's internal webserver (e.g. because of url-rewriting in .htaccess etc), it would be really great if we could use this from apache in a live running system.

There are great ideas (#505, #121) but they seem to take some time on order to be implemented.

Can't we just specify a path for input/output which is used instead of stdin/stout where PsySH reads commands from and prints output to? Then we could SSH to the webserver, create a unix named pipe with mknod and read/write to that. This should work with apache or am I missing something?

I am trying to figure out where to hook in, but maybe someone can give me a hint where to look....

@t-oster t-oster changed the title Use unix pipe instead of stdin/stdout? Use unix named pipe instead of stdin/stdout? May 24, 2020
@t-oster
Copy link
Author

t-oster commented May 26, 2020

Well this is pretty hacky right now, but it works (after all every PHP programmer is a pirate,isn't he?)...
Until this is implemented cleanly if you want to debug your running PHP application on apache:

# Make two fifos
mkfifo /tmp/i
mkfifo /tmp/o
# patch ConsoleOutput to write to /tmp/o instead of php://stdout/err
sed -i 's#php://stdout#/tmp/o#g' vendor/symfony/console/Output/ConsoleOutput.php
sed -i 's#php://stderr#/tmp/o#g' vendor/symfony/console/Output/ConsoleOutput.php
# patch Transient.php to read from /tmp/i instead of php::/stdin
sed -i 's#php://stdin#/tmp/i#g' vendor/psy/psysh/src/Readline/Transient.php
# Change your config to NOT use readline
cat > ~/.config/psysh/config.php << EOF
<?php
return [
	"useReadline" => false
];
EOF
# listen to your new console 
echo "now call eval(\Psy\sh());"
cat /tmp/o&
cat > /tmp/i

USE AT YOUR OWN RISK!

@bobthecow
Copy link
Owner

No need for hacks!

Output is already streamable if you use a lower-level API for starting the interactive session. And since you're doing that, you can supply your own Readline implementation that reads from a stream rather than stdin 🙂

Screen Shot 2020-07-26 at 2 58 16 PM

#!/usr/bin/env php
<?php

require 'vendor/autoload.php';

// Initialize input with the first command line argument.
$readline = new StreamingReadline(\fopen($argv[1], 'r'));
// Provide our own streamed console output using the second command line argument.
$output = new \Symfony\Component\Console\Output\StreamOutput(\fopen($argv[2], 'w'));

$config = new \Psy\Configuration();
$config->setReadline($readline);
$shell = new \Psy\Shell($config);
$shell->run(null, $output); // $input param is only used for initial cli arguments, so don't override

And the StreamingReadline implementation is really straightforward:

<?php

class StreamingReadline implements \Psy\Readline\Readline
{
    private $stream;
    private $history = [];

    public static function isSupported() {
        return true;
    }

    public function __construct($stream) {
        if (!\is_resource($stream) || \get_resource_type($stream) !== 'stream') {
            throw new \InvalidArgumentException('The StreamingReadline class needs a stream as its first argument.');
        }

        $this->stream  = $stream;
    }

    public function addHistory($line) {
        $this->history[] = $line;

        return true;
    }

    public function clearHistory() {
        $this->history = [];

        return true;
    }

    public function listHistory() {
        return $this->history;
    }

    public function readHistory() {
        return true;
    }

    public function readline($prompt = null) {
        return \rtrim(\fgets($this->stream), "\n\r");
    }

    public function redisplay() {
        // noop
    }

    public function writeHistory() {
        return true;
    }
}

@t-oster
Copy link
Author

t-oster commented Jul 30, 2020

nice, so we don't even need sed. If we could include the StreamingReadline class in the source, we could make this really easy to run on an existing project.

@t-oster t-oster closed this as completed Jul 30, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants