32$IP = getenv(
"MW_INSTALL_PATH" ) ?: __DIR__ .
"/../../..";
33if ( !is_readable(
"$IP/maintenance/Maintenance.php" ) ) {
34 die(
"MW_INSTALL_PATH needs to be set to your MediaWiki installation.\n" );
36require_once (
"$IP/maintenance/Maintenance.php" );
60 parent::__construct();
61 $this->
addDescription(
"CLI utility to replace text wherever it is " .
62 "found in the wiki." );
64 $this->
addArg(
"target",
"Target text to find.",
false );
65 $this->
addArg(
"replace",
"Text to replace.",
false );
67 $this->
addOption(
"dry-run",
"Only find the texts, don't replace.",
69 $this->
addOption(
"regex",
"This is a regex (false).",
71 $this->
addOption(
"user",
"The user to attribute this to (uid 1).",
73 $this->
addOption(
"yes",
"Skip all prompts with an assumed 'yes'.",
75 $this->
addOption(
"summary",
"Alternate edit summary. (%r is where to " .
76 " place the replacement text, %f the text to look for.)",
78 $this->
addOption(
"nsall",
"Search all canonical namespaces (false). " .
79 "If true, this option overrides the ns option.",
false,
false,
'a' );
80 $this->
addOption(
"ns",
"Comma separated namespaces to search in " .
81 "(Main) .",
false,
true );
82 $this->
addOption(
"replacements",
"File containing the list of " .
83 "replacements to be made. Fields in the file are tab-separated. " .
84 "See --show-file-format for more information.",
false,
true,
"f" );
85 $this->
addOption(
"show-file-format",
"Show a description of the " .
86 "file format to use with --replacements.",
false,
false );
87 $this->
addOption(
"no-announce",
"Do not announce edits on Special:RecentChanges or " .
88 "watchlists.",
false,
false,
"m" );
89 $this->
addOption(
"debug",
"Display replacements being made.",
false,
false );
90 $this->
addOption(
"listns",
"List out the namespaces on this wiki.",
92 $this->
addOption(
'rename',
"Rename page titles instead of replacing contents.",
96 if ( method_exists( $this,
'requireExtension' ) ) {
102 $userReplacing = $this->
getOption(
"user", 1 );
104 $user = is_numeric( $userReplacing ) ?
105 User::newFromId( $userReplacing ) :
106 User::newFromName( $userReplacing );
108 if ( get_class(
$user ) !==
'User' ) {
110 "Couldn't translate '$userReplacing' to a user.",
true
118 $ret = $this->
getArg( 0 );
120 $this->
error(
"You have to specify a target.",
true );
126 $ret = $this->
getArg( 1 );
128 $this->
error(
"You have to specify replacement text.",
true );
139 if ( !is_readable(
$file ) ) {
140 throw new MWException(
"File does not exist or is not readable: "
144 $handle = fopen(
$file,
"r" );
145 if ( $handle ===
false ) {
146 throw new MWException(
"Trouble opening file: $file\n" );
150 $this->defaultContinue =
true;
152 while ( (
$line = fgets( $handle ) ) !==
false ) {
154 $field = explode(
"\t", substr(
$line, 0, -1 ) );
155 if ( !isset( $field[1] ) ) {
159 $this->target[] = $field[0];
160 $this->replacement[] = $field[1];
167 if ( !is_bool( $this->defaultContinue ) ) {
168 $this->defaultContinue =
179 if ( $this->
getOption(
"summary" ) !==
null ) {
180 $msg = str_replace( [
'%f',
'%r' ],
181 [ $this->target, $this->replacement ],
188 echo
"Index\tNamespace\n";
191 foreach ( $nsList as $int => $val ) {
195 echo
" $int\t$val\n";
202The format of the replacements file is tab separated with three fields.
203Any line that does not have a tab is ignored and can be considered a comment.
207 1. String to search
for.
208 2. String to replace found text with.
209 3. (optional) The presence of
this field indicates that the previous two
210 are considered a regular expression.
216regex(p*) Count the Ps; \\1
true
225 if ( !$nsall && !$ns ) {
234 if ( is_numeric( $n ) ) {
235 if ( isset( $canonical[ $n ] ) ) {
244 }, explode(
",", $ns ) );
248 return $val !==
null;
276 $this->
output(
"$title -> $newTitle\n" );
289 'user_id' => $this->user->getId(),
295 $params[
'move_page' ] =
true;
296 $params[
'create_redirect' ] =
false;
297 $params[
'watch_page' ] =
false;
300 echo
"Replacing on $title... ";
302 if (
$job->run() !==
true ) {
303 $this->
error(
"Trouble on the page '$title'." );
314 while ( $reply !==
"y" && $reply !==
"n" ) {
316 $reply = substr( strtolower( $reply ), 0, 1 );
318 return $reply ===
"y";
326 if ( $this->
getOption(
"show-file-format" ) ) {
330 $this->user = $this->
getUser();
351 $this->doAnnounce =
true;
356 if ( $this->namespaces === [] ) {
357 $this->
error(
"No matching namespaces.",
true );
360 foreach ( array_keys( $this->target ) as $index ) {
361 $target = $this->target[$index];
366 echo
"Replacing '$target' with '$replacement'";
368 echo
" as regular expression.";
373 if ( $this->rename ) {
393 if ( count(
$titles ) === 0 ) {
394 $this->
error(
'No targets found to replace.',
true );
406 if ( !$this->
getReply(
'Replace instances on these pages?' ) ) {
412 if ( $this->
getOption(
"user",
null ) ===
null ) {
413 $comment =
" (Use --user to override)";
415 if ( $this->
getOption(
"no-announce",
false ) ) {
416 $this->doAnnounce =
false;
419 "Attribute changes to the user '{$this->user}'?$comment"
$wgShowExceptionDetails
If set to true, uncaught exceptions will print the exception message and a complete stack trace to ou...
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
const RUN_MAINTENANCE_IF_MAIN
static getCanonicalNamespaces()
Returns array of all defined namespaces with their canonical (English) names.
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
error( $err, $die=0)
Throw an error to the user.
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.
output( $out, $channel=null)
Throw some output to the user.
hasOption( $name)
Checks to see if a particular option exists.
static readconsole( $prompt='> ')
Prompt the console for input.
getArg( $argId=0, $default=null)
Get an argument.
addDescription( $text)
Set the description text.
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
getOption( $name, $default=null)
Get an option, or return the default.
Maintenance script that replaces text in pages.
listTitles( $titles, $target, $replacement, $regex, $rename)
__construct()
Default constructor.
getSummary( $target, $replacement)
execute()
Do the actual work.All child classes will need to implement thisbool|null|void True for success,...
shouldContinueByDefault()
replaceTitles( $titles, $target, $replacement, $useRegex, $rename)
Background job to replace text in a given page.
static doSearchQuery( $search, $namespaces, $category, $prefix, $use_regex=false)
static getReplacedTitle(Title $title, $search, $replacement, $regex)
Do a replacement on a title.
static getMatchingTitles( $str, $namespaces, $category, $prefix, $use_regex=false)
if(count( $args)< 1) $job
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.