Execute “less” from command-line PHP w/ Scrolling

2019-05-16 08:28发布

问题:

I want to execute less and similar programs from the command-line in PHP.

I have tried the usual suspects (exec, shell_exec, passthru, etc), and while many of them can dump the file to the screen, the process is terminated before I can make use of it. If I wanted cat, I'd use it.

How do I execute a program in this fashion?

回答1:

You could use proc_open to feed input to and get output back from a process via pipes. However, it doesn't seem like less allows for user interaction via pipes as it basically degrades to a cat command. Here's my first (failed) approach:

<?php
$dspec = array(
  0 = array('pipe', 'r'), // pipe to child process's stdin
  1 = array('pipe', 'w'), // pipe from child process's stdout
  2 = array('file', 'error_log', 'a'), // stderr dumped to file
);
// run the external command
$proc = proc_open('less name_of_file_here', $dspec, $pipes, null, null);
if (is_resource($proc)) {
  while (($cmd = readline('')) != 'q') {
    // if the external command expects input, it will get it from us here
    fwrite($pipes[0], $cmd);
    fflush($pipes[0]);
    // we can get the response from the external command here
    echo fread($pipes[1], 1024);
  }
fclose($pipes[0]);
fclose($pipes[1]);
echo proc_close($proc);

I guess for some commands this approach might actually work - and there are some examples in the php manpage for proc_open that might be helpful to look over - but for less, you get the whole file back and no possibility for interaction, maybe for reasons mentioned by Viper_Sb's answer.

...But it seems easy enough to simulate less if that's all you need. For example, you could read the output of the command into an array of lines and feed it in bite-sized chunks:

<?php
$pid = popen('cat name_of_file_here', 'r');
$buf = array();
while ($s = fgets($pid, 1024))
  $buf[] = $s;
pclose($pid);
for ($i = 0; $i < count($buf)/25 && readline('more') != 'q'; $i++) {
  for ($j = 0; $j < 25; $j++) {
    echo array_shift($buf);
  }
}


回答2:

I don't believe this is possible. PHP is not a VM/shell environment, the commands it has to access other programs all return control to it, and normally there is no interaction while PHP is running.

One last thing, try with the backtick operators, if that doesn't work then I'm pretty sure you can't do this without writing up something yourself that will sleep and allow user input etc... by default no

`nano file.txt`


回答3:

Adding exec('stty cbreak'); to the PHP script also fixes the issue.

I put the following in a file defined by the auto_prepend_file setting in php.ini

So, I would do something like edit php.ini to the following:

auto_prepend_file = /path/to/prepend.php

Then in, /path/to/prepend.php, I would add the following line:

if (php_sapi_name() == 'cli') exec('stty cbreak');

I'm not exactly sure of the cause. I've read bug reports for PHP. I'm not sure about versions though. I noticed the problem with the following setup:

$ php -v
PHP 5.3.3 (cli) (built: Jul 12 2013 20:35:47)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies

However, the following did not show the issue:

# php -v
PHP 5.3.26 (cli) (built: Oct 21 2013 16:50:03)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2013 Zend Technologies
    with the ionCube PHP Loader v4.4.1, Copyright (c) 2002-2013, by ionCube Ltd.

It is worth noting that the version without the issue was using cPanel and the other was using the default CentOS 6 install via yum.