MediaWiki  1.31.0
Maintenance.php
Go to the documentation of this file.
1 <?php
23 // Bail on old versions of PHP, or if composer has not been run yet to install
24 // dependencies.
25 require_once __DIR__ . '/../includes/PHPVersionCheck.php';
26 wfEntryPointCheck( 'cli' );
27 
30 
36 // Define this so scripts can easily find doMaintenance.php
37 define( 'RUN_MAINTENANCE_IF_MAIN', __DIR__ . '/doMaintenance.php' );
38 
42 define( 'DO_MAINTENANCE', RUN_MAINTENANCE_IF_MAIN ); // original name, harmless
43 
44 $maintClass = false;
45 
51 
61 abstract class Maintenance {
66  const DB_NONE = 0;
67  const DB_STD = 1;
68  const DB_ADMIN = 2;
69 
70  // Const for getStdin()
71  const STDIN_ALL = 'all';
72 
73  // This is the desired params
74  protected $mParams = [];
75 
76  // Array of mapping short parameters to long ones
77  protected $mShortParamsMap = [];
78 
79  // Array of desired args
80  protected $mArgList = [];
81 
82  // This is the list of options that were actually passed
83  protected $mOptions = [];
84 
85  // This is the list of arguments that were actually passed
86  protected $mArgs = [];
87 
88  // Name of the script currently running
89  protected $mSelf;
90 
91  // Special vars for params that are always used
92  protected $mQuiet = false;
93  protected $mDbUser, $mDbPass;
94 
95  // A description of the script, children should change this via addDescription()
96  protected $mDescription = '';
97 
98  // Have we already loaded our user input?
99  protected $mInputLoaded = false;
100 
107  protected $mBatchSize = null;
108 
109  // Generic options added by addDefaultParams()
110  private $mGenericParameters = [];
111  // Generic options which might or not be supported by the script
112  private $mDependantParameters = [];
113 
118  private $mDb = null;
119 
121  private $lastReplicationWait = 0.0;
122 
127  public $fileHandle;
128 
134  private $config;
135 
140  private $requiredExtensions = [];
141 
153  public $orderedOptions = [];
154 
159  public function __construct() {
160  // Setup $IP, using MW_INSTALL_PATH if it exists
161  global $IP;
162  $IP = strval( getenv( 'MW_INSTALL_PATH' ) ) !== ''
163  ? getenv( 'MW_INSTALL_PATH' )
164  : realpath( __DIR__ . '/..' );
165 
166  $this->addDefaultParams();
167  register_shutdown_function( [ $this, 'outputChanneled' ], false );
168  }
169 
177  public static function shouldExecute() {
179 
180  if ( !function_exists( 'debug_backtrace' ) ) {
181  // If someone has a better idea...
182  return $wgCommandLineMode;
183  }
184 
185  $bt = debug_backtrace();
186  $count = count( $bt );
187  if ( $count < 2 ) {
188  return false; // sanity
189  }
190  if ( $bt[0]['class'] !== self::class || $bt[0]['function'] !== 'shouldExecute' ) {
191  return false; // last call should be to this function
192  }
193  $includeFuncs = [ 'require_once', 'require', 'include', 'include_once' ];
194  for ( $i = 1; $i < $count; $i++ ) {
195  if ( !in_array( $bt[$i]['function'], $includeFuncs ) ) {
196  return false; // previous calls should all be "requires"
197  }
198  }
199 
200  return true;
201  }
202 
206  abstract public function execute();
207 
219  protected function addOption( $name, $description, $required = false,
220  $withArg = false, $shortName = false, $multiOccurrence = false
221  ) {
222  $this->mParams[$name] = [
223  'desc' => $description,
224  'require' => $required,
225  'withArg' => $withArg,
226  'shortName' => $shortName,
227  'multiOccurrence' => $multiOccurrence
228  ];
229 
230  if ( $shortName !== false ) {
231  $this->mShortParamsMap[$shortName] = $name;
232  }
233  }
234 
240  protected function hasOption( $name ) {
241  return isset( $this->mOptions[$name] );
242  }
243 
254  protected function getOption( $name, $default = null ) {
255  if ( $this->hasOption( $name ) ) {
256  return $this->mOptions[$name];
257  } else {
258  // Set it so we don't have to provide the default again
259  $this->mOptions[$name] = $default;
260 
261  return $this->mOptions[$name];
262  }
263  }
264 
271  protected function addArg( $arg, $description, $required = true ) {
272  $this->mArgList[] = [
273  'name' => $arg,
274  'desc' => $description,
275  'require' => $required
276  ];
277  }
278 
283  protected function deleteOption( $name ) {
284  unset( $this->mParams[$name] );
285  }
286 
291  protected function addDescription( $text ) {
292  $this->mDescription = $text;
293  }
294 
300  protected function hasArg( $argId = 0 ) {
301  return isset( $this->mArgs[$argId] );
302  }
303 
310  protected function getArg( $argId = 0, $default = null ) {
311  return $this->hasArg( $argId ) ? $this->mArgs[$argId] : $default;
312  }
313 
321  protected function getBatchSize() {
322  return $this->mBatchSize;
323  }
324 
329  protected function setBatchSize( $s = 0 ) {
330  $this->mBatchSize = $s;
331 
332  // If we support $mBatchSize, show the option.
333  // Used to be in addDefaultParams, but in order for that to
334  // work, subclasses would have to call this function in the constructor
335  // before they called parent::__construct which is just weird
336  // (and really wasn't done).
337  if ( $this->mBatchSize ) {
338  $this->addOption( 'batch-size', 'Run this many operations ' .
339  'per batch, default: ' . $this->mBatchSize, false, true );
340  if ( isset( $this->mParams['batch-size'] ) ) {
341  // This seems a little ugly...
342  $this->mDependantParameters['batch-size'] = $this->mParams['batch-size'];
343  }
344  }
345  }
346 
351  public function getName() {
352  return $this->mSelf;
353  }
354 
361  protected function getStdin( $len = null ) {
362  if ( $len == self::STDIN_ALL ) {
363  return file_get_contents( 'php://stdin' );
364  }
365  $f = fopen( 'php://stdin', 'rt' );
366  if ( !$len ) {
367  return $f;
368  }
369  $input = fgets( $f, $len );
370  fclose( $f );
371 
372  return rtrim( $input );
373  }
374 
378  public function isQuiet() {
379  return $this->mQuiet;
380  }
381 
388  protected function output( $out, $channel = null ) {
389  // This is sometimes called very early, before Setup.php is included.
390  if ( class_exists( MediaWikiServices::class ) ) {
391  // Try to periodically flush buffered metrics to avoid OOMs
392  $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
393  if ( $stats->getDataCount() > 1000 ) {
394  MediaWiki::emitBufferedStatsdData( $stats, $this->getConfig() );
395  }
396  }
397 
398  if ( $this->mQuiet ) {
399  return;
400  }
401  if ( $channel === null ) {
402  $this->cleanupChanneled();
403  print $out;
404  } else {
405  $out = preg_replace( '/\n\z/', '', $out );
406  $this->outputChanneled( $out, $channel );
407  }
408  }
409 
416  protected function error( $err, $die = 0 ) {
417  if ( intval( $die ) !== 0 ) {
418  wfDeprecated( __METHOD__ . '( $err, $die )', '1.31' );
419  $this->fatalError( $err, intval( $die ) );
420  }
421  $this->outputChanneled( false );
422  if (
423  ( PHP_SAPI == 'cli' || PHP_SAPI == 'phpdbg' ) &&
424  !defined( 'MW_PHPUNIT_TEST' )
425  ) {
426  fwrite( STDERR, $err . "\n" );
427  } else {
428  print $err;
429  }
430  }
431 
439  protected function fatalError( $msg, $exitCode = 1 ) {
440  $this->error( $msg );
441  exit( $exitCode );
442  }
443 
444  private $atLineStart = true;
445  private $lastChannel = null;
446 
450  public function cleanupChanneled() {
451  if ( !$this->atLineStart ) {
452  print "\n";
453  $this->atLineStart = true;
454  }
455  }
456 
465  public function outputChanneled( $msg, $channel = null ) {
466  if ( $msg === false ) {
467  $this->cleanupChanneled();
468 
469  return;
470  }
471 
472  // End the current line if necessary
473  if ( !$this->atLineStart && $channel !== $this->lastChannel ) {
474  print "\n";
475  }
476 
477  print $msg;
478 
479  $this->atLineStart = false;
480  if ( $channel === null ) {
481  // For unchanneled messages, output trailing newline immediately
482  print "\n";
483  $this->atLineStart = true;
484  }
485  $this->lastChannel = $channel;
486  }
487 
498  public function getDbType() {
499  return self::DB_STD;
500  }
501 
505  protected function addDefaultParams() {
506  # Generic (non script dependant) options:
507 
508  $this->addOption( 'help', 'Display this help message', false, false, 'h' );
509  $this->addOption( 'quiet', 'Whether to supress non-error output', false, false, 'q' );
510  $this->addOption( 'conf', 'Location of LocalSettings.php, if not default', false, true );
511  $this->addOption( 'wiki', 'For specifying the wiki ID', false, true );
512  $this->addOption( 'globals', 'Output globals at the end of processing for debugging' );
513  $this->addOption(
514  'memory-limit',
515  'Set a specific memory limit for the script, '
516  . '"max" for no limit or "default" to avoid changing it',
517  false,
518  true
519  );
520  $this->addOption( 'server', "The protocol and server name to use in URLs, e.g. " .
521  "http://en.wikipedia.org. This is sometimes necessary because " .
522  "server name detection may fail in command line scripts.", false, true );
523  $this->addOption( 'profiler', 'Profiler output format (usually "text")', false, true );
524  // This is named --mwdebug, because --debug would conflict in the phpunit.php CLI script.
525  $this->addOption( 'mwdebug', 'Enable built-in MediaWiki development settings', false, true );
526 
527  # Save generic options to display them separately in help
528  $this->mGenericParameters = $this->mParams;
529 
530  # Script dependant options:
531 
532  // If we support a DB, show the options
533  if ( $this->getDbType() > 0 ) {
534  $this->addOption( 'dbuser', 'The DB user to use for this script', false, true );
535  $this->addOption( 'dbpass', 'The password to use for this script', false, true );
536  }
537 
538  # Save additional script dependant options to display
539  #  them separately in help
540  $this->mDependantParameters = array_diff_key( $this->mParams, $this->mGenericParameters );
541  }
542 
547  public function getConfig() {
548  if ( $this->config === null ) {
549  $this->config = MediaWikiServices::getInstance()->getMainConfig();
550  }
551 
552  return $this->config;
553  }
554 
559  public function setConfig( Config $config ) {
560  $this->config = $config;
561  }
562 
572  protected function requireExtension( $name ) {
573  $this->requiredExtensions[] = $name;
574  }
575 
581  public function checkRequiredExtensions() {
582  $registry = ExtensionRegistry::getInstance();
583  $missing = [];
584  foreach ( $this->requiredExtensions as $name ) {
585  if ( !$registry->isLoaded( $name ) ) {
586  $missing[] = $name;
587  }
588  }
589 
590  if ( $missing ) {
591  $joined = implode( ', ', $missing );
592  $msg = "The following extensions are required to be installed "
593  . "for this script to run: $joined. Please enable them and then try again.";
594  $this->fatalError( $msg );
595  }
596  }
597 
602  public function setAgentAndTriggers() {
603  if ( function_exists( 'posix_getpwuid' ) ) {
604  $agent = posix_getpwuid( posix_geteuid() )['name'];
605  } else {
606  $agent = 'sysadmin';
607  }
608  $agent .= '@' . wfHostname();
609 
610  $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
611  // Add a comment for easy SHOW PROCESSLIST interpretation
612  $lbFactory->setAgentName(
613  mb_strlen( $agent ) > 15 ? mb_substr( $agent, 0, 15 ) . '...' : $agent
614  );
615  self::setLBFactoryTriggers( $lbFactory, $this->getConfig() );
616  }
617 
623  public static function setLBFactoryTriggers( LBFactory $LBFactory, Config $config ) {
624  $services = MediaWikiServices::getInstance();
625  $stats = $services->getStatsdDataFactory();
626  // Hook into period lag checks which often happen in long-running scripts
627  $lbFactory = $services->getDBLoadBalancerFactory();
628  $lbFactory->setWaitForReplicationListener(
629  __METHOD__,
630  function () use ( $stats, $config ) {
631  // Check config in case of JobRunner and unit tests
632  if ( $config->get( 'CommandLineMode' ) ) {
634  }
635  // Try to periodically flush buffered metrics to avoid OOMs
637  }
638  );
639  // Check for other windows to run them. A script may read or do a few writes
640  // to the master but mostly be writing to something else, like a file store.
641  $lbFactory->getMainLB()->setTransactionListener(
642  __METHOD__,
643  function ( $trigger ) use ( $stats, $config ) {
644  // Check config in case of JobRunner and unit tests
645  if ( $config->get( 'CommandLineMode' ) && $trigger === IDatabase::TRIGGER_COMMIT ) {
647  }
648  // Try to periodically flush buffered metrics to avoid OOMs
650  }
651  );
652  }
653 
661  public function runChild( $maintClass, $classFile = null ) {
662  // Make sure the class is loaded first
663  if ( !class_exists( $maintClass ) ) {
664  if ( $classFile ) {
665  require_once $classFile;
666  }
667  if ( !class_exists( $maintClass ) ) {
668  $this->error( "Cannot spawn child: $maintClass" );
669  }
670  }
671 
675  $child = new $maintClass();
676  $child->loadParamsAndArgs( $this->mSelf, $this->mOptions, $this->mArgs );
677  if ( !is_null( $this->mDb ) ) {
678  $child->setDB( $this->mDb );
679  }
680 
681  return $child;
682  }
683 
687  public function setup() {
689 
690  # Abort if called from a web server
691  # wfIsCLI() is not available yet
692  if ( PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg' ) {
693  $this->fatalError( 'This script must be run from the command line' );
694  }
695 
696  if ( $IP === null ) {
697  $this->fatalError( "\$IP not set, aborting!\n" .
698  '(Did you forget to call parent::__construct() in your maintenance script?)' );
699  }
700 
701  # Make sure we can handle script parameters
702  if ( !defined( 'HPHP_VERSION' ) && !ini_get( 'register_argc_argv' ) ) {
703  $this->fatalError( 'Cannot get command line arguments, register_argc_argv is set to false' );
704  }
705 
706  // Send PHP warnings and errors to stderr instead of stdout.
707  // This aids in diagnosing problems, while keeping messages
708  // out of redirected output.
709  if ( ini_get( 'display_errors' ) ) {
710  ini_set( 'display_errors', 'stderr' );
711  }
712 
713  $this->loadParamsAndArgs();
714  $this->maybeHelp();
715 
716  # Set the memory limit
717  # Note we need to set it again later in cache LocalSettings changed it
718  $this->adjustMemoryLimit();
719 
720  # Set max execution time to 0 (no limit). PHP.net says that
721  # "When running PHP from the command line the default setting is 0."
722  # But sometimes this doesn't seem to be the case.
723  ini_set( 'max_execution_time', 0 );
724 
725  # Define us as being in MediaWiki
726  define( 'MEDIAWIKI', true );
727 
728  $wgCommandLineMode = true;
729 
730  # Turn off output buffering if it's on
731  while ( ob_get_level() > 0 ) {
732  ob_end_flush();
733  }
734 
735  $this->validateParamsAndArgs();
736  }
737 
747  public function memoryLimit() {
748  $limit = $this->getOption( 'memory-limit', 'max' );
749  $limit = trim( $limit, "\" '" ); // trim quotes in case someone misunderstood
750  return $limit;
751  }
752 
756  protected function adjustMemoryLimit() {
757  $limit = $this->memoryLimit();
758  if ( $limit == 'max' ) {
759  $limit = -1; // no memory limit
760  }
761  if ( $limit != 'default' ) {
762  ini_set( 'memory_limit', $limit );
763  }
764  }
765 
769  protected function activateProfiler() {
771 
772  $output = $this->getOption( 'profiler' );
773  if ( !$output ) {
774  return;
775  }
776 
777  if ( is_array( $wgProfiler ) && isset( $wgProfiler['class'] ) ) {
778  $class = $wgProfiler['class'];
780  $profiler = new $class(
781  [ 'sampling' => 1, 'output' => [ $output ] ]
782  + $wgProfiler
783  + [ 'threshold' => $wgProfileLimit ]
784  );
785  $profiler->setTemplated( true );
786  Profiler::replaceStubInstance( $profiler );
787  }
788 
789  $trxProfiler = Profiler::instance()->getTransactionProfiler();
790  $trxProfiler->setLogger( LoggerFactory::getInstance( 'DBPerformance' ) );
791  $trxProfiler->setExpectations( $wgTrxProfilerLimits['Maintenance'], __METHOD__ );
792  }
793 
797  public function clearParamsAndArgs() {
798  $this->mOptions = [];
799  $this->mArgs = [];
800  $this->mInputLoaded = false;
801  }
802 
810  public function loadWithArgv( $argv ) {
811  $options = [];
812  $args = [];
813  $this->orderedOptions = [];
814 
815  # Parse arguments
816  for ( $arg = reset( $argv ); $arg !== false; $arg = next( $argv ) ) {
817  if ( $arg == '--' ) {
818  # End of options, remainder should be considered arguments
819  $arg = next( $argv );
820  while ( $arg !== false ) {
821  $args[] = $arg;
822  $arg = next( $argv );
823  }
824  break;
825  } elseif ( substr( $arg, 0, 2 ) == '--' ) {
826  # Long options
827  $option = substr( $arg, 2 );
828  if ( isset( $this->mParams[$option] ) && $this->mParams[$option]['withArg'] ) {
829  $param = next( $argv );
830  if ( $param === false ) {
831  $this->error( "\nERROR: $option parameter needs a value after it\n" );
832  $this->maybeHelp( true );
833  }
834 
835  $this->setParam( $options, $option, $param );
836  } else {
837  $bits = explode( '=', $option, 2 );
838  if ( count( $bits ) > 1 ) {
839  $option = $bits[0];
840  $param = $bits[1];
841  } else {
842  $param = 1;
843  }
844 
845  $this->setParam( $options, $option, $param );
846  }
847  } elseif ( $arg == '-' ) {
848  # Lonely "-", often used to indicate stdin or stdout.
849  $args[] = $arg;
850  } elseif ( substr( $arg, 0, 1 ) == '-' ) {
851  # Short options
852  $argLength = strlen( $arg );
853  for ( $p = 1; $p < $argLength; $p++ ) {
854  $option = $arg[$p];
855  if ( !isset( $this->mParams[$option] ) && isset( $this->mShortParamsMap[$option] ) ) {
856  $option = $this->mShortParamsMap[$option];
857  }
858 
859  if ( isset( $this->mParams[$option]['withArg'] ) && $this->mParams[$option]['withArg'] ) {
860  $param = next( $argv );
861  if ( $param === false ) {
862  $this->error( "\nERROR: $option parameter needs a value after it\n" );
863  $this->maybeHelp( true );
864  }
865  $this->setParam( $options, $option, $param );
866  } else {
867  $this->setParam( $options, $option, 1 );
868  }
869  }
870  } else {
871  $args[] = $arg;
872  }
873  }
874 
875  $this->mOptions = $options;
876  $this->mArgs = $args;
877  $this->loadSpecialVars();
878  $this->mInputLoaded = true;
879  }
880 
893  private function setParam( &$options, $option, $value ) {
894  $this->orderedOptions[] = [ $option, $value ];
895 
896  if ( isset( $this->mParams[$option] ) ) {
897  $multi = $this->mParams[$option]['multiOccurrence'];
898  } else {
899  $multi = false;
900  }
901  $exists = array_key_exists( $option, $options );
902  if ( $multi && $exists ) {
903  $options[$option][] = $value;
904  } elseif ( $multi ) {
905  $options[$option] = [ $value ];
906  } elseif ( !$exists ) {
907  $options[$option] = $value;
908  } else {
909  $this->error( "\nERROR: $option parameter given twice\n" );
910  $this->maybeHelp( true );
911  }
912  }
913 
923  public function loadParamsAndArgs( $self = null, $opts = null, $args = null ) {
924  # If we were given opts or args, set those and return early
925  if ( $self ) {
926  $this->mSelf = $self;
927  $this->mInputLoaded = true;
928  }
929  if ( $opts ) {
930  $this->mOptions = $opts;
931  $this->mInputLoaded = true;
932  }
933  if ( $args ) {
934  $this->mArgs = $args;
935  $this->mInputLoaded = true;
936  }
937 
938  # If we've already loaded input (either by user values or from $argv)
939  # skip on loading it again. The array_shift() will corrupt values if
940  # it's run again and again
941  if ( $this->mInputLoaded ) {
942  $this->loadSpecialVars();
943 
944  return;
945  }
946 
947  global $argv;
948  $this->mSelf = $argv[0];
949  $this->loadWithArgv( array_slice( $argv, 1 ) );
950  }
951 
955  protected function validateParamsAndArgs() {
956  $die = false;
957  # Check to make sure we've got all the required options
958  foreach ( $this->mParams as $opt => $info ) {
959  if ( $info['require'] && !$this->hasOption( $opt ) ) {
960  $this->error( "Param $opt required!" );
961  $die = true;
962  }
963  }
964  # Check arg list too
965  foreach ( $this->mArgList as $k => $info ) {
966  if ( $info['require'] && !$this->hasArg( $k ) ) {
967  $this->error( 'Argument <' . $info['name'] . '> required!' );
968  $die = true;
969  }
970  }
971 
972  if ( $die ) {
973  $this->maybeHelp( true );
974  }
975  }
976 
980  protected function loadSpecialVars() {
981  if ( $this->hasOption( 'dbuser' ) ) {
982  $this->mDbUser = $this->getOption( 'dbuser' );
983  }
984  if ( $this->hasOption( 'dbpass' ) ) {
985  $this->mDbPass = $this->getOption( 'dbpass' );
986  }
987  if ( $this->hasOption( 'quiet' ) ) {
988  $this->mQuiet = true;
989  }
990  if ( $this->hasOption( 'batch-size' ) ) {
991  $this->mBatchSize = intval( $this->getOption( 'batch-size' ) );
992  }
993  }
994 
999  protected function maybeHelp( $force = false ) {
1000  if ( !$force && !$this->hasOption( 'help' ) ) {
1001  return;
1002  }
1003 
1004  $screenWidth = 80; // TODO: Calculate this!
1005  $tab = " ";
1006  $descWidth = $screenWidth - ( 2 * strlen( $tab ) );
1007 
1008  ksort( $this->mParams );
1009  $this->mQuiet = false;
1010 
1011  // Description ...
1012  if ( $this->mDescription ) {
1013  $this->output( "\n" . wordwrap( $this->mDescription, $screenWidth ) . "\n" );
1014  }
1015  $output = "\nUsage: php " . basename( $this->mSelf );
1016 
1017  // ... append parameters ...
1018  if ( $this->mParams ) {
1019  $output .= " [--" . implode( "|--", array_keys( $this->mParams ) ) . "]";
1020  }
1021 
1022  // ... and append arguments.
1023  if ( $this->mArgList ) {
1024  $output .= ' ';
1025  foreach ( $this->mArgList as $k => $arg ) {
1026  if ( $arg['require'] ) {
1027  $output .= '<' . $arg['name'] . '>';
1028  } else {
1029  $output .= '[' . $arg['name'] . ']';
1030  }
1031  if ( $k < count( $this->mArgList ) - 1 ) {
1032  $output .= ' ';
1033  }
1034  }
1035  }
1036  $this->output( "$output\n\n" );
1037 
1038  # TODO abstract some repetitive code below
1039 
1040  // Generic parameters
1041  $this->output( "Generic maintenance parameters:\n" );
1042  foreach ( $this->mGenericParameters as $par => $info ) {
1043  if ( $info['shortName'] !== false ) {
1044  $par .= " (-{$info['shortName']})";
1045  }
1046  $this->output(
1047  wordwrap( "$tab--$par: " . $info['desc'], $descWidth,
1048  "\n$tab$tab" ) . "\n"
1049  );
1050  }
1051  $this->output( "\n" );
1052 
1053  $scriptDependantParams = $this->mDependantParameters;
1054  if ( count( $scriptDependantParams ) > 0 ) {
1055  $this->output( "Script dependant parameters:\n" );
1056  // Parameters description
1057  foreach ( $scriptDependantParams as $par => $info ) {
1058  if ( $info['shortName'] !== false ) {
1059  $par .= " (-{$info['shortName']})";
1060  }
1061  $this->output(
1062  wordwrap( "$tab--$par: " . $info['desc'], $descWidth,
1063  "\n$tab$tab" ) . "\n"
1064  );
1065  }
1066  $this->output( "\n" );
1067  }
1068 
1069  // Script specific parameters not defined on construction by
1070  // Maintenance::addDefaultParams()
1071  $scriptSpecificParams = array_diff_key(
1072  # all script parameters:
1073  $this->mParams,
1074  # remove the Maintenance default parameters:
1075  $this->mGenericParameters,
1076  $this->mDependantParameters
1077  );
1078  if ( count( $scriptSpecificParams ) > 0 ) {
1079  $this->output( "Script specific parameters:\n" );
1080  // Parameters description
1081  foreach ( $scriptSpecificParams as $par => $info ) {
1082  if ( $info['shortName'] !== false ) {
1083  $par .= " (-{$info['shortName']})";
1084  }
1085  $this->output(
1086  wordwrap( "$tab--$par: " . $info['desc'], $descWidth,
1087  "\n$tab$tab" ) . "\n"
1088  );
1089  }
1090  $this->output( "\n" );
1091  }
1092 
1093  // Print arguments
1094  if ( count( $this->mArgList ) > 0 ) {
1095  $this->output( "Arguments:\n" );
1096  // Arguments description
1097  foreach ( $this->mArgList as $info ) {
1098  $openChar = $info['require'] ? '<' : '[';
1099  $closeChar = $info['require'] ? '>' : ']';
1100  $this->output(
1101  wordwrap( "$tab$openChar" . $info['name'] . "$closeChar: " .
1102  $info['desc'], $descWidth, "\n$tab$tab" ) . "\n"
1103  );
1104  }
1105  $this->output( "\n" );
1106  }
1107 
1108  die( 1 );
1109  }
1110 
1114  public function finalSetup() {
1118 
1119  # Turn off output buffering again, it might have been turned on in the settings files
1120  if ( ob_get_level() ) {
1121  ob_end_flush();
1122  }
1123  # Same with these
1124  $wgCommandLineMode = true;
1125 
1126  # Override $wgServer
1127  if ( $this->hasOption( 'server' ) ) {
1128  $wgServer = $this->getOption( 'server', $wgServer );
1129  }
1130 
1131  # If these were passed, use them
1132  if ( $this->mDbUser ) {
1134  }
1135  if ( $this->mDbPass ) {
1137  }
1138 
1139  if ( $this->getDbType() == self::DB_ADMIN && isset( $wgDBadminuser ) ) {
1142 
1143  if ( $wgDBservers ) {
1147  foreach ( $wgDBservers as $i => $server ) {
1148  $wgDBservers[$i]['user'] = $wgDBuser;
1149  $wgDBservers[$i]['password'] = $wgDBpassword;
1150  }
1151  }
1152  if ( isset( $wgLBFactoryConf['serverTemplate'] ) ) {
1153  $wgLBFactoryConf['serverTemplate']['user'] = $wgDBuser;
1154  $wgLBFactoryConf['serverTemplate']['password'] = $wgDBpassword;
1155  }
1156  MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->destroy();
1157  }
1158 
1159  # Apply debug settings
1160  if ( $this->hasOption( 'mwdebug' ) ) {
1161  require __DIR__ . '/../includes/DevelopmentSettings.php';
1162  }
1163 
1164  // Per-script profiling; useful for debugging
1165  $this->activateProfiler();
1166 
1167  $this->afterFinalSetup();
1168 
1169  $wgShowSQLErrors = true;
1170 
1171  Wikimedia\suppressWarnings();
1172  set_time_limit( 0 );
1173  Wikimedia\restoreWarnings();
1174 
1175  $this->adjustMemoryLimit();
1176  }
1177 
1181  protected function afterFinalSetup() {
1182  if ( defined( 'MW_CMDLINE_CALLBACK' ) ) {
1183  call_user_func( MW_CMDLINE_CALLBACK );
1184  }
1185  }
1186 
1191  public function globals() {
1192  if ( $this->hasOption( 'globals' ) ) {
1193  print_r( $GLOBALS );
1194  }
1195  }
1196 
1201  public function loadSettings() {
1203 
1204  if ( isset( $this->mOptions['conf'] ) ) {
1205  $settingsFile = $this->mOptions['conf'];
1206  } elseif ( defined( "MW_CONFIG_FILE" ) ) {
1207  $settingsFile = MW_CONFIG_FILE;
1208  } else {
1209  $settingsFile = "$IP/LocalSettings.php";
1210  }
1211  if ( isset( $this->mOptions['wiki'] ) ) {
1212  $bits = explode( '-', $this->mOptions['wiki'] );
1213  if ( count( $bits ) == 1 ) {
1214  $bits[] = '';
1215  }
1216  define( 'MW_DB', $bits[0] );
1217  define( 'MW_PREFIX', $bits[1] );
1218  } elseif ( isset( $this->mOptions['server'] ) ) {
1219  // Provide the option for site admins to detect and configure
1220  // multiple wikis based on server names. This offers --server
1221  // as alternative to --wiki.
1222  // See https://www.mediawiki.org/wiki/Manual:Wiki_family
1223  $_SERVER['SERVER_NAME'] = $this->mOptions['server'];
1224  }
1225 
1226  if ( !is_readable( $settingsFile ) ) {
1227  $this->fatalError( "A copy of your installation's LocalSettings.php\n" .
1228  "must exist and be readable in the source directory.\n" .
1229  "Use --conf to specify it." );
1230  }
1231  $wgCommandLineMode = true;
1232 
1233  return $settingsFile;
1234  }
1235 
1241  public function purgeRedundantText( $delete = true ) {
1242  # Data should come off the master, wrapped in a transaction
1243  $dbw = $this->getDB( DB_MASTER );
1244  $this->beginTransaction( $dbw, __METHOD__ );
1245 
1246  # Get "active" text records from the revisions table
1247  $cur = [];
1248  $this->output( 'Searching for active text records in revisions table...' );
1249  $res = $dbw->select( 'revision', 'rev_text_id', [], __METHOD__, [ 'DISTINCT' ] );
1250  foreach ( $res as $row ) {
1251  $cur[] = $row->rev_text_id;
1252  }
1253  $this->output( "done.\n" );
1254 
1255  # Get "active" text records from the archive table
1256  $this->output( 'Searching for active text records in archive table...' );
1257  $res = $dbw->select( 'archive', 'ar_text_id', [], __METHOD__, [ 'DISTINCT' ] );
1258  foreach ( $res as $row ) {
1259  # old pre-MW 1.5 records can have null ar_text_id's.
1260  if ( $row->ar_text_id !== null ) {
1261  $cur[] = $row->ar_text_id;
1262  }
1263  }
1264  $this->output( "done.\n" );
1265 
1266  # Get the IDs of all text records not in these sets
1267  $this->output( 'Searching for inactive text records...' );
1268  $cond = 'old_id NOT IN ( ' . $dbw->makeList( $cur ) . ' )';
1269  $res = $dbw->select( 'text', 'old_id', [ $cond ], __METHOD__, [ 'DISTINCT' ] );
1270  $old = [];
1271  foreach ( $res as $row ) {
1272  $old[] = $row->old_id;
1273  }
1274  $this->output( "done.\n" );
1275 
1276  # Inform the user of what we're going to do
1277  $count = count( $old );
1278  $this->output( "$count inactive items found.\n" );
1279 
1280  # Delete as appropriate
1281  if ( $delete && $count ) {
1282  $this->output( 'Deleting...' );
1283  $dbw->delete( 'text', [ 'old_id' => $old ], __METHOD__ );
1284  $this->output( "done.\n" );
1285  }
1286 
1287  # Done
1288  $this->commitTransaction( $dbw, __METHOD__ );
1289  }
1290 
1295  protected function getDir() {
1296  return __DIR__;
1297  }
1298 
1309  protected function getDB( $db, $groups = [], $wiki = false ) {
1310  if ( is_null( $this->mDb ) ) {
1311  return wfGetDB( $db, $groups, $wiki );
1312  } else {
1313  return $this->mDb;
1314  }
1315  }
1316 
1322  public function setDB( IDatabase $db ) {
1323  $this->mDb = $db;
1324  }
1325 
1336  protected function beginTransaction( IDatabase $dbw, $fname ) {
1337  $dbw->begin( $fname );
1338  }
1339 
1351  protected function commitTransaction( IDatabase $dbw, $fname ) {
1352  $dbw->commit( $fname );
1353  try {
1354  $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
1355  $lbFactory->waitForReplication(
1356  [ 'timeout' => 30, 'ifWritesSince' => $this->lastReplicationWait ]
1357  );
1358  $this->lastReplicationWait = microtime( true );
1359 
1360  return true;
1361  } catch ( DBReplicationWaitError $e ) {
1362  return false;
1363  }
1364  }
1365 
1376  protected function rollbackTransaction( IDatabase $dbw, $fname ) {
1377  $dbw->rollback( $fname );
1378  }
1379 
1384  private function lockSearchindex( $db ) {
1385  $write = [ 'searchindex' ];
1386  $read = [
1387  'page',
1388  'revision',
1389  'text',
1390  'interwiki',
1391  'l10n_cache',
1392  'user',
1393  'page_restrictions'
1394  ];
1395  $db->lockTables( $read, $write, __CLASS__ . '::' . __METHOD__ );
1396  }
1397 
1402  private function unlockSearchindex( $db ) {
1403  $db->unlockTables( __CLASS__ . '::' . __METHOD__ );
1404  }
1405 
1411  private function relockSearchindex( $db ) {
1412  $this->unlockSearchindex( $db );
1413  $this->lockSearchindex( $db );
1414  }
1415 
1423  public function updateSearchIndex( $maxLockTime, $callback, $dbw, $results ) {
1424  $lockTime = time();
1425 
1426  # Lock searchindex
1427  if ( $maxLockTime ) {
1428  $this->output( " --- Waiting for lock ---" );
1429  $this->lockSearchindex( $dbw );
1430  $lockTime = time();
1431  $this->output( "\n" );
1432  }
1433 
1434  # Loop through the results and do a search update
1435  foreach ( $results as $row ) {
1436  # Allow reads to be processed
1437  if ( $maxLockTime && time() > $lockTime + $maxLockTime ) {
1438  $this->output( " --- Relocking ---" );
1439  $this->relockSearchindex( $dbw );
1440  $lockTime = time();
1441  $this->output( "\n" );
1442  }
1443  call_user_func( $callback, $dbw, $row );
1444  }
1445 
1446  # Unlock searchindex
1447  if ( $maxLockTime ) {
1448  $this->output( " --- Unlocking --" );
1449  $this->unlockSearchindex( $dbw );
1450  $this->output( "\n" );
1451  }
1452  }
1453 
1460  public function updateSearchIndexForPage( $dbw, $pageId ) {
1461  // Get current revision
1462  $rev = Revision::loadFromPageId( $dbw, $pageId );
1463  $title = null;
1464  if ( $rev ) {
1465  $titleObj = $rev->getTitle();
1466  $title = $titleObj->getPrefixedDBkey();
1467  $this->output( "$title..." );
1468  # Update searchindex
1469  $u = new SearchUpdate( $pageId, $titleObj->getText(), $rev->getContent() );
1470  $u->doUpdate();
1471  $this->output( "\n" );
1472  }
1473 
1474  return $title;
1475  }
1476 
1487  protected function countDown( $seconds ) {
1488  if ( $this->isQuiet() ) {
1489  return;
1490  }
1491  for ( $i = $seconds; $i >= 0; $i-- ) {
1492  if ( $i != $seconds ) {
1493  $this->output( str_repeat( "\x08", strlen( $i + 1 ) ) );
1494  }
1495  $this->output( $i );
1496  if ( $i ) {
1497  sleep( 1 );
1498  }
1499  }
1500  $this->output( "\n" );
1501  }
1502 
1511  public static function posix_isatty( $fd ) {
1512  if ( !function_exists( 'posix_isatty' ) ) {
1513  return !$fd;
1514  } else {
1515  return posix_isatty( $fd );
1516  }
1517  }
1518 
1524  public static function readconsole( $prompt = '> ' ) {
1525  static $isatty = null;
1526  if ( is_null( $isatty ) ) {
1527  $isatty = self::posix_isatty( 0 /*STDIN*/ );
1528  }
1529 
1530  if ( $isatty && function_exists( 'readline' ) ) {
1531  return readline( $prompt );
1532  } else {
1533  if ( $isatty ) {
1534  $st = self::readlineEmulation( $prompt );
1535  } else {
1536  if ( feof( STDIN ) ) {
1537  $st = false;
1538  } else {
1539  $st = fgets( STDIN, 1024 );
1540  }
1541  }
1542  if ( $st === false ) {
1543  return false;
1544  }
1545  $resp = trim( $st );
1546 
1547  return $resp;
1548  }
1549  }
1550 
1556  private static function readlineEmulation( $prompt ) {
1557  $bash = ExecutableFinder::findInDefaultPaths( 'bash' );
1558  if ( !wfIsWindows() && $bash ) {
1559  $retval = false;
1560  $encPrompt = wfEscapeShellArg( $prompt );
1561  $command = "read -er -p $encPrompt && echo \"\$REPLY\"";
1562  $encCommand = wfEscapeShellArg( $command );
1563  $line = wfShellExec( "$bash -c $encCommand", $retval, [], [ 'walltime' => 0 ] );
1564 
1565  if ( $retval == 0 ) {
1566  return $line;
1567  } elseif ( $retval == 127 ) {
1568  // Couldn't execute bash even though we thought we saw it.
1569  // Shell probably spit out an error message, sorry :(
1570  // Fall through to fgets()...
1571  } else {
1572  // EOF/ctrl+D
1573  return false;
1574  }
1575  }
1576 
1577  // Fallback... we'll have no editing controls, EWWW
1578  if ( feof( STDIN ) ) {
1579  return false;
1580  }
1581  print $prompt;
1582 
1583  return fgets( STDIN, 1024 );
1584  }
1585 
1593  public static function getTermSize() {
1594  $default = [ 80, 50 ];
1595  if ( wfIsWindows() ) {
1596  return $default;
1597  }
1598  // It's possible to get the screen size with VT-100 terminal escapes,
1599  // but reading the responses is not possible without setting raw mode
1600  // (unless you want to require the user to press enter), and that
1601  // requires an ioctl(), which we can't do. So we have to shell out to
1602  // something that can do the relevant syscalls. There are a few
1603  // options. Linux and Mac OS X both have "stty size" which does the
1604  // job directly.
1605  $result = Shell::command( 'stty', 'size' )
1606  ->execute();
1607  if ( $result->getExitCode() !== 0 ) {
1608  return $default;
1609  }
1610  if ( !preg_match( '/^(\d+) (\d+)$/', $result->getStdout(), $m ) ) {
1611  return $default;
1612  }
1613  return [ intval( $m[2] ), intval( $m[1] ) ];
1614  }
1615 
1620  public static function requireTestsAutoloader() {
1621  require_once __DIR__ . '/../tests/common/TestsAutoLoader.php';
1622  }
1623 }
1624 
1629  protected $mSelf = "FakeMaintenanceScript";
1630 
1631  public function execute() {
1632  return;
1633  }
1634 }
1635 
1640 abstract class LoggedUpdateMaintenance extends Maintenance {
1641  public function __construct() {
1642  parent::__construct();
1643  $this->addOption( 'force', 'Run the update even if it was completed already' );
1644  $this->setBatchSize( 200 );
1645  }
1646 
1647  public function execute() {
1648  $db = $this->getDB( DB_MASTER );
1649  $key = $this->getUpdateKey();
1650 
1651  if ( !$this->hasOption( 'force' )
1652  && $db->selectRow( 'updatelog', '1', [ 'ul_key' => $key ], __METHOD__ )
1653  ) {
1654  $this->output( "..." . $this->updateSkippedMessage() . "\n" );
1655 
1656  return true;
1657  }
1658 
1659  if ( !$this->doDBUpdates() ) {
1660  return false;
1661  }
1662 
1663  if ( $db->insert( 'updatelog', [ 'ul_key' => $key ], __METHOD__, 'IGNORE' ) ) {
1664  return true;
1665  } else {
1666  $this->output( $this->updatelogFailedMessage() . "\n" );
1667 
1668  return false;
1669  }
1670  }
1671 
1676  protected function updateSkippedMessage() {
1677  $key = $this->getUpdateKey();
1678 
1679  return "Update '{$key}' already logged as completed.";
1680  }
1681 
1686  protected function updatelogFailedMessage() {
1687  $key = $this->getUpdateKey();
1688 
1689  return "Unable to log update '{$key}' as completed.";
1690  }
1691 
1697  abstract protected function doDBUpdates();
1698 
1703  abstract protected function getUpdateKey();
1704 }
$wgProfileLimit
$wgProfileLimit
Only record profiling info for pages that took longer than this.
Definition: DefaultSettings.php:6300
FakeMaintenance\$mSelf
$mSelf
Definition: Maintenance.php:1629
RUN_MAINTENANCE_IF_MAIN
const RUN_MAINTENANCE_IF_MAIN
Definition: Maintenance.php:37
Maintenance\$mBatchSize
int $mBatchSize
Batch size.
Definition: Maintenance.php:107
LoggedUpdateMaintenance\__construct
__construct()
Default constructor.
Definition: Maintenance.php:1641
MediaWiki\Shell\Shell
Executes shell commands.
Definition: Shell.php:44
Maintenance\setParam
setParam(&$options, $option, $value)
Helper function used solely by loadParamsAndArgs to prevent code duplication.
Definition: Maintenance.php:893
Maintenance\getTermSize
static getTermSize()
Get the terminal size as a two-element array where the first element is the width (number of columns)...
Definition: Maintenance.php:1593
$wgShowSQLErrors
$wgShowSQLErrors
Whether to show "we're sorry, but there has been a database error" pages.
Definition: DefaultSettings.php:6240
Maintenance\$mShortParamsMap
$mShortParamsMap
Definition: Maintenance.php:77
MediaWiki\emitBufferedStatsdData
static emitBufferedStatsdData(IBufferingStatsdDataFactory $stats, Config $config)
Send out any buffered statsd data according to sampling rules.
Definition: MediaWiki.php:933
Maintenance\getStdin
getStdin( $len=null)
Return input from stdin.
Definition: Maintenance.php:361
Profiler\replaceStubInstance
static replaceStubInstance(Profiler $profiler)
Replace the current profiler with $profiler if no non-stub profiler is set.
Definition: Profiler.php:98
Profiler\instance
static instance()
Singleton.
Definition: Profiler.php:62
Maintenance\getDbType
getDbType()
Does the script need different DB access? By default, we give Maintenance scripts normal rights to th...
Definition: Maintenance.php:498
$opt
$opt
Definition: postprocess-phan.php:115
Maintenance\maybeHelp
maybeHelp( $force=false)
Maybe show the help.
Definition: Maintenance.php:999
Maintenance\fatalError
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
Definition: Maintenance.php:439
captcha-old.count
count
Definition: captcha-old.py:249
Maintenance\$mDbPass
$mDbPass
Definition: Maintenance.php:93
Maintenance\addDescription
addDescription( $text)
Set the description text.
Definition: Maintenance.php:291
Maintenance\setup
setup()
Do some sanity checking and basic setup.
Definition: Maintenance.php:687
Maintenance\$requiredExtensions
array $requiredExtensions
Definition: Maintenance.php:140
Maintenance\runChild
runChild( $maintClass, $classFile=null)
Run a child maintenance script.
Definition: Maintenance.php:661
Maintenance\setLBFactoryTriggers
static setLBFactoryTriggers(LBFactory $LBFactory, Config $config)
Definition: Maintenance.php:623
Maintenance\readconsole
static readconsole( $prompt='> ')
Prompt the console for input.
Definition: Maintenance.php:1524
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. Return false to stop further processing of the tag $reader:XMLReader object $logInfo:Array of information 'ImportHandlePageXMLTag':When parsing a XML tag in a page. Return false to stop further processing of the tag $reader:XMLReader object & $pageInfo:Array of information 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. Return false to stop further processing of the tag $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. Return false to stop further processing of the tag $reader:XMLReader object 'ImportHandleUnknownUser':When a user doesn 't exist locally, this hook is called to give extensions an opportunity to auto-create it. If the auto-creation is successful, return false. $name:User name 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. Return false to stop further processing of the tag $reader:XMLReader object $revisionInfo:Array of information 'ImportLogInterwikiLink':Hook to change the interwiki link used in log entries and edit summaries for transwiki imports. & $fullInterwikiPrefix:Interwiki prefix, may contain colons. & $pageTitle:String that contains page title. 'ImportSources':Called when reading from the $wgImportSources configuration variable. Can be used to lazy-load the import sources list. & $importSources:The value of $wgImportSources. Modify as necessary. See the comment in DefaultSettings.php for the detail of how to structure this array. 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. & $title:Title object for the current page & $request:WebRequest & $ignoreRedirect:boolean to skip redirect check & $target:Title/string of redirect target & $article:Article object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) & $article:article(object) being checked 'IsTrustedProxy':Override the result of IP::isTrustedProxy() & $ip:IP being check & $result:Change this value to override the result of IP::isTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of Sanitizer::validateEmail(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetMagic':DEPRECATED! Use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language & $magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetSpecialPageAliases':DEPRECATED! Use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead. Use to define aliases of special pages names depending of the language & $specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code:language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Array with elements of the form "language:title" in the order that they will be output. & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LanguageSelector':Hook to change the language selector available on a page. $out:The output page. $cssClassName:CSS class name of the language selector. 'LinkBegin':DEPRECATED! Use HtmlPageLinkRendererBegin instead. Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1985
Wikimedia\Rdbms\DBReplicationWaitError
Exception class for replica DB wait timeouts.
Definition: DBReplicationWaitError.php:28
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
Maintenance\loadParamsAndArgs
loadParamsAndArgs( $self=null, $opts=null, $args=null)
Process command line arguments $mOptions becomes an array with keys set to the option names $mArgs be...
Definition: Maintenance.php:923
Maintenance\relockSearchindex
relockSearchindex( $db)
Unlock and lock again Since the lock is low-priority, queued reads will be able to complete.
Definition: Maintenance.php:1411
Maintenance\getName
getName()
Get the script's name.
Definition: Maintenance.php:351
wfHostname
wfHostname()
Fetch server name for use in error reporting etc.
Definition: GlobalFunctions.php:1408
$wgLBFactoryConf
$wgLBFactoryConf
Load balancer factory configuration To set up a multi-master wiki farm, set the class here to somethi...
Definition: DefaultSettings.php:1985
$s
$s
Definition: mergeMessageFileList.php:187
Maintenance\hasArg
hasArg( $argId=0)
Does a given argument exist?
Definition: Maintenance.php:300
Maintenance\setDB
setDB(IDatabase $db)
Sets database object to be returned by getDB().
Definition: Maintenance.php:1322
$res
$res
Definition: database.txt:21
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:302
Maintenance
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
Definition: maintenance.txt:39
Maintenance\setConfig
setConfig(Config $config)
Definition: Maintenance.php:559
$maintClass
$maintClass
Definition: Maintenance.php:44
$wgDBpassword
$wgDBpassword
Database user's password.
Definition: DefaultSettings.php:1793
Maintenance\$lastChannel
$lastChannel
Definition: Maintenance.php:445
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
Maintenance\loadWithArgv
loadWithArgv( $argv)
Load params and arguments from a given array of command-line arguments.
Definition: Maintenance.php:810
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
Maintenance\checkRequiredExtensions
checkRequiredExtensions()
Verify that the required extensions are installed.
Definition: Maintenance.php:581
script
script(document.cookie)%253c/script%253e</pre ></div > !! end !! test XSS is escaped(inline) !!input< source lang
Maintenance\finalSetup
finalSetup()
Handle some last-minute setup here.
Definition: Maintenance.php:1114
Maintenance\rollbackTransaction
rollbackTransaction(IDatabase $dbw, $fname)
Rollback the transcation on a DB handle.
Definition: Maintenance.php:1376
wfEntryPointCheck
wfEntryPointCheck( $entryPoint)
Check php version and that external dependencies are installed, and display an informative error if e...
Definition: PHPVersionCheck.php:275
Wikimedia\Rdbms\IDatabase\commit
commit( $fname=__METHOD__, $flush='')
Commits a transaction previously started using begin().
Maintenance\$mDescription
$mDescription
Definition: Maintenance.php:96
Maintenance\beginTransaction
beginTransaction(IDatabase $dbw, $fname)
Begin a transcation on a DB.
Definition: Maintenance.php:1336
Maintenance\afterFinalSetup
afterFinalSetup()
Execute a callback function at the end of initialisation.
Definition: Maintenance.php:1181
ExtensionRegistry\getInstance
static getInstance()
Definition: ExtensionRegistry.php:88
$wgDBadminuser
$wgDBadminuser
Separate username for maintenance tasks.
Definition: DefaultSettings.php:1823
Maintenance\unlockSearchindex
unlockSearchindex( $db)
Unlock the tables.
Definition: Maintenance.php:1402
Maintenance\clearParamsAndArgs
clearParamsAndArgs()
Clear all params and arguments.
Definition: Maintenance.php:797
Config
Interface for configuration instances.
Definition: Config.php:28
$wgDBservers
$wgDBservers
Database load balancer This is a two-dimensional array, an array of server info structures Fields are...
Definition: DefaultSettings.php:1973
Maintenance\$mSelf
$mSelf
Definition: Maintenance.php:89
Maintenance\updateSearchIndex
updateSearchIndex( $maxLockTime, $callback, $dbw, $results)
Perform a search index update with locking.
Definition: Maintenance.php:1423
Maintenance\$mArgs
$mArgs
Definition: Maintenance.php:86
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:934
Maintenance\loadSpecialVars
loadSpecialVars()
Handle the special variables that are global to all scripts.
Definition: Maintenance.php:980
Maintenance\getConfig
getConfig()
Definition: Maintenance.php:547
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
Definition: GlobalFunctions.php:1111
LoggedUpdateMaintenance
Class for scripts that perform database maintenance and want to log the update in updatelog so we can...
Definition: Maintenance.php:1640
Maintenance\$atLineStart
$atLineStart
Definition: Maintenance.php:444
Config\get
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2800
Maintenance\$lastReplicationWait
float $lastReplicationWait
UNIX timestamp.
Definition: Maintenance.php:121
$input
if(is_array( $mode)) switch( $mode) $input
Definition: postprocess-phan.php:141
$wgCommandLineMode
global $wgCommandLineMode
Definition: DevelopmentSettings.php:27
Revision\loadFromPageId
static loadFromPageId( $db, $pageid, $id=0)
Load either the current, or a specified, revision that's attached to a given page.
Definition: Revision.php:256
Maintenance\addOption
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
Definition: Maintenance.php:219
$IP
$IP
Definition: update.php:3
Maintenance\$mDbUser
$mDbUser
Definition: Maintenance.php:93
Maintenance\requireExtension
requireExtension( $name)
Indicate that the specified extension must be loaded before the script can run.
Definition: Maintenance.php:572
Maintenance\$orderedOptions
array $orderedOptions
Used to read the options in the order they were passed.
Definition: Maintenance.php:153
Maintenance\globals
globals()
Potentially debug globals.
Definition: Maintenance.php:1191
LoggedUpdateMaintenance\updatelogFailedMessage
updatelogFailedMessage()
Message to show that the update log was unable to log the completion of this update.
Definition: Maintenance.php:1686
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
$output
$output
Definition: SyntaxHighlight.php:338
FakeMaintenance
Fake maintenance wrapper, mostly used for the web installer/updater.
Definition: Maintenance.php:1628
DB_MASTER
const DB_MASTER
Definition: defines.php:26
Maintenance\addDefaultParams
addDefaultParams()
Add the default parameters to the scripts.
Definition: Maintenance.php:505
Maintenance\readlineEmulation
static readlineEmulation( $prompt)
Emulate readline()
Definition: Maintenance.php:1556
Maintenance\countDown
countDown( $seconds)
Count down from $seconds to zero on the terminal, with a one-second pause between showing each number...
Definition: Maintenance.php:1487
Maintenance\DB_ADMIN
const DB_ADMIN
Definition: Maintenance.php:68
$services
static configuration should be added through ResourceLoaderGetConfigVars instead can be used to get the real title after the basic globals have been set but before ordinary actions take place or wrap services the preferred way to define a new service is the $wgServiceWiringFiles array $services
Definition: hooks.txt:2220
Maintenance\$mGenericParameters
$mGenericParameters
Definition: Maintenance.php:110
Maintenance\deleteOption
deleteOption( $name)
Remove an option.
Definition: Maintenance.php:283
$fname
if(defined( 'MW_SETUP_CALLBACK')) $fname
Customization point after all loading (constants, functions, classes, DefaultSettings,...
Definition: Setup.php:112
Maintenance\shouldExecute
static shouldExecute()
Should we execute the maintenance script, or just allow it to be included as a standalone class?...
Definition: Maintenance.php:177
$command
$command
Definition: cdb.php:65
$line
$line
Definition: cdb.php:59
LoggedUpdateMaintenance\execute
execute()
Do the actual work.
Definition: Maintenance.php:1647
Maintenance\DB_STD
const DB_STD
Definition: Maintenance.php:67
$e
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException' returning false will NOT prevent logging $e
Definition: hooks.txt:2163
Maintenance\updateSearchIndexForPage
updateSearchIndexForPage( $dbw, $pageId)
Update the searchindex table for a given pageid.
Definition: Maintenance.php:1460
$value
$value
Definition: styleTest.css.php:45
Maintenance\$mQuiet
$mQuiet
Definition: Maintenance.php:92
Maintenance\isQuiet
isQuiet()
Definition: Maintenance.php:378
Maintenance\activateProfiler
activateProfiler()
Activate the profiler (assuming $wgProfiler is set)
Definition: Maintenance.php:769
DeferredUpdates\tryOpportunisticExecute
static tryOpportunisticExecute( $mode='run')
Run all deferred updates immediately if there are no DB writes active.
Definition: DeferredUpdates.php:283
$retval
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account incomplete not yet checked for validity & $retval
Definition: hooks.txt:244
wfIsWindows
wfIsWindows()
Check if the operating system is Windows.
Definition: GlobalFunctions.php:2007
Maintenance\$mParams
$mParams
Definition: Maintenance.php:74
$wgServer
$wgServer
URL of the server.
Definition: DefaultSettings.php:105
wfEscapeShellArg
wfEscapeShellArg()
Version of escapeshellarg() that works better on Windows.
Definition: GlobalFunctions.php:2197
Maintenance\requireTestsAutoloader
static requireTestsAutoloader()
Call this to set up the autoloader to allow classes to be used from the tests directory.
Definition: Maintenance.php:1620
Maintenance\posix_isatty
static posix_isatty( $fd)
Wrapper for posix_isatty() We default as considering stdin a tty (for nice readline methods) but trea...
Definition: Maintenance.php:1511
LoggedUpdateMaintenance\updateSkippedMessage
updateSkippedMessage()
Message to show that the update was done already and was just skipped.
Definition: Maintenance.php:1676
Wikimedia\Rdbms\IDatabase\rollback
rollback( $fname=__METHOD__, $flush='')
Rollback a transaction previously started using begin().
Maintenance\$mDependantParameters
$mDependantParameters
Definition: Maintenance.php:112
Maintenance\commitTransaction
commitTransaction(IDatabase $dbw, $fname)
Commit the transcation on a DB handle and wait for replica DBs to catch up.
Definition: Maintenance.php:1351
Maintenance\validateParamsAndArgs
validateParamsAndArgs()
Run some validation checks on the params, etc.
Definition: Maintenance.php:955
Maintenance\$config
Config $config
Accessible via getConfig()
Definition: Maintenance.php:134
$wgProfiler
if(!defined( 'MEDIAWIKI')) $wgProfiler
This file is not a valid entry point, perform no further processing unless MEDIAWIKI is defined.
Definition: Setup.php:41
Maintenance\cleanupChanneled
cleanupChanneled()
Clean up channeled output.
Definition: Maintenance.php:450
Maintenance\DB_NONE
const DB_NONE
Constants for DB access type.
Definition: Maintenance.php:66
Maintenance\loadSettings
loadSettings()
Generic setup for most installs.
Definition: Maintenance.php:1201
LoggedUpdateMaintenance\doDBUpdates
doDBUpdates()
Do the actual work.
Maintenance\adjustMemoryLimit
adjustMemoryLimit()
Adjusts PHP's memory limit to better suit our needs, if needed.
Definition: Maintenance.php:756
LoggedUpdateMaintenance\getUpdateKey
getUpdateKey()
Get the update key name to go in the update log table.
Maintenance\purgeRedundantText
purgeRedundantText( $delete=true)
Support function for cleaning up redundant text records.
Definition: Maintenance.php:1241
$self
$self
Definition: doMaintenance.php:55
Maintenance\$fileHandle
resource $fileHandle
Used when creating separate schema files.
Definition: Maintenance.php:127
$args
if( $line===false) $args
Definition: cdb.php:64
Maintenance\$mInputLoaded
$mInputLoaded
Definition: Maintenance.php:99
Maintenance\getOption
getOption( $name, $default=null)
Get an option, or return the default.
Definition: Maintenance.php:254
$options
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1987
Maintenance\STDIN_ALL
const STDIN_ALL
Definition: Maintenance.php:71
Maintenance\addArg
addArg( $arg, $description, $required=true)
Add some args that are needed.
Definition: Maintenance.php:271
Wikimedia\Rdbms\LBFactory
An interface for generating database load balancers.
Definition: LBFactory.php:39
$rev
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
Definition: hooks.txt:1767
Maintenance\getBatchSize
getBatchSize()
Returns batch size.
Definition: Maintenance.php:321
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
Maintenance\$mOptions
$mOptions
Definition: Maintenance.php:83
Maintenance\setAgentAndTriggers
setAgentAndTriggers()
Set triggers like when to try to run deferred updates.
Definition: Maintenance.php:602
Maintenance\getDB
getDB( $db, $groups=[], $wiki=false)
Returns a database to be used by current maintenance script.
Definition: Maintenance.php:1309
LoggerFactory
MediaWiki Logger LoggerFactory implements a PSR[0] compatible message logging system Named Psr Log LoggerInterface instances can be obtained from the MediaWiki Logger LoggerFactory::getInstance() static method. MediaWiki\Logger\LoggerFactory expects a class implementing the MediaWiki\Logger\Spi interface to act as a factory for new Psr\Log\LoggerInterface instances. The "Spi" in MediaWiki\Logger\Spi stands for "service provider interface". An SPI is an API intended to be implemented or extended by a third party. This software design pattern is intended to enable framework extension and replaceable components. It is specifically used in the MediaWiki\Logger\LoggerFactory service to allow alternate PSR-3 logging implementations to be easily integrated with MediaWiki. The service provider interface allows the backend logging library to be implemented in multiple ways. The $wgMWLoggerDefaultSpi global provides the classname of the default MediaWiki\Logger\Spi implementation to be loaded at runtime. This can either be the name of a class implementing the MediaWiki\Logger\Spi with a zero argument const ructor or a callable that will return an MediaWiki\Logger\Spi instance. Alternately the MediaWiki\Logger\LoggerFactory MediaWiki Logger LoggerFactory
Definition: logger.txt:5
Maintenance\error
error( $err, $die=0)
Throw an error to the user.
Definition: Maintenance.php:416
Maintenance\output
output( $out, $channel=null)
Throw some output to the user.
Definition: Maintenance.php:388
Maintenance\$mArgList
$mArgList
Definition: Maintenance.php:80
$argv
global $argv
Definition: autoload.ide.php:24
Maintenance\getDir
getDir()
Get the maintenance directory.
Definition: Maintenance.php:1295
class
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
$wgDBuser
$wgDBuser
Database username.
Definition: DefaultSettings.php:1788
ExecutableFinder\findInDefaultPaths
static findInDefaultPaths( $names, $versionInfo=false)
Same as locateExecutable(), but checks in getPossibleBinPaths() by default.
Definition: ExecutableFinder.php:96
MediaWikiServices
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
Maintenance\hasOption
hasOption( $name)
Checks to see if a particular param exists.
Definition: Maintenance.php:240
Maintenance\getArg
getArg( $argId=0, $default=null)
Get an argument.
Definition: Maintenance.php:310
Maintenance::execute
public function execute()
Definition: maintenance.txt:45
$wgDBadminpassword
$wgDBadminpassword
Separate password for maintenance tasks.
Definition: DefaultSettings.php:1828
Maintenance\outputChanneled
outputChanneled( $msg, $channel=null)
Message outputter with channeled message support.
Definition: Maintenance.php:465
Maintenance\__construct
__construct()
Default constructor.
Definition: Maintenance.php:159
Wikimedia\Rdbms\IMaintainableDatabase
Advanced database interface for IDatabase handles that include maintenance methods.
Definition: IMaintainableDatabase.php:38
FakeMaintenance\execute
execute()
Do the actual work.
Definition: Maintenance.php:1631
$wgTrxProfilerLimits
$wgTrxProfilerLimits
Performance expectations for DB usage.
Definition: DefaultSettings.php:6107
$GLOBALS
$GLOBALS['IP']
Definition: ComposerHookHandler.php:6
Wikimedia\Rdbms\IDatabase\begin
begin( $fname=__METHOD__, $mode=self::TRANSACTION_EXPLICIT)
Begin a transaction.
Maintenance\lockSearchindex
lockSearchindex( $db)
Lock the search index.
Definition: Maintenance.php:1384
array
the array() calling protocol came about after MediaWiki 1.4rc1.
Maintenance\setBatchSize
setBatchSize( $s=0)
Set the batch size.
Definition: Maintenance.php:329
Maintenance\$mDb
IMaintainableDatabase $mDb
Used by getDB() / setDB()
Definition: Maintenance.php:118
Maintenance\memoryLimit
memoryLimit()
Normally we disable the memory_limit when running admin scripts.
Definition: Maintenance.php:747
wfShellExec
wfShellExec( $cmd, &$retval=null, $environ=[], $limits=[], $options=[])
Execute a shell command, with time and memory limits mirrored from the PHP configuration if supported...
Definition: GlobalFunctions.php:2238
$out
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Definition: hooks.txt:783