MediaWiki  1.33.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( 'text' );
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 
72 abstract class Maintenance {
77  const DB_NONE = 0;
78  const DB_STD = 1;
79  const DB_ADMIN = 2;
80 
81  // Const for getStdin()
82  const STDIN_ALL = 'all';
83 
84  // Array of desired/allowed params
85  protected $mParams = [];
86 
87  // Array of mapping short parameters to long ones
88  protected $mShortParamsMap = [];
89 
90  // Array of desired/allowed args
91  protected $mArgList = [];
92 
93  // This is the list of options that were actually passed
94  protected $mOptions = [];
95 
96  // This is the list of arguments that were actually passed
97  protected $mArgs = [];
98 
99  // Allow arbitrary options to be passed, or only specified ones?
100  protected $mAllowUnregisteredOptions = false;
101 
102  // Name of the script currently running
103  protected $mSelf;
104 
105  // Special vars for params that are always used
106  protected $mQuiet = false;
107  protected $mDbUser, $mDbPass;
108 
109  // A description of the script, children should change this via addDescription()
110  protected $mDescription = '';
111 
112  // Have we already loaded our user input?
113  protected $mInputLoaded = false;
114 
121  protected $mBatchSize = null;
122 
123  // Generic options added by addDefaultParams()
124  private $mGenericParameters = [];
125  // Generic options which might or not be supported by the script
126  private $mDependantParameters = [];
127 
132  private $mDb = null;
133 
135  private $lastReplicationWait = 0.0;
136 
141  public $fileHandle;
142 
148  private $config;
149 
154  private $requiredExtensions = [];
155 
167  public $orderedOptions = [];
168 
173  public function __construct() {
174  // Setup $IP, using MW_INSTALL_PATH if it exists
175  global $IP;
176  $IP = strval( getenv( 'MW_INSTALL_PATH' ) ) !== ''
177  ? getenv( 'MW_INSTALL_PATH' )
178  : realpath( __DIR__ . '/..' );
179 
180  $this->addDefaultParams();
181  register_shutdown_function( [ $this, 'outputChanneled' ], false );
182  }
183 
191  public static function shouldExecute() {
192  global $wgCommandLineMode;
193 
194  if ( !function_exists( 'debug_backtrace' ) ) {
195  // If someone has a better idea...
196  return $wgCommandLineMode;
197  }
198 
199  $bt = debug_backtrace();
200  $count = count( $bt );
201  if ( $count < 2 ) {
202  return false; // sanity
203  }
204  if ( $bt[0]['class'] !== self::class || $bt[0]['function'] !== 'shouldExecute' ) {
205  return false; // last call should be to this function
206  }
207  $includeFuncs = [ 'require_once', 'require', 'include', 'include_once' ];
208  for ( $i = 1; $i < $count; $i++ ) {
209  if ( !in_array( $bt[$i]['function'], $includeFuncs ) ) {
210  return false; // previous calls should all be "requires"
211  }
212  }
213 
214  return true;
215  }
216 
225  abstract public function execute();
226 
233  protected function supportsOption( $name ) {
234  return isset( $this->mParams[$name] );
235  }
236 
248  protected function addOption( $name, $description, $required = false,
249  $withArg = false, $shortName = false, $multiOccurrence = false
250  ) {
251  $this->mParams[$name] = [
252  'desc' => $description,
253  'require' => $required,
254  'withArg' => $withArg,
255  'shortName' => $shortName,
256  'multiOccurrence' => $multiOccurrence
257  ];
258 
259  if ( $shortName !== false ) {
260  $this->mShortParamsMap[$shortName] = $name;
261  }
262  }
263 
269  protected function hasOption( $name ) {
270  return isset( $this->mOptions[$name] );
271  }
272 
283  protected function getOption( $name, $default = null ) {
284  if ( $this->hasOption( $name ) ) {
285  return $this->mOptions[$name];
286  } else {
287  // Set it so we don't have to provide the default again
288  $this->mOptions[$name] = $default;
289 
290  return $this->mOptions[$name];
291  }
292  }
293 
300  protected function addArg( $arg, $description, $required = true ) {
301  $this->mArgList[] = [
302  'name' => $arg,
303  'desc' => $description,
304  'require' => $required
305  ];
306  }
307 
312  protected function deleteOption( $name ) {
313  unset( $this->mParams[$name] );
314  }
315 
321  protected function setAllowUnregisteredOptions( $allow ) {
322  $this->mAllowUnregisteredOptions = $allow;
323  }
324 
329  protected function addDescription( $text ) {
330  $this->mDescription = $text;
331  }
332 
338  protected function hasArg( $argId = 0 ) {
339  if ( func_num_args() === 0 ) {
340  wfDeprecated( __METHOD__ . ' without an $argId', '1.33' );
341  }
342 
343  return isset( $this->mArgs[$argId] );
344  }
345 
352  protected function getArg( $argId = 0, $default = null ) {
353  if ( func_num_args() === 0 ) {
354  wfDeprecated( __METHOD__ . ' without an $argId', '1.33' );
355  }
356 
357  return $this->hasArg( $argId ) ? $this->mArgs[$argId] : $default;
358  }
359 
367  protected function getBatchSize() {
368  return $this->mBatchSize;
369  }
370 
375  protected function setBatchSize( $s = 0 ) {
376  $this->mBatchSize = $s;
377 
378  // If we support $mBatchSize, show the option.
379  // Used to be in addDefaultParams, but in order for that to
380  // work, subclasses would have to call this function in the constructor
381  // before they called parent::__construct which is just weird
382  // (and really wasn't done).
383  if ( $this->mBatchSize ) {
384  $this->addOption( 'batch-size', 'Run this many operations ' .
385  'per batch, default: ' . $this->mBatchSize, false, true );
386  if ( isset( $this->mParams['batch-size'] ) ) {
387  // This seems a little ugly...
388  $this->mDependantParameters['batch-size'] = $this->mParams['batch-size'];
389  }
390  }
391  }
392 
397  public function getName() {
398  return $this->mSelf;
399  }
400 
407  protected function getStdin( $len = null ) {
408  if ( $len == self::STDIN_ALL ) {
409  return file_get_contents( 'php://stdin' );
410  }
411  $f = fopen( 'php://stdin', 'rt' );
412  if ( !$len ) {
413  return $f;
414  }
415  $input = fgets( $f, $len );
416  fclose( $f );
417 
418  return rtrim( $input );
419  }
420 
424  public function isQuiet() {
425  return $this->mQuiet;
426  }
427 
434  protected function output( $out, $channel = null ) {
435  // This is sometimes called very early, before Setup.php is included.
436  if ( class_exists( MediaWikiServices::class ) ) {
437  // Try to periodically flush buffered metrics to avoid OOMs
438  $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
439  if ( $stats->getDataCount() > 1000 ) {
440  MediaWiki::emitBufferedStatsdData( $stats, $this->getConfig() );
441  }
442  }
443 
444  if ( $this->mQuiet ) {
445  return;
446  }
447  if ( $channel === null ) {
448  $this->cleanupChanneled();
449  print $out;
450  } else {
451  $out = preg_replace( '/\n\z/', '', $out );
452  $this->outputChanneled( $out, $channel );
453  }
454  }
455 
462  protected function error( $err, $die = 0 ) {
463  if ( intval( $die ) !== 0 ) {
464  wfDeprecated( __METHOD__ . '( $err, $die )', '1.31' );
465  $this->fatalError( $err, intval( $die ) );
466  }
467  $this->outputChanneled( false );
468  if (
469  ( PHP_SAPI == 'cli' || PHP_SAPI == 'phpdbg' ) &&
470  !defined( 'MW_PHPUNIT_TEST' )
471  ) {
472  fwrite( STDERR, $err . "\n" );
473  } else {
474  print $err;
475  }
476  }
477 
485  protected function fatalError( $msg, $exitCode = 1 ) {
486  $this->error( $msg );
487  exit( $exitCode );
488  }
489 
490  private $atLineStart = true;
491  private $lastChannel = null;
492 
496  public function cleanupChanneled() {
497  if ( !$this->atLineStart ) {
498  print "\n";
499  $this->atLineStart = true;
500  }
501  }
502 
511  public function outputChanneled( $msg, $channel = null ) {
512  if ( $msg === false ) {
513  $this->cleanupChanneled();
514 
515  return;
516  }
517 
518  // End the current line if necessary
519  if ( !$this->atLineStart && $channel !== $this->lastChannel ) {
520  print "\n";
521  }
522 
523  print $msg;
524 
525  $this->atLineStart = false;
526  if ( $channel === null ) {
527  // For unchanneled messages, output trailing newline immediately
528  print "\n";
529  $this->atLineStart = true;
530  }
531  $this->lastChannel = $channel;
532  }
533 
544  public function getDbType() {
545  return self::DB_STD;
546  }
547 
551  protected function addDefaultParams() {
552  # Generic (non script dependant) options:
553 
554  $this->addOption( 'help', 'Display this help message', false, false, 'h' );
555  $this->addOption( 'quiet', 'Whether to suppress non-error output', false, false, 'q' );
556  $this->addOption( 'conf', 'Location of LocalSettings.php, if not default', false, true );
557  $this->addOption( 'wiki', 'For specifying the wiki ID', false, true );
558  $this->addOption( 'globals', 'Output globals at the end of processing for debugging' );
559  $this->addOption(
560  'memory-limit',
561  'Set a specific memory limit for the script, '
562  . '"max" for no limit or "default" to avoid changing it',
563  false,
564  true
565  );
566  $this->addOption( 'server', "The protocol and server name to use in URLs, e.g. " .
567  "http://en.wikipedia.org. This is sometimes necessary because " .
568  "server name detection may fail in command line scripts.", false, true );
569  $this->addOption( 'profiler', 'Profiler output format (usually "text")', false, true );
570  // This is named --mwdebug, because --debug would conflict in the phpunit.php CLI script.
571  $this->addOption( 'mwdebug', 'Enable built-in MediaWiki development settings', false, true );
572 
573  # Save generic options to display them separately in help
574  $this->mGenericParameters = $this->mParams;
575 
576  # Script dependant options:
577 
578  // If we support a DB, show the options
579  if ( $this->getDbType() > 0 ) {
580  $this->addOption( 'dbuser', 'The DB user to use for this script', false, true );
581  $this->addOption( 'dbpass', 'The password to use for this script', false, true );
582  $this->addOption( 'dbgroupdefault', 'The default DB group to use.', false, true );
583  }
584 
585  # Save additional script dependant options to display
586  # ┬áthem separately in help
587  $this->mDependantParameters = array_diff_key( $this->mParams, $this->mGenericParameters );
588  }
589 
594  public function getConfig() {
595  if ( $this->config === null ) {
596  $this->config = MediaWikiServices::getInstance()->getMainConfig();
597  }
598 
599  return $this->config;
600  }
601 
606  public function setConfig( Config $config ) {
607  $this->config = $config;
608  }
609 
619  protected function requireExtension( $name ) {
620  $this->requiredExtensions[] = $name;
621  }
622 
628  public function checkRequiredExtensions() {
629  $registry = ExtensionRegistry::getInstance();
630  $missing = [];
631  foreach ( $this->requiredExtensions as $name ) {
632  if ( !$registry->isLoaded( $name ) ) {
633  $missing[] = $name;
634  }
635  }
636 
637  if ( $missing ) {
638  $joined = implode( ', ', $missing );
639  $msg = "The following extensions are required to be installed "
640  . "for this script to run: $joined. Please enable them and then try again.";
641  $this->fatalError( $msg );
642  }
643  }
644 
649  public function setAgentAndTriggers() {
650  if ( function_exists( 'posix_getpwuid' ) ) {
651  $agent = posix_getpwuid( posix_geteuid() )['name'];
652  } else {
653  $agent = 'sysadmin';
654  }
655  $agent .= '@' . wfHostname();
656 
657  $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
658  // Add a comment for easy SHOW PROCESSLIST interpretation
659  $lbFactory->setAgentName(
660  mb_strlen( $agent ) > 15 ? mb_substr( $agent, 0, 15 ) . '...' : $agent
661  );
662  self::setLBFactoryTriggers( $lbFactory, $this->getConfig() );
663  }
664 
670  public static function setLBFactoryTriggers( LBFactory $LBFactory, Config $config ) {
671  $services = MediaWikiServices::getInstance();
672  $stats = $services->getStatsdDataFactory();
673  // Hook into period lag checks which often happen in long-running scripts
674  $lbFactory = $services->getDBLoadBalancerFactory();
675  $lbFactory->setWaitForReplicationListener(
676  __METHOD__,
677  function () use ( $stats, $config ) {
678  // Check config in case of JobRunner and unit tests
679  if ( $config->get( 'CommandLineMode' ) ) {
681  }
682  // Try to periodically flush buffered metrics to avoid OOMs
684  }
685  );
686  // Check for other windows to run them. A script may read or do a few writes
687  // to the master but mostly be writing to something else, like a file store.
688  $lbFactory->getMainLB()->setTransactionListener(
689  __METHOD__,
690  function ( $trigger ) use ( $stats, $config ) {
691  // Check config in case of JobRunner and unit tests
692  if ( $config->get( 'CommandLineMode' ) && $trigger === IDatabase::TRIGGER_COMMIT ) {
694  }
695  // Try to periodically flush buffered metrics to avoid OOMs
697  }
698  );
699  }
700 
708  public function runChild( $maintClass, $classFile = null ) {
709  // Make sure the class is loaded first
710  if ( !class_exists( $maintClass ) ) {
711  if ( $classFile ) {
712  require_once $classFile;
713  }
714  if ( !class_exists( $maintClass ) ) {
715  $this->error( "Cannot spawn child: $maintClass" );
716  }
717  }
718 
722  $child = new $maintClass();
723  $child->loadParamsAndArgs( $this->mSelf, $this->mOptions, $this->mArgs );
724  if ( !is_null( $this->mDb ) ) {
725  $child->setDB( $this->mDb );
726  }
727 
728  return $child;
729  }
730 
734  public function setup() {
735  global $IP, $wgCommandLineMode;
736 
737  # Abort if called from a web server
738  # wfIsCLI() is not available yet
739  if ( PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg' ) {
740  $this->fatalError( 'This script must be run from the command line' );
741  }
742 
743  if ( $IP === null ) {
744  $this->fatalError( "\$IP not set, aborting!\n" .
745  '(Did you forget to call parent::__construct() in your maintenance script?)' );
746  }
747 
748  # Make sure we can handle script parameters
749  if ( !defined( 'HPHP_VERSION' ) && !ini_get( 'register_argc_argv' ) ) {
750  $this->fatalError( 'Cannot get command line arguments, register_argc_argv is set to false' );
751  }
752 
753  // Send PHP warnings and errors to stderr instead of stdout.
754  // This aids in diagnosing problems, while keeping messages
755  // out of redirected output.
756  if ( ini_get( 'display_errors' ) ) {
757  ini_set( 'display_errors', 'stderr' );
758  }
759 
760  $this->loadParamsAndArgs();
761 
762  # Set the memory limit
763  # Note we need to set it again later in cache LocalSettings changed it
764  $this->adjustMemoryLimit();
765 
766  # Set max execution time to 0 (no limit). PHP.net says that
767  # "When running PHP from the command line the default setting is 0."
768  # But sometimes this doesn't seem to be the case.
769  ini_set( 'max_execution_time', 0 );
770 
771  # Define us as being in MediaWiki
772  define( 'MEDIAWIKI', true );
773 
774  $wgCommandLineMode = true;
775 
776  # Turn off output buffering if it's on
777  while ( ob_get_level() > 0 ) {
778  ob_end_flush();
779  }
780  }
781 
791  public function memoryLimit() {
792  $limit = $this->getOption( 'memory-limit', 'max' );
793  $limit = trim( $limit, "\" '" ); // trim quotes in case someone misunderstood
794  return $limit;
795  }
796 
800  protected function adjustMemoryLimit() {
801  $limit = $this->memoryLimit();
802  if ( $limit == 'max' ) {
803  $limit = -1; // no memory limit
804  }
805  if ( $limit != 'default' ) {
806  ini_set( 'memory_limit', $limit );
807  }
808  }
809 
813  protected function activateProfiler() {
815 
816  $output = $this->getOption( 'profiler' );
817  if ( !$output ) {
818  return;
819  }
820 
821  if ( is_array( $wgProfiler ) && isset( $wgProfiler['class'] ) ) {
822  $class = $wgProfiler['class'];
824  $profiler = new $class(
825  [ 'sampling' => 1, 'output' => [ $output ] ]
826  + $wgProfiler
827  + [ 'threshold' => $wgProfileLimit ]
828  );
829  $profiler->setTemplated( true );
830  Profiler::replaceStubInstance( $profiler );
831  }
832 
833  $trxProfiler = Profiler::instance()->getTransactionProfiler();
834  $trxProfiler->setLogger( LoggerFactory::getInstance( 'DBPerformance' ) );
835  $trxProfiler->setExpectations( $wgTrxProfilerLimits['Maintenance'], __METHOD__ );
836  }
837 
841  public function clearParamsAndArgs() {
842  $this->mOptions = [];
843  $this->mArgs = [];
844  $this->mInputLoaded = false;
845  }
846 
854  public function loadWithArgv( $argv ) {
855  $options = [];
856  $args = [];
857  $this->orderedOptions = [];
858 
859  # Parse arguments
860  for ( $arg = reset( $argv ); $arg !== false; $arg = next( $argv ) ) {
861  if ( $arg == '--' ) {
862  # End of options, remainder should be considered arguments
863  $arg = next( $argv );
864  while ( $arg !== false ) {
865  $args[] = $arg;
866  $arg = next( $argv );
867  }
868  break;
869  } elseif ( substr( $arg, 0, 2 ) == '--' ) {
870  # Long options
871  $option = substr( $arg, 2 );
872  if ( isset( $this->mParams[$option] ) && $this->mParams[$option]['withArg'] ) {
873  $param = next( $argv );
874  if ( $param === false ) {
875  $this->error( "\nERROR: $option parameter needs a value after it\n" );
876  $this->maybeHelp( true );
877  }
878 
879  $this->setParam( $options, $option, $param );
880  } else {
881  $bits = explode( '=', $option, 2 );
882  $this->setParam( $options, $bits[0], $bits[1] ?? 1 );
883  }
884  } elseif ( $arg == '-' ) {
885  # Lonely "-", often used to indicate stdin or stdout.
886  $args[] = $arg;
887  } elseif ( substr( $arg, 0, 1 ) == '-' ) {
888  # Short options
889  $argLength = strlen( $arg );
890  for ( $p = 1; $p < $argLength; $p++ ) {
891  $option = $arg[$p];
892  if ( !isset( $this->mParams[$option] ) && isset( $this->mShortParamsMap[$option] ) ) {
893  $option = $this->mShortParamsMap[$option];
894  }
895 
896  if ( isset( $this->mParams[$option]['withArg'] ) && $this->mParams[$option]['withArg'] ) {
897  $param = next( $argv );
898  if ( $param === false ) {
899  $this->error( "\nERROR: $option parameter needs a value after it\n" );
900  $this->maybeHelp( true );
901  }
902  $this->setParam( $options, $option, $param );
903  } else {
904  $this->setParam( $options, $option, 1 );
905  }
906  }
907  } else {
908  $args[] = $arg;
909  }
910  }
911 
912  $this->mOptions = $options;
913  $this->mArgs = $args;
914  $this->loadSpecialVars();
915  $this->mInputLoaded = true;
916  }
917 
930  private function setParam( &$options, $option, $value ) {
931  $this->orderedOptions[] = [ $option, $value ];
932 
933  if ( isset( $this->mParams[$option] ) ) {
934  $multi = $this->mParams[$option]['multiOccurrence'];
935  } else {
936  $multi = false;
937  }
938  $exists = array_key_exists( $option, $options );
939  if ( $multi && $exists ) {
940  $options[$option][] = $value;
941  } elseif ( $multi ) {
942  $options[$option] = [ $value ];
943  } elseif ( !$exists ) {
944  $options[$option] = $value;
945  } else {
946  $this->error( "\nERROR: $option parameter given twice\n" );
947  $this->maybeHelp( true );
948  }
949  }
950 
960  public function loadParamsAndArgs( $self = null, $opts = null, $args = null ) {
961  # If we were given opts or args, set those and return early
962  if ( $self ) {
963  $this->mSelf = $self;
964  $this->mInputLoaded = true;
965  }
966  if ( $opts ) {
967  $this->mOptions = $opts;
968  $this->mInputLoaded = true;
969  }
970  if ( $args ) {
971  $this->mArgs = $args;
972  $this->mInputLoaded = true;
973  }
974 
975  # If we've already loaded input (either by user values or from $argv)
976  # skip on loading it again. The array_shift() will corrupt values if
977  # it's run again and again
978  if ( $this->mInputLoaded ) {
979  $this->loadSpecialVars();
980 
981  return;
982  }
983 
984  global $argv;
985  $this->mSelf = $argv[0];
986  $this->loadWithArgv( array_slice( $argv, 1 ) );
987  }
988 
992  public function validateParamsAndArgs() {
993  $die = false;
994  # Check to make sure we've got all the required options
995  foreach ( $this->mParams as $opt => $info ) {
996  if ( $info['require'] && !$this->hasOption( $opt ) ) {
997  $this->error( "Param $opt required!" );
998  $die = true;
999  }
1000  }
1001  # Check arg list too
1002  foreach ( $this->mArgList as $k => $info ) {
1003  if ( $info['require'] && !$this->hasArg( $k ) ) {
1004  $this->error( 'Argument <' . $info['name'] . '> required!' );
1005  $die = true;
1006  }
1007  }
1008  if ( !$this->mAllowUnregisteredOptions ) {
1009  # Check for unexpected options
1010  foreach ( $this->mOptions as $opt => $val ) {
1011  if ( !$this->supportsOption( $opt ) ) {
1012  $this->error( "Unexpected option $opt!" );
1013  $die = true;
1014  }
1015  }
1016  }
1017 
1018  $this->maybeHelp( $die );
1019  }
1020 
1024  protected function loadSpecialVars() {
1025  if ( $this->hasOption( 'dbuser' ) ) {
1026  $this->mDbUser = $this->getOption( 'dbuser' );
1027  }
1028  if ( $this->hasOption( 'dbpass' ) ) {
1029  $this->mDbPass = $this->getOption( 'dbpass' );
1030  }
1031  if ( $this->hasOption( 'quiet' ) ) {
1032  $this->mQuiet = true;
1033  }
1034  if ( $this->hasOption( 'batch-size' ) ) {
1035  $this->mBatchSize = intval( $this->getOption( 'batch-size' ) );
1036  }
1037  }
1038 
1043  protected function maybeHelp( $force = false ) {
1044  if ( !$force && !$this->hasOption( 'help' ) ) {
1045  return;
1046  }
1047 
1048  $screenWidth = 80; // TODO: Calculate this!
1049  $tab = " ";
1050  $descWidth = $screenWidth - ( 2 * strlen( $tab ) );
1051 
1052  ksort( $this->mParams );
1053  $this->mQuiet = false;
1054 
1055  // Description ...
1056  if ( $this->mDescription ) {
1057  $this->output( "\n" . wordwrap( $this->mDescription, $screenWidth ) . "\n" );
1058  }
1059  $output = "\nUsage: php " . basename( $this->mSelf );
1060 
1061  // ... append parameters ...
1062  if ( $this->mParams ) {
1063  $output .= " [--" . implode( "|--", array_keys( $this->mParams ) ) . "]";
1064  }
1065 
1066  // ... and append arguments.
1067  if ( $this->mArgList ) {
1068  $output .= ' ';
1069  foreach ( $this->mArgList as $k => $arg ) {
1070  if ( $arg['require'] ) {
1071  $output .= '<' . $arg['name'] . '>';
1072  } else {
1073  $output .= '[' . $arg['name'] . ']';
1074  }
1075  if ( $k < count( $this->mArgList ) - 1 ) {
1076  $output .= ' ';
1077  }
1078  }
1079  }
1080  $this->output( "$output\n\n" );
1081 
1082  # TODO abstract some repetitive code below
1083 
1084  // Generic parameters
1085  $this->output( "Generic maintenance parameters:\n" );
1086  foreach ( $this->mGenericParameters as $par => $info ) {
1087  if ( $info['shortName'] !== false ) {
1088  $par .= " (-{$info['shortName']})";
1089  }
1090  $this->output(
1091  wordwrap( "$tab--$par: " . $info['desc'], $descWidth,
1092  "\n$tab$tab" ) . "\n"
1093  );
1094  }
1095  $this->output( "\n" );
1096 
1097  $scriptDependantParams = $this->mDependantParameters;
1098  if ( count( $scriptDependantParams ) > 0 ) {
1099  $this->output( "Script dependant parameters:\n" );
1100  // Parameters description
1101  foreach ( $scriptDependantParams as $par => $info ) {
1102  if ( $info['shortName'] !== false ) {
1103  $par .= " (-{$info['shortName']})";
1104  }
1105  $this->output(
1106  wordwrap( "$tab--$par: " . $info['desc'], $descWidth,
1107  "\n$tab$tab" ) . "\n"
1108  );
1109  }
1110  $this->output( "\n" );
1111  }
1112 
1113  // Script specific parameters not defined on construction by
1114  // Maintenance::addDefaultParams()
1115  $scriptSpecificParams = array_diff_key(
1116  # all script parameters:
1117  $this->mParams,
1118  # remove the Maintenance default parameters:
1119  $this->mGenericParameters,
1120  $this->mDependantParameters
1121  );
1122  if ( count( $scriptSpecificParams ) > 0 ) {
1123  $this->output( "Script specific parameters:\n" );
1124  // Parameters description
1125  foreach ( $scriptSpecificParams as $par => $info ) {
1126  if ( $info['shortName'] !== false ) {
1127  $par .= " (-{$info['shortName']})";
1128  }
1129  $this->output(
1130  wordwrap( "$tab--$par: " . $info['desc'], $descWidth,
1131  "\n$tab$tab" ) . "\n"
1132  );
1133  }
1134  $this->output( "\n" );
1135  }
1136 
1137  // Print arguments
1138  if ( count( $this->mArgList ) > 0 ) {
1139  $this->output( "Arguments:\n" );
1140  // Arguments description
1141  foreach ( $this->mArgList as $info ) {
1142  $openChar = $info['require'] ? '<' : '[';
1143  $closeChar = $info['require'] ? '>' : ']';
1144  $this->output(
1145  wordwrap( "$tab$openChar" . $info['name'] . "$closeChar: " .
1146  $info['desc'], $descWidth, "\n$tab$tab" ) . "\n"
1147  );
1148  }
1149  $this->output( "\n" );
1150  }
1151 
1152  die( 1 );
1153  }
1154 
1158  public function finalSetup() {
1162 
1163  # Turn off output buffering again, it might have been turned on in the settings files
1164  if ( ob_get_level() ) {
1165  ob_end_flush();
1166  }
1167  # Same with these
1168  $wgCommandLineMode = true;
1169 
1170  # Override $wgServer
1171  if ( $this->hasOption( 'server' ) ) {
1172  $wgServer = $this->getOption( 'server', $wgServer );
1173  }
1174 
1175  # If these were passed, use them
1176  if ( $this->mDbUser ) {
1178  }
1179  if ( $this->mDbPass ) {
1181  }
1182  if ( $this->hasOption( 'dbgroupdefault' ) ) {
1183  $wgDBDefaultGroup = $this->getOption( 'dbgroupdefault', null );
1184 
1185  MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->destroy();
1186  }
1187 
1188  if ( $this->getDbType() == self::DB_ADMIN && isset( $wgDBadminuser ) ) {
1191 
1192  if ( $wgDBservers ) {
1196  foreach ( $wgDBservers as $i => $server ) {
1197  $wgDBservers[$i]['user'] = $wgDBuser;
1198  $wgDBservers[$i]['password'] = $wgDBpassword;
1199  }
1200  }
1201  if ( isset( $wgLBFactoryConf['serverTemplate'] ) ) {
1202  $wgLBFactoryConf['serverTemplate']['user'] = $wgDBuser;
1203  $wgLBFactoryConf['serverTemplate']['password'] = $wgDBpassword;
1204  }
1205  MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->destroy();
1206  }
1207 
1208  # Apply debug settings
1209  if ( $this->hasOption( 'mwdebug' ) ) {
1210  require __DIR__ . '/../includes/DevelopmentSettings.php';
1211  }
1212 
1213  // Per-script profiling; useful for debugging
1214  $this->activateProfiler();
1215 
1216  $this->afterFinalSetup();
1217 
1218  $wgShowExceptionDetails = true;
1219  $wgShowHostnames = true;
1220 
1221  Wikimedia\suppressWarnings();
1222  set_time_limit( 0 );
1223  Wikimedia\restoreWarnings();
1224 
1225  $this->adjustMemoryLimit();
1226  }
1227 
1231  protected function afterFinalSetup() {
1232  if ( defined( 'MW_CMDLINE_CALLBACK' ) ) {
1233  call_user_func( MW_CMDLINE_CALLBACK );
1234  }
1235  }
1236 
1241  public function globals() {
1242  if ( $this->hasOption( 'globals' ) ) {
1243  print_r( $GLOBALS );
1244  }
1245  }
1246 
1251  public function loadSettings() {
1252  global $wgCommandLineMode, $IP;
1253 
1254  if ( isset( $this->mOptions['conf'] ) ) {
1255  $settingsFile = $this->mOptions['conf'];
1256  } elseif ( defined( "MW_CONFIG_FILE" ) ) {
1257  $settingsFile = MW_CONFIG_FILE;
1258  } else {
1259  $settingsFile = "$IP/LocalSettings.php";
1260  }
1261  if ( isset( $this->mOptions['wiki'] ) ) {
1262  $bits = explode( '-', $this->mOptions['wiki'], 2 );
1263  define( 'MW_DB', $bits[0] );
1264  define( 'MW_PREFIX', $bits[1] ?? '' );
1265  } elseif ( isset( $this->mOptions['server'] ) ) {
1266  // Provide the option for site admins to detect and configure
1267  // multiple wikis based on server names. This offers --server
1268  // as alternative to --wiki.
1269  // See https://www.mediawiki.org/wiki/Manual:Wiki_family
1270  $_SERVER['SERVER_NAME'] = $this->mOptions['server'];
1271  }
1272 
1273  if ( !is_readable( $settingsFile ) ) {
1274  $this->fatalError( "A copy of your installation's LocalSettings.php\n" .
1275  "must exist and be readable in the source directory.\n" .
1276  "Use --conf to specify it." );
1277  }
1278  $wgCommandLineMode = true;
1279 
1280  return $settingsFile;
1281  }
1282 
1288  public function purgeRedundantText( $delete = true ) {
1290 
1291  # Data should come off the master, wrapped in a transaction
1292  $dbw = $this->getDB( DB_MASTER );
1293  $this->beginTransaction( $dbw, __METHOD__ );
1294 
1296  # Get "active" text records from the revisions table
1297  $cur = [];
1298  $this->output( 'Searching for active text records in revisions table...' );
1299  $res = $dbw->select( 'revision', 'rev_text_id', [], __METHOD__, [ 'DISTINCT' ] );
1300  foreach ( $res as $row ) {
1301  $cur[] = $row->rev_text_id;
1302  }
1303  $this->output( "done.\n" );
1304 
1305  # Get "active" text records from the archive table
1306  $this->output( 'Searching for active text records in archive table...' );
1307  $res = $dbw->select( 'archive', 'ar_text_id', [], __METHOD__, [ 'DISTINCT' ] );
1308  foreach ( $res as $row ) {
1309  # old pre-MW 1.5 records can have null ar_text_id's.
1310  if ( $row->ar_text_id !== null ) {
1311  $cur[] = $row->ar_text_id;
1312  }
1313  }
1314  $this->output( "done.\n" );
1315  } else {
1316  # Get "active" text records via the content table
1317  $cur = [];
1318  $this->output( 'Searching for active text records via contents table...' );
1319  $res = $dbw->select( 'content', 'content_address', [], __METHOD__, [ 'DISTINCT' ] );
1320  $blobStore = MediaWikiServices::getInstance()->getBlobStore();
1321  foreach ( $res as $row ) {
1322  $textId = $blobStore->getTextIdFromAddress( $row->content_address );
1323  if ( $textId ) {
1324  $cur[] = $textId;
1325  }
1326  }
1327  $this->output( "done.\n" );
1328  }
1329  $this->output( "done.\n" );
1330 
1331  # Get the IDs of all text records not in these sets
1332  $this->output( 'Searching for inactive text records...' );
1333  $cond = 'old_id NOT IN ( ' . $dbw->makeList( $cur ) . ' )';
1334  $res = $dbw->select( 'text', 'old_id', [ $cond ], __METHOD__, [ 'DISTINCT' ] );
1335  $old = [];
1336  foreach ( $res as $row ) {
1337  $old[] = $row->old_id;
1338  }
1339  $this->output( "done.\n" );
1340 
1341  # Inform the user of what we're going to do
1342  $count = count( $old );
1343  $this->output( "$count inactive items found.\n" );
1344 
1345  # Delete as appropriate
1346  if ( $delete && $count ) {
1347  $this->output( 'Deleting...' );
1348  $dbw->delete( 'text', [ 'old_id' => $old ], __METHOD__ );
1349  $this->output( "done.\n" );
1350  }
1351 
1352  $this->commitTransaction( $dbw, __METHOD__ );
1353  }
1354 
1359  protected function getDir() {
1360  return __DIR__;
1361  }
1362 
1373  protected function getDB( $db, $groups = [], $wiki = false ) {
1374  if ( $this->mDb === null ) {
1375  return wfGetDB( $db, $groups, $wiki );
1376  }
1377  return $this->mDb;
1378  }
1379 
1385  public function setDB( IDatabase $db ) {
1386  $this->mDb = $db;
1387  }
1388 
1399  protected function beginTransaction( IDatabase $dbw, $fname ) {
1400  $dbw->begin( $fname );
1401  }
1402 
1414  protected function commitTransaction( IDatabase $dbw, $fname ) {
1415  $dbw->commit( $fname );
1416  $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
1417  $waitSucceeded = $lbFactory->waitForReplication(
1418  [ 'timeout' => 30, 'ifWritesSince' => $this->lastReplicationWait ]
1419  );
1420  $this->lastReplicationWait = microtime( true );
1421  return $waitSucceeded;
1422  }
1423 
1434  protected function rollbackTransaction( IDatabase $dbw, $fname ) {
1435  $dbw->rollback( $fname );
1436  }
1437 
1442  private function lockSearchindex( $db ) {
1443  $write = [ 'searchindex' ];
1444  $read = [
1445  'page',
1446  'revision',
1447  'text',
1448  'interwiki',
1449  'l10n_cache',
1450  'user',
1451  'page_restrictions'
1452  ];
1453  $db->lockTables( $read, $write, __CLASS__ . '-searchIndexLock' );
1454  }
1455 
1460  private function unlockSearchindex( $db ) {
1461  $db->unlockTables( __CLASS__ . '-searchIndexLock' );
1462  }
1463 
1469  private function relockSearchindex( $db ) {
1470  $this->unlockSearchindex( $db );
1471  $this->lockSearchindex( $db );
1472  }
1473 
1481  public function updateSearchIndex( $maxLockTime, $callback, $dbw, $results ) {
1482  $lockTime = time();
1483 
1484  # Lock searchindex
1485  if ( $maxLockTime ) {
1486  $this->output( " --- Waiting for lock ---" );
1487  $this->lockSearchindex( $dbw );
1488  $lockTime = time();
1489  $this->output( "\n" );
1490  }
1491 
1492  # Loop through the results and do a search update
1493  foreach ( $results as $row ) {
1494  # Allow reads to be processed
1495  if ( $maxLockTime && time() > $lockTime + $maxLockTime ) {
1496  $this->output( " --- Relocking ---" );
1497  $this->relockSearchindex( $dbw );
1498  $lockTime = time();
1499  $this->output( "\n" );
1500  }
1501  call_user_func( $callback, $dbw, $row );
1502  }
1503 
1504  # Unlock searchindex
1505  if ( $maxLockTime ) {
1506  $this->output( " --- Unlocking --" );
1507  $this->unlockSearchindex( $dbw );
1508  $this->output( "\n" );
1509  }
1510  }
1511 
1518  public function updateSearchIndexForPage( $dbw, $pageId ) {
1519  // Get current revision
1520  $rev = Revision::loadFromPageId( $dbw, $pageId );
1521  $title = null;
1522  if ( $rev ) {
1523  $titleObj = $rev->getTitle();
1524  $title = $titleObj->getPrefixedDBkey();
1525  $this->output( "$title..." );
1526  # Update searchindex
1527  $u = new SearchUpdate( $pageId, $titleObj->getText(), $rev->getContent() );
1528  $u->doUpdate();
1529  $this->output( "\n" );
1530  }
1531 
1532  return $title;
1533  }
1534 
1545  protected function countDown( $seconds ) {
1546  if ( $this->isQuiet() ) {
1547  return;
1548  }
1549  for ( $i = $seconds; $i >= 0; $i-- ) {
1550  if ( $i != $seconds ) {
1551  $this->output( str_repeat( "\x08", strlen( $i + 1 ) ) );
1552  }
1553  $this->output( $i );
1554  if ( $i ) {
1555  sleep( 1 );
1556  }
1557  }
1558  $this->output( "\n" );
1559  }
1560 
1569  public static function posix_isatty( $fd ) {
1570  if ( !function_exists( 'posix_isatty' ) ) {
1571  return !$fd;
1572  } else {
1573  return posix_isatty( $fd );
1574  }
1575  }
1576 
1582  public static function readconsole( $prompt = '> ' ) {
1583  static $isatty = null;
1584  if ( is_null( $isatty ) ) {
1585  $isatty = self::posix_isatty( 0 /*STDIN*/ );
1586  }
1587 
1588  if ( $isatty && function_exists( 'readline' ) ) {
1589  return readline( $prompt );
1590  } else {
1591  if ( $isatty ) {
1592  $st = self::readlineEmulation( $prompt );
1593  } else {
1594  if ( feof( STDIN ) ) {
1595  $st = false;
1596  } else {
1597  $st = fgets( STDIN, 1024 );
1598  }
1599  }
1600  if ( $st === false ) {
1601  return false;
1602  }
1603  $resp = trim( $st );
1604 
1605  return $resp;
1606  }
1607  }
1608 
1614  private static function readlineEmulation( $prompt ) {
1615  $bash = ExecutableFinder::findInDefaultPaths( 'bash' );
1616  if ( !wfIsWindows() && $bash ) {
1617  $retval = false;
1618  $encPrompt = Shell::escape( $prompt );
1619  $command = "read -er -p $encPrompt && echo \"\$REPLY\"";
1620  $encCommand = Shell::escape( $command );
1621  $line = Shell::escape( "$bash -c $encCommand", $retval, [], [ 'walltime' => 0 ] );
1622 
1623  if ( $retval == 0 ) {
1624  return $line;
1625  } elseif ( $retval == 127 ) {
1626  // Couldn't execute bash even though we thought we saw it.
1627  // Shell probably spit out an error message, sorry :(
1628  // Fall through to fgets()...
1629  } else {
1630  // EOF/ctrl+D
1631  return false;
1632  }
1633  }
1634 
1635  // Fallback... we'll have no editing controls, EWWW
1636  if ( feof( STDIN ) ) {
1637  return false;
1638  }
1639  print $prompt;
1640 
1641  return fgets( STDIN, 1024 );
1642  }
1643 
1651  public static function getTermSize() {
1652  $default = [ 80, 50 ];
1653  if ( wfIsWindows() ) {
1654  return $default;
1655  }
1656  if ( Shell::isDisabled() ) {
1657  return $default;
1658  }
1659  // It's possible to get the screen size with VT-100 terminal escapes,
1660  // but reading the responses is not possible without setting raw mode
1661  // (unless you want to require the user to press enter), and that
1662  // requires an ioctl(), which we can't do. So we have to shell out to
1663  // something that can do the relevant syscalls. There are a few
1664  // options. Linux and Mac OS X both have "stty size" which does the
1665  // job directly.
1666  $result = Shell::command( 'stty', 'size' )
1667  ->execute();
1668  if ( $result->getExitCode() !== 0 ) {
1669  return $default;
1670  }
1671  if ( !preg_match( '/^(\d+) (\d+)$/', $result->getStdout(), $m ) ) {
1672  return $default;
1673  }
1674  return [ intval( $m[2] ), intval( $m[1] ) ];
1675  }
1676 
1681  public static function requireTestsAutoloader() {
1682  require_once __DIR__ . '/../tests/common/TestsAutoLoader.php';
1683  }
1684 }
1685 
1690  protected $mSelf = "FakeMaintenanceScript";
1691 
1692  public function execute() {
1693  }
1694 }
1695 
1700 abstract class LoggedUpdateMaintenance extends Maintenance {
1701  public function __construct() {
1702  parent::__construct();
1703  $this->addOption( 'force', 'Run the update even if it was completed already' );
1704  $this->setBatchSize( 200 );
1705  }
1706 
1707  public function execute() {
1708  $db = $this->getDB( DB_MASTER );
1709  $key = $this->getUpdateKey();
1710 
1711  if ( !$this->hasOption( 'force' )
1712  && $db->selectRow( 'updatelog', '1', [ 'ul_key' => $key ], __METHOD__ )
1713  ) {
1714  $this->output( "..." . $this->updateSkippedMessage() . "\n" );
1715 
1716  return true;
1717  }
1718 
1719  if ( !$this->doDBUpdates() ) {
1720  return false;
1721  }
1722 
1723  $db->insert( 'updatelog', [ 'ul_key' => $key ], __METHOD__, 'IGNORE' );
1724 
1725  return true;
1726  }
1727 
1732  protected function updateSkippedMessage() {
1733  $key = $this->getUpdateKey();
1734 
1735  return "Update '{$key}' already logged as completed.";
1736  }
1737 
1743  abstract protected function doDBUpdates();
1744 
1749  abstract protected function getUpdateKey();
1750 }
$wgProfileLimit
$wgProfileLimit
Only record profiling info for pages that took longer than this.
Definition: DefaultSettings.php:6407
FakeMaintenance\$mSelf
$mSelf
Definition: Maintenance.php:1690
RUN_MAINTENANCE_IF_MAIN
const RUN_MAINTENANCE_IF_MAIN
Definition: Maintenance.php:36
Maintenance\$mBatchSize
int $mBatchSize
Batch size.
Definition: Maintenance.php:121
LoggedUpdateMaintenance\__construct
__construct()
Default constructor.
Definition: Maintenance.php:1701
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:930
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:1651
Maintenance\$mShortParamsMap
$mShortParamsMap
Definition: Maintenance.php:88
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:407
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:544
$opt
$opt
Definition: postprocess-phan.php:115
Maintenance\maybeHelp
maybeHelp( $force=false)
Maybe show the help.
Definition: Maintenance.php:1043
Maintenance\fatalError
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
Definition: Maintenance.php:485
captcha-old.count
count
Definition: captcha-old.py:249
Maintenance\$mDbPass
$mDbPass
Definition: Maintenance.php:107
Maintenance\addDescription
addDescription( $text)
Set the description text.
Definition: Maintenance.php:329
Maintenance\setup
setup()
Do some sanity checking and basic setup.
Definition: Maintenance.php:734
Maintenance\$requiredExtensions
array $requiredExtensions
Definition: Maintenance.php:154
Maintenance\runChild
runChild( $maintClass, $classFile=null)
Run a child maintenance script.
Definition: Maintenance.php:708
Maintenance\setLBFactoryTriggers
static setLBFactoryTriggers(LBFactory $LBFactory, Config $config)
Definition: Maintenance.php:670
Maintenance\readconsole
static readconsole( $prompt='> ')
Prompt the console for input.
Definition: Maintenance.php:1582
$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. '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 '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:1983
$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 When $user is not it can be in the form of< username >< more info > e g for bot passwords intended to be added to log contexts Fields it might only if the login was with a bot password 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:780
$wgShowHostnames
$wgShowHostnames
Expose backend server host names through the API and various HTML comments.
Definition: DefaultSettings.php:6316
Maintenance\$mAllowUnregisteredOptions
$mAllowUnregisteredOptions
Definition: Maintenance.php:100
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:960
Maintenance\relockSearchindex
relockSearchindex( $db)
Unlock and lock again Since the lock is low-priority, queued reads will be able to complete.
Definition: Maintenance.php:1469
Maintenance\getName
getName()
Get the script's name.
Definition: Maintenance.php:397
wfHostname
wfHostname()
Fetch server name for use in error reporting etc.
Definition: GlobalFunctions.php:1352
$wgMultiContentRevisionSchemaMigrationStage
int $wgMultiContentRevisionSchemaMigrationStage
RevisionStore table schema migration stage (content, slots, content_models & slot_roles tables).
Definition: DefaultSettings.php:8955
$wgLBFactoryConf
$wgLBFactoryConf
Load balancer factory configuration To set up a multi-master wiki farm, set the class here to somethi...
Definition: DefaultSettings.php:2083
$s
$s
Definition: mergeMessageFileList.php:186
Maintenance\hasArg
hasArg( $argId=0)
Does a given argument exist?
Definition: Maintenance.php:338
Maintenance\setDB
setDB(IDatabase $db)
Sets database object to be returned by getDB().
Definition: Maintenance.php:1385
$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:606
$maintClass
$maintClass
Definition: Maintenance.php:43
$wgDBpassword
$wgDBpassword
Database user's password.
Definition: DefaultSettings.php:1883
Maintenance\$lastChannel
$lastChannel
Definition: Maintenance.php:491
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:854
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:628
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:1158
Maintenance\rollbackTransaction
rollbackTransaction(IDatabase $dbw, $fname)
Rollback the transcation on a DB handle.
Definition: Maintenance.php:1434
Wikimedia\Rdbms\IDatabase\commit
commit( $fname=__METHOD__, $flush='')
Commits a transaction previously started using begin().
Maintenance\$mDescription
$mDescription
Definition: Maintenance.php:110
Maintenance\beginTransaction
beginTransaction(IDatabase $dbw, $fname)
Begin a transcation on a DB.
Definition: Maintenance.php:1399
Maintenance\afterFinalSetup
afterFinalSetup()
Execute a callback function at the end of initialisation.
Definition: Maintenance.php:1231
ExtensionRegistry\getInstance
static getInstance()
Definition: ExtensionRegistry.php:98
$wgDBadminuser
$wgDBadminuser
Separate username for maintenance tasks.
Definition: DefaultSettings.php:1913
Maintenance\unlockSearchindex
unlockSearchindex( $db)
Unlock the tables.
Definition: Maintenance.php:1460
Maintenance\clearParamsAndArgs
clearParamsAndArgs()
Clear all params and arguments.
Definition: Maintenance.php:841
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:2071
Maintenance\$mSelf
$mSelf
Definition: Maintenance.php:103
$wgDBDefaultGroup
$wgDBDefaultGroup
Default group to use when getting database connections.
Definition: DefaultSettings.php:1966
Maintenance\updateSearchIndex
updateSearchIndex( $maxLockTime, $callback, $dbw, $results)
Perform a search index update with locking.
Definition: Maintenance.php:1481
Maintenance\$mArgs
$mArgs
Definition: Maintenance.php:97
$wgProfiler
$wgProfiler
Profiler configuration.
Definition: DefaultSettings.php:6394
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:925
Maintenance\loadSpecialVars
loadSpecialVars()
Handle the special variables that are global to all scripts.
Definition: Maintenance.php:1024
Maintenance\getConfig
getConfig()
Definition: Maintenance.php:594
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
Definition: GlobalFunctions.php:1078
LoggedUpdateMaintenance
Class for scripts that perform database maintenance and want to log the update in updatelog so we can...
Definition: Maintenance.php:1700
Maintenance\$atLineStart
$atLineStart
Definition: Maintenance.php:490
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:2636
Maintenance\$lastReplicationWait
float $lastReplicationWait
UNIX timestamp.
Definition: Maintenance.php:135
$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:260
Maintenance\addOption
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
Definition: Maintenance.php:248
$IP
$IP
Definition: update.php:3
Maintenance\$mDbUser
$mDbUser
Definition: Maintenance.php:107
Maintenance\requireExtension
requireExtension( $name)
Indicate that the specified extension must be loaded before the script can run.
Definition: Maintenance.php:619
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:167
Maintenance\globals
globals()
Potentially debug globals.
Definition: Maintenance.php:1241
$output
$output
Definition: SyntaxHighlight.php:334
FakeMaintenance
Fake maintenance wrapper, mostly used for the web installer/updater.
Definition: Maintenance.php:1689
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:551
Maintenance\readlineEmulation
static readlineEmulation( $prompt)
Emulate readline()
Definition: Maintenance.php:1614
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:1545
Maintenance\DB_ADMIN
const DB_ADMIN
Definition: Maintenance.php:79
Maintenance\$mGenericParameters
$mGenericParameters
Definition: Maintenance.php:124
Maintenance\deleteOption
deleteOption( $name)
Remove an option.
Definition: Maintenance.php:312
$fname
if(defined( 'MW_SETUP_CALLBACK')) $fname
Customization point after all loading (constants, functions, classes, DefaultSettings,...
Definition: Setup.php:123
Maintenance\shouldExecute
static shouldExecute()
Should we execute the maintenance script, or just allow it to be included as a standalone class?...
Definition: Maintenance.php:191
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:271
$command
$command
Definition: cdb.php:65
$line
$line
Definition: cdb.php:59
LoggedUpdateMaintenance\execute
execute()
Do the actual work.
Definition: Maintenance.php:1707
Maintenance\DB_STD
const DB_STD
Definition: Maintenance.php:78
Maintenance\updateSearchIndexForPage
updateSearchIndexForPage( $dbw, $pageId)
Update the searchindex table for a given pageid.
Definition: Maintenance.php:1518
Maintenance\supportsOption
supportsOption( $name)
Checks to see if a particular option in supported.
Definition: Maintenance.php:233
$value
$value
Definition: styleTest.css.php:49
Maintenance\$mQuiet
$mQuiet
Definition: Maintenance.php:106
Maintenance\isQuiet
isQuiet()
Definition: Maintenance.php:424
Maintenance\activateProfiler
activateProfiler()
Activate the profiler (assuming $wgProfiler is set)
Definition: Maintenance.php:813
DeferredUpdates\tryOpportunisticExecute
static tryOpportunisticExecute( $mode='run')
Run all deferred updates immediately if there are no DB writes active.
Definition: DeferredUpdates.php:305
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:321
wfIsWindows
wfIsWindows()
Check if the operating system is Windows.
Definition: GlobalFunctions.php:1951
Maintenance\$mParams
$mParams
Definition: Maintenance.php:85
$wgServer
$wgServer
URL of the server.
Definition: DefaultSettings.php:106
Maintenance\requireTestsAutoloader
static requireTestsAutoloader()
Call this to set up the autoloader to allow classes to be used from the tests directory.
Definition: Maintenance.php:1681
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:1569
LoggedUpdateMaintenance\updateSkippedMessage
updateSkippedMessage()
Message to show that the update was done already and was just skipped.
Definition: Maintenance.php:1732
Wikimedia\Rdbms\IDatabase\rollback
rollback( $fname=__METHOD__, $flush='')
Rollback a transaction previously started using begin().
Maintenance\$mDependantParameters
$mDependantParameters
Definition: Maintenance.php:126
Maintenance\commitTransaction
commitTransaction(IDatabase $dbw, $fname)
Commit the transcation on a DB handle and wait for replica DBs to catch up.
Definition: Maintenance.php:1414
Maintenance\validateParamsAndArgs
validateParamsAndArgs()
Run some validation checks on the params, etc.
Definition: Maintenance.php:992
Maintenance\$config
Config $config
Accessible via getConfig()
Definition: Maintenance.php:148
Maintenance\cleanupChanneled
cleanupChanneled()
Clean up channeled output.
Definition: Maintenance.php:496
Maintenance\DB_NONE
const DB_NONE
Constants for DB access type.
Definition: Maintenance.php:77
Maintenance\loadSettings
loadSettings()
Generic setup for most installs.
Definition: Maintenance.php:1251
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:800
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:1288
$self
$self
Definition: doMaintenance.php:55
Maintenance\$fileHandle
resource $fileHandle
Used when creating separate schema files.
Definition: Maintenance.php:141
$args
if( $line===false) $args
Definition: cdb.php:64
Maintenance\$mInputLoaded
$mInputLoaded
Definition: Maintenance.php:113
Maintenance\getOption
getOption( $name, $default=null)
Get an option, or return the default.
Definition: Maintenance.php:283
$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:1985
Maintenance\STDIN_ALL
const STDIN_ALL
Definition: Maintenance.php:82
Maintenance\addArg
addArg( $arg, $description, $required=true)
Add some args that are needed.
Definition: Maintenance.php:300
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:1769
Maintenance\getBatchSize
getBatchSize()
Returns batch size.
Definition: Maintenance.php:367
$wgShowExceptionDetails
$wgShowExceptionDetails
If set to true, uncaught exceptions will print the exception message and a complete stack trace to ou...
Definition: DefaultSettings.php:6288
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:94
Maintenance\setAgentAndTriggers
setAgentAndTriggers()
Set triggers like when to try to run deferred updates.
Definition: Maintenance.php:649
Maintenance\getDB
getDB( $db, $groups=[], $wiki=false)
Returns a database to be used by current maintenance script.
Definition: Maintenance.php:1373
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:462
Maintenance\output
output( $out, $channel=null)
Throw some output to the user.
Definition: Maintenance.php:434
Maintenance\$mArgList
$mArgList
Definition: Maintenance.php:91
Maintenance\getDir
getDir()
Get the maintenance directory.
Definition: Maintenance.php:1359
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:1878
$f
$f
Definition: router.php:79
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:2220
wfEntryPointCheck
wfEntryPointCheck( $format='text', $scriptPath='/')
Check PHP version and that external dependencies are installed, and display an informative error if e...
Definition: PHPVersionCheck.php:276
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:269
Maintenance\getArg
getArg( $argId=0, $default=null)
Get an argument.
Definition: Maintenance.php:352
Maintenance::execute
public function execute()
Definition: maintenance.txt:45
$wgDBadminpassword
$wgDBadminpassword
Separate password for maintenance tasks.
Definition: DefaultSettings.php:1918
Maintenance\outputChanneled
outputChanneled( $msg, $channel=null)
Message outputter with channeled message support.
Definition: Maintenance.php:511
Maintenance\__construct
__construct()
Default constructor.
Definition: Maintenance.php:173
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:1692
$wgTrxProfilerLimits
$wgTrxProfilerLimits
Performance expectations for DB usage.
Definition: DefaultSettings.php:6139
SCHEMA_COMPAT_READ_OLD
const SCHEMA_COMPAT_READ_OLD
Definition: Defines.php:285
$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:1442
Maintenance\setBatchSize
setBatchSize( $s=0)
Set the batch size.
Definition: Maintenance.php:375
Maintenance\$mDb
IMaintainableDatabase $mDb
Used by getDB() / setDB()
Definition: Maintenance.php:132
Maintenance\memoryLimit
memoryLimit()
Normally we disable the memory_limit when running admin scripts.
Definition: Maintenance.php:791