Wikipedista:DaBlerBot/src
Vzhled
#!/usr/bin/php
<?php
/*
WikiBot for PHP
VERSION: 2010-10-08
AUTHOR: [[Wikipedista:DaBler]]
TODO:
* co udělat s více <br/> na konci odrážek?
* používat výjimky k hlášení chyb
* interwiki (vysbírat, třidit, uniq, nakonec)
* kategorie (vysbírat, třidit, uniq, nakonec)
* seznam článků k editaci setřídit a uniq
* rozšířit opravy pravopisu
* možnost lokalizace (použití na jiných než cs wiki)
* odstranit prázdné odrážky
* z "; term" odstranit tučné a italiku
* nahradit [http://cs.wikipedia.org/wiki/...] interními odkazy
* nahradit <i> a <b>
*/
class WikiBot
{
private $base;
private $user;
private $pass;
private $token;
private $user_agent;
private $name;
private static $dict = array();
const COOKIEFILE = 'cookies.txt';
const SLEEP = 4;
public function __construct($base='http://cs.wikipedia.org/w/index.php', $user='DaBlerBot', $pass='heslo')
{
$this->base = $base;
$this->user = $user;
$this->pass = $pass;
$this->token = '';
$this->user_agent = 'WikiBot for PHP (bot=cs:User:DaBlerBot, operator=cs:User:DaBler)';
}
public function run($file='cs.txt')
{
echo "Logging into '{$this->base}'...\n";
if(FALSE === $this->login())
{
echo "Login fails, exiting...\n";
return FALSE;
}
echo "Logged in as {$this->user}\n";
echo "Processing articles in file '${file}'...\n";
$list = array();
$fp = fopen($file, 'r');
if($fp)
{
while(!feof($fp))
{
$b = fgets($fp, 4096);
$b = str_replace("\n", '', $b);
$b = str_replace("\r", '', $b);
if($b)
$list[] = $b;
}
fclose($fp);
}
else
{
echo "Warning: no input\n";
}
foreach($list as $name)
{
echo "Loading article '${name}'...\n";
try
{
$page = $this->edit($name);
if(FALSE === $page)
{
echo "Edit fails, exiting...\n";
return FALSE;
}
echo "Processing...\n";
$this->name = $name;
$new = self::process($page['text']);
$page['attr']['wpSummary'] = $new['summary'];
$page['attr']['wpTextbox1'] = $new['text'];
echo "Posting...\n";
if(FALSE === $this->post($page, $name))
{
throw new Exception('Post fails!');
}
}
catch(Exception $e)
{
echo 'Caught exception: ', $e->getMessage(), "\n";
}
echo "OK (sleeping for ".self::SLEEP." seconds)...\n";
sleep(self::SLEEP);
}
echo "Done.\n";
}
private function getToken()
{
$user = urlencode($this->user);
$pass = urlencode($this->pass);
$url = "{$this->base}?title=Special:Userlogin";
$token = urlencode($this->token);
$c = curl_init();
curl_setopt($c, CURLOPT_URL, $url);
curl_setopt($c, CURLOPT_COOKIEJAR, self::COOKIEFILE);
curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_USERAGENT, "WikiBot for PHP (bot=cs:User:DaBlerBot, operator=cs:User:DaBler)");
curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($c, CURLOPT_USERAGENT, $this->user_agent);
$r = curl_exec($c);
if( FALSE === $r)
return FALSE;
$pattern = '/<input .*name="wpLoginToken" .*value="([0-9a-z]+)".*>/';
$matches = array();
preg_match($pattern, $r, $matches);
if( count($matches) != 2)
return FALSE;
$this->token = $matches[1];
return TRUE;
}
private function login()
{
$this->getToken();
$user = urlencode($this->user);
$pass = urlencode($this->pass);
$url = "{$this->base}?title=Special:Userlogin&action=submitlogin&type=login";
$token = urlencode($this->token);
$c = curl_init();
curl_setopt($c, CURLOPT_URL, $url);
curl_setopt($c, CURLOPT_COOKIEJAR, self::COOKIEFILE);
curl_setopt($c, CURLOPT_COOKIEFILE, self::COOKIEFILE);
curl_setopt($c, CURLOPT_POST, TRUE);
curl_setopt($c, CURLOPT_POSTFIELDS, "wpName=${user}&wpLoginAttempt=Log+in&wpPassword=${pass}&wpLoginToken=${token}" );
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_USERAGENT, $this->user_agent);
$r = curl_exec($c);
if( FALSE !== $r && ($r === "" || FALSE !== strpos($r,"wgUserName=\"{$this->user}\"")) )
return TRUE;
else
return FALSE;
}
private function edit($name)
{
$title = rawurlencode(str_replace(' ', '_', $name));
$url = "{$this->base}?title=${title}&action=edit";
$c = curl_init();
curl_setopt($c, CURLOPT_URL, $url);
curl_setopt($c, CURLOPT_COOKIEFILE, self::COOKIEFILE);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_USERAGENT, $this->user_agent);
$r = curl_exec($c);
if(FALSE === $r)
return FALSE;
xml_parse_into_struct(xml_parser_create('UTF-8'), $r, $val, $ind);
$p = strpos($r, '<textarea');
$k = substr($r, $p, strpos($r, '</textarea>') - $p);
$k = substr($k, strpos($k, '>') + 1);
$text = html_entity_decode($k, ENT_QUOTES, 'UTF-8');
if(!isset($ind['INPUT']))
throw new Exception('No input element (MediaWiki has generated non-valid (X)HTML?)');
foreach($ind['INPUT'] as $_=>$num)
$attr[$val[$num]['attributes']['NAME']] = $val[$num]['attributes']['VALUE'];
unset($attr['search']);
unset($attr['go']);
unset($attr['fulltext']);
unset($attr['wpPreview']);
unset($attr['wpWatchthis']);
unset($attr['wpDiff']);
unset($attr['title']);
return array('text' => $text, 'attr' => $attr);
}
private static function fix_headings_cb($m)
{
$str = $m[2];
// '''
$str = preg_replace('/(.*?)\'\'\'(.*?)\'\'\'(.*?)/m', '\1\2\3', $str);
// ''
$str = preg_replace('/(.*?)\'\'(.*?)\'\'(.*?)/m', '\1\2\3', $str);
// [[|]]
$str = preg_replace('/(.*?)\[\[(([^\]]*?)\|)?(.*?)\]\](.*?)/m', '\1\4\5', $str);
// :
$str = preg_replace('/^ *(.*?)( *:?)* *$/', '\1', $str);
return "${m[1]} ${str} ${m[1]}";
}
private static function fix_headings(&$str)
{
$old = $str;
// pekne nadpisy
$str = preg_replace_callback('/^(=+) *(.+?) *(=+) *\r?$/m', "WikiBot::fix_headings_cb", $str);
// nahrada nadpisu
$str = preg_replace('/^(=+) Viz též (=+)\r?$/m', '\1 Související články \2', $str, -1, $tmp);
$str = preg_replace('/^(=+) Podívejte se také na (=+)\r?$/m', '\1 Související články \2', $str, -1, $tmp);
// pred nadpisem bude presne 1 enter, za nadpisem max. 1 enter
$str = preg_replace('/^(=+ .+? =+)\n+$/m', "\\1\n", $str, -1, $tmp);
$str = preg_replace('/^\n*(=+ .+? =+)$/m', "\n\\1", $str, -1, $tmp);
return !($old == $str);
}
private static function fix_categories(&$str)
{
$old = $str;
// kategorie v anglictine
$str = preg_replace('/\[\[ *(:?) *Category *: *(.+?) *\]\]/im', '[[\1Kategorie:\2]]', $str, -1, $tmp);
return !($old == $str);
}
private static function fix_bullets_cb($m)
{
if( preg_match('/^#REDIRECT *(\[\[[^\]]+?\]\]) *\r?$/', $m[0]) || preg_match('/^#PŘESMĚRUJ *(\[\[[^\]]+?\]\]) *\r?$/', $m[0]) )
return "$m[0]";
else
return "$m[1] $m[2]";
}
private static function fix_bullets(&$str)
{
$old = $str;
// odrazky orezat o mezery
$str = preg_replace_callback('/^([\*#;:]+) *(.*?) *\r?$/m', "WikiBot::fix_bullets_cb", $str, -1, $tmp);
// zbavit se <br/> u odrazek
$str = preg_replace('|^([\*#;:]+) (.*?) *<br */?'.'>\r?$|m', '\1 \2', $str, -1, $tmp);
return !($old == $str);
}
private static function fix_entities(&$str)
{
$old = $str;
// HTML entity
$str = preg_replace('/–/m', '–', $str, -1, $tmp);
$str = preg_replace('/—/m', '—', $str, -1, $tmp);
$str = preg_replace('/…/m', '…', $str, -1, $tmp);
return !($old == $str);
}
private static function pref($prefixes, $words)
{
$ret = array();
$prefixes = explode('|', $prefixes);
foreach($prefixes as $p)
foreach($words as $k => $v)
$ret += array($p.$k => $p.$v);
return $ret;
}
private static function postf($postfixes, $words)
{
$ret = array();
$postfixes = explode('|', $postfixes);
foreach($words as $k => $v)
foreach($postfixes as $p)
$ret += array($k.$p => $v.$p);
return $ret;
}
private static function up($arr)
{
$ret = array();
foreach($arr as $k => $v)
{
$ret += array( $k => $v );
$ret += array( ucfirst($k) => ucfirst($v) );
}
return $ret;
}
public static function get_dictionary()
{
$replace = array(
'ocely' => 'oceli',
'mysly' => 'mysli',
'směsy' => 'směsi',
'myšy' => 'myši',
'mosazy' => 'mosazi',
'lžy' => 'lži',
'potmně' => 'potmě',
'zda-li' => 'zdali',
);
// nejde o spřažený výraz
$replace += array(
'nashledanou' => 'na shledanou',
'naviděnou' => 'na viděnou',
'naslyšenou' => 'na slyšenou',
'narozloučenou' => 'na rozloučenou',
'naodchodnou' => 'na odchodnou',
'nauvítanou' => 'na uvítanou',
'nazotavenou' => 'na zotavenou',
'naposilněnou' => 'na posilněnou',
'napováženou' => 'na pováženou',
'nauváženou' => 'na uváženou',
'narozmyšlenou' => 'na rozmyšlenou',
'navysvětlenou' => 'na vysvětlenou',
'nasrozuměnou' => 'na srozuměnou',
'naupřesněnou' => 'na upřesněnou',
'navybranou' => 'na vybranou',
'nazavolanou' => 'na zavolanou',
'narozdíl' => 'na rozdíl',
);
// vyjímka => výjimka
$replace += self::postf(
'ka|ce|ek|kách|kám|kami|kou|ku|ky',
array( 'vyjím' => 'výjim' )
);
// (bez)vyjímečný => (bez)výjimečný
$replace += self::pref(
'|bez',
self::postf(
'ý|á|é|ého|ém|ému|í|ost|ostech|ostem|osti|ostmi|ou|ých|ým|ýma|ými|ě',
array( 'vyjímečn' => 'výjimečn' )
)
);
// (nej)vyjímečnější => (nej)výjimečnější
$replace += self::pref(
'|nej',
self::postf(
'|ch|ho|m|ma|mi|mu',
array( 'vyjímečnější' => 'výjimečnější' )
)
);
// telefoní => telefonní
$replace += self::postf(
'|ch|ho|m|ma|mi|mu',
array( 'telefoní' => 'telefonní' )
);
// standart- => standard-
$replace += self::postf(
'ech|em|ům',
array( 'standart' => 'standard' )
);
// (nad)standartní => (nad)standardní
$replace += self::pref(
'|nad',
self::postf(
'|ch|ho|m|ma|mi|mu',
array( 'standartní' => 'standardní' )
)
);
// standartnost => standardnost
$replace += self::postf(
'|ech|em|i|mi',
array( 'standartnost' => 'standardnost' )
);
// standartizace => standardizace
$replace += self::postf(
'e|emi|i|ích|ím',
array( 'standartizac' => 'standardizac' )
);
// (nej)standartnější => (nej)standardnější
$replace += self::pref(
'|nej',
self::postf(
'|ch|ho|m|ma|mi|mu',
array( 'standartnější' => 'standardnější' )
)
);
// (za|vz|o)pomě(n|l) => (za|cz|o)pomně(n|l)
$replace += self::pref(
'za|vz|o',
self::postf(
'í|ích|ím|ími',
array( 'poměn' => 'pomněn' )
)
+
self::postf(
'|a|i|o|y',
array(
'poměn' => 'pomněn',
'poměl' => 'pomněl'
)
)
);
// vlasní => vlastní
$replace += self::postf(
'|ch|ho|m|ma|mi|mu',
array( 'vlasní' => 'vlastní' )
);
// vlasnost => vlastnost
$replace += self::postf(
'|ech|em|i|mi',
array( 'vlasnost' => 'vlastnost' )
);
$replace += array(
'vlasně' => 'vlastně'
);
// vlasnický => vlastnický
$replace += self::postf(
'ý|á|é|ého|ém|ému|ou|ých|ým|ýma|ými',
array( 'vlasnick' => 'vlastnick' )
);
$replace += array(
'vlasničtí' => 'vlastničtí'
);
// vlasnictví => vlastnictví
$replace += self::postf(
'|ch|m|mi',
array( 'vlasnictví' => 'vlastnictví' )
);
// vlasník => vlastník
$replace += self::postf(
'k|ci|cích|ka|kem|kovi|ku|kům|ky',
array( 'vlasní' => 'vlastní' )
);
// (vy)vlasnit => (vy)vlastnit
$replace += self::pref(
'|vy',
self::postf(
'it|ěme|ěte|í|i|íc|íce|il|ila|ili|ilo|ily|ím|íme|íš|íte|iti',
array( 'vlasn' => 'vlastn' )
)
);
// součastný => současný
$replace += self::postf(
'ý|á|é|ého|ém|ému|í|ost|ostech|ostem|osti|ostmi|ou|ých|ým|ýma|ými',
array( 'součastn' => 'současn' )
);
// tamnější => tamější, vyší => vyšší
$replace += self::postf(
'|ch|ho|m|ma|mi|mu',
array(
'vyší' => 'vyšší',
'tamnější' => 'tamější'
)
);
// roviný => rovinný
$replace += self::postf(
'ý|á|é|ého|ém|ému|í|ost|ostech|ostem|osti|ostmi|ých|ým|ýma|ými',
array( 'rovin' => 'rovinn' )
);
// kamený => kamenný
$replace += self::postf(
'ý|á|é|ého|ém|ému|ost|ostech|ostem|osti|ostmi|ou|ých|ým|ýma|ými',
array( 'kamen' => 'kamenn' )
);
// (ne|mnoho)straný => (ne|mnoho)stranný
$replace += self::pref(
'mnoho|ne',
self::postf(
'ý|á|é|ého|ém|ému|í|ost|ostech|ostem|osti|ostmi|ou|ých|ým|ýma|ými|ě',
array( 'stran' => 'strann' )
)
);
// postraní => postranní
$replace += self::postf(
'|ch|ho|m|ma|mi|mu',
array( 'postraní' => 'postranní' )
);
// proměný => proměnný
$replace += self::postf(
'ý|á|é|ého|ém|ému|ost|ostech|ostem|osti|ostmi|ých|ým|ýma|ými',
array( 'proměn' => 'proměnn' )
);
// -dení => -denní
$replace += self::pref(
'|celo|celotý|čtrnácti|jedno|jednotý|každo|každotý|kolika|kolikatý|několika|několikatý|ob|rovno|tý|dvou|dvoutý|tří|třítý|čtyř|čtyčtý|pěti|pětitý|šesti|šestitý|sedmi|sedmitý|osmi|osmitý|devíti|devítitý|deseti|desetitý|více|vícetý',
self::postf(
'í|ích|ího|ím|íma|ími|ímu|ě',
array( 'den' => 'denn' )
)
);
// i s velkým počátečním písmenem
$replace = self::up($replace);
// tyhle náhrady jsou case sensitive
$replace += array(
'khz' => 'kHz',
'Mhz' => 'MHz',
'Ghz' => 'GHz',
);
self::$dict = $replace;
}
private static function fix_orthography(&$str)
{
$old = $str;
$sep = '[ ,\.;*#\-–—…&\(\)\/\[\]|\'{}=:<>?!"„“\n]';
$replace = self::$dict;
foreach($replace as $pattern => $replacement)
{
$str = preg_replace("/(${sep})${pattern}(${sep})/m", "\\1${replacement}\\2", $str);
}
// dělá to co má, jen by to asi mělo být ve funkci fix_extlinks()
$str = preg_replace('|\[http://http://([^\]]+?) *\]|m', '[http://\1]', $str);
return !($old == $str);
}
private static function fix_links_ex_cb($m)
{
$link = $m[1];
$delim = $m[2];
$fragment = $m[3];
// TODO: link do čitelné podoby
$link = preg_replace("/_/m", " ", $link);
// TODO: fragment do čitelné podoby
$fragment = preg_replace("/_/m", " ", $fragment);
return "${link}${delim}${fragment}";
}
private function fix_links_cb($m)
{
$link = $m[1];
$delim = $m[2];
$desc = $m[3];
if($link === $desc)
$desc = $delim = '';
$link = preg_replace_callback('/^([^#]*)(#?)(.*)/', "WikiBot::fix_links_ex_cb", $link);
if($link === $this->name)
{
if($desc == '')
return "'''${link}'''";
else
return "'''${desc}'''";
}
else
return "[[${link}${delim}${desc}]]";
}
private function fix_links(&$str)
{
$old = $str;
$str = preg_replace_callback("/\\[\\[([^\\|\\]]+)(\\|?)([^\\]]+)?\\]\\]/", array($this, "fix_links_cb"), $str);
return !($old == $str);
}
private function process($str)
{
$summary = "[[Wikipedie:WCW]]:";
// windowsove entery za linuxove, kvuli enterum kolem nadpisu
$str = preg_replace('/\r\n/', "\n", $str);
if(self::fix_headings($str))
$summary .= " opravy nadpisů,";
if(self::fix_bullets($str))
$summary .= " opravy odrážek,";
if(self::fix_entities($str))
$summary .= " náhrada HTML entit,";
if(self::fix_categories($str))
$summary .= " opravy kategorií v angličtině, ";
if(self::fix_orthography($str))
$summary .= " opravy pravopisu, ";
if(self::fix_links($str))
$summary .= " opravy odkazů, ";
if($str == '')
throw new Exception('Empty output!');
$summary .= "…";
return array('text' => $str, 'summary' => $summary);
}
private function post($page, $name)
{
$title = rawurlencode(str_replace(' ', '_', $name));
$mp = array();
foreach($page['attr'] as $aname=>$val)
$mp[$aname] = $val;
$url = "{$this->base}?title=${title}&action=submit";
$c = curl_init();
curl_setopt($c, CURLOPT_URL, $url);
curl_setopt($c, CURLOPT_COOKIEFILE, self::COOKIEFILE);
curl_setopt($c, CURLOPT_POST, 1);
curl_setopt($c, CURLOPT_POSTFIELDS, $mp);
curl_setopt($c, CURLOPT_HTTPHEADER, array('Expect:'));
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_USERAGENT, $this->user_agent);
$ret = curl_exec($c);
if( '' === $ret )
return TRUE;
else
return FALSE;
}
}
$bot = new WikiBot();
$bot->get_dictionary();
$bot->run();
?>