bobthecow / psysh

A REPL for PHP
https://psysh.org
MIT License
9.74k stars 310 forks source link

Have psysh break into a web interface #505

Open supriyo-biswas opened 6 years ago

supriyo-biswas commented 6 years ago

Recently, when working with the Python Flask framework, I discovered a cool feature β€” it allows you to run code inside the web browser:

flask

Could we have the PsySH breakpoint launch a web interface? Not having to switch back-and-forth between the terminal and the browser would be a great plus.

bobthecow commented 6 years ago

Yep, this is a great idea! Wanna open a pull request? πŸ˜‰

supriyo-biswas commented 6 years ago

Well, I have a lot to learn about the PsySH codebase before I can usefully contribute. πŸ˜‰

In particular, I'm not sure how the forking loop is implemented, does it fork when PHP runs as a web server, or does it always fork?

bobthecow commented 6 years ago

It always forks, if your PHP install has the pcntl and posix extensions.

If you don't have those two extensions (i.e. Windows but not WSL or Cygwin users) it has a non-forking mode which doesn't fork at all… which is a bit less awesome, because uncatchable fatal errors drop you back out to the command line rather than continuing. But we can probably ignore these users, as I doubt we'd be able to implement in-browser breakpoints without forks.

For everyone else, basically:

  1. Upon starting PsySH, we fork into a main process and a worker process which actually does things.
  2. The main process then just stops and waits for the other process to finish.
    • Once it's finished, the main process reads and unserializes the REPL session return value from a socket, and returns that value.
  3. The worker process immediately forks to create a savegame process, which also just stops and waits.
  4. The worker process executes user input.
    • If it succeeds, the worker kills the last savegame and creates a new one.
    • If the worker dies (because of an uncatchable fatal error) the savegame picks up where the worker left off, becomes the new worker, and continues execution.
  5. If the user input was exit, serialize the return value, send it back to the main process via our handy socket, then kill the worker thread.
  6. If the worker thread is still around: goto 3.
filips123 commented 6 years ago

Maybe you could also collaborate with Whoops which is error handler framework for PHP. It also include user friendly error handler page, but it currently doesn't have REPL.

Maybe you could collaborate with them and integrate PsySH into their error handlers (or opposite).

See https://github.com/filp/whoops/issues/585.

Whoops Error Handler

staabm commented 6 years ago

I would love having something like this in whoops, but I guess it needs to be some kind of external optional feature because it might double the codebase in terms of lines of code I guess?

filips123 commented 6 years ago

@staabm Yes, this could be a problem. There are two possible solutions. First is to have it as external optional feature like you said and second is to maybe join PsySH and Whoops so they will have some shared code.

GrahamCampbell commented 4 years ago

https://github.com/spatie/laravel-web-tinker is related to this.

tgr commented 1 year ago

This would very significantly change the security footprint of PsySH. Right now there isn't much risk in making it available on a production server - anyone who can get a shell on the server and can execute PHP can already do anything PsySH can do, just less comfortably. But getting access to a web port is much easier and much harder to control than getting shell access; I would be very uncomfortable with code for a remote code execution backdoor being present on production servers, even if the feature is off by default - from there on it's just one small mistake, either by the PsySH developers or by whoever is configuring PsySH for the given application, and anyone who can get a HTTP connection can run code on the server.

IMO if a feature like this gets implemented, it should be in a separate Composer package so the code only gets installed on servers where it's wanted.