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