TL;DR:如何向每个页面的内容(而不是标题或全局模板)添加文本(通知)?
(非常)长的问题,背景如下:我计划将 MediaWiki 迁移到另一个 wiki。该 wiki 的内容之前已从一个更旧的 wiki 迁移过来(其中产生了格式错误),随着时间的推移,内容不断增长,现在大部分内容已经过时。这就是为什么我们要从一个空白 wiki 开始,手动迁移内容,丢弃和/或更新过时的页面。
为了简化此过程,我想在每个现有页面的顶部添加一个文本块,具体来说是一个模板,其中有一条通知,指出该页面尚未迁移或丢弃,以及收集所有这些页面的类别(例如 category:migration_pending)。然后,每个用户都应该查看他负责的页面,将内容复制到新 wiki,并将模板更改为另一个模板,将页面标记为已迁移(category:migration_done)或已丢弃(category:migration_discarded)。这样,就可以获得一个干净、最新的 wiki,而不会遗漏任何重要内容。
答案1
Replace_Text 扩展失败了,所以我最终编写了自己的使用 MediaWiki API 的脚本。
我开始从这里登录脚本并写了这个脚本:
#!/usr/bin/php
<?php
$settings['wikiroot'] = "https://server/mediawiki";
$settings['user'] = "username";
$settings['pass'] = "password";
// $settings['domain'] = 'Windows';
$settings['cookiefile'] = "cookies.tmp";
$prepend = "{{migration_pending}}\n\n";
function httpRequest($url, $post="") {
global $settings;
$ch = curl_init();
//Change the user agent below suitably
curl_setopt($ch, CURLOPT_USERAGENT, 'MediaWiki Migration Script 0.1');
curl_setopt($ch, CURLOPT_URL, ($url));
curl_setopt($ch, CURLOPT_ENCODING, "UTF-8" );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, $settings['cookiefile']);
curl_setopt($ch, CURLOPT_COOKIEJAR, $settings['cookiefile']);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
if (!empty($post)) curl_setopt($ch,CURLOPT_POSTFIELDS,$post);
//UNCOMMENT TO DEBUG TO output.tmp
//curl_setopt($ch, CURLOPT_VERBOSE, true); // Display communication with server
//$fp = fopen("output.tmp", "w");
//curl_setopt($ch, CURLOPT_STDERR, $fp); // Display communication with server
$xml = curl_exec($ch);
if (!$xml) {
throw new Exception("Error getting data from server ($url): " . curl_error($ch));
}
//var_dump($xml);
curl_close($ch);
return $xml;
}
function login ($user, $pass, $token='') {
global $settings;
$url = $settings['wikiroot'] . "/api.php?action=login&format=xml";
$params = "action=login&lgname=$user&lgpassword=$pass";
if (!empty($settings['domain'])) {
$params .= "&lgdomain=" . $settings['domain'];
}
if (!empty($token)) {
$params .= "&lgtoken=$token";
}
$data = httpRequest($url, $params);
if (empty($data)) {
throw new Exception("No data received from server. Check that API is enabled.");
}
$xml = simplexml_load_string($data);
if (!empty($token)) {
//Check for successful login
$expr = "/api/login[@result='Success']";
$result = $xml->xpath($expr);
if(!count($result)) {
throw new Exception("Login failed");
}
} else {
$expr = "/api/login[@token]";
$result = $xml->xpath($expr);
if(!count($result)) {
throw new Exception("Login token not found in XML");
}
}
return $result[0]->attributes()->token;
}
try {
global $settings;
$token = login($settings['user'], $settings['pass']);
login($settings['user'], $settings['pass'], $token);
$star = "*";
$dash1 = "-1";
// get edit token
$result = httpRequest($settings['wikiroot'] . "/api.php?action=query&format=json&prop=info|revisions&intoken=edit&titles=Main%20Page");
$result = json_decode($result);
$editToken = $result->query->pages->$dash1->edittoken;
// only from namespace: apnamespace=100
$result = httpRequest($settings['wikiroot'] . "/api.php?action=query&list=allpages&format=json&aplimit=5000&apnamespace=100");
$result = json_decode($result);
$allpages = $result->query->allpages;
foreach ($allpages as $page) {
echo "Fetching '{$page->title}' ({$page->pageid})...\n";
$revisions = httpRequest(sprintf($settings['wikiroot'] . "/api.php?action=query&prop=revisions&rvlimit=1&format=json&rvprop=content&titles=%s", urlencode($page->title)));
$revisions = json_decode($revisions);
if (isset($revisions->error)) {
echo "ERROR: " . $revisions->error->info . "\n";
continue;
}
$content = $revisions->query->pages->{$page->pageid}->revisions[0]->$star;
if (preg_match("/\{\{migration_/", $content)) {
echo "Already marked ... skipping.\n";
continue;
}
echo "Updating...";
// add text to content and edit page
$content = $prepend . $content;
$post = sprintf("title=%s&text=%s&token=%s", urlencode($page->title), urlencode($content), urlencode($editToken));
$result = httpRequest($settings['wikiroot'] . "/api.php?action=edit&format=json", $post);
echo "done\n";
}
echo ("Finished (".sizeof($allpages)." pages).\n");
} catch (Exception $e) {
die("FAILED: " . $e->getMessage());
}
?>
该脚本主要做的事情是:
- 使用现有账户登录
- 获取允许其执行编辑操作的令牌
- 检索给定命名空间内的所有页面的列表
- 对于每一页:
- 获取最新修订版本的内容
- 向内容中添加预定义文本
- 保存包含新内容的页面
一些补充说明:
- 确保您要使用的用户存在并且对所有需要的命名空间具有写权限。
- 将用户添加到“Bot”组。这将消除一些限制,例如,允许 bot 在 5000 个组中执行批量操作,而不是像普通用户那样只能在 500 个组中执行批量操作。不确定这个脚本是否有必要,但它不会有什么坏处。
- 当使用 LdapAuthentication 等身份验证扩展时,
domain
必须设置该参数。并且必须将其设置为姓名LDAP 源的配置方式LocalSettings.php
,而不是域的实际名称。 - 在运行脚本之前禁用电子邮件通知。否则,每个关注 wiki 页面的人都会收到他关注的每个更改页面的通知。对我来说 ,这
$wgEnableEmail = false;
是。$wgEnotifWatchlist = false;
LocalSettings.php
- 我从命令行运行了该脚本,速度不快,处理 1000 多页需要几分钟。如果我通过 Web 服务器运行它,它肯定会超时。
migration_pending
最后,但并非最不重要的一点,我添加到 MediaWiki 的模板:
{|class=warningbox
| [[Image:Emblem-important.png]]
| This page hasn't been audited yet, the information on it could be outdated. If you are responsible for this page, please check it's content. If it is still current, add it to the new wiki and change this template to <nowiki>{{Migration_done}}</nowiki>. If the information on this page is not needed anymore change the template to <nowiki>{{Migration_discarded}}</nowiki>
|}
[[Category:MigrationPending]]
这使用了我们之前使用的表格 CSS 类,并将页面添加到特定类别。我添加了类似的模板以及migration_done
相应migration_discarded
的类别。