MediaWiki  1.32.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 
29 
35 // Define this so scripts can easily find doMaintenance.php
36 define( 'RUN_MAINTENANCE_IF_MAIN', __DIR__ . '/doMaintenance.php' );
37 
41 define( 'DO_MAINTENANCE', RUN_MAINTENANCE_IF_MAIN ); // original name, harmless
42 
43 $maintClass = false;
44 
50 
60 abstract class Maintenance {
65  const DB_NONE = 0;
66  const DB_STD = 1;
67  const DB_ADMIN = 2;
68 
69  // Const for getStdin()
70  const STDIN_ALL = 'all';
71 
72  // This is the desired params
73  protected $mParams = [];
74 
75  // Array of mapping short parameters to long ones
76  protected $mShortParamsMap = [];
77 
78  // Array of desired args
79  protected $mArgList = [];
80 
81  // This is the list of options that were actually passed
82  protected $mOptions = [];
83 
84  // This is the list of arguments that were actually passed
85  protected $mArgs = [];
86 
87  // Allow arbitrary options to be passed, or only specified ones?
88  protected $mAllowUnregisteredOptions = false;
89 
90  // Name of the script currently running
91  protected $mSelf;
92 
93  // Special vars for params that are always used
94  protected $mQuiet = false;
95  protected $mDbUser, $mDbPass;
96 
97  // A description of the script, children should change this via addDescription()
98  protected $mDescription = '';
99 
100  // Have we already loaded our user input?
101  protected $mInputLoaded = false;
102 
109  protected $mBatchSize = null;
110 
111  // Generic options added by addDefaultParams()
112  private $mGenericParameters = [];
113  // Generic options which might or not be supported by the script
114  private $mDependantParameters = [];
115 
120  private $mDb = null;
121 
123  private $lastReplicationWait = 0.0;
124 
129  public $fileHandle;
130 
136  private $config;
137 
142  private $requiredExtensions = [];
143 
155  public $orderedOptions = [];
156 
161  public function __construct() {
162  // Setup $IP, using MW_INSTALL_PATH if it exists
163  global $IP;
164  $IP = strval( getenv( 'MW_INSTALL_PATH' ) ) !== ''
165  ? getenv( 'MW_INSTALL_PATH' )
166  : realpath( __DIR__ . '/..' );
167 
168  $this->addDefaultParams();
169  register_shutdown_function( [ $this, 'outputChanneled' ], false );
170  }
171 
179  public static function shouldExecute() {
180  global $wgCommandLineMode;
181 
182  if ( !function_exists( 'debug_backtrace' ) ) {
183  // If someone has a better idea...
184  return $wgCommandLineMode;
185  }
186 
187  $bt = debug_backtrace();
188  $count = count( $bt );
189  if ( $count < 2 ) {
190  return false; // sanity
191  }
192  if ( $bt[0]['class'] !== self::class || $bt[0]['function'] !== 'shouldExecute' ) {
193  return false; // last call should be to this function
194  }
195  $includeFuncs = [ 'require_once', 'require', 'include', 'include_once' ];
196  for ( $i = 1; $i < $count; $i++ ) {
197  if ( !in_array( $bt[$i]['function'], $includeFuncs ) ) {
198  return false; // previous calls should all be "requires"
199  }
200  }
201 
202  return true;
203  }
204 
213  abstract public function execute();
214 
221  protected function supportsOption( $name ) {
222  return isset( $this->mParams[$name] );
223  }
224 
236  protected function addOption( $name, $description, $required = false,
237  $withArg = false, $shortName = false, $multiOccurrence = false
238  ) {
239  $this->mParams[$name] = [
240  'desc' => $description,
241  'require' => $required,
242  'withArg' => $withArg,
243  'shortName' => $shortName,
244  'multiOccurrence' => $multiOccurrence
245  ];
246 
247  if ( $shortName !== false ) {
248  $this->mShortParamsMap[$shortName] = $name;
249  }
250  }
251 
257  protected function hasOption( $name ) {
258  return isset( $this->mOptions[$name] );
259  }
260 
271  protected function getOption( $name, $default = null ) {
272  if ( $this->hasOption( $name ) ) {
273  return $this->mOptions[$name];
274  } else {
275  // Set it so we don't have to provide the default again
276  $this->mOptions[$name] = $default;
277 
278  return $this->mOptions[$name];
279  }
280  }
281 
288  protected function addArg( $arg, $description, $required = true ) {
289  $this->mArgList[] = [
290  'name' => $arg,
291  'desc' => $description,
292  'require' => $required
293  ];
294  }
295 
300  protected function deleteOption( $name ) {
301  unset( $this->mParams[$name] );
302  }
303 
309  protected function setAllowUnregisteredOptions( $allow ) {
310  $this->mAllowUnregisteredOptions = $allow;
311  }
312 
317  protected function addDescription( $text ) {
318  $this->mDescription = $text;
319  }
320 
326  protected function hasArg( $argId = 0 ) {
327  return isset( $this->mArgs[$argId] );
328  }
329 
336  protected function getArg( $argId = 0, $default = null ) {
337  return $this->hasArg( $argId ) ? $this->mArgs[$argId] : $default;
338  }
339 
347  protected function getBatchSize() {
348  return $this->mBatchSize;
349  }
350 
355  protected function setBatchSize( $s = 0 ) {
356  $this->mBatchSize = $s;
357 
358  // If we support $mBatchSize, show the option.
359  // Used to be in addDefaultParams, but in order for that to
360  // work, subclasses would have to call this function in the constructor
361  // before they called parent::__construct which is just weird
362  // (and really wasn't done).
363  if ( $this->mBatchSize ) {
364  $this->addOption( 'batch-size', 'Run this many operations ' .
365  'per batch, default: ' . $this->mBatchSize, false, true );
366  if ( isset( $this->mParams['batch-size'] ) ) {
367  // This seems a little ugly...
368  $this->mDependantParameters['batch-size'] = $this->mParams['batch-size'];
369  }
370  }
371  }
372 
377  public function getName() {
378  return $this->mSelf;
379  }
380 
387  protected function getStdin( $len = null ) {
388  if ( $len == self::STDIN_ALL ) {
389  return file_get_contents( 'php://stdin' );
390  }
391  $f = fopen( 'php://stdin', 'rt' );
392  if ( !$len ) {
393  return $f;
394  }
395  $input = fgets( $f, $len );
396  fclose( $f );
397 
398  return rtrim( $input );
399  }
400 
404  public function isQuiet() {
405  return $this->mQuiet;
406  }
407 
414  protected function output( $out, $channel = null ) {
415  // This is sometimes called very early, before Setup.php is included.
416  if ( class_exists( MediaWikiServices::class ) ) {
417  // Try to periodically flush buffered metrics to avoid OOMs
418  $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
419  if ( $stats->getDataCount() > 1000 ) {
420  MediaWiki::emitBufferedStatsdData( $stats, $this->getConfig() );
421  }
422  }
423 
424  if ( $this->mQuiet ) {
425  return;
426  }
427  if ( $channel === null ) {
428  $this->cleanupChanneled();
429  print $out;
430  } else {
431  $out = preg_replace( '/\n\z/', '', $out );
432  $this->outputChanneled( $out, $channel );
433  }
434  }
435 
442  protected function error( $err, $die = 0 ) {
443  if ( intval( $die ) !== 0 ) {
444  wfDeprecated( __METHOD__ . '( $err, $die )', '1.31' );
445  $this->fatalError( $err, intval( $die ) );
446  }
447  $this->outputChanneled( false );
448  if (
449  ( PHP_SAPI == 'cli' || PHP_SAPI == 'phpdbg' ) &&
450  !defined( 'MW_PHPUNIT_TEST' )
451  ) {
452  fwrite( STDERR, $err . "\n" );
453  } else {
454  print $err;
455  }
456  }
457 
465  protected function fatalError( $msg, $exitCode = 1 ) {
466  $this->error( $msg );
467  exit( $exitCode );
468  }
469 
470  private $atLineStart = true;
471  private $lastChannel = null;
472 
476  public function cleanupChanneled() {
477  if ( !$this->atLineStart ) {
478  print "\n";
479  $this->atLineStart = true;
480  }
481  }
482 
491  public function outputChanneled( $msg, $channel = null ) {
492  if ( $msg === false ) {
493  $this->cleanupChanneled();
494 
495  return;
496  }
497 
498  // End the current line if necessary
499  if ( !$this->atLineStart && $channel !== $this->lastChannel ) {
500  print "\n";
501  }
502 
503  print $msg;
504 
505  $this->atLineStart = false;
506  if ( $channel === null ) {
507  // For unchanneled messages, output trailing newline immediately
508  print "\n";
509  $this->atLineStart = true;
510  }
511  $this->lastChannel = $channel;
512  }
513 
524  public function getDbType() {
525  return self::DB_STD;
526  }
527 
531  protected function addDefaultParams() {
532  # Generic (non script dependant) options:
533 
534  $this->addOption( 'help', 'Display this help message', false, false, 'h' );
535  $this->addOption( 'quiet', 'Whether to suppress non-error output', false, false, 'q' );
536  $this->addOption( 'conf', 'Location of LocalSettings.php, if not default', false, true );
537  $this->addOption( 'wiki', 'For specifying the wiki ID', false, true );
538  $this->addOption( 'globals', 'Output globals at the end of processing for debugging' );
539  $this->addOption(
540  'memory-limit',
541  'Set a specific memory limit for the script, '
542  . '"max" for no limit or "default" to avoid changing it',
543  false,
544  true
545  );
546  $this->addOption( 'server', "The protocol and server name to use in URLs, e.g. " .
547  "http://en.wikipedia.org. This is sometimes necessary because " .
548  "server name detection may fail in command line scripts.", false, true );
549  $this->addOption( 'profiler', 'Profiler output format (usually "text")', false, true );
550  // This is named --mwdebug, because --debug would conflict in the phpunit.php CLI script.
551  $this->addOption( 'mwdebug', 'Enable built-in MediaWiki development settings', false, true );
552 
553  # Save generic options to display them separately in help
554  $this->mGenericParameters = $this->mParams;
555 
556  # Script dependant options:
557 
558  // If we support a DB, show the options
559  if ( $this->getDbType() > 0 ) {
560  $this->addOption( 'dbuser', 'The DB user to use for this script', false, true );
561  $this->addOption( 'dbpass', 'The password to use for this script', false, true );
562  $this->addOption( 'dbgroupdefault', 'The default DB group to use.', false, true );
563  }
564 
565  # Save additional script dependant options to display
566  #  them separately in help
567  $this->mDependantParameters = array_diff_key( $this->mParams, $this->mGenericParameters );
568  }
569 
574  public function getConfig() {
575  if ( $this->config === null ) {
576  $this->config = MediaWikiServices::getInstance()->getMainConfig();
577  }
578 
579  return $this->config;
580  }
581 
586  public function setConfig( Config $config ) {
587  $this->config = $config;
588  }
589 
599  protected function requireExtension( $name ) {
600  $this->requiredExtensions[] = $name;
601  }
602 
608  public function checkRequiredExtensions() {
609  $registry = ExtensionRegistry::getInstance();
610  $missing = [];
611  foreach ( $this->requiredExtensions as $name ) {
612  if ( !$registry->isLoaded( $name ) ) {
613  $missing[] = $name;
614  }
615  }
616 
617  if ( $missing ) {
618  $joined = implode( ', ', $missing );
619  $msg = "The following extensions are required to be installed "
620  . "for this script to run: $joined. Please enable them and then try again.";
621  $this->fatalError( $msg );
622  }
623  }
624 
629  public function setAgentAndTriggers() {
630  if ( function_exists( 'posix_getpwuid' ) ) {
631  $agent = posix_getpwuid( posix_geteuid() )['name'];
632  } else {
633  $agent = 'sysadmin';
634  }
635  $agent .= '@' . wfHostname();
636 
637  $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
638  // Add a comment for easy SHOW PROCESSLIST interpretation
639  $lbFactory->setAgentName(
640  mb_strlen( $agent ) > 15 ? mb_substr( $agent, 0, 15 ) . '...' : $agent
641  );
642  self::setLBFactoryTriggers( $lbFactory, $this->getConfig() );
643  }
644 
650  public static function setLBFactoryTriggers( LBFactory $LBFactory, Config $config ) {
651  $services = MediaWikiServices::getInstance();
652  $stats = $services->getStatsdDataFactory();
653  // Hook into period lag checks which often happen in long-running scripts
654  $lbFactory = $services->getDBLoadBalancerFactory();
655  $lbFactory->setWaitForReplicationListener(
656  __METHOD__,
657  function () use ( $stats, $config ) {
658  // Check config in case of JobRunner and unit tests
659  if ( $config->get( 'CommandLineMode' ) ) {
661  }
662  // Try to periodically flush buffered metrics to avoid OOMs
664  }
665  );
666  // Check for other windows to run them. A script may read or do a few writes
667  // to the master but mostly be writing to something else, like a file store.
668  $lbFactory->getMainLB()->setTransactionListener(
669  __METHOD__,
670  function ( $trigger ) use ( $stats, $config ) {
671  // Check config in case of JobRunner and unit tests
672  if ( $config->get( 'CommandLineMode' ) && $trigger === IDatabase::TRIGGER_COMMIT ) {
674  }
675  // Try to periodically flush buffered metrics to avoid OOMs
677  }
678  );
679  }
680 
688  public function runChild( $maintClass, $classFile = null ) {
689  // Make sure the class is loaded first
690  if ( !class_exists( $maintClass ) ) {
691  if ( $classFile ) {
692  require_once $classFile;
693  }
694  if ( !class_exists( $maintClass ) ) {
695  $this->error( "Cannot spawn child: $maintClass" );
696  }
697  }
698 
702  $child = new $maintClass();
703  $child->loadParamsAndArgs( $this->mSelf, $this->mOptions, $this->mArgs );
704  if ( !is_null( $this->mDb ) ) {
705  $child->setDB( $this->mDb );
706  }
707 
708  return $child;
709  }
710 
714  public function setup() {
715  global $IP, $wgCommandLineMode;
716 
717  # Abort if called from a web server
718  # wfIsCLI() is not available yet
719  if ( PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg' ) {
720  $this->fatalError( 'This script must be run from the command line' );
721  }
722 
723  if ( $IP === null ) {
724  $this->fatalError( "\$IP not set, aborting!\n" .
725  '(Did you forget to call parent::__construct() in your maintenance script?)' );
726  }
727 
728  # Make sure we can handle script parameters
729  if ( !defined( 'HPHP_VERSION' ) && !ini_get( 'register_argc_argv' ) ) {
730  $this->fatalError( 'Cannot get command line arguments, register_argc_argv is set to false' );
731  }
732 
733  // Send PHP warnings and errors to stderr instead of stdout.
734  // This aids in diagnosing problems, while keeping messages
735  // out of redirected output.
736  if ( ini_get( 'display_errors' ) ) {
737  ini_set( 'display_errors', 'stderr' );
738  }
739 
740  $this->loadParamsAndArgs();
741  $this->maybeHelp();
742 
743  # Set the memory limit
744  # Note we need to set it again later in cache LocalSettings changed it
745  $this->adjustMemoryLimit();
746 
747  # Set max execution time to 0 (no limit). PHP.net says that
748  # "When running PHP from the command line the default setting is 0."
749  # But sometimes this doesn't seem to be the case.
750  ini_set( 'max_execution_time', 0 );
751 
752  # Define us as being in MediaWiki
753  define( 'MEDIAWIKI', true );
754 
755  $wgCommandLineMode = true;
756 
757  # Turn off output buffering if it's on
758  while ( ob_get_level() > 0 ) {
759  ob_end_flush();
760  }
761 
762  $this->validateParamsAndArgs();
763  }
764 
774  public function memoryLimit() {
775  $limit = $this->getOption( 'memory-limit', 'max' );
776  $limit = trim( $limit, "\" '" ); // trim quotes in case someone misunderstood
777  return $limit;
778  }
779 
783  protected function adjustMemoryLimit() {
784  $limit = $this->memoryLimit();
785  if ( $limit == 'max' ) {
786  $limit = -1; // no memory limit
787  }
788  if ( $limit != 'default' ) {
789  ini_set( 'memory_limit', $limit );
790  }
791  }
792 
796  protected function activateProfiler() {
798 
799  $output = $this->getOption( 'profiler' );
800  if ( !$output ) {
801  return;
802  }
803 
804  if ( is_array( $wgProfiler ) && isset( $wgProfiler['class'] ) ) {
805  $class = $wgProfiler['class'];
807  $profiler = new $class(
808  [ 'sampling' => 1, 'output' => [ $output ] ]
809  + $wgProfiler
810  + [ 'threshold' => $wgProfileLimit ]
811  );
812  $profiler->setTemplated( true );
813  Profiler::replaceStubInstance( $profiler );
814  }
815 
816  $trxProfiler = Profiler::instance()->getTransactionProfiler();
817  $trxProfiler->setLogger( LoggerFactory::getInstance( 'DBPerformance' ) );
818  $trxProfiler->setExpectations( $wgTrxProfilerLimits['Maintenance'], __METHOD__ );
819  }
820 
824  public function clearParamsAndArgs() {
825  $this->mOptions = [];
826  $this->mArgs = [];
827  $this->mInputLoaded = false;
828  }
829 
837  public function loadWithArgv( $argv ) {
838  $options = [];
839  $args = [];
840  $this->orderedOptions = [];
841 
842  # Parse arguments
843  for ( $arg = reset( $argv ); $arg !== false; $arg = next( $argv ) ) {
844  if ( $arg == '--' ) {
845  # End of options, remainder should be considered arguments
846  $arg = next( $argv );
847  while ( $arg !== false ) {
848  $args[] = $arg;
849  $arg = next( $argv );
850  }
851  break;
852  } elseif ( substr( $arg, 0, 2 ) == '--' ) {
853  # Long options
854  $option = substr( $arg, 2 );
855  if ( isset( $this->mParams[$option] ) && $this->mParams[$option]['withArg'] ) {
856  $param = next( $argv );
857  if ( $param === false ) {
858  $this->error( "\nERROR: $option parameter needs a value after it\n" );
859  $this->maybeHelp( true );
860  }
861 
862  $this->setParam( $options, $option, $param );
863  } else {
864  $bits = explode( '=', $option, 2 );
865  if ( count( $bits ) > 1 ) {
866  $option = $bits[0];
867  $param = $bits[1];
868  } else {
869  $param = 1;
870  }
871 
872  $this->setParam( $options, $option, $param );
873  }
874  } elseif ( $arg == '-' ) {
875  # Lonely "-", often used to indicate stdin or stdout.
876  $args[] = $arg;
877  } elseif ( substr( $arg, 0, 1 ) == '-' ) {
878  # Short options
879  $argLength = strlen( $arg );
880  for ( $p = 1; $p < $argLength; $p++ ) {
881  $option = $arg[$p];
882  if ( !isset( $this->mParams[$option] ) && isset( $this->mShortParamsMap[$option] ) ) {
883  $option = $this->mShortParamsMap[$option];
884  }
885 
886  if ( isset( $this->mParams[$option]['withArg'] ) && $this->mParams[$option]['withArg'] ) {
887  $param = next( $argv );
888  if ( $param === false ) {
889  $this->error( "\nERROR: $option parameter needs a value after it\n" );
890  $this->maybeHelp( true );
891  }
892  $this->setParam( $options, $option, $param );
893  } else {
894  $this->setParam( $options, $option, 1 );
895  }
896  }
897  } else {
898  $args[] = $arg;
899  }
900  }
901 
902  $this->mOptions = $options;
903  $this->mArgs = $args;
904  $this->loadSpecialVars();
905  $this->mInputLoaded = true;
906  }
907 
920  private function setParam( &$options, $option, $value ) {
921  $this->orderedOptions[] = [ $option, $value ];
922 
923  if ( isset( $this->mParams[$option] ) ) {
924  $multi = $this->mParams[$option]['multiOccurrence'];
925  } else {
926  $multi = false;
927  }
928  $exists = array_key_exists( $option, $options );
929  if ( $multi && $exists ) {
930  $options[$option][] = $value;
931  } elseif ( $multi ) {
932  $options[$option] = [ $value ];
933  } elseif ( !$exists ) {
934  $options[$option] = $value;
935  } else {
936  $this->error( "\nERROR: $option parameter given twice\n" );
937  $this->maybeHelp( true );
938  }
939  }
940 
950  public function loadParamsAndArgs( $self = null, $opts = null, $args = null ) {
951  # If we were given opts or args, set those and return early
952  if ( $self ) {
953  $this->mSelf = $self;
954  $this->mInputLoaded = true;
955  }
956  if ( $opts ) {
957  $this->mOptions = $opts;
958  $this->mInputLoaded = true;
959  }
960  if ( $args ) {
961  $this->mArgs = $args;
962  $this->mInputLoaded = true;
963  }
964 
965  # If we've already loaded input (either by user values or from $argv)
966  # skip on loading it again. The array_shift() will corrupt values if
967  # it's run again and again
968  if ( $this->mInputLoaded ) {
969  $this->loadSpecialVars();
970 
971  return;
972  }
973 
974  global $argv;
975  $this->mSelf = $argv[0];
976  $this->loadWithArgv( array_slice( $argv, 1 ) );
977  }
978 
982  protected function validateParamsAndArgs() {
983  $die = false;
984  # Check to make sure we've got all the required options
985  foreach ( $this->mParams as $opt => $info ) {
986  if ( $info['require'] && !$this->hasOption( $opt ) ) {
987  $this->error( "Param $opt required!" );
988  $die = true;
989  }
990  }
991  # Check arg list too
992  foreach ( $this->mArgList as $k => $info ) {
993  if ( $info['require'] && !$this->hasArg( $k ) ) {
994  $this->error( 'Argument <' . $info['name'] . '> required!' );
995  $die = true;
996  }
997  }
998  if ( !$this->mAllowUnregisteredOptions ) {
999  # Check for unexpected options
1000  foreach ( $this->mOptions as $opt => $val ) {
1001  if ( !$this->supportsOption( $opt ) ) {
1002  $this->error( "Unexpected option $opt!" );
1003  $die = true;
1004  }
1005  }
1006  }
1007 
1008  if ( $die ) {
1009  $this->maybeHelp( true );
1010  }
1011  }
1012 
1016  protected function loadSpecialVars() {
1017  if ( $this->hasOption( 'dbuser' ) ) {
1018  $this->mDbUser = $this->getOption( 'dbuser' );
1019  }
1020  if ( $this->hasOption( 'dbpass' ) ) {
1021  $this->mDbPass = $this->getOption( 'dbpass' );
1022  }
1023  if ( $this->hasOption( 'quiet' ) ) {
1024  $this->mQuiet = true;
1025  }
1026  if ( $this->hasOption( 'batch-size' ) ) {
1027  $this->mBatchSize = intval( $this->getOption( 'batch-size' ) );
1028  }
1029  }
1030 
1035  protected function maybeHelp( $force = false ) {
1036  if ( !$force && !$this->hasOption( 'help' ) ) {
1037  return;
1038  }
1039 
1040  $screenWidth = 80; // TODO: Calculate this!
1041  $tab = " ";
1042  $descWidth = $screenWidth - ( 2 * strlen( $tab ) );
1043 
1044  ksort( $this->mParams );
1045  $this->mQuiet = false;
1046 
1047  // Description ...
1048  if ( $this->mDescription ) {
1049  $this->output( "\n" . wordwrap( $this->mDescription, $screenWidth ) . "\n" );
1050  }
1051  $output = "\nUsage: php " . basename( $this->mSelf );
1052 
1053  // ... append parameters ...
1054  if ( $this->mParams ) {
1055  $output .= " [--" . implode( "|--", array_keys( $this->mParams ) ) . "]";
1056  }
1057 
1058  // ... and append arguments.
1059  if ( $this->mArgList ) {
1060  $output .= ' ';
1061  foreach ( $this->mArgList as $k => $arg ) {
1062  if ( $arg['require'] ) {
1063  $output .= '<' . $arg['name'] . '>';
1064  } else {
1065  $output .= '[' . $arg['name'] . ']';
1066  }
1067  if ( $k < count( $this->mArgList ) - 1 ) {
1068  $output .= ' ';
1069  }
1070  }
1071  }
1072  $this->output( "$output\n\n" );
1073 
1074  # TODO abstract some repetitive code below
1075 
1076  // Generic parameters
1077  $this->output( "Generic maintenance parameters:\n" );
1078  foreach ( $this->mGenericParameters as $par => $info ) {
1079  if ( $info['shortName'] !== false ) {
1080  $par .= " (-{$info['shortName']})";
1081  }
1082  $this->output(
1083  wordwrap( "$tab--$par: " . $info['desc'], $descWidth,
1084  "\n$tab$tab" ) . "\n"
1085  );
1086  }
1087  $this->output( "\n" );
1088 
1089  $scriptDependantParams = $this->mDependantParameters;
1090  if ( count( $scriptDependantParams ) > 0 ) {
1091  $this->output( "Script dependant parameters:\n" );
1092  // Parameters description
1093  foreach ( $scriptDependantParams as $par => $info ) {
1094  if ( $info['shortName'] !== false ) {
1095  $par .= " (-{$info['shortName']})";
1096  }
1097  $this->output(
1098  wordwrap( "$tab--$par: " . $info['desc'], $descWidth,
1099  "\n$tab$tab" ) . "\n"
1100  );
1101  }
1102  $this->output( "\n" );
1103  }
1104 
1105  // Script specific parameters not defined on construction by
1106  // Maintenance::addDefaultParams()
1107  $scriptSpecificParams = array_diff_key(
1108  # all script parameters:
1109  $this->mParams,
1110  # remove the Maintenance default parameters:
1111  $this->mGenericParameters,
1112  $this->mDependantParameters
1113  );
1114  if ( count( $scriptSpecificParams ) > 0 ) {
1115  $this->output( "Script specific parameters:\n" );
1116  // Parameters description
1117  foreach ( $scriptSpecificParams as $par => $info ) {
1118  if ( $info['shortName'] !== false ) {
1119  $par .= " (-{$info['shortName']})";
1120  }
1121  $this->output(
1122  wordwrap( "$tab--$par: " . $info['desc'], $descWidth,
1123  "\n$tab$tab" ) . "\n"
1124  );
1125  }
1126  $this->output( "\n" );
1127  }
1128 
1129  // Print arguments
1130  if ( count( $this->mArgList ) > 0 ) {
1131  $this->output( "Arguments:\n" );
1132  // Arguments description
1133  foreach ( $this->mArgList as $info ) {
1134  $openChar = $info['require'] ? '<' : '[';
1135  $closeChar = $info['require'] ? '>' : ']';
1136  $this->output(
1137  wordwrap( "$tab$openChar" . $info['name'] . "$closeChar: " .
1138  $info['desc'], $descWidth, "\n$tab$tab" ) . "\n"
1139  );
1140  }
1141  $this->output( "\n" );
1142  }
1143 
1144  die( 1 );
1145  }
1146 
1150  public function finalSetup() {
1154 
1155  # Turn off output buffering again, it might have been turned on in the settings files
1156  if ( ob_get_level() ) {
1157  ob_end_flush();
1158  }
1159  # Same with these
1160  $wgCommandLineMode = true;
1161 
1162  # Override $wgServer
1163  if ( $this->hasOption( 'server' ) ) {
1164  $wgServer = $this->getOption( 'server', $wgServer );
1165  }
1166 
1167  # If these were passed, use them
1168  if ( $this->mDbUser ) {
1170  }
1171  if ( $this->mDbPass ) {
1173  }
1174  if ( $this->hasOption( 'dbgroupdefault' ) ) {
1175  $wgDBDefaultGroup = $this->getOption( 'dbgroupdefault', null );
1176 
1177  MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->destroy();
1178  }
1179 
1180  if ( $this->getDbType() == self::DB_ADMIN && isset( $wgDBadminuser ) ) {
1183 
1184  if ( $wgDBservers ) {
1188  foreach ( $wgDBservers as $i => $server ) {
1189  $wgDBservers[$i]['user'] = $wgDBuser;
1190  $wgDBservers[$i]['password'] = $wgDBpassword;
1191  }
1192  }
1193  if ( isset( $wgLBFactoryConf['serverTemplate'] ) ) {
1194  $wgLBFactoryConf['serverTemplate']['user'] = $wgDBuser;
1195  $wgLBFactoryConf['serverTemplate']['password'] = $wgDBpassword;
1196  }
1197  MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->destroy();
1198  }
1199 
1200  # Apply debug settings
1201  if ( $this->hasOption( 'mwdebug' ) ) {
1202  require __DIR__ . '/../includes/DevelopmentSettings.php';
1203  }
1204 
1205  // Per-script profiling; useful for debugging
1206  $this->activateProfiler();
1207 
1208  $this->afterFinalSetup();
1209 
1210  $wgShowExceptionDetails = true;
1211  $wgShowHostnames = true;
1212 
1213  Wikimedia\suppressWarnings();
1214  set_time_limit( 0 );
1215  Wikimedia\restoreWarnings();
1216 
1217  $this->adjustMemoryLimit();
1218  }
1219 
1223  protected function afterFinalSetup() {
1224  if ( defined( 'MW_CMDLINE_CALLBACK' ) ) {
1225  call_user_func( MW_CMDLINE_CALLBACK );
1226  }
1227  }
1228 
1233  public function globals() {
1234  if ( $this->hasOption( 'globals' ) ) {
1235  print_r( $GLOBALS );
1236  }
1237  }
1238 
1243  public function loadSettings() {
1244  global $wgCommandLineMode, $IP;
1245 
1246  if ( isset( $this->mOptions['conf'] ) ) {
1247  $settingsFile = $this->mOptions['conf'];
1248  } elseif ( defined( "MW_CONFIG_FILE" ) ) {
1249  $settingsFile = MW_CONFIG_FILE;
1250  } else {
1251  $settingsFile = "$IP/LocalSettings.php";
1252  }
1253  if ( isset( $this->mOptions['wiki'] ) ) {
1254  $bits = explode( '-', $this->mOptions['wiki'] );
1255  if ( count( $bits ) == 1 ) {
1256  $bits[] = '';
1257  }
1258  define( 'MW_DB', $bits[0] );
1259  define( 'MW_PREFIX', $bits[1] );
1260  } elseif ( isset( $this->mOptions['server'] ) ) {
1261  // Provide the option for site admins to detect and configure
1262  // multiple wikis based on server names. This offers --server
1263  // as alternative to --wiki.
1264  // See https://www.mediawiki.org/wiki/Manual:Wiki_family
1265  $_SERVER['SERVER_NAME'] = $this->mOptions['server'];
1266  }
1267 
1268  if ( !is_readable( $settingsFile ) ) {
1269  $this->fatalError( "A copy of your installation's LocalSettings.php\n" .
1270  "must exist and be readable in the source directory.\n" .
1271  "Use --conf to specify it." );
1272  }
1273  $wgCommandLineMode = true;
1274 
1275  return $settingsFile;
1276  }
1277 
1283  public function purgeRedundantText( $delete = true ) {
1284  # Data should come off the master, wrapped in a transaction
1285  $dbw = $this->getDB( DB_MASTER );
1286  $this->beginTransaction( $dbw, __METHOD__ );
1287 
1288  # Get "active" text records from the revisions table
1289  $cur = [];
1290  $this->output( 'Searching for active text records in revisions table...' );
1291  $res = $dbw->select( 'revision', 'rev_text_id', [], __METHOD__, [ 'DISTINCT' ] );
1292  foreach ( $res as $row ) {
1293  $cur[] = $row->rev_text_id;
1294  }
1295  $this->output( "done.\n" );
1296 
1297  # Get "active" text records from the archive table
1298  $this->output( 'Searching for active text records in archive table...' );
1299  $res = $dbw->select( 'archive', 'ar_text_id', [], __METHOD__, [ 'DISTINCT' ] );
1300  foreach ( $res as $row ) {
1301  # old pre-MW 1.5 records can have null ar_text_id's.
1302  if ( $row->ar_text_id !== null ) {
1303  $cur[] = $row->ar_text_id;
1304  }
1305  }
1306  $this->output( "done.\n" );
1307 
1308  # Get the IDs of all text records not in these sets
1309  $this->output( 'Searching for inactive text records...' );
1310  $cond = 'old_id NOT IN ( ' . $dbw->makeList( $cur ) . ' )';
1311  $res = $dbw->select( 'text', 'old_id', [ $cond ], __METHOD__, [ 'DISTINCT' ] );
1312  $old = [];
1313  foreach ( $res as $row ) {
1314  $old[] = $row->old_id;
1315  }
1316  $this->output( "done.\n" );
1317 
1318  # Inform the user of what we're going to do
1319  $count = count( $old );
1320  $this->output( "$count inactive items found.\n" );
1321 
1322  # Delete as appropriate
1323  if ( $delete && $count ) {
1324  $this->output( 'Deleting...' );
1325  $dbw->delete( 'text', [ 'old_id' => $old ], __METHOD__ );
1326  $this->output( "done.\n" );
1327  }
1328 
1329  # Done
1330  $this->commitTransaction( $dbw, __METHOD__ );
1331  }
1332 
1337  protected function getDir() {
1338  return __DIR__;
1339  }
1340 
1351  protected function getDB( $db, $groups = [], $wiki = false ) {
1352  if ( is_null( $this->mDb ) ) {
1353  return wfGetDB( $db, $groups, $wiki );
1354  } else {
1355  return $this->mDb;
1356  }
1357  }
1358 
1364  public function setDB( IDatabase $db ) {
1365  $this->mDb = $db;
1366  }
1367 
1378  protected function beginTransaction( IDatabase $dbw, $fname ) {
1379  $dbw->begin( $fname );
1380  }
1381 
1393  protected function commitTransaction( IDatabase $dbw, $fname ) {
1394  $dbw->commit( $fname );
1395  $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
1396  $waitSucceeded = $lbFactory->waitForReplication(
1397  [ 'timeout' => 30, 'ifWritesSince' => $this->lastReplicationWait ]
1398  );
1399  $this->lastReplicationWait = microtime( true );
1400  return $waitSucceeded;
1401  }
1402 
1413  protected function rollbackTransaction( IDatabase $dbw, $fname ) {
1414  $dbw->rollback( $fname );
1415  }
1416 
1421  private function lockSearchindex( $db ) {
1422  $write = [ 'searchindex' ];
1423  $read = [
1424  'page',
1425  'revision',
1426  'text',
1427  'interwiki',
1428  'l10n_cache',
1429  'user',
1430  'page_restrictions'
1431  ];
1432  $db->lockTables( $read, $write, __CLASS__ . '::' . __METHOD__ );
1433  }
1434 
1439  private function unlockSearchindex( $db ) {
1440  $db->unlockTables( __CLASS__ . '::' . __METHOD__ );
1441  }
1442 
1448  private function relockSearchindex( $db ) {
1449  $this->unlockSearchindex( $db );
1450  $this->lockSearchindex( $db );
1451  }
1452 
1460  public function updateSearchIndex( $maxLockTime, $callback, $dbw, $results ) {
1461  $lockTime = time();
1462 
1463  # Lock searchindex
1464  if ( $maxLockTime ) {
1465  $this->output( " --- Waiting for lock ---" );
1466  $this->lockSearchindex( $dbw );
1467  $lockTime = time();
1468  $this->output( "\n" );
1469  }
1470 
1471  # Loop through the results and do a search update
1472  foreach ( $results as $row ) {
1473  # Allow reads to be processed
1474  if ( $maxLockTime && time() > $lockTime + $maxLockTime ) {
1475  $this->output( " --- Relocking ---" );
1476  $this->relockSearchindex( $dbw );
1477  $lockTime = time();
1478  $this->output( "\n" );
1479  }
1480  call_user_func( $callback, $dbw, $row );
1481  }
1482 
1483  # Unlock searchindex
1484  if ( $maxLockTime ) {
1485  $this->output( " --- Unlocking --" );
1486  $this->unlockSearchindex( $dbw );
1487  $this->output( "\n" );
1488  }
1489  }
1490 
1497  public function updateSearchIndexForPage( $dbw, $pageId ) {
1498  // Get current revision
1499  $rev = Revision::loadFromPageId( $dbw, $pageId );
1500  $title = null;
1501  if ( $rev ) {
1502  $titleObj = $rev->getTitle();
1503  $title = $titleObj->getPrefixedDBkey();
1504  $this->output( "$title..." );
1505  # Update searchindex
1506  $u = new SearchUpdate( $pageId, $titleObj->getText(), $rev->getContent() );
1507  $u->doUpdate();
1508  $this->output( "\n" );
1509  }
1510 
1511  return $title;
1512  }
1513 
1524  protected function countDown( $seconds ) {
1525  if ( $this->isQuiet() ) {
1526  return;
1527  }
1528  for ( $i = $seconds; $i >= 0; $i-- ) {
1529  if ( $i != $seconds ) {
1530  $this->output( str_repeat( "\x08", strlen( $i + 1 ) ) );
1531  }
1532  $this->output( $i );
1533  if ( $i ) {
1534  sleep( 1 );
1535  }
1536  }
1537  $this->output( "\n" );
1538  }
1539 
1548  public static function posix_isatty( $fd ) {
1549  if ( !function_exists( 'posix_isatty' ) ) {
1550  return !$fd;
1551  } else {
1552  return posix_isatty( $fd );
1553  }
1554  }
1555 
1561  public static function readconsole( $prompt = '> ' ) {
1562  static $isatty = null;
1563  if ( is_null( $isatty ) ) {
1564  $isatty = self::posix_isatty( 0 /*STDIN*/ );
1565  }
1566 
1567  if ( $isatty && function_exists( 'readline' ) ) {
1568  return readline( $prompt );
1569  } else {
1570  if ( $isatty ) {
1571  $st = self::readlineEmulation( $prompt );
1572  } else {
1573  if ( feof( STDIN ) ) {
1574  $st = false;
1575  } else {
1576  $st = fgets( STDIN, 1024 );
1577  }
1578  }
1579  if ( $st === false ) {
1580  return false;
1581  }
1582  $resp = trim( $st );
1583 
1584  return $resp;
1585  }
1586  }
1587 
1593  private static function readlineEmulation( $prompt ) {
1594  $bash = ExecutableFinder::findInDefaultPaths( 'bash' );
1595  if ( !wfIsWindows() && $bash ) {
1596  $retval = false;
1597  $encPrompt = wfEscapeShellArg( $prompt );
1598  $command = "read -er -p $encPrompt && echo \"\$REPLY\"";
1599  $encCommand = wfEscapeShellArg( $command );
1600  $line = wfShellExec( "$bash -c $encCommand", $retval, [], [ 'walltime' => 0 ] );
1601 
1602  if ( $retval == 0 ) {
1603  return $line;
1604  } elseif ( $retval == 127 ) {
1605  // Couldn't execute bash even though we thought we saw it.
1606  // Shell probably spit out an error message, sorry :(
1607  // Fall through to fgets()...
1608  } else {
1609  // EOF/ctrl+D
1610  return false;
1611  }
1612  }
1613 
1614  // Fallback... we'll have no editing controls, EWWW
1615  if ( feof( STDIN ) ) {
1616  return false;
1617  }
1618  print $prompt;
1619 
1620  return fgets( STDIN, 1024 );
1621  }
1622 
1630  public static function getTermSize() {
1631  $default = [ 80, 50 ];
1632  if ( wfIsWindows() ) {
1633  return $default;
1634  }
1635  if ( Shell::isDisabled() ) {
1636  return $default;
1637  }
1638  // It's possible to get the screen size with VT-100 terminal escapes,
1639  // but reading the responses is not possible without setting raw mode
1640  // (unless you want to require the user to press enter), and that
1641  // requires an ioctl(), which we can't do. So we have to shell out to
1642  // something that can do the relevant syscalls. There are a few
1643  // options. Linux and Mac OS X both have "stty size" which does the
1644  // job directly.
1645  $result = Shell::command( 'stty', 'size' )
1646  ->execute();
1647  if ( $result->getExitCode() !== 0 ) {
1648  return $default;
1649  }
1650  if ( !preg_match( '/^(\d+) (\d+)$/', $result->getStdout(), $m ) ) {
1651  return $default;
1652  }
1653  return [ intval( $m[2] ), intval( $m[1] ) ];
1654  }
1655 
1660  public static function requireTestsAutoloader() {
1661  require_once __DIR__ . '/../tests/common/TestsAutoLoader.php';
1662  }
1663 }
1664 
1669  protected $mSelf = "FakeMaintenanceScript";
1670 
1671  public function execute() {
1672  }
1673 }
1674 
1679 abstract class LoggedUpdateMaintenance extends Maintenance {
1680  public function __construct() {
1681  parent::__construct();
1682  $this->addOption( 'force', 'Run the update even if it was completed already' );
1683  $this->setBatchSize( 200 );
1684  }
1685 
1686  public function execute() {
1687  $db = $this->getDB( DB_MASTER );
1688  $key = $this->getUpdateKey();
1689 
1690  if ( !$this->hasOption( 'force' )
1691  && $db->selectRow( 'updatelog', '1', [ 'ul_key' => $key ], __METHOD__ )
1692  ) {
1693  $this->output( "..." . $this->updateSkippedMessage() . "\n" );
1694 
1695  return true;
1696  }
1697 
1698  if ( !$this->doDBUpdates() ) {
1699  return false;
1700  }
1701 
1702  if ( $db->insert( 'updatelog', [ 'ul_key' => $key ], __METHOD__, 'IGNORE' ) ) {
1703  return true;
1704  } else {
1705  $this->output( $this->updatelogFailedMessage() . "\n" );
1706 
1707  return false;
1708  }
1709  }
1710 
1715  protected function updateSkippedMessage() {
1716  $key = $this->getUpdateKey();
1717 
1718  return "Update '{$key}' already logged as completed.";
1719  }
1720 
1725  protected function updatelogFailedMessage() {
1726  $key = $this->getUpdateKey();
1727 
1728  return "Unable to log update '{$key}' as completed.";
1729  }
1730 
1736  abstract protected function doDBUpdates();
1737 
1742  abstract protected function getUpdateKey();
1743 }
$wgProfileLimit
$wgProfileLimit
Only record profiling info for pages that took longer than this.
Definition: DefaultSettings.php:6429
FakeMaintenance\$mSelf
$mSelf
Definition: Maintenance.php:1669
RUN_MAINTENANCE_IF_MAIN
const RUN_MAINTENANCE_IF_MAIN
Definition: Maintenance.php:36
Maintenance\$mBatchSize
int $mBatchSize
Batch size.
Definition: Maintenance.php:109
LoggedUpdateMaintenance\__construct
__construct()
Default constructor.
Definition: Maintenance.php:1680
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:920
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:1630
Maintenance\$mShortParamsMap
$mShortParamsMap
Definition: Maintenance.php:76
MediaWiki\emitBufferedStatsdData
static emitBufferedStatsdData(IBufferingStatsdDataFactory $stats, Config $config)
Send out any buffered statsd data according to sampling rules.
Definition: MediaWiki.php:929
Maintenance\getStdin
getStdin( $len=null)
Return input from stdin.
Definition: Maintenance.php:387
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:524
$opt
$opt
Definition: postprocess-phan.php:115
Maintenance\maybeHelp
maybeHelp( $force=false)
Maybe show the help.
Definition: Maintenance.php:1035
Maintenance\fatalError
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
Definition: Maintenance.php:465
captcha-old.count
count
Definition: captcha-old.py:249
Maintenance\$mDbPass
$mDbPass
Definition: Maintenance.php:95
Maintenance\addDescription
addDescription( $text)
Set the description text.
Definition: Maintenance.php:317
Maintenance\setup
setup()
Do some sanity checking and basic setup.
Definition: Maintenance.php:714
Maintenance\$requiredExtensions
array $requiredExtensions
Definition: Maintenance.php:142
Maintenance\runChild
runChild( $maintClass, $classFile=null)
Run a child maintenance script.
Definition: Maintenance.php:688
Maintenance\setLBFactoryTriggers
static setLBFactoryTriggers(LBFactory $LBFactory, Config $config)
Definition: Maintenance.php:650
Maintenance\readconsole
static readconsole( $prompt='> ')
Prompt the console for input.
Definition: Maintenance.php:1561
$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 since 1.16! 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 since 1.28! 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:2034
$wgShowHostnames
$wgShowHostnames
Expose backend server host names through the API and various HTML comments.
Definition: DefaultSettings.php:6338
Maintenance\$mAllowUnregisteredOptions
$mAllowUnregisteredOptions
Definition: Maintenance.php:88
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:950
Maintenance\relockSearchindex
relockSearchindex( $db)
Unlock and lock again Since the lock is low-priority, queued reads will be able to complete.
Definition: Maintenance.php:1448
Maintenance\getName
getName()
Get the script's name.
Definition: Maintenance.php:377
wfHostname
wfHostname()
Fetch server name for use in error reporting etc.
Definition: GlobalFunctions.php:1392
$wgLBFactoryConf
$wgLBFactoryConf
Load balancer factory configuration To set up a multi-master wiki farm, set the class here to somethi...
Definition: DefaultSettings.php:2071
$s
$s
Definition: mergeMessageFileList.php:187
Maintenance\hasArg
hasArg( $argId=0)
Does a given argument exist?
Definition: Maintenance.php:326
Maintenance\setDB
setDB(IDatabase $db)
Sets database object to be returned by getDB().
Definition: Maintenance.php:1364
$res
$res
Definition: database.txt:21
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:586
$maintClass
$maintClass
Definition: Maintenance.php:43
$wgDBpassword
$wgDBpassword
Database user's password.
Definition: DefaultSettings.php:1872
Maintenance\$lastChannel
$lastChannel
Definition: Maintenance.php:471
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:837
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:608
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:1150
Maintenance\rollbackTransaction
rollbackTransaction(IDatabase $dbw, $fname)
Rollback the transcation on a DB handle.
Definition: Maintenance.php:1413
wfEntryPointCheck
wfEntryPointCheck( $entryPoint)
Check php version and that external dependencies are installed, and display an informative error if e...
Definition: PHPVersionCheck.php:276
Wikimedia\Rdbms\IDatabase\commit
commit( $fname=__METHOD__, $flush='')
Commits a transaction previously started using begin().
Maintenance\$mDescription
$mDescription
Definition: Maintenance.php:98
Maintenance\beginTransaction
beginTransaction(IDatabase $dbw, $fname)
Begin a transcation on a DB.
Definition: Maintenance.php:1378
Maintenance\afterFinalSetup
afterFinalSetup()
Execute a callback function at the end of initialisation.
Definition: Maintenance.php:1223
ExtensionRegistry\getInstance
static getInstance()
Definition: ExtensionRegistry.php:88
$wgDBadminuser
$wgDBadminuser
Separate username for maintenance tasks.
Definition: DefaultSettings.php:1902
Maintenance\unlockSearchindex
unlockSearchindex( $db)
Unlock the tables.
Definition: Maintenance.php:1439
Maintenance\clearParamsAndArgs
clearParamsAndArgs()
Clear all params and arguments.
Definition: Maintenance.php:824
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:2059
Maintenance\$mSelf
$mSelf
Definition: Maintenance.php:91
$wgDBDefaultGroup
$wgDBDefaultGroup
Default group to use when getting database connections.
Definition: DefaultSettings.php:1954
Maintenance\updateSearchIndex
updateSearchIndex( $maxLockTime, $callback, $dbw, $results)
Perform a search index update with locking.
Definition: Maintenance.php:1460
Maintenance\$mArgs
$mArgs
Definition: Maintenance.php:85
$wgProfiler
$wgProfiler
Profiler configuration.
Definition: DefaultSettings.php:6416
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:964
Maintenance\loadSpecialVars
loadSpecialVars()
Handle the special variables that are global to all scripts.
Definition: Maintenance.php:1016
Maintenance\getConfig
getConfig()
Definition: Maintenance.php:574
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
Definition: GlobalFunctions.php:1118
LoggedUpdateMaintenance
Class for scripts that perform database maintenance and want to log the update in updatelog so we can...
Definition: Maintenance.php:1679
Maintenance\$atLineStart
$atLineStart
Definition: Maintenance.php:470
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:2693
Maintenance\$lastReplicationWait
float $lastReplicationWait
UNIX timestamp.
Definition: Maintenance.php:123
$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:236
$IP
$IP
Definition: update.php:3
Maintenance\$mDbUser
$mDbUser
Definition: Maintenance.php:95
Maintenance\requireExtension
requireExtension( $name)
Indicate that the specified extension must be loaded before the script can run.
Definition: Maintenance.php:599
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\$orderedOptions
array $orderedOptions
Used to read the options in the order they were passed.
Definition: Maintenance.php:155
Maintenance\globals
globals()
Potentially debug globals.
Definition: Maintenance.php:1233
LoggedUpdateMaintenance\updatelogFailedMessage
updatelogFailedMessage()
Message to show that the update log was unable to log the completion of this update.
Definition: Maintenance.php:1725
$output
$output
Definition: SyntaxHighlight.php:334
FakeMaintenance
Fake maintenance wrapper, mostly used for the web installer/updater.
Definition: Maintenance.php:1668
DB_MASTER
const DB_MASTER
Definition: defines.php:26
array
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
Maintenance\addDefaultParams
addDefaultParams()
Add the default parameters to the scripts.
Definition: Maintenance.php:531
Maintenance\readlineEmulation
static readlineEmulation( $prompt)
Emulate readline()
Definition: Maintenance.php:1593
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:1524
Maintenance\DB_ADMIN
const DB_ADMIN
Definition: Maintenance.php:67
Maintenance\$mGenericParameters
$mGenericParameters
Definition: Maintenance.php:112
Maintenance\deleteOption
deleteOption( $name)
Remove an option.
Definition: Maintenance.php:300
$fname
if(defined( 'MW_SETUP_CALLBACK')) $fname
Customization point after all loading (constants, functions, classes, DefaultSettings,...
Definition: Setup.php:121
Maintenance\shouldExecute
static shouldExecute()
Should we execute the maintenance script, or just allow it to be included as a standalone class?...
Definition: Maintenance.php:179
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:302
$command
$command
Definition: cdb.php:65
$line
$line
Definition: cdb.php:59
LoggedUpdateMaintenance\execute
execute()
Do the actual work.
Definition: Maintenance.php:1686
Maintenance\DB_STD
const DB_STD
Definition: Maintenance.php:66
Maintenance\updateSearchIndexForPage
updateSearchIndexForPage( $dbw, $pageId)
Update the searchindex table for a given pageid.
Definition: Maintenance.php:1497
Maintenance\supportsOption
supportsOption( $name)
Checks to see if a particular option in supported.
Definition: Maintenance.php:221
$value
$value
Definition: styleTest.css.php:49
Maintenance\$mQuiet
$mQuiet
Definition: Maintenance.php:94
Maintenance\isQuiet
isQuiet()
Definition: Maintenance.php:404
Maintenance\activateProfiler
activateProfiler()
Activate the profiler (assuming $wgProfiler is set)
Definition: Maintenance.php:796
DeferredUpdates\tryOpportunisticExecute
static tryOpportunisticExecute( $mode='run')
Run all deferred updates immediately if there are no DB writes active.
Definition: DeferredUpdates.php:301
Maintenance\setAllowUnregisteredOptions
setAllowUnregisteredOptions( $allow)
Sets whether to allow unregistered options, which are options passed to a script that do not match an...
Definition: Maintenance.php:309
$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:1993
Maintenance\$mParams
$mParams
Definition: Maintenance.php:73
$wgServer
$wgServer
URL of the server.
Definition: DefaultSettings.php:105
Maintenance\requireTestsAutoloader
static requireTestsAutoloader()
Call this to set up the autoloader to allow classes to be used from the tests directory.
Definition: Maintenance.php:1660
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:1548
LoggedUpdateMaintenance\updateSkippedMessage
updateSkippedMessage()
Message to show that the update was done already and was just skipped.
Definition: Maintenance.php:1715
Wikimedia\Rdbms\IDatabase\rollback
rollback( $fname=__METHOD__, $flush='')
Rollback a transaction previously started using begin().
Maintenance\$mDependantParameters
$mDependantParameters
Definition: Maintenance.php:114
Maintenance\commitTransaction
commitTransaction(IDatabase $dbw, $fname)
Commit the transcation on a DB handle and wait for replica DBs to catch up.
Definition: Maintenance.php:1393
Maintenance\validateParamsAndArgs
validateParamsAndArgs()
Run some validation checks on the params, etc.
Definition: Maintenance.php:982
Maintenance\$config
Config $config
Accessible via getConfig()
Definition: Maintenance.php:136
Maintenance\cleanupChanneled
cleanupChanneled()
Clean up channeled output.
Definition: Maintenance.php:476
Maintenance\DB_NONE
const DB_NONE
Constants for DB access type.
Definition: Maintenance.php:65
Maintenance\loadSettings
loadSettings()
Generic setup for most installs.
Definition: Maintenance.php:1243
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:783
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:1283
$self
$self
Definition: doMaintenance.php:55
Maintenance\$fileHandle
resource $fileHandle
Used when creating separate schema files.
Definition: Maintenance.php:129
$args
if( $line===false) $args
Definition: cdb.php:64
Maintenance\$mInputLoaded
$mInputLoaded
Definition: Maintenance.php:101
Maintenance\getOption
getOption( $name, $default=null)
Get an option, or return the default.
Definition: Maintenance.php:271
$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:2036
Maintenance\STDIN_ALL
const STDIN_ALL
Definition: Maintenance.php:70
Maintenance\addArg
addArg( $arg, $description, $required=true)
Add some args that are needed.
Definition: Maintenance.php:288
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:1808
Maintenance\getBatchSize
getBatchSize()
Returns batch size.
Definition: Maintenance.php:347
$wgShowExceptionDetails
$wgShowExceptionDetails
If set to true, uncaught exceptions will print the exception message and a complete stack trace to ou...
Definition: DefaultSettings.php:6310
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:82
Maintenance\setAgentAndTriggers
setAgentAndTriggers()
Set triggers like when to try to run deferred updates.
Definition: Maintenance.php:629
Maintenance\getDB
getDB( $db, $groups=[], $wiki=false)
Returns a database to be used by current maintenance script.
Definition: Maintenance.php:1351
wfEscapeShellArg
wfEscapeShellArg(... $args)
Version of escapeshellarg() that works better on Windows.
Definition: GlobalFunctions.php:2183
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:442
Maintenance\output
output( $out, $channel=null)
Throw some output to the user.
Definition: Maintenance.php:414
Maintenance\$mArgList
$mArgList
Definition: Maintenance.php:79
Maintenance\getDir
getDir()
Get the maintenance directory.
Definition: Maintenance.php:1337
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:1867
ExecutableFinder\findInDefaultPaths
static findInDefaultPaths( $names, $versionInfo=false)
Same as locateExecutable(), but checks in getPossibleBinPaths() by default.
Definition: ExecutableFinder.php:96
$services
static configuration should be added through ResourceLoaderGetConfigVars instead can be used to get the real title e g db for database replication lag or jobqueue for job queue size converted to pseudo seconds It is possible to add more fields and they will be returned to the user in the API response 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:2270
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 option exists.
Definition: Maintenance.php:257
Maintenance\getArg
getArg( $argId=0, $default=null)
Get an argument.
Definition: Maintenance.php:336
Maintenance::execute
public function execute()
Definition: maintenance.txt:45
$wgDBadminpassword
$wgDBadminpassword
Separate password for maintenance tasks.
Definition: DefaultSettings.php:1907
Maintenance\outputChanneled
outputChanneled( $msg, $channel=null)
Message outputter with channeled message support.
Definition: Maintenance.php:491
Maintenance\__construct
__construct()
Default constructor.
Definition: Maintenance.php:161
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:1671
$wgTrxProfilerLimits
$wgTrxProfilerLimits
Performance expectations for DB usage.
Definition: DefaultSettings.php:6160
$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:1421
Maintenance\setBatchSize
setBatchSize( $s=0)
Set the batch size.
Definition: Maintenance.php:355
Maintenance\$mDb
IMaintainableDatabase $mDb
Used by getDB() / setDB()
Definition: Maintenance.php:120
Maintenance\memoryLimit
memoryLimit()
Normally we disable the memory_limit when running admin scripts.
Definition: Maintenance.php:774
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:2210
$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:813