Skip to content

Run yii command in web process #14

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ class Module extends \yii\base\Module
*/
public $yiiScript = '@app/yii';

/**
* @var string path to the yii console app configuration file
* used to run the yii command in the same process as the web application's
* if so chosen.
*/
public $consoleConfig = '@app/config/console.php';

/**
* @var array the list of IPs that are allowed to access this module.
* Each array element represents a single IP filter which can be either an IP address
Expand Down
64 changes: 62 additions & 2 deletions controllers/DefaultController.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,71 @@ public function actionRpc()

switch ($options['method']) {
case 'yii':
list ($status, $output) = $this->runConsole(implode(' ', $options['params']));
return ['result' => $output];
$exitCode = 1;
$output = null;
$params = explode(' ', $options['params']);

if (!empty($params) and in_array($params[0], ['-wp', '--runInWebProcess'])) {
array_shift($params); // remove runInWebProcess option parameter

// mimicking yii command behaviour
// just typing 'yii' in console defaults to 'yii help'
if (empty($params))
$params[] = 'help';

list($exitCode, $output) = $this->runYiiConsoleCommandsInWebProcess($params);
}
else
list ($exitCode, $output) = $this->runConsole(implode(' ', $params));

return [
'exitCode' => $exitCode,
'output' => $output
];
}
}

// popen might be disabled for security reasons in the php.ini.
// this is common on shared hosting.
// read http://www.cyberciti.biz/faq/linux-unix-apache-lighttpd-phpini-disable-functions/
// refer to http://php.net/manual/en/ini.core.php#ini.disable-functions
private function runYiiConsoleCommandsInWebProcess(array $requestParams)
{
// remember current web app
// inspired by https://github.com/tebazil/yii2-console-runner/blob/master/src/ConsoleCommandRunner.php
$webApp = Yii::$app;

try {
//use console request to resolve command and arguments
$request = new \yii\console\Request;
$request->setParams($requestParams);
list ($route, $params) = $request->resolve();

/* redefine STDOUT and STDERR streams
to write to the memory stream which is readable.
this might cause a PHP Notice because of global constant
redefinition if they're previously defined or this method
is called mor than once per HTTP request. */
define('STDOUT', fopen('php://memory', 'w+'));
define('STDERR', STDOUT);
ob_start(); // aditionally buffer output, echo() and printf() write to this
// set app context
Yii::$app = new \yii\console\Application(require(Yii::getAlias($this->module->consoleConfig)));
$exitCode = Yii::$app->runAction($route, $params);
rewind(STDOUT);
$output = stream_get_contents(STDOUT); // whatever has been written to STDOUT and STDERR
$output .= ob_get_clean(); // and what has been echoed and printed
fclose(STDOUT);
}
catch (\Exception $ex) {
$output = $webApp->errorHandler->convertExceptionToString($ex);
$exitCode = 1;
}

Yii::$app = $webApp; // revert to web app context
return [$exitCode, $output];
}

/**
* Runs console command
*
Expand Down
16 changes: 10 additions & 6 deletions views/default/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,21 @@
webshell.terminal(
function(command, term) {
if (command.indexOf('yii') === 0 || command.indexOf('yii') === 3) {
$.jrpc('{$endpoint}', 'yii', [command.replace(/^yii ?/, '')], function(json) {
term.echo(json.result);
$.jrpc('{$endpoint}', 'yii', command.replace(/^yii ?/, ''), function(json) {
term.echo(json.output);
scrollDown();
});
} else if (command === 'help') {
term.echo('Available commands are:');
term.echo('');
term.echo("clear\tClear console");
term.echo('help\tThis help text');
term.echo('yii\tyii command');
term.echo('quit\tQuit web shell');
term.echo('help\t This help text');
term.echo('clear\tClear console');
term.echo('quit\t Quit web shell');
term.echo('yii [-wp|--runInWebProcess] <command>');
term.echo('\tcommand \t\t\t\t A yii console command. Type "yii help" to list available commands.');
term.echo('\t-wp|--runInWebProcess\tRun command in the web application process.');
term.echo('\t\t\t\t\t\t\t Does not require creating a background process via "popen",');
term.echo('\t\t\t\t\t\t\t a function which might be disabled in your PHP config.');
scrollDown();
} else if (command === 'quit') {
var exitUrl = '{$quitUrl}';
Expand Down