MediaWiki  master
Shell.php
Go to the documentation of this file.
1 <?php
23 namespace MediaWiki\Shell;
24 
25 use Hooks;
27 
44 class Shell {
45 
52  public const NO_ROOT = 1;
53 
60  public const SECCOMP = 2;
61 
67  public const PRIVATE_DEV = 4;
68 
75  public const NO_NETWORK = 8;
76 
83  public const NO_EXECVE = 16;
84 
90  public const NO_LOCALSETTINGS = 32;
91 
100  public const RESTRICT_DEFAULT = self::NO_ROOT | self::SECCOMP | self::PRIVATE_DEV |
102 
108  public const RESTRICT_NONE = 0;
109 
119  public static function command( ...$commands ): Command {
120  if ( count( $commands ) === 1 && is_array( reset( $commands ) ) ) {
121  // If only one argument has been passed, and that argument is an array,
122  // treat it as a list of arguments
123  $commands = reset( $commands );
124  }
126  ->getShellCommandFactory()
127  ->create();
128 
129  return $command->params( $commands );
130  }
131 
137  public static function isDisabled(): bool {
138  static $disabled = null;
139 
140  if ( $disabled === null ) {
141  if ( !function_exists( 'proc_open' ) ) {
142  wfDebug( "proc_open() is disabled" );
143  $disabled = true;
144  } else {
145  $disabled = false;
146  }
147  }
148 
149  return $disabled;
150  }
151 
163  public static function escape( ...$args ): string {
164  if ( count( $args ) === 1 && is_array( reset( $args ) ) ) {
165  // If only one argument has been passed, and that argument is an array,
166  // treat it as a list of arguments
167  $args = reset( $args );
168  }
169 
170  $first = true;
171  $retVal = '';
172  foreach ( $args as $arg ) {
173  if ( $arg === null ) {
174  continue;
175  }
176  if ( !$first ) {
177  $retVal .= ' ';
178  } else {
179  $first = false;
180  }
181 
182  if ( wfIsWindows() ) {
183  // Escaping for an MSVC-style command line parser and CMD.EXE
184  // Refs:
185  // * https://web.archive.org/web/20020708081031/http://mailman.lyra.org/pipermail/scite-interest/2002-March/000436.html
186  // * https://technet.microsoft.com/en-us/library/cc723564.aspx
187  // * T15518
188  // * CR r63214
189  // Double the backslashes before any double quotes. Escape the double quotes.
190  $tokens = preg_split( '/(\\\\*")/', $arg, -1, PREG_SPLIT_DELIM_CAPTURE );
191  $arg = '';
192  $iteration = 0;
193  foreach ( $tokens as $token ) {
194  if ( $iteration % 2 == 1 ) {
195  // Delimiter, a double quote preceded by zero or more slashes
196  $arg .= str_replace( '\\', '\\\\', substr( $token, 0, -1 ) ) . '\\"';
197  } elseif ( $iteration % 4 == 2 ) {
198  // ^ in $token will be outside quotes, need to be escaped
199  $arg .= str_replace( '^', '^^', $token );
200  } else { // $iteration % 4 == 0
201  // ^ in $token will appear inside double quotes, so leave as is
202  $arg .= $token;
203  }
204  $iteration++;
205  }
206  // Double the backslashes before the end of the string, because
207  // we will soon add a quote
208  $m = [];
209  if ( preg_match( '/^(.*?)(\\\\+)$/', $arg, $m ) ) {
210  $arg = $m[1] . str_replace( '\\', '\\\\', $m[2] );
211  }
212 
213  // Add surrounding quotes
214  $retVal .= '"' . $arg . '"';
215  } else {
216  $retVal .= escapeshellarg( $arg );
217  }
218  }
219  return $retVal;
220  }
221 
236  public static function makeScriptCommand(
237  string $script, array $parameters, $options = []
238  ): Command {
239  global $wgPhpCli;
240  // Give site config file a chance to run the script in a wrapper.
241  // The caller may likely want to call wfBasename() on $script.
242  Hooks::runner()->onWfShellWikiCmd( $script, $parameters, $options );
243  $cmd = [ $options['php'] ?? $wgPhpCli ];
244  if ( isset( $options['wrapper'] ) ) {
245  $cmd[] = $options['wrapper'];
246  }
247  $cmd[] = $script;
248 
249  return self::command( $cmd )
250  ->params( $parameters )
251  ->restrict( self::RESTRICT_DEFAULT & ~self::NO_LOCALSETTINGS );
252  }
253 }
MediaWiki\Shell\Shell\NO_EXECVE
const NO_EXECVE
Deny execve syscall with seccomp.
Definition: Shell.php:83
$wgPhpCli
$wgPhpCli
Executable path of the PHP cli binary.
Definition: DefaultSettings.php:8721
MediaWiki\Shell\Shell
Executes shell commands.
Definition: Shell.php:44
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:146
MediaWiki\Shell\Command
Class used for executing shell commands.
Definition: Command.php:36
MediaWiki\Shell\Shell\SECCOMP
const SECCOMP
Use seccomp to block dangerous syscalls.
Definition: Shell.php:60
MediaWiki\Shell\Shell\command
static command(... $commands)
Returns a new instance of Command class.
Definition: Shell.php:119
MediaWiki\MediaWikiServices\getInstance
static getInstance()
Returns the global default instance of the top level service locator.
Definition: MediaWikiServices.php:177
$args
if( $line===false) $args
Definition: mcc.php:124
MediaWiki\Shell\Shell\isDisabled
static isDisabled()
Check if this class is effectively disabled via php.ini config.
Definition: Shell.php:137
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:913
MediaWiki\Shell\Shell\NO_ROOT
const NO_ROOT
Disallow any root access.
Definition: Shell.php:52
MediaWiki\Shell\Shell\RESTRICT_DEFAULT
const RESTRICT_DEFAULT
Apply a default set of restrictions for improved security out of the box.
Definition: Shell.php:100
wfIsWindows
wfIsWindows()
Check if the operating system is Windows.
Definition: GlobalFunctions.php:1844
Hooks\runner
static runner()
Get a HookRunner instance for calling hooks using the new interfaces.
Definition: Hooks.php:171
MediaWiki\Shell\Shell\escape
static escape(... $args)
Version of escapeshellarg() that works better on Windows.
Definition: Shell.php:163
$command
$command
Definition: mcc.php:125
MediaWiki\Shell
Copyright (C) 2017 Kunal Mehta legoktm@member.fsf.org
Definition: Command.php:21
MediaWiki\Shell\Shell\PRIVATE_DEV
const PRIVATE_DEV
Create a private /dev.
Definition: Shell.php:67
MediaWiki\Shell\Shell\NO_NETWORK
const NO_NETWORK
Restrict the request to have no network access.
Definition: Shell.php:75
MediaWiki\Shell\Shell\makeScriptCommand
static makeScriptCommand(string $script, array $parameters, $options=[])
Generate a Command object to run a MediaWiki CLI script.
Definition: Shell.php:236
MediaWiki\Shell\Shell\RESTRICT_NONE
const RESTRICT_NONE
Don't apply any restrictions.
Definition: Shell.php:108
MediaWiki\Shell\Shell\NO_LOCALSETTINGS
const NO_LOCALSETTINGS
Deny access to LocalSettings.php (MW_CONFIG_FILE)
Definition: Shell.php:90
Hooks
Hooks class.
Definition: Hooks.php:38