MediaWiki  1.28.1
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 
33 // Define this so scripts can easily find doMaintenance.php
34 define( 'RUN_MAINTENANCE_IF_MAIN', __DIR__ . '/doMaintenance.php' );
35 define( 'DO_MAINTENANCE', RUN_MAINTENANCE_IF_MAIN ); // original name, harmless
36 
37 $maintClass = false;
38 
41 
52 abstract class Maintenance {
57  const DB_NONE = 0;
58  const DB_STD = 1;
59  const DB_ADMIN = 2;
60 
61  // Const for getStdin()
62  const STDIN_ALL = 'all';
63 
64  // This is the desired params
65  protected $mParams = [];
66 
67  // Array of mapping short parameters to long ones
68  protected $mShortParamsMap = [];
69 
70  // Array of desired args
71  protected $mArgList = [];
72 
73  // This is the list of options that were actually passed
74  protected $mOptions = [];
75 
76  // This is the list of arguments that were actually passed
77  protected $mArgs = [];
78 
79  // Name of the script currently running
80  protected $mSelf;
81 
82  // Special vars for params that are always used
83  protected $mQuiet = false;
84  protected $mDbUser, $mDbPass;
85 
86  // A description of the script, children should change this via addDescription()
87  protected $mDescription = '';
88 
89  // Have we already loaded our user input?
90  protected $mInputLoaded = false;
91 
98  protected $mBatchSize = null;
99 
100  // Generic options added by addDefaultParams()
101  private $mGenericParameters = [];
102  // Generic options which might or not be supported by the script
103  private $mDependantParameters = [];
104 
109  private $mDb = null;
110 
112  private $lastReplicationWait = 0.0;
113 
118  public $fileHandle;
119 
125  private $config;
126 
131  private $requiredExtensions = [];
132 
144  public $orderedOptions = [];
145 
150  public function __construct() {
151  // Setup $IP, using MW_INSTALL_PATH if it exists
152  global $IP;
153  $IP = strval( getenv( 'MW_INSTALL_PATH' ) ) !== ''
154  ? getenv( 'MW_INSTALL_PATH' )
155  : realpath( __DIR__ . '/..' );
156 
157  $this->addDefaultParams();
158  register_shutdown_function( [ $this, 'outputChanneled' ], false );
159  }
160 
168  public static function shouldExecute() {
170 
171  if ( !function_exists( 'debug_backtrace' ) ) {
172  // If someone has a better idea...
173  return $wgCommandLineMode;
174  }
175 
176  $bt = debug_backtrace();
177  $count = count( $bt );
178  if ( $count < 2 ) {
179  return false; // sanity
180  }
181  if ( $bt[0]['class'] !== 'Maintenance' || $bt[0]['function'] !== 'shouldExecute' ) {
182  return false; // last call should be to this function
183  }
184  $includeFuncs = [ 'require_once', 'require', 'include', 'include_once' ];
185  for ( $i = 1; $i < $count; $i++ ) {
186  if ( !in_array( $bt[$i]['function'], $includeFuncs ) ) {
187  return false; // previous calls should all be "requires"
188  }
189  }
190 
191  return true;
192  }
193 
197  abstract public function execute();
198 
210  protected function addOption( $name, $description, $required = false,
211  $withArg = false, $shortName = false, $multiOccurrence = false
212  ) {
213  $this->mParams[$name] = [
214  'desc' => $description,
215  'require' => $required,
216  'withArg' => $withArg,
217  'shortName' => $shortName,
218  'multiOccurrence' => $multiOccurrence
219  ];
220 
221  if ( $shortName !== false ) {
222  $this->mShortParamsMap[$shortName] = $name;
223  }
224  }
225 
231  protected function hasOption( $name ) {
232  return isset( $this->mOptions[$name] );
233  }
234 
245  protected function getOption( $name, $default = null ) {
246  if ( $this->hasOption( $name ) ) {
247  return $this->mOptions[$name];
248  } else {
249  // Set it so we don't have to provide the default again
250  $this->mOptions[$name] = $default;
251 
252  return $this->mOptions[$name];
253  }
254  }
255 
262  protected function addArg( $arg, $description, $required = true ) {
263  $this->mArgList[] = [
264  'name' => $arg,
265  'desc' => $description,
266  'require' => $required
267  ];
268  }
269 
274  protected function deleteOption( $name ) {
275  unset( $this->mParams[$name] );
276  }
277 
282  protected function addDescription( $text ) {
283  $this->mDescription = $text;
284  }
285 
291  protected function hasArg( $argId = 0 ) {
292  return isset( $this->mArgs[$argId] );
293  }
294 
301  protected function getArg( $argId = 0, $default = null ) {
302  return $this->hasArg( $argId ) ? $this->mArgs[$argId] : $default;
303  }
304 
309  protected function setBatchSize( $s = 0 ) {
310  $this->mBatchSize = $s;
311 
312  // If we support $mBatchSize, show the option.
313  // Used to be in addDefaultParams, but in order for that to
314  // work, subclasses would have to call this function in the constructor
315  // before they called parent::__construct which is just weird
316  // (and really wasn't done).
317  if ( $this->mBatchSize ) {
318  $this->addOption( 'batch-size', 'Run this many operations ' .
319  'per batch, default: ' . $this->mBatchSize, false, true );
320  if ( isset( $this->mParams['batch-size'] ) ) {
321  // This seems a little ugly...
322  $this->mDependantParameters['batch-size'] = $this->mParams['batch-size'];
323  }
324  }
325  }
326 
331  public function getName() {
332  return $this->mSelf;
333  }
334 
341  protected function getStdin( $len = null ) {
342  if ( $len == Maintenance::STDIN_ALL ) {
343  return file_get_contents( 'php://stdin' );
344  }
345  $f = fopen( 'php://stdin', 'rt' );
346  if ( !$len ) {
347  return $f;
348  }
349  $input = fgets( $f, $len );
350  fclose( $f );
351 
352  return rtrim( $input );
353  }
354 
358  public function isQuiet() {
359  return $this->mQuiet;
360  }
361 
368  protected function output( $out, $channel = null ) {
369  if ( $this->mQuiet ) {
370  return;
371  }
372  if ( $channel === null ) {
373  $this->cleanupChanneled();
374  print $out;
375  } else {
376  $out = preg_replace( '/\n\z/', '', $out );
377  $this->outputChanneled( $out, $channel );
378  }
379  }
380 
387  protected function error( $err, $die = 0 ) {
388  $this->outputChanneled( false );
389  if ( PHP_SAPI == 'cli' ) {
390  fwrite( STDERR, $err . "\n" );
391  } else {
392  print $err;
393  }
394  $die = intval( $die );
395  if ( $die > 0 ) {
396  die( $die );
397  }
398  }
399 
400  private $atLineStart = true;
401  private $lastChannel = null;
402 
406  public function cleanupChanneled() {
407  if ( !$this->atLineStart ) {
408  print "\n";
409  $this->atLineStart = true;
410  }
411  }
412 
421  public function outputChanneled( $msg, $channel = null ) {
422  if ( $msg === false ) {
423  $this->cleanupChanneled();
424 
425  return;
426  }
427 
428  // End the current line if necessary
429  if ( !$this->atLineStart && $channel !== $this->lastChannel ) {
430  print "\n";
431  }
432 
433  print $msg;
434 
435  $this->atLineStart = false;
436  if ( $channel === null ) {
437  // For unchanneled messages, output trailing newline immediately
438  print "\n";
439  $this->atLineStart = true;
440  }
441  $this->lastChannel = $channel;
442  }
443 
454  public function getDbType() {
455  return Maintenance::DB_STD;
456  }
457 
461  protected function addDefaultParams() {
462 
463  # Generic (non script dependant) options:
464 
465  $this->addOption( 'help', 'Display this help message', false, false, 'h' );
466  $this->addOption( 'quiet', 'Whether to supress non-error output', false, false, 'q' );
467  $this->addOption( 'conf', 'Location of LocalSettings.php, if not default', false, true );
468  $this->addOption( 'wiki', 'For specifying the wiki ID', false, true );
469  $this->addOption( 'globals', 'Output globals at the end of processing for debugging' );
470  $this->addOption(
471  'memory-limit',
472  'Set a specific memory limit for the script, '
473  . '"max" for no limit or "default" to avoid changing it'
474  );
475  $this->addOption( 'server', "The protocol and server name to use in URLs, e.g. " .
476  "http://en.wikipedia.org. This is sometimes necessary because " .
477  "server name detection may fail in command line scripts.", false, true );
478  $this->addOption( 'profiler', 'Profiler output format (usually "text")', false, true );
479 
480  # Save generic options to display them separately in help
481  $this->mGenericParameters = $this->mParams;
482 
483  # Script dependant options:
484 
485  // If we support a DB, show the options
486  if ( $this->getDbType() > 0 ) {
487  $this->addOption( 'dbuser', 'The DB user to use for this script', false, true );
488  $this->addOption( 'dbpass', 'The password to use for this script', false, true );
489  }
490 
491  # Save additional script dependant options to display
492  #  them separately in help
493  $this->mDependantParameters = array_diff_key( $this->mParams, $this->mGenericParameters );
494  }
495 
500  public function getConfig() {
501  if ( $this->config === null ) {
502  $this->config = ConfigFactory::getDefaultInstance()->makeConfig( 'main' );
503  }
504 
505  return $this->config;
506  }
507 
512  public function setConfig( Config $config ) {
513  $this->config = $config;
514  }
515 
525  protected function requireExtension( $name ) {
526  $this->requiredExtensions[] = $name;
527  }
528 
534  public function checkRequiredExtensions() {
535  $registry = ExtensionRegistry::getInstance();
536  $missing = [];
537  foreach ( $this->requiredExtensions as $name ) {
538  if ( !$registry->isLoaded( $name ) ) {
539  $missing[] = $name;
540  }
541  }
542 
543  if ( $missing ) {
544  $joined = implode( ', ', $missing );
545  $msg = "The following extensions are required to be installed "
546  . "for this script to run: $joined. Please enable them and then try again.";
547  $this->error( $msg, 1 );
548  }
549 
550  }
551 
556  public function setAgentAndTriggers() {
557  if ( function_exists( 'posix_getpwuid' ) ) {
558  $agent = posix_getpwuid( posix_geteuid() )['name'];
559  } else {
560  $agent = 'sysadmin';
561  }
562  $agent .= '@' . wfHostname();
563 
564  $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
565  // Add a comment for easy SHOW PROCESSLIST interpretation
566  $lbFactory->setAgentName(
567  mb_strlen( $agent ) > 15 ? mb_substr( $agent, 0, 15 ) . '...' : $agent
568  );
569  self::setLBFactoryTriggers( $lbFactory );
570  }
571 
576  public static function setLBFactoryTriggers( LBFactory $LBFactory ) {
577  // Hook into period lag checks which often happen in long-running scripts
578  $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
579  $lbFactory->setWaitForReplicationListener(
580  __METHOD__,
581  function () {
583  // Check config in case of JobRunner and unit tests
584  if ( $wgCommandLineMode ) {
586  }
587  }
588  );
589  // Check for other windows to run them. A script may read or do a few writes
590  // to the master but mostly be writing to something else, like a file store.
591  $lbFactory->getMainLB()->setTransactionListener(
592  __METHOD__,
593  function ( $trigger ) {
595  // Check config in case of JobRunner and unit tests
596  if ( $wgCommandLineMode && $trigger === IDatabase::TRIGGER_COMMIT ) {
598  }
599  }
600  );
601  }
602 
610  public function runChild( $maintClass, $classFile = null ) {
611  // Make sure the class is loaded first
612  if ( !class_exists( $maintClass ) ) {
613  if ( $classFile ) {
614  require_once $classFile;
615  }
616  if ( !class_exists( $maintClass ) ) {
617  $this->error( "Cannot spawn child: $maintClass" );
618  }
619  }
620 
624  $child = new $maintClass();
625  $child->loadParamsAndArgs( $this->mSelf, $this->mOptions, $this->mArgs );
626  if ( !is_null( $this->mDb ) ) {
627  $child->setDB( $this->mDb );
628  }
629 
630  return $child;
631  }
632 
636  public function setup() {
638 
639  # Abort if called from a web server
640  if ( isset( $_SERVER ) && isset( $_SERVER['REQUEST_METHOD'] ) ) {
641  $this->error( 'This script must be run from the command line', true );
642  }
643 
644  if ( $IP === null ) {
645  $this->error( "\$IP not set, aborting!\n" .
646  '(Did you forget to call parent::__construct() in your maintenance script?)', 1 );
647  }
648 
649  # Make sure we can handle script parameters
650  if ( !defined( 'HPHP_VERSION' ) && !ini_get( 'register_argc_argv' ) ) {
651  $this->error( 'Cannot get command line arguments, register_argc_argv is set to false', true );
652  }
653 
654  // Send PHP warnings and errors to stderr instead of stdout.
655  // This aids in diagnosing problems, while keeping messages
656  // out of redirected output.
657  if ( ini_get( 'display_errors' ) ) {
658  ini_set( 'display_errors', 'stderr' );
659  }
660 
661  $this->loadParamsAndArgs();
662  $this->maybeHelp();
663 
664  # Set the memory limit
665  # Note we need to set it again later in cache LocalSettings changed it
666  $this->adjustMemoryLimit();
667 
668  # Set max execution time to 0 (no limit). PHP.net says that
669  # "When running PHP from the command line the default setting is 0."
670  # But sometimes this doesn't seem to be the case.
671  ini_set( 'max_execution_time', 0 );
672 
673  $wgRequestTime = microtime( true );
674 
675  # Define us as being in MediaWiki
676  define( 'MEDIAWIKI', true );
677 
678  $wgCommandLineMode = true;
679 
680  # Turn off output buffering if it's on
681  while ( ob_get_level() > 0 ) {
682  ob_end_flush();
683  }
684 
685  $this->validateParamsAndArgs();
686  }
687 
697  public function memoryLimit() {
698  $limit = $this->getOption( 'memory-limit', 'max' );
699  $limit = trim( $limit, "\" '" ); // trim quotes in case someone misunderstood
700  return $limit;
701  }
702 
706  protected function adjustMemoryLimit() {
707  $limit = $this->memoryLimit();
708  if ( $limit == 'max' ) {
709  $limit = -1; // no memory limit
710  }
711  if ( $limit != 'default' ) {
712  ini_set( 'memory_limit', $limit );
713  }
714  }
715 
719  protected function activateProfiler() {
720  global $wgProfiler, $wgProfileLimit, $wgTrxProfilerLimits;
721 
722  $output = $this->getOption( 'profiler' );
723  if ( !$output ) {
724  return;
725  }
726 
727  if ( is_array( $wgProfiler ) && isset( $wgProfiler['class'] ) ) {
728  $class = $wgProfiler['class'];
730  $profiler = new $class(
731  [ 'sampling' => 1, 'output' => [ $output ] ]
732  + $wgProfiler
733  + [ 'threshold' => $wgProfileLimit ]
734  );
735  $profiler->setTemplated( true );
736  Profiler::replaceStubInstance( $profiler );
737  }
738 
739  $trxProfiler = Profiler::instance()->getTransactionProfiler();
740  $trxProfiler->setLogger( LoggerFactory::getInstance( 'DBPerformance' ) );
741  $trxProfiler->setExpectations( $wgTrxProfilerLimits['Maintenance'], __METHOD__ );
742  }
743 
747  public function clearParamsAndArgs() {
748  $this->mOptions = [];
749  $this->mArgs = [];
750  $this->mInputLoaded = false;
751  }
752 
760  public function loadWithArgv( $argv ) {
761  $options = [];
762  $args = [];
763  $this->orderedOptions = [];
764 
765  # Parse arguments
766  for ( $arg = reset( $argv ); $arg !== false; $arg = next( $argv ) ) {
767  if ( $arg == '--' ) {
768  # End of options, remainder should be considered arguments
769  $arg = next( $argv );
770  while ( $arg !== false ) {
771  $args[] = $arg;
772  $arg = next( $argv );
773  }
774  break;
775  } elseif ( substr( $arg, 0, 2 ) == '--' ) {
776  # Long options
777  $option = substr( $arg, 2 );
778  if ( isset( $this->mParams[$option] ) && $this->mParams[$option]['withArg'] ) {
779  $param = next( $argv );
780  if ( $param === false ) {
781  $this->error( "\nERROR: $option parameter needs a value after it\n" );
782  $this->maybeHelp( true );
783  }
784 
785  $this->setParam( $options, $option, $param );
786  } else {
787  $bits = explode( '=', $option, 2 );
788  if ( count( $bits ) > 1 ) {
789  $option = $bits[0];
790  $param = $bits[1];
791  } else {
792  $param = 1;
793  }
794 
795  $this->setParam( $options, $option, $param );
796  }
797  } elseif ( $arg == '-' ) {
798  # Lonely "-", often used to indicate stdin or stdout.
799  $args[] = $arg;
800  } elseif ( substr( $arg, 0, 1 ) == '-' ) {
801  # Short options
802  $argLength = strlen( $arg );
803  for ( $p = 1; $p < $argLength; $p++ ) {
804  $option = $arg[$p];
805  if ( !isset( $this->mParams[$option] ) && isset( $this->mShortParamsMap[$option] ) ) {
806  $option = $this->mShortParamsMap[$option];
807  }
808 
809  if ( isset( $this->mParams[$option]['withArg'] ) && $this->mParams[$option]['withArg'] ) {
810  $param = next( $argv );
811  if ( $param === false ) {
812  $this->error( "\nERROR: $option parameter needs a value after it\n" );
813  $this->maybeHelp( true );
814  }
815  $this->setParam( $options, $option, $param );
816  } else {
817  $this->setParam( $options, $option, 1 );
818  }
819  }
820  } else {
821  $args[] = $arg;
822  }
823  }
824 
825  $this->mOptions = $options;
826  $this->mArgs = $args;
827  $this->loadSpecialVars();
828  $this->mInputLoaded = true;
829  }
830 
843  private function setParam( &$options, $option, $value ) {
844  $this->orderedOptions[] = [ $option, $value ];
845 
846  if ( isset( $this->mParams[$option] ) ) {
847  $multi = $this->mParams[$option]['multiOccurrence'];
848  } else {
849  $multi = false;
850  }
851  $exists = array_key_exists( $option, $options );
852  if ( $multi && $exists ) {
853  $options[$option][] = $value;
854  } elseif ( $multi ) {
855  $options[$option] = [ $value ];
856  } elseif ( !$exists ) {
857  $options[$option] = $value;
858  } else {
859  $this->error( "\nERROR: $option parameter given twice\n" );
860  $this->maybeHelp( true );
861  }
862  }
863 
873  public function loadParamsAndArgs( $self = null, $opts = null, $args = null ) {
874  # If we were given opts or args, set those and return early
875  if ( $self ) {
876  $this->mSelf = $self;
877  $this->mInputLoaded = true;
878  }
879  if ( $opts ) {
880  $this->mOptions = $opts;
881  $this->mInputLoaded = true;
882  }
883  if ( $args ) {
884  $this->mArgs = $args;
885  $this->mInputLoaded = true;
886  }
887 
888  # If we've already loaded input (either by user values or from $argv)
889  # skip on loading it again. The array_shift() will corrupt values if
890  # it's run again and again
891  if ( $this->mInputLoaded ) {
892  $this->loadSpecialVars();
893 
894  return;
895  }
896 
897  global $argv;
898  $this->mSelf = $argv[0];
899  $this->loadWithArgv( array_slice( $argv, 1 ) );
900  }
901 
905  protected function validateParamsAndArgs() {
906  $die = false;
907  # Check to make sure we've got all the required options
908  foreach ( $this->mParams as $opt => $info ) {
909  if ( $info['require'] && !$this->hasOption( $opt ) ) {
910  $this->error( "Param $opt required!" );
911  $die = true;
912  }
913  }
914  # Check arg list too
915  foreach ( $this->mArgList as $k => $info ) {
916  if ( $info['require'] && !$this->hasArg( $k ) ) {
917  $this->error( 'Argument <' . $info['name'] . '> required!' );
918  $die = true;
919  }
920  }
921 
922  if ( $die ) {
923  $this->maybeHelp( true );
924  }
925  }
926 
930  protected function loadSpecialVars() {
931  if ( $this->hasOption( 'dbuser' ) ) {
932  $this->mDbUser = $this->getOption( 'dbuser' );
933  }
934  if ( $this->hasOption( 'dbpass' ) ) {
935  $this->mDbPass = $this->getOption( 'dbpass' );
936  }
937  if ( $this->hasOption( 'quiet' ) ) {
938  $this->mQuiet = true;
939  }
940  if ( $this->hasOption( 'batch-size' ) ) {
941  $this->mBatchSize = intval( $this->getOption( 'batch-size' ) );
942  }
943  }
944 
949  protected function maybeHelp( $force = false ) {
950  if ( !$force && !$this->hasOption( 'help' ) ) {
951  return;
952  }
953 
954  $screenWidth = 80; // TODO: Calculate this!
955  $tab = " ";
956  $descWidth = $screenWidth - ( 2 * strlen( $tab ) );
957 
958  ksort( $this->mParams );
959  $this->mQuiet = false;
960 
961  // Description ...
962  if ( $this->mDescription ) {
963  $this->output( "\n" . wordwrap( $this->mDescription, $screenWidth ) . "\n" );
964  }
965  $output = "\nUsage: php " . basename( $this->mSelf );
966 
967  // ... append parameters ...
968  if ( $this->mParams ) {
969  $output .= " [--" . implode( array_keys( $this->mParams ), "|--" ) . "]";
970  }
971 
972  // ... and append arguments.
973  if ( $this->mArgList ) {
974  $output .= ' ';
975  foreach ( $this->mArgList as $k => $arg ) {
976  if ( $arg['require'] ) {
977  $output .= '<' . $arg['name'] . '>';
978  } else {
979  $output .= '[' . $arg['name'] . ']';
980  }
981  if ( $k < count( $this->mArgList ) - 1 ) {
982  $output .= ' ';
983  }
984  }
985  }
986  $this->output( "$output\n\n" );
987 
988  # TODO abstract some repetitive code below
989 
990  // Generic parameters
991  $this->output( "Generic maintenance parameters:\n" );
992  foreach ( $this->mGenericParameters as $par => $info ) {
993  if ( $info['shortName'] !== false ) {
994  $par .= " (-{$info['shortName']})";
995  }
996  $this->output(
997  wordwrap( "$tab--$par: " . $info['desc'], $descWidth,
998  "\n$tab$tab" ) . "\n"
999  );
1000  }
1001  $this->output( "\n" );
1002 
1003  $scriptDependantParams = $this->mDependantParameters;
1004  if ( count( $scriptDependantParams ) > 0 ) {
1005  $this->output( "Script dependant parameters:\n" );
1006  // Parameters description
1007  foreach ( $scriptDependantParams as $par => $info ) {
1008  if ( $info['shortName'] !== false ) {
1009  $par .= " (-{$info['shortName']})";
1010  }
1011  $this->output(
1012  wordwrap( "$tab--$par: " . $info['desc'], $descWidth,
1013  "\n$tab$tab" ) . "\n"
1014  );
1015  }
1016  $this->output( "\n" );
1017  }
1018 
1019  // Script specific parameters not defined on construction by
1020  // Maintenance::addDefaultParams()
1021  $scriptSpecificParams = array_diff_key(
1022  # all script parameters:
1023  $this->mParams,
1024  # remove the Maintenance default parameters:
1025  $this->mGenericParameters,
1026  $this->mDependantParameters
1027  );
1028  if ( count( $scriptSpecificParams ) > 0 ) {
1029  $this->output( "Script specific parameters:\n" );
1030  // Parameters description
1031  foreach ( $scriptSpecificParams as $par => $info ) {
1032  if ( $info['shortName'] !== false ) {
1033  $par .= " (-{$info['shortName']})";
1034  }
1035  $this->output(
1036  wordwrap( "$tab--$par: " . $info['desc'], $descWidth,
1037  "\n$tab$tab" ) . "\n"
1038  );
1039  }
1040  $this->output( "\n" );
1041  }
1042 
1043  // Print arguments
1044  if ( count( $this->mArgList ) > 0 ) {
1045  $this->output( "Arguments:\n" );
1046  // Arguments description
1047  foreach ( $this->mArgList as $info ) {
1048  $openChar = $info['require'] ? '<' : '[';
1049  $closeChar = $info['require'] ? '>' : ']';
1050  $this->output(
1051  wordwrap( "$tab$openChar" . $info['name'] . "$closeChar: " .
1052  $info['desc'], $descWidth, "\n$tab$tab" ) . "\n"
1053  );
1054  }
1055  $this->output( "\n" );
1056  }
1057 
1058  die( 1 );
1059  }
1060 
1064  public function finalSetup() {
1065  global $wgCommandLineMode, $wgShowSQLErrors, $wgServer;
1068 
1069  # Turn off output buffering again, it might have been turned on in the settings files
1070  if ( ob_get_level() ) {
1071  ob_end_flush();
1072  }
1073  # Same with these
1074  $wgCommandLineMode = true;
1075 
1076  # Override $wgServer
1077  if ( $this->hasOption( 'server' ) ) {
1078  $wgServer = $this->getOption( 'server', $wgServer );
1079  }
1080 
1081  # If these were passed, use them
1082  if ( $this->mDbUser ) {
1083  $wgDBadminuser = $this->mDbUser;
1084  }
1085  if ( $this->mDbPass ) {
1086  $wgDBadminpassword = $this->mDbPass;
1087  }
1088 
1089  if ( $this->getDbType() == self::DB_ADMIN && isset( $wgDBadminuser ) ) {
1090  $wgDBuser = $wgDBadminuser;
1091  $wgDBpassword = $wgDBadminpassword;
1092 
1093  if ( $wgDBservers ) {
1097  foreach ( $wgDBservers as $i => $server ) {
1098  $wgDBservers[$i]['user'] = $wgDBuser;
1099  $wgDBservers[$i]['password'] = $wgDBpassword;
1100  }
1101  }
1102  if ( isset( $wgLBFactoryConf['serverTemplate'] ) ) {
1103  $wgLBFactoryConf['serverTemplate']['user'] = $wgDBuser;
1104  $wgLBFactoryConf['serverTemplate']['password'] = $wgDBpassword;
1105  }
1106  MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->destroy();
1107  }
1108 
1109  // Per-script profiling; useful for debugging
1110  $this->activateProfiler();
1111 
1112  $this->afterFinalSetup();
1113 
1114  $wgShowSQLErrors = true;
1115 
1116  MediaWiki\suppressWarnings();
1117  set_time_limit( 0 );
1118  MediaWiki\restoreWarnings();
1119 
1120  $this->adjustMemoryLimit();
1121  }
1122 
1126  protected function afterFinalSetup() {
1127  if ( defined( 'MW_CMDLINE_CALLBACK' ) ) {
1128  call_user_func( MW_CMDLINE_CALLBACK );
1129  }
1130  }
1131 
1136  public function globals() {
1137  if ( $this->hasOption( 'globals' ) ) {
1138  print_r( $GLOBALS );
1139  }
1140  }
1141 
1146  public function loadSettings() {
1148 
1149  if ( isset( $this->mOptions['conf'] ) ) {
1150  $settingsFile = $this->mOptions['conf'];
1151  } elseif ( defined( "MW_CONFIG_FILE" ) ) {
1152  $settingsFile = MW_CONFIG_FILE;
1153  } else {
1154  $settingsFile = "$IP/LocalSettings.php";
1155  }
1156  if ( isset( $this->mOptions['wiki'] ) ) {
1157  $bits = explode( '-', $this->mOptions['wiki'] );
1158  if ( count( $bits ) == 1 ) {
1159  $bits[] = '';
1160  }
1161  define( 'MW_DB', $bits[0] );
1162  define( 'MW_PREFIX', $bits[1] );
1163  }
1164 
1165  if ( !is_readable( $settingsFile ) ) {
1166  $this->error( "A copy of your installation's LocalSettings.php\n" .
1167  "must exist and be readable in the source directory.\n" .
1168  "Use --conf to specify it.", true );
1169  }
1170  $wgCommandLineMode = true;
1171 
1172  return $settingsFile;
1173  }
1174 
1180  public function purgeRedundantText( $delete = true ) {
1181  # Data should come off the master, wrapped in a transaction
1182  $dbw = $this->getDB( DB_MASTER );
1183  $this->beginTransaction( $dbw, __METHOD__ );
1184 
1185  # Get "active" text records from the revisions table
1186  $cur = [];
1187  $this->output( 'Searching for active text records in revisions table...' );
1188  $res = $dbw->select( 'revision', 'rev_text_id', [], __METHOD__, [ 'DISTINCT' ] );
1189  foreach ( $res as $row ) {
1190  $cur[] = $row->rev_text_id;
1191  }
1192  $this->output( "done.\n" );
1193 
1194  # Get "active" text records from the archive table
1195  $this->output( 'Searching for active text records in archive table...' );
1196  $res = $dbw->select( 'archive', 'ar_text_id', [], __METHOD__, [ 'DISTINCT' ] );
1197  foreach ( $res as $row ) {
1198  # old pre-MW 1.5 records can have null ar_text_id's.
1199  if ( $row->ar_text_id !== null ) {
1200  $cur[] = $row->ar_text_id;
1201  }
1202  }
1203  $this->output( "done.\n" );
1204 
1205  # Get the IDs of all text records not in these sets
1206  $this->output( 'Searching for inactive text records...' );
1207  $cond = 'old_id NOT IN ( ' . $dbw->makeList( $cur ) . ' )';
1208  $res = $dbw->select( 'text', 'old_id', [ $cond ], __METHOD__, [ 'DISTINCT' ] );
1209  $old = [];
1210  foreach ( $res as $row ) {
1211  $old[] = $row->old_id;
1212  }
1213  $this->output( "done.\n" );
1214 
1215  # Inform the user of what we're going to do
1216  $count = count( $old );
1217  $this->output( "$count inactive items found.\n" );
1218 
1219  # Delete as appropriate
1220  if ( $delete && $count ) {
1221  $this->output( 'Deleting...' );
1222  $dbw->delete( 'text', [ 'old_id' => $old ], __METHOD__ );
1223  $this->output( "done.\n" );
1224  }
1225 
1226  # Done
1227  $this->commitTransaction( $dbw, __METHOD__ );
1228  }
1229 
1234  protected function getDir() {
1235  return __DIR__;
1236  }
1237 
1248  protected function getDB( $db, $groups = [], $wiki = false ) {
1249  if ( is_null( $this->mDb ) ) {
1250  return wfGetDB( $db, $groups, $wiki );
1251  } else {
1252  return $this->mDb;
1253  }
1254  }
1255 
1261  public function setDB( IDatabase $db ) {
1262  $this->mDb = $db;
1263  }
1264 
1275  protected function beginTransaction( IDatabase $dbw, $fname ) {
1276  $dbw->begin( $fname );
1277  }
1278 
1290  protected function commitTransaction( IDatabase $dbw, $fname ) {
1291  $dbw->commit( $fname );
1292  try {
1293  $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
1294  $lbFactory->waitForReplication(
1295  [ 'timeout' => 30, 'ifWritesSince' => $this->lastReplicationWait ]
1296  );
1297  $this->lastReplicationWait = microtime( true );
1298 
1299  return true;
1300  } catch ( DBReplicationWaitError $e ) {
1301  return false;
1302  }
1303  }
1304 
1315  protected function rollbackTransaction( IDatabase $dbw, $fname ) {
1316  $dbw->rollback( $fname );
1317  }
1318 
1323  private function lockSearchindex( $db ) {
1324  $write = [ 'searchindex' ];
1325  $read = [
1326  'page',
1327  'revision',
1328  'text',
1329  'interwiki',
1330  'l10n_cache',
1331  'user',
1332  'page_restrictions'
1333  ];
1334  $db->lockTables( $read, $write, __CLASS__ . '::' . __METHOD__ );
1335  }
1336 
1341  private function unlockSearchindex( $db ) {
1342  $db->unlockTables( __CLASS__ . '::' . __METHOD__ );
1343  }
1344 
1350  private function relockSearchindex( $db ) {
1351  $this->unlockSearchindex( $db );
1352  $this->lockSearchindex( $db );
1353  }
1354 
1362  public function updateSearchIndex( $maxLockTime, $callback, $dbw, $results ) {
1363  $lockTime = time();
1364 
1365  # Lock searchindex
1366  if ( $maxLockTime ) {
1367  $this->output( " --- Waiting for lock ---" );
1368  $this->lockSearchindex( $dbw );
1369  $lockTime = time();
1370  $this->output( "\n" );
1371  }
1372 
1373  # Loop through the results and do a search update
1374  foreach ( $results as $row ) {
1375  # Allow reads to be processed
1376  if ( $maxLockTime && time() > $lockTime + $maxLockTime ) {
1377  $this->output( " --- Relocking ---" );
1378  $this->relockSearchindex( $dbw );
1379  $lockTime = time();
1380  $this->output( "\n" );
1381  }
1382  call_user_func( $callback, $dbw, $row );
1383  }
1384 
1385  # Unlock searchindex
1386  if ( $maxLockTime ) {
1387  $this->output( " --- Unlocking --" );
1388  $this->unlockSearchindex( $dbw );
1389  $this->output( "\n" );
1390  }
1391  }
1392 
1399  public function updateSearchIndexForPage( $dbw, $pageId ) {
1400  // Get current revision
1401  $rev = Revision::loadFromPageId( $dbw, $pageId );
1402  $title = null;
1403  if ( $rev ) {
1404  $titleObj = $rev->getTitle();
1405  $title = $titleObj->getPrefixedDBkey();
1406  $this->output( "$title..." );
1407  # Update searchindex
1408  $u = new SearchUpdate( $pageId, $titleObj->getText(), $rev->getContent() );
1409  $u->doUpdate();
1410  $this->output( "\n" );
1411  }
1412 
1413  return $title;
1414  }
1415 
1424  public static function posix_isatty( $fd ) {
1425  if ( !function_exists( 'posix_isatty' ) ) {
1426  return !$fd;
1427  } else {
1428  return posix_isatty( $fd );
1429  }
1430  }
1431 
1437  public static function readconsole( $prompt = '> ' ) {
1438  static $isatty = null;
1439  if ( is_null( $isatty ) ) {
1440  $isatty = self::posix_isatty( 0 /*STDIN*/ );
1441  }
1442 
1443  if ( $isatty && function_exists( 'readline' ) ) {
1444  $resp = readline( $prompt );
1445  if ( $resp === null ) {
1446  // Workaround for https://github.com/facebook/hhvm/issues/4776
1447  return false;
1448  } else {
1449  return $resp;
1450  }
1451  } else {
1452  if ( $isatty ) {
1453  $st = self::readlineEmulation( $prompt );
1454  } else {
1455  if ( feof( STDIN ) ) {
1456  $st = false;
1457  } else {
1458  $st = fgets( STDIN, 1024 );
1459  }
1460  }
1461  if ( $st === false ) {
1462  return false;
1463  }
1464  $resp = trim( $st );
1465 
1466  return $resp;
1467  }
1468  }
1469 
1475  private static function readlineEmulation( $prompt ) {
1476  $bash = Installer::locateExecutableInDefaultPaths( [ 'bash' ] );
1477  if ( !wfIsWindows() && $bash ) {
1478  $retval = false;
1479  $encPrompt = wfEscapeShellArg( $prompt );
1480  $command = "read -er -p $encPrompt && echo \"\$REPLY\"";
1481  $encCommand = wfEscapeShellArg( $command );
1482  $line = wfShellExec( "$bash -c $encCommand", $retval, [], [ 'walltime' => 0 ] );
1483 
1484  if ( $retval == 0 ) {
1485  return $line;
1486  } elseif ( $retval == 127 ) {
1487  // Couldn't execute bash even though we thought we saw it.
1488  // Shell probably spit out an error message, sorry :(
1489  // Fall through to fgets()...
1490  } else {
1491  // EOF/ctrl+D
1492  return false;
1493  }
1494  }
1495 
1496  // Fallback... we'll have no editing controls, EWWW
1497  if ( feof( STDIN ) ) {
1498  return false;
1499  }
1500  print $prompt;
1501 
1502  return fgets( STDIN, 1024 );
1503  }
1504 
1509  public static function requireTestsAutoloader() {
1510  require_once __DIR__ . '/../tests/common/TestsAutoLoader.php';
1511  }
1512 }
1513 
1518  protected $mSelf = "FakeMaintenanceScript";
1519 
1520  public function execute() {
1521  return;
1522  }
1523 }
1524 
1529 abstract class LoggedUpdateMaintenance extends Maintenance {
1530  public function __construct() {
1531  parent::__construct();
1532  $this->addOption( 'force', 'Run the update even if it was completed already' );
1533  $this->setBatchSize( 200 );
1534  }
1535 
1536  public function execute() {
1537  $db = $this->getDB( DB_MASTER );
1538  $key = $this->getUpdateKey();
1539 
1540  if ( !$this->hasOption( 'force' )
1541  && $db->selectRow( 'updatelog', '1', [ 'ul_key' => $key ], __METHOD__ )
1542  ) {
1543  $this->output( "..." . $this->updateSkippedMessage() . "\n" );
1544 
1545  return true;
1546  }
1547 
1548  if ( !$this->doDBUpdates() ) {
1549  return false;
1550  }
1551 
1552  if ( $db->insert( 'updatelog', [ 'ul_key' => $key ], __METHOD__, 'IGNORE' ) ) {
1553  return true;
1554  } else {
1555  $this->output( $this->updatelogFailedMessage() . "\n" );
1556 
1557  return false;
1558  }
1559  }
1560 
1565  protected function updateSkippedMessage() {
1566  $key = $this->getUpdateKey();
1567 
1568  return "Update '{$key}' already logged as completed.";
1569  }
1570 
1575  protected function updatelogFailedMessage() {
1576  $key = $this->getUpdateKey();
1577 
1578  return "Unable to log update '{$key}' as completed.";
1579  }
1580 
1586  abstract protected function doDBUpdates();
1587 
1592  abstract protected function getUpdateKey();
1593 }
#define the
table suitable for use with IDatabase::select()
unlockSearchindex($db)
Unlock the tables.
loadParamsAndArgs($self=null, $opts=null, $args=null)
Process command line arguments $mOptions becomes an array with keys set to the option names $mArgs be...
commitTransaction(IDatabase $dbw, $fname)
Commit the transcation on a DB handle and wait for replica DBs to catch up.
wfGetDB($db, $groups=[], $wiki=false)
Get a Database object.
const STDIN_ALL
Definition: Maintenance.php:62
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:802
const DB_NONE
Constants for DB access type.
Definition: Maintenance.php:57
const RUN_MAINTENANCE_IF_MAIN
Definition: Maintenance.php:34
checkRequiredExtensions()
Verify that the required extensions are installed.
static setLBFactoryTriggers(LBFactory $LBFactory)
setParam(&$options, $option, $value)
Helper function used solely by loadParamsAndArgs to prevent code duplication.
$IP
Definition: WebStart.php:58
$wgDBadminpassword
Separate password for maintenance tasks.
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
addArg($arg, $description, $required=true)
Add some args that are needed.
getDir()
Get the maintenance directory.
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException'returning false will NOT prevent logging $e
Definition: hooks.txt:2102
array $orderedOptions
Used to read the options in the order they were passed.
$command
Definition: cdb.php:65
static instance()
Singleton.
Definition: Profiler.php:61
$wgDBpassword
Database user's password.
wfHostname()
Fetch server name for use in error reporting etc.
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
Definition: maintenance.txt:39
getName()
Get the script's name.
doUpdate()
Perform actual update for the entry.
$wgProfiler
Definition: WebStart.php:73
addDefaultParams()
Add the default parameters to the scripts.
finalSetup()
Handle some last-minute setup here.
rollbackTransaction(IDatabase $dbw, $fname)
Rollback the transcation on a DB handle.
lockSearchindex($db)
Lock the search index.
afterFinalSetup()
Execute a callback function at the end of initialisation.
$value
Database $mDb
Used by getDB() / setDB()
setConfig(Config $config)
getDB($db, $groups=[], $wiki=false)
Returns a database to be used by current maintenance script.
hasOption($name)
Checks to see if a particular param exists.
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
$wgDBuser
Database username.
static locateExecutableInDefaultPaths($names, $versionInfo=false)
Same as locateExecutable(), but checks in getPossibleBinPaths() by default.
Definition: Installer.php:1235
loadSpecialVars()
Handle the special variables that are global to all scripts.
wfShellExec($cmd, &$retval=null, $environ=[], $limits=[], $options=[])
Execute a shell command, with time and memory limits mirrored from the PHP configuration if supported...
static tryOpportunisticExecute($mode= 'run')
Run all deferred updates immediately if there are no DB writes active.
when a variable name is used in a it is silently declared as a new local masking the global
Definition: design.txt:93
wfIsWindows()
Check if the operating system is Windows.
static posix_isatty($fd)
Wrapper for posix_isatty() We default as considering stdin a tty (for nice readline methods) but trea...
const DB_MASTER
Definition: defines.php:23
array $requiredExtensions
getStdin($len=null)
Return input from stdin.
$maintClass
Definition: Maintenance.php:37
if($line===false) $args
Definition: cdb.php:64
cleanupChanneled()
Clean up channeled output.
static replaceStubInstance(Profiler $profiler)
Replace the current profiler with $profiler if no non-stub profiler is set.
Definition: Profiler.php:96
Database independant search index updater.
updatelogFailedMessage()
Message to show that the update log was unable to log the completion of this update.
Fake maintenance wrapper, mostly used for the web installer/updater.
activateProfiler()
Activate the profiler (assuming $wgProfiler is set)
addOption($name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
global $wgCommandLineMode
Definition: Setup.php:495
static requireTestsAutoloader()
Call this to set up the autoloader to allow classes to be used from the tests directory.
Exception class for replica DB wait timeouts.
$GLOBALS['IP']
deleteOption($name)
Remove an option.
doDBUpdates()
Do the actual work.
updateSearchIndex($maxLockTime, $callback, $dbw, $results)
Perform a search index update with locking.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context $options
Definition: hooks.txt:1046
relockSearchindex($db)
Unlock and lock again Since the lock is low-priority, queued reads will be able to complete...
$self
$res
Definition: database.txt:21
float $lastReplicationWait
UNIX timestamp.
const DB_ADMIN
Definition: Maintenance.php:59
setup()
Do some sanity checking and basic setup.
setDB(IDatabase $db)
Sets database object to be returned by getDB().
clearParamsAndArgs()
Clear all params and arguments.
hasArg($argId=0)
Does a given argument exist?
$wgDBservers
Database load balancer This is a two-dimensional array, an array of server info structures Fields are...
globals()
Potentially debug globals.
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:953
adjustMemoryLimit()
Adjusts PHP's memory limit to better suit our needs, if needed.
getUpdateKey()
Get the update key name to go in the update log table.
requireExtension($name)
Indicate that the specified extension must be loaded before the script can run.
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:1721
resource $fileHandle
Used when creating separate schema files.
addDescription($text)
Set the description text.
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
getOption($name, $default=null)
Get an option, or return the default.
static shouldExecute()
Should we execute the maintenance script, or just allow it to be included as a standalone class...
output($out, $channel=null)
Throw some output to the user.
purgeRedundantText($delete=true)
Support function for cleaning up redundant text records.
begin($fname=__METHOD__, $mode=self::TRANSACTION_EXPLICIT)
Begin a transaction.
const DB_STD
Definition: Maintenance.php:58
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context the output can only depend on parameters provided to this hook not on global state indicating whether full HTML should be generated If generation of HTML may be but other information should still be present in the ParserOutput object & $output
Definition: hooks.txt:1046
static getDefaultInstance()
commit($fname=__METHOD__, $flush= '')
Commits a transaction previously started using begin().
loadWithArgv($argv)
Load params and arguments from a given array of command-line arguments.
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
maybeHelp($force=false)
Maybe show the help.
$lbFactory
if(!defined( 'MEDIAWIKI')) $fname
This file is not a valid entry point, perform no further processing unless MEDIAWIKI is defined...
Definition: Setup.php:36
Class for scripts that perform database maintenance and want to log the update in updatelog so we can...
$wgDBadminuser
Separate username for maintenance tasks.
static readconsole($prompt= '> ')
Prompt the console for input.
static readlineEmulation($prompt)
Emulate readline()
memoryLimit()
Normally we disable the memory_limit when running admin scripts.
int $mBatchSize
Batch size.
Definition: Maintenance.php:98
$line
Definition: cdb.php:59
setAgentAndTriggers()
Set triggers like when to try to run deferred updates.
error($err, $die=0)
Throw an error to the user.
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
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context the output can only depend on parameters provided to this hook not on global state indicating whether full HTML should be generated If generation of HTML may be but other information should still be present in the ParserOutput object to manipulate or replace but no entry for that model exists in $wgContentHandlers if desired whether it is OK to use $contentModel on $title Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok inclusive $limit
Definition: hooks.txt:1046
wfEntryPointCheck($entryPoint)
Check php version and that external dependencies are installed, and display an informative error if e...
updateSearchIndexForPage($dbw, $pageId)
Update the searchindex table for a given pageid.
updateSkippedMessage()
Message to show that the update was done already and was just skipped.
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
$count
wfEscapeShellArg()
Version of escapeshellarg() that works better on Windows.
$wgServer
URL of the server.
getArg($argId=0, $default=null)
Get an argument.
$wgLBFactoryConf
Load balancer factory configuration To set up a multi-master wiki farm, set the class here to somethi...
loadSettings()
Generic setup for most installs.
rollback($fname=__METHOD__, $flush= '')
Rollback a transaction previously started using begin().
setBatchSize($s=0)
Set the batch size.
float $wgRequestTime
Request start time as fractional seconds since epoch.
Definition: WebStart.php:43
validateParamsAndArgs()
Run some validation checks on the params, etc.
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 local account incomplete not yet checked for validity & $retval
Definition: hooks.txt:242
Config $config
Accessible via getConfig()
runChild($maintClass, $classFile=null)
Run a child maintenance script.
outputChanneled($msg, $channel=null)
Message outputter with channeled message support.
getDbType()
Does the script need different DB access? By default, we give Maintenance scripts normal rights to th...
public function execute()
Definition: maintenance.txt:45
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:34
__construct()
Default constructor.
beginTransaction(IDatabase $dbw, $fname)
Begin a transcation on a DB.
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:300