Current File : //usr/local/lsws/add-ons/webcachemgr/src/UserCommand.php |
<?php
/** *********************************************
* LiteSpeed Web Server Cache Manager
*
* @author Michael Alegre
* @copyright (c) 2018-2023 LiteSpeed Technologies, Inc.
* *******************************************
*/
namespace Lsc\Wp;
use Exception;
use Lsc\Wp\Context\Context;
use Lsc\Wp\Context\ContextOption;
use Lsc\Wp\Context\UserCLIContextOption;
use Lsc\Wp\Panel\ControlPanel;
/**
* Running as user - suexec
*/
class UserCommand
{
/**
* @var int
*/
const EXIT_ERROR = 1;
/**
* @var int
*/
const EXIT_SUCC = 2;
/**
* @var int
*/
const EXIT_FAIL = 4;
/**
* @var int
*/
const EXIT_INCR_SUCC = 8;
/**
* @var int
*/
const EXIT_INCR_FAIL = 16;
/**
* @var int
*/
const EXIT_INCR_BYPASS = 32;
/**
* @var int
*/
const RETURN_CODE_TIMEOUT = 124;
/**
* @var string
*/
const CMD_STATUS = 'status';
/**
* @var string
*/
const CMD_ENABLE = 'enable';
/**
* @var string
*/
const CMD_DIRECT_ENABLE = 'direct_enable';
/**
* @var string
*/
const CMD_MASS_ENABLE = 'mass_enable';
/**
* @var string
*/
const CMD_DISABLE = 'disable';
/**
* @var string
*/
const CMD_MASS_DISABLE = 'mass_disable';
/**
* @var string
*/
const CMD_UPGRADE = 'upgrade';
/**
* @var string
*/
const CMD_MASS_UPGRADE = 'mass_upgrade';
/**
* @var string
*/
const CMD_UPDATE_TRANSLATION = 'update_translation';
/**
* @var string
*/
const CMD_REMOVE_LSCWP_PLUGIN_FILES = 'remove_lscwp_plugin_files';
/**
* @var string
*/
const CMD_DASH_NOTIFY = 'dash_notify';
/**
* @var string
*/
const CMD_MASS_DASH_NOTIFY = 'mass_dash_notify';
/**
* @var string
*/
const CMD_DASH_DISABLE = 'dash_disable';
/**
* @var string
*/
const CMD_MASS_DASH_DISABLE = 'mass_dash_disable';
/**
* @var string
*/
const CMD_DASH_GET_MSG = 'dash_get_msg';
/**
* @var string
*/
const CMD_DASH_ADD_MSG = 'dash_add_msg';
/**
* @var string
*/
const CMD_DASH_DELETE_MSG = 'dash_delete_msg';
/**
* @since 1.12
* @var string
*/
const CMD_GET_QUICCLOUD_API_KEY = 'getQuicCloudApiKey';
/**
* @var bool
*/
private $asUser;
/**
* @var WPInstall
*/
private $currInstall;
/**
* @var string
*/
private $action;
/**
* @var string[]
*/
private $extraArgs;
/**
*
* @param bool $asUser
*
* @throws LSCMException Thrown indirectly by Context::initialize() call.
*/
private function __construct( $asUser = false )
{
if ( ($this->asUser = $asUser) ) {
require_once __DIR__ . '/../autoloader.php';
date_default_timezone_set('UTC');
Context::initialize(new UserCLIContextOption('userCommand'));
}
}
/**
* Handles logging unexpected error output (or not if too long) and returns
* a crafted message to be displayed instead.
*
* @param WPInstall $wpInstall WordPress Installation object.
* @param string $err Compiled error message.
* @param int $lines Number of $output lines read into the error
* msg.
*
* @return string Message to be displayed instead.
*
* @throws LSCMException Thrown indirectly by Logger::error() call.
* @throws LSCMException Thrown indirectly by Logger::error() call.
*/
private static function handleUnexpectedError(
WPInstall $wpInstall,
$err,
$lines )
{
$msg = 'Unexpected Error Encountered!';
$path = $wpInstall->getPath();
/**
* $lines > 500 are likely some custom code triggering a page render.
* Throw out actual message in this case.
*/
if ( $lines < 500 ) {
$match = false;
$commonErrs = array(
WPInstall::ST_ERR_EXECMD_DB =>
'Error establishing a database connection'
);
foreach ( $commonErrs as $statusBit => $commonErr ) {
if ( strpos($err, $commonErr) !== false ) {
$wpInstall->unsetStatusBit(WPInstall::ST_ERR_EXECMD);
$wpInstall->setStatusBit($statusBit);
$msg .= " $commonErr.";
$match = true;
break;
}
}
if ( !$match ) {
Logger::error("$path - $err");
return "$msg See " . ContextOption::LOG_FILE_NAME
. " for more information.";
}
}
Logger::error("$path - $msg");
return $msg;
}
/**
* Parse out locale and plugin version information from issue() result
* output GET_TRANSLATION or BAD_TRANSLATION line.
*
* @since 1.14
*
* @param string $line
*
* @return string[]
*/
private static function parseTranslationLocaleAndPluginVer( $line )
{
list($locale, $pluginVer) = explode(' ', $line);
return array( 'locale' => $locale, 'pluginVer' => $pluginVer );
}
/**
*
* @since 1.9
*
* @param WPInstall $wpInstall
* @param string $output
*
* @throws LSCMException Thrown indirectly by
* PluginVersion::retrieveTranslation() call.
* @throws LSCMException Thrown indirectly by self::subCommandIssue() call.
* @throws LSCMException Thrown indirectly by
* PluginVersion::removeTranslationZip() call.
*/
private static function handleGetTranslationOutput(
WPInstall $wpInstall,
$output )
{
$translationInfo = self::parseTranslationLocaleAndPluginVer($output);
$translationRetrieved = PluginVersion::retrieveTranslation(
$translationInfo['locale'],
$translationInfo['pluginVer']
);
if ( $translationRetrieved ) {
$subOutput =
self::subCommandIssue(self::CMD_UPDATE_TRANSLATION, $wpInstall);
foreach ( $subOutput as $subLine ) {
if ( preg_match('/BAD_TRANSLATION=(.+)/', $subLine, $m) ) {
$badTranslationInfo =
self::parseTranslationLocaleAndPluginVer($m[1]);
PluginVersion::removeTranslationZip(
$badTranslationInfo['locale'],
$badTranslationInfo['pluginVer']
);
}
}
}
}
/**
*
* @since 1.9
*
* @param WPInstall $wpInstall
* @param string $line
* @param int $retStatus
* @param int $cmdStatus
* @param string $err
*
* @return bool
*
* @throws LSCMException Thrown indirectly by
* $wpInstall->populateDataFromUrl() call.
* @throws LSCMException Thrown indirectly by
* self::handleGetTranslationOutput() call.
*/
private static function handleResultOutput(
WPInstall $wpInstall,
$line,
&$retStatus,
&$cmdStatus,
&$err )
{
if ( preg_match('/SITEURL=(.+)/', $line, $m) ) {
if ( !$wpInstall->populateDataFromUrl($m[1]) ) {
/**
* Matching docroot could not be found, ignore other
* output. setCmdStatusAndMsg() etc already handled in
* setSiteUrl().
*/
return false;
}
}
elseif ( preg_match('/STATUS=(.+)/', $line, $m) ) {
$retStatus = (int)$m[1];
}
elseif ( preg_match('/MASS_INCR=(.+)/', $line, $m) ) {
if ( $m[1] == 'SUCC' ) {
$cmdStatus |= UserCommand::EXIT_INCR_SUCC;
}
elseif ( $m[1] == 'FAIL' ) {
$cmdStatus |= UserCommand::EXIT_INCR_FAIL;
}
elseif( $m[1] = 'BYPASS' ) {
$cmdStatus |= UserCommand::EXIT_INCR_BYPASS;
}
}
elseif ( preg_match('/GET_TRANSLATION=(.+)/', $line, $m) ) {
self::handleGetTranslationOutput($wpInstall, $m[1]);
}
else {
$err .= "Unexpected result line: $line\n";
}
return true;
}
/**
*
* @since 1.9
*
* @param WPInstall $wpInstall
*
* @throws LSCMException Thrown indirectly by self::subCommandIssue() call.
*/
private static function removeLeftoverLscwpFiles( WPInstall $wpInstall )
{
self::subCommandIssue(self::CMD_REMOVE_LSCWP_PLUGIN_FILES, $wpInstall);
$wpInstall->removeNewLscwpFlagFile();
}
/**
*
* @param string $action
* @param WPInstall $wpInstall
* @param array $extraArgs
*
* @return string
*
* @throws LSCMException Thrown indirectly by $wpInstall->getPhpBinary()
* call.
* @throws LSCMException Thrown indirectly by Context::getOption() call.
*/
protected static function getIssueCmd(
$action,
WPInstall $wpInstall,
array $extraArgs = array() )
{
$su = $wpInstall->getSuCmd();
$timeout = ControlPanel::PHP_TIMEOUT;
$phpBin = $wpInstall->getPhpBinary();
$path = $wpInstall->getPath();
$serverName = $wpInstall->getData(WPInstall::FLD_SERVERNAME);
$env = Context::getOption()->getInvokerName();
if ( $serverName === null ) {
$serverName = $docRoot = 'x';
}
else {
$docRoot = $wpInstall->getData(WPInstall::FLD_DOCROOT);
if ( $docRoot === null ) {
$docRoot = 'x';
}
}
$modifier = implode(' ', $extraArgs);
$file = __FILE__;
return "$su -c \"cd $path/wp-admin && timeout $timeout $phpBin $file "
. "$action $path $docRoot $serverName $env"
. (($modifier !== '') ? " $modifier\"" : '"');
}
/**
*
* @since 1.12
*
* @param string $action
* @param WPInstall $wpInstall
* @param string[] $extraArgs
*
* @return null|string
*
* @throws LSCMException Thrown indirectly by self::preIssueValidation()
* call.
* @throws LSCMException Thrown indirectly by self::getIssueCmd() call.
* @throws LSCMException Thrown indirectly by Logger::debug() call.
* @throws LSCMException Thrown indirectly by Logger::debug() call.
* @throws LSCMException Thrown indirectly by Logger::logMsg() call.
* @throws LSCMException Thrown indirectly by Logger::logMsg() call.
*/
public static function getValueFromWordPress(
$action,
WPInstall $wpInstall,
array $extraArgs = array() )
{
if ( !self::preIssueValidation($action, $wpInstall, $extraArgs) ) {
return null;
}
$cmd = self::getIssueCmd($action, $wpInstall, $extraArgs);
exec($cmd, $output, $return_var);
Logger::debug(
"getValueFromWordPress command $action=$return_var $wpInstall\n$cmd"
);
Logger::debug('output = ' . var_export($output, true));
$ret = null;
$debug = $upgrade = $err = '';
$curr = &$err;
foreach ( $output as $line ) {
/**
* If this line is not present in output, did not return normally.
* This line will appear after any [UPGRADE] output.
*/
if ( strpos($line, 'LS UserCommand Output Start') !== false ) {
continue;
}
elseif ( strpos($line, '[RESULT]') !== false ) {
if ( preg_match('/API_KEY=(.+)/', $line, $m) ) {
$ret = $m[1];
}
else {
$err .= "Unexpected result line $line\n";
}
}
elseif ( ($pos = strpos($line, '[DEBUG]')) !== false ) {
$debug .= substr($line, $pos + 7) . "\n";
$curr = &$debug;
}
elseif ( strpos($line, '[UPGRADE]') !== false ) {
//Ignore this output
$curr = &$upgrade;
}
else {
$curr .= "$line\n";
}
}
$path = $wpInstall->getPath();
if ( $debug ) {
Logger::logMsg("$path - $debug", Logger::L_DEBUG);
}
if ( $err ) {
Logger::logMsg("$path - $err", Logger::L_ERROR);
}
return $ret;
}
/**
*
* @since 1.14
*
* @param string $subAction
* @param WPInstall $wpInstall
*
* @return string[]
*
* @throws LSCMException Thrown indirectly by self::getIssueCmd() call.
* @throws LSCMException Thrown indirectly by Logger::debug() call.
* @throws LSCMException Thrown indirectly by Logger::debug() call.
*/
private static function subCommandIssue(
$subAction,
WPInstall $wpInstall )
{
$subCmd = self::getIssueCmd($subAction, $wpInstall);
exec($subCmd, $subOutput, $subReturn_var);
Logger::debug(
"Issue sub command $subAction=$subReturn_var $wpInstall\n$subCmd"
);
Logger::debug('sub output = ' . var_export($subOutput, true));
return $subOutput;
}
/**
*
* @param string $action
* @param WPInstall $wpInstall
* @param string[] $extraArgs
*
* @return bool
*
* @throws LSCMException Thrown indirectly by self::preIssueValidation()
* call.
* @throws LSCMException Thrown indirectly by self::getIssueCmd() call.
* @throws LSCMException Thrown indirectly by Logger::debug() call.
* @throws LSCMException Thrown indirectly by Logger::debug() call.
* @throws LSCMException Thrown indirectly by
* self::removeLeftoverLscwpFiles() call.
* @throws LSCMException Thrown indirectly by self::handleResultOutput()
* call.
* @throws LSCMException Thrown indirectly by Logger::logMsg() call.
* @throws LSCMException Thrown indirectly by Logger::logMsg() call.
* @throws LSCMException Thrown indirectly by $wpInstall->addUserFlagFile()
* call.
* @throws LSCMException Thrown indirectly by Logger::error() call.
* @throws LSCMException Thrown indirectly by self::handleUnexpectedError()
* call.
*/
public static function issue(
$action,
WPInstall $wpInstall,
array $extraArgs = array() )
{
if ( !self::preIssueValidation($action, $wpInstall, $extraArgs) ) {
return false;
}
$cmd = self::getIssueCmd($action, $wpInstall, $extraArgs);
exec($cmd, $output, $return_var);
Logger::debug(
"Issue command $action=$return_var $wpInstall\n$cmd"
);
Logger::debug('output = ' . var_export($output, true));
if ( $wpInstall->hasNewLscwpFlagFile() ) {
self::removeLeftoverLscwpFiles($wpInstall);
}
$errorStatus = $retStatus = $cmdStatus = 0;
switch ( $return_var ) {
case UserCommand::RETURN_CODE_TIMEOUT:
$errorStatus |= WPInstall::ST_ERR_TIMEOUT;
break;
case UserCommand::EXIT_ERROR:
case 255:
$errorStatus |= WPInstall::ST_ERR_EXECMD;
break;
//no default
}
$isExpectedOutput = false;
$unexpectedLines = 0;
$succ = $upgrade = $err = $msg = $logMsg = '';
$logLvl = -1;
$curr = &$err;
foreach ( $output as $line ) {
/**
* If this line is not present in output, did not return normally.
* This line will appear after any [UPGRADE] output.
*/
if ( strpos($line, 'LS UserCommand Output Start') !== false ) {
$isExpectedOutput = true;
}
elseif ( strpos($line, '[RESULT]') !== false ) {
$ret = self::handleResultOutput(
$wpInstall,
$line,
$retStatus,
$cmdStatus,
$err
);
if ( !$ret ) {
/**
* Problem handling RESULT output, ignore other output.
*/
return false;
}
}
elseif ( ($pos = strpos($line, '[SUCCESS]')) !== false ) {
$succ .= substr($line, $pos + 9) . "\n";
$curr = &$succ;
}
elseif ( ($pos = strpos($line, '[ERROR]')) !== false ) {
$err .= substr($line, $pos + 7) . "\n";
$curr = &$err;
}
elseif ( strpos($line, '[LOG]') !== false ) {
if ( $logMsg != '' ) {
Logger::logMsg(trim($logMsg), $logLvl);
$logMsg = '';
}
if ( preg_match('/\[(\d+)] (.+)/', $line, $m) ) {
$logLvl = $m[1];
$logMsg = "{$wpInstall->getPath()} - $m[2]\n";
}
$curr = &$logMsg;
}
elseif ( strpos($line, '[UPGRADE]') !== false ) {
/**
* Ignore this output
*/
$curr = &$upgrade;
}
else {
if ( !$isExpectedOutput ) {
$line = htmlentities($line);
$unexpectedLines++;
}
$curr .= "$line\n";
}
}
if ( $logMsg != '' ) {
Logger::logMsg(trim($logMsg), $logLvl);
}
if ( !$isExpectedOutput && !$errorStatus ) {
$errorStatus |= WPInstall::ST_ERR_EXECMD;
}
if ( $errorStatus ) {
$wpInstall->addUserFlagFile(false);
$errorStatus |= WPInstall::ST_FLAGGED;
$cmdStatus |= UserCommand::EXIT_INCR_FAIL;
}
$newStatus = ($errorStatus | $retStatus);
if ( $newStatus != 0 ) {
$wpInstall->setStatus($newStatus);
}
if ( $succ ) {
$cmdStatus |= UserCommand::EXIT_SUCC;
$msg = $succ;
}
if ( $err ) {
if ( $return_var == UserCommand::EXIT_FAIL ) {
$cmdStatus |= UserCommand::EXIT_FAIL;
}
else {
$cmdStatus |= UserCommand::EXIT_ERROR;
}
if ( $isExpectedOutput ) {
$msg = $err;
Logger::error("{$wpInstall->getPath()} - $err");
}
else {
$msg = self::handleUnexpectedError(
$wpInstall,
$err,
$unexpectedLines
);
}
}
$wpInstall->setCmdStatusAndMsg($cmdStatus, $msg);
return true;
}
/**
*
* @param string[] $args
*
* @return null|WPInstall
*/
public static function newFromCmdArgs( array &$args )
{
if ( !($wpPath = array_shift($args))
|| !($docRoot = array_shift($args))
|| !($serverName = array_shift($args)) ) {
return null;
}
if ( !is_dir($wpPath) ) {
return null;
}
/**
* LSCWP_REF used by LSCWP plugin.
*/
Util::define_wrapper('LSCWP_REF', array_shift($args));
$install = new WPInstall($wpPath);
if ( $docRoot != 'x' ) {
$install->setDocRoot($docRoot);
}
if ( $serverName != 'x' ) {
$install->setServerName($serverName);
}
return $install;
}
/**
*
* @param string $action
* @param WPInstall $wpInstall
* @param string[] $extraArgs Not used at the moment.
*
* @return bool
*
* @throws LSCMException Thrown when $action value is unsupported.
* @throws LSCMException Thrown indirectly by $wpInstall->hasValidPath()
* call.
* @throws LSCMException Thrown indirectly by Logger::debug() call.
* @throws LSCMException Thrown indirectly by $wpInstall->refreshStatus()
* call.
* @throws LSCMException Thrown indirectly by $wpInstall->addUserFlagFile()
* call.
* @throws LSCMException Thrown indirectly by Logger::debug() call.
* @throws LSCMException Thrown indirectly by
* DashNotifier::prepLocalDashPluginFiles() call.
*
* @noinspection PhpUnusedParameterInspection
*/
private static function preIssueValidation(
$action,
WPInstall $wpInstall,
array $extraArgs )
{
if ( !self::isSupportedIssueCmd($action) ) {
throw new LSCMException(
"Illegal action $action.",
LSCMException::E_PROGRAM
);
}
if ( !$wpInstall->hasValidPath() ) {
return false;
}
switch ( $action ) {
case self::CMD_MASS_ENABLE:
case self::CMD_MASS_DISABLE:
case self::CMD_MASS_UPGRADE:
if ( $wpInstall->hasFlagFile() ) {
Logger::debug(
"Bypass mass operation for flagged install $wpInstall"
);
return false;
}
//fallthrough
case self::CMD_MASS_DASH_NOTIFY:
case self::CMD_MASS_DASH_DISABLE:
if ( $wpInstall->hasFatalError() ) {
$wpInstall->refreshStatus();
if ( $wpInstall->hasFatalError() ) {
$wpInstall->addUserFlagFile(false);
Logger::debug(
'Bypassed mass operation for error install and '
. "flagged $wpInstall"
);
return false;
}
}
//no default
}
if ( $action == self::CMD_DASH_NOTIFY
|| $action == self::CMD_MASS_DASH_NOTIFY ) {
DashNotifier::prepLocalDashPluginFiles();
}
return true;
}
/**
*
* @since 1.9 Changed echoed output format to include "[LOG][$lvl] $msg".
* Stopped echoing "[DEBUG] $msg" output.
*
* @return int
*/
private function runAsUser()
{
try
{
$ret = 0;
if ( $this->action == self::CMD_REMOVE_LSCWP_PLUGIN_FILES ) {
$proc = WPCaller::getInstance($this->currInstall, false);
$proc->removeLscwpPluginFiles();
$ret = self::EXIT_SUCC;
}
else {
$proc = WPCaller::getInstance($this->currInstall);
switch ( $this->action ) {
case self::CMD_STATUS:
$ret = $proc->updateStatus(true);
break;
case self::CMD_ENABLE:
$ret = $proc->enable($this->extraArgs);
$this->currInstall->removeNewLscwpFlagFile();
break;
case self::CMD_DIRECT_ENABLE:
$ret = $proc->directEnable();
$this->currInstall->removeNewLscwpFlagFile();
break;
case self::CMD_MASS_ENABLE:
$ret = $proc->massEnable($this->extraArgs);
$this->currInstall->removeNewLscwpFlagFile();
break;
case self::CMD_DISABLE:
$ret = $proc->disable($this->extraArgs);
break;
case self::CMD_MASS_DISABLE:
$ret = $proc->massDisable($this->extraArgs);
break;
case self::CMD_UPGRADE:
$ret = $proc->upgrade($this->extraArgs);
break;
case self::CMD_MASS_UPGRADE:
$ret = $proc->massUpgrade($this->extraArgs);
break;
case self::CMD_UPDATE_TRANSLATION:
$proc->updateTranslationFiles();
$ret = self::EXIT_SUCC;
break;
case self::CMD_DASH_NOTIFY:
$ret = $proc->dashNotify($this->extraArgs);
break;
case self::CMD_MASS_DASH_NOTIFY:
$ret = $proc->massDashNotify($this->extraArgs);
break;
case self::CMD_DASH_DISABLE:
$ret = $proc->dashDisable($this->extraArgs);
break;
case self::CMD_MASS_DASH_DISABLE:
$ret = $proc->massDashDisable($this->extraArgs);
break;
case self::CMD_GET_QUICCLOUD_API_KEY:
$proc->getQuicCloudAPIKey(true);
$ret = self::EXIT_SUCC;
break;
//no default
}
}
echo "LS UserCommand Output Start\n";
foreach ( $proc->getOutputResult() as $key => $value ) {
echo "[RESULT] $key=$value\n";
}
foreach ( Logger::getUiMsgs(Logger::UI_SUCC) as $msg ) {
echo "[SUCCESS] $msg\n";
}
foreach ( Logger::getUiMsgs(Logger::UI_ERR) as $msg ) {
echo "[ERROR] $msg\n";
}
foreach ( Logger::getLogMsgQueue() as $logEntry ) {
$lvl = $logEntry->getLvl();
$msg = $logEntry->getMsg();
echo "[LOG][$lvl] $msg\n";
}
}
catch ( Exception $e )
{
$ret = UserCommand::EXIT_ERROR;
if ( $e instanceof LSCMException
&& $e->getCode() == LSCMException::E_NON_FATAL ) {
$ret = UserCommand::EXIT_FAIL;
}
echo "LS UserCommand Output Start\n";
echo "[ERROR] {$e->getMessage()}\n";
}
return $ret;
}
/**
*
* @param string $action
*
* @return bool
*/
private static function isSupportedIssueCmd( $action )
{
$supported = array(
self::CMD_STATUS,
self::CMD_ENABLE,
self::CMD_DIRECT_ENABLE,
self::CMD_MASS_ENABLE,
self::CMD_DISABLE,
self::CMD_MASS_DISABLE,
self::CMD_UPGRADE,
self::CMD_MASS_UPGRADE,
self::CMD_UPDATE_TRANSLATION,
self::CMD_REMOVE_LSCWP_PLUGIN_FILES,
self::CMD_DASH_NOTIFY,
self::CMD_MASS_DASH_NOTIFY,
self::CMD_DASH_DISABLE,
self::CMD_MASS_DASH_DISABLE,
self::CMD_GET_QUICCLOUD_API_KEY
);
return in_array($action, $supported);
}
/**
*
* @param string[] $args
*
* @return bool
*/
private function initArgs( $args )
{
$action = array_shift($args);
if ( self::isSupportedIssueCmd($action) ) {
$this->action = $action;
if ( $install = self::newFromCmdArgs($args) ) {
$this->currInstall = $install;
$this->extraArgs = $args;
return true;
}
}
return false;
}
/**
*
* @return UserCommand
*
* @throws LSCMException Thrown indirectly by "new self()" call.
*
* @noinspection PhpDocRedundantThrowsInspection
*/
private static function getUserCommand()
{
/**
* Check if invoked from shell.
*/
if ( empty($_SERVER['argv']) ) {
return null;
}
$args = $_SERVER['argv'];
if ( array_shift($args) != __FILE__ ) {
return null;
}
$instance = new self(true);
if ( !$instance->initArgs($args) ) {
echo 'illegal input ' . implode(' ', $_SERVER['argv']);
exit(self::EXIT_ERROR);
}
return $instance;
}
/**
*
* @throws LSCMException Thrown indirectly by self::getUserCommand() call.
*/
public static function run()
{
if ( $cmd = self::getUserCommand() ) {
if ( !defined('LSCM_RUN_AS_USER') ) {
Util::define_wrapper('LSCM_RUN_AS_USER', 1);
}
$ret = $cmd->runAsUser();
exit($ret);
}
}
}
/**
* This should only be invoked from command line.
*
* @noinspection PhpUnhandledExceptionInspection
*/
UserCommand::run();