mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/ReplaceText
synced 2024-11-15 19:09:27 +00:00
c690bf4627
process, showing the user a list of pages to be replaced among which they can choose.
253 lines
9.1 KiB
PHP
253 lines
9.1 KiB
PHP
<?php
|
|
/**
|
|
* Replace Text - a MediaWiki extension that provides a special page to
|
|
* allow administrators to do a global string find-and-replace on all the
|
|
* content pages of a wiki.
|
|
*
|
|
* http://www.mediawiki.org/wiki/Extension:Text_Replace
|
|
*
|
|
* The special page created is 'Special:ReplaceText', and it provides
|
|
* a form to do a global search-and-replace, with the changes to every
|
|
* page showing up as a wiki edit, with the administrator who performed
|
|
* the replacement as the user, and an edit summary that looks like
|
|
* "Text replace: 'search string' * to 'replacement string'".
|
|
*
|
|
* If the replacement string is blank, or is already found in the wiki,
|
|
* the page provides a warning prompt to the user before doing the
|
|
* replacement, since it is not easily reversible.
|
|
*
|
|
* @version 0.2
|
|
* @author Yaron Koren
|
|
*/
|
|
|
|
if (!defined('MEDIAWIKI')) die();
|
|
|
|
global $IP;
|
|
require_once( "$IP/includes/SpecialPage.php" );
|
|
$grIP = $IP . '/extensions/ReplaceText';
|
|
|
|
$wgExtensionFunctions[] = 'grSetupExtension';
|
|
|
|
if (version_compare($wgVersion, '1.11', '>=')) {
|
|
$wgExtensionMessagesFiles['ReplaceText'] = $grIP . '/ReplaceText.i18n.php';
|
|
} else {
|
|
$wgExtensionFunctions[] = 'grfLoadMessagesManually';
|
|
}
|
|
|
|
$wgJobClasses['replaceText'] = 'ReplaceTextJob';
|
|
|
|
require_once( "$IP/includes/JobQueue.php" );
|
|
require_once($grIP . '/ReplaceTextJob.php');
|
|
|
|
function grSetupExtension() {
|
|
global $wgVersion, $wgExtensionCredits;
|
|
|
|
if (version_compare($wgVersion, '1.11', '>='))
|
|
wfLoadExtensionMessages( 'ReplaceText' );
|
|
|
|
// credits
|
|
$wgExtensionCredits['specialpage'][] = array(
|
|
'name' => 'Replace Text',
|
|
'version' => '0.2',
|
|
'author' => 'Yaron Koren',
|
|
'url' => 'http://www.mediawiki.org/wiki/Extension:Text_Replace',
|
|
'description' => 'A special page that lets administrators run a global search-and-replace',
|
|
'descriptionmsg' => 'replacetext-desc',
|
|
);
|
|
|
|
// the 'delete' specifies that only users who can delete pages
|
|
// (usually, sysops) can access this page
|
|
SpecialPage::addPage(new SpecialPage('ReplaceText', 'delete', true, 'doReplaceText', false));
|
|
}
|
|
|
|
/**
|
|
* Initialize messages - these settings must be applied later on, since
|
|
* the MessageCache does not exist yet when the settings are loaded in
|
|
* LocalSettings.php.
|
|
* Function based on version in ContributionScores extension
|
|
*/
|
|
function grfInitMessages() {
|
|
global $wgVersion, $wgExtensionFunctions;
|
|
}
|
|
|
|
/**
|
|
* Setting of message cache for versions of MediaWiki that do not support
|
|
* wgExtensionFunctions - based on ceContributionScores() in
|
|
* ContributionScores extension
|
|
*/
|
|
function grfLoadMessagesManually() {
|
|
global $grIP, $wgMessageCache;
|
|
|
|
# add messages
|
|
require($grIP . '/ReplaceText.i18n.php');
|
|
foreach($messages as $key => $value) {
|
|
$wgMessageCache->addMessages($messages[$key], $key);
|
|
}
|
|
}
|
|
|
|
function displayConfirmForm($message) {
|
|
global $wgRequest;
|
|
$target_str = $wgRequest->getVal('target_str');
|
|
$replacement_str = $wgRequest->getVal('replacement_str');
|
|
$continue_label = wfMsg('replacetext_continue');
|
|
$cancel_label = wfMsg('replacetext_cancel');
|
|
$text =<<<END
|
|
<form method="post" action="">
|
|
<input type="hidden" name="target_str" value="$target_str">
|
|
<input type="hidden" name="replacement_str" value="$replacement_str">
|
|
<p>$message</p>
|
|
<p><input type="Submit" name="confirm" value="$continue_label"></p>
|
|
<p>$cancel_label</p>
|
|
</form>
|
|
|
|
END;
|
|
return $text;
|
|
}
|
|
|
|
function doReplaceText() {
|
|
global $wgUser, $wgOut, $wgRequest;
|
|
|
|
if ($wgRequest->getCheck('replace')) {
|
|
$target_str = $wgRequest->getVal('target_str');
|
|
$replacement_str = $wgRequest->getVal('replacement_str');
|
|
$replacement_params = array();
|
|
$replacement_params['user_id'] = $wgUser->getId();
|
|
$replacement_params['target_str'] = $target_str;
|
|
$replacement_params['replacement_str'] = $replacement_str;
|
|
$replacement_params['edit_summary'] = wfMsgForContent('replacetext_editsummary', $target_str, $replacement_str);
|
|
foreach ($wgRequest->getValues() as $key => $value) {
|
|
if ($value == 'on') {
|
|
$title = Title::newFromId($key);
|
|
/*
|
|
$num_matches;
|
|
$new_text = str_replace($target_str, $replacement_str, $article_text, $num_matches);
|
|
// if there's at least one replacement, modify the page, using an edit
|
|
// summary in the language of the wiki
|
|
if ($num_matches > 0) {
|
|
$edit_summary = wfMsgForContent('replacetext_editsummary', $target_str, $replacement_str);
|
|
$article->doEdit($new_text, $edit_summary);
|
|
}
|
|
*/
|
|
$jobs[] = new ReplaceTextJob( $title, $replacement_params );
|
|
}
|
|
}
|
|
Job::batchInsert( $jobs );
|
|
$num_modified_pages = count($jobs);
|
|
$wgOut->addHTML(wfMsg('replacetext_success', $target_str, $replacement_str, $num_modified_pages));
|
|
} elseif ($wgRequest->getCheck('target_str')) {
|
|
$dbr =& wfGetDB( DB_SLAVE );
|
|
$fname = 'doReplaceText';
|
|
$target_str = $wgRequest->getVal('target_str');
|
|
$replacement_str = $wgRequest->getVal('replacement_str');
|
|
|
|
// create an array of all the page titles for the wiki
|
|
$res = $dbr->select( 'page',
|
|
array( 'page_title', 'page_namespace' ),
|
|
array( 'page_is_redirect' => false ),
|
|
$fname
|
|
);
|
|
|
|
$titles = array();
|
|
while( $s = $dbr->fetchObject( $res ) ) {
|
|
// ignore pages in Talk and MediaWiki namespaces
|
|
if (($s->page_namespace != NS_TALK) && ($s->page_namespace != NS_MEDIAWIKI)) {
|
|
$title = Title::newFromText($s->page_title, $s->page_namespace);
|
|
$titles[] = $title;
|
|
}
|
|
}
|
|
|
|
if (! $wgRequest->getCheck('confirm')) {
|
|
// display a page to make the user confirm the replacement, if the
|
|
// replacement string is either blank or found elsewhere on the wiki
|
|
// (since undoing the replacement would be difficult in either case)
|
|
if ($replacement_str == '') {
|
|
$text = wfMsg('replacetext_blankwarning');
|
|
$wgOut->addHTML(displayConfirmForm($text));
|
|
return;
|
|
} else {
|
|
$num_pages_with_replacement_str = 0;
|
|
foreach ($titles as $title) {
|
|
$article = new Article($title);
|
|
$article_text = $article->fetchContent();
|
|
if (strpos($article_text, $replacement_str)) {
|
|
$num_pages_with_replacement_str++;
|
|
}
|
|
}
|
|
if ($num_pages_with_replacement_str > 0) {
|
|
$text = wfMsg('replacetext_warning', $num_pages_with_replacement_str, $replacement_str);
|
|
$wgOut->addHTML(displayConfirmForm($text));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
$jobs = array();
|
|
$num_modified_pages = 0;
|
|
$found_titles = array();
|
|
$angle_brackets = array('<', '>');
|
|
$escaped_angle_brackets = array('<', '>');
|
|
foreach ($titles as $title) {
|
|
$article = new Article($title);
|
|
$article_text = $article->fetchContent();
|
|
if ($target_pos = strpos($article_text, $target_str)) {
|
|
$left_padding = min($target_pos, 30);
|
|
$right_padding = min(strlen($article_text) - $target_pos, 30);
|
|
$len = strlen($article_text);
|
|
$context_str = "";
|
|
if ($left_padding == 30)
|
|
$context_str .= "... ";
|
|
$context_str .= str_replace($angle_brackets, $escaped_angle_brackets, substr($article_text, $target_pos - $left_padding, $left_padding)) . "<span class=\"searchmatch\">" . str_replace($angle_brackets, $escaped_angle_brackets, substr($article_text, $target_pos, strlen($target_str))) . "</span>" . str_replace($angle_brackets, $escaped_angle_brackets, substr($article_text, $target_pos + strlen($target_str), $right_padding));
|
|
if ($right_padding == 30)
|
|
$context_str .= " ...";
|
|
$found_titles[] = array($title, $context_str);
|
|
$num_modified_pages++;
|
|
}
|
|
}
|
|
|
|
if ($num_modified_pages == 0)
|
|
$wgOut->addHTML(wfMsg('replacetext_noreplacement', $target_str));
|
|
else {
|
|
$replace_label = wfMsg('replacetext_replace');
|
|
$choose_pages_label = wfMsg('replacetext_choosepages', $target_str, $replacement_str);
|
|
$skin = $wgUser->getSkin();
|
|
$text =<<<END
|
|
<p>$choose_pages_label</p>
|
|
<form method="post">
|
|
<input type="hidden" name="target_str" value="$target_str">
|
|
<input type="hidden" name="replacement_str" value="$replacement_str">
|
|
|
|
END;
|
|
foreach ($found_titles as $value_pair) {
|
|
list($title, $context_str) = $value_pair;
|
|
$text .= "<input type=\"checkbox\" name=\"{$title->getArticleID()}\" checked /> {$skin->makeLinkObj( $title, $title->prefix($title->getText()) )} - <small>$context_str</small><br />\n";
|
|
}
|
|
$text .=<<<END
|
|
<p><input type="Submit" name="replace" value="$replace_label"></p>
|
|
</form>
|
|
|
|
END;
|
|
$wgOut->addHTML($text);
|
|
}
|
|
} else {
|
|
$replacement_label = wfMsg('replacetext_docu');
|
|
$replacement_note = wfMsg('replacetext_note');
|
|
$original_text_label = wfMsg('replacetext_originaltext');
|
|
$replacement_text_label = wfMsg('replacetext_replacementtext');
|
|
$continue_label = wfMsg('replacetext_continue');
|
|
$text =<<<END
|
|
<form method="get" action="">
|
|
<p>$replacement_label</p>
|
|
<p>$replacement_note</p>
|
|
<br />
|
|
<p>$original_text_label: <input type="text" length="10" name="target_str">
|
|
|
|
$replacement_text_label: <input type="text" length="10" name="replacement_str"></p>
|
|
<p><input type="Submit" value="$continue_label"></p>
|
|
</form>
|
|
|
|
END;
|
|
$wgOut->addHTML($text);
|
|
}
|
|
|
|
}
|