PageRenderTime 69ms CodeModel.GetById 38ms RepoModel.GetById 1ms app.codeStats 0ms

/depreciated/botclasses.php

https://github.com/Dispositif/addbot
PHP | 1111 lines | 648 code | 67 blank | 396 comment | 90 complexity | 45b3b7ceb7208d585732f0d61b03db10 MD5 | raw file
  1. <?php
  2. /**
  3. * botclasses.php - Bot classes for interacting with mediawiki.
  4. *
  5. * (c) 2008-2012 Chris G - http://en.wikipedia.org/wiki/User:Chris_G
  6. * (c) 2009-2010 Fale - http://en.wikipedia.org/wiki/User:Fale
  7. * (c) 2010 Kaldari - http://en.wikipedia.org/wiki/User:Kaldari
  8. * (c) 2011 Gutza - http://en.wikipedia.org/wiki/User:Gutza
  9. * (c) 2012 Sean - http://en.wikipedia.org/wiki/User:SColombo
  10. * (c) 2012 Brain - http://en.wikipedia.org/wiki/User:Brian_McNeil
  11. * (c) 2012 Addshore - http://en.wikipedia.org/wiki/User:Addshore
  12. *
  13. * This program is free software; you can redistribute it and/or modify
  14. * it under the terms of the GNU General Public License as published by
  15. * the Free Software Foundation; either version 2 of the License, or
  16. * (at your option) any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License
  24. * along with this program; if not, write to the Free Software
  25. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26. *
  27. * Developers (add yourself here if you worked on the code):
  28. * Cobi - [[User:Cobi]] - Wrote the http class and some of the wikipedia class
  29. * Chris - [[User:Chris_G]] - Wrote the most of the wikipedia class
  30. * Fale - [[User:Fale]] - Polish, wrote the extended and some of the wikipedia class
  31. * Kaldari - [[User:Kaldari]] - Submitted a patch for the imagematches function
  32. * Gutza - [[User:Gutza]] - Submitted a patch for http->setHTTPcreds(), and http->quiet
  33. * Sean - [[User:SColombo]] - Wrote the lyricwiki class (now moved to lyricswiki.php)
  34. * Brain - [[User:Brian_McNeil]] - Wrote wikipedia->getfileuploader() and wikipedia->getfilelocation
  35. * Addshore- [[User:Addshore]] - Functions for Addbot (lastedit,firstedit)
  36. **/
  37. /*
  38. * Forks/Alternative versions:
  39. * There's a couple of different versions of this code lying around.
  40. * I'll try to list them here for reference purpopses:
  41. * https://en.wikinews.org/wiki/User:NewsieBot/botclasses.php
  42. */
  43. /**
  44. * This class is designed to provide a simplified interface to cURL which maintains cookies.
  45. * @author Cobi
  46. **/
  47. class http {
  48. private $ch;
  49. private $uid;
  50. public $cookie_jar;
  51. public $postfollowredirs;
  52. public $getfollowredirs;
  53. public $quiet=true;
  54. function data_encode ($data, $keyprefix = "", $keypostfix = "") {
  55. assert( is_array($data) );
  56. $vars=null;
  57. foreach($data as $key=>$value) {
  58. if(is_array($value))
  59. $vars .= $this->data_encode($value, $keyprefix.$key.$keypostfix.urlencode("["), urlencode("]"));
  60. else
  61. $vars .= $keyprefix.$key.$keypostfix."=".urlencode($value)."&";
  62. }
  63. return $vars;
  64. }
  65. function __construct () {
  66. $this->ch = curl_init();
  67. $this->uid = dechex(rand(0,99999999));
  68. curl_setopt($this->ch,CURLOPT_COOKIEJAR,'/tmp/cluewikibot.cookies.'.$this->uid.'.dat');
  69. curl_setopt($this->ch,CURLOPT_COOKIEFILE,'/tmp/cluewikibot.cookies.'.$this->uid.'.dat');
  70. curl_setopt($this->ch,CURLOPT_MAXCONNECTS,100);
  71. curl_setopt($this->ch,CURLOPT_CLOSEPOLICY,CURLCLOSEPOLICY_LEAST_RECENTLY_USED);
  72. $this->postfollowredirs = 0;
  73. $this->getfollowredirs = 1;
  74. $this->cookie_jar = array();
  75. }
  76. function post ($url,$data) {
  77. //echo 'POST: '.$url."\n";
  78. $time = microtime(1);
  79. curl_setopt($this->ch,CURLOPT_URL,$url);
  80. curl_setopt($this->ch,CURLOPT_USERAGENT,'php wikibot classes');
  81. /* Crappy hack to add extra cookies, should be cleaned up */
  82. $cookies = null;
  83. foreach ($this->cookie_jar as $name => $value) {
  84. if (empty($cookies))
  85. $cookies = "$name=$value";
  86. else
  87. $cookies .= "; $name=$value";
  88. }
  89. if ($cookies != null)
  90. curl_setopt($this->ch,CURLOPT_COOKIE,$cookies);
  91. curl_setopt($this->ch,CURLOPT_FOLLOWLOCATION,$this->postfollowredirs);
  92. curl_setopt($this->ch,CURLOPT_MAXREDIRS,10);
  93. curl_setopt($this->ch, CURLOPT_HTTPHEADER, array('Expect:'));
  94. curl_setopt($this->ch,CURLOPT_RETURNTRANSFER,1);
  95. curl_setopt($this->ch,CURLOPT_TIMEOUT,30);
  96. curl_setopt($this->ch,CURLOPT_CONNECTTIMEOUT,10);
  97. curl_setopt($this->ch,CURLOPT_POST,1);
  98. // curl_setopt($this->ch,CURLOPT_FAILONERROR,1);
  99. // curl_setopt($this->ch,CURLOPT_POSTFIELDS, substr($this->data_encode($data), 0, -1) );
  100. curl_setopt($this->ch,CURLOPT_POSTFIELDS, $data);
  101. $data = curl_exec($this->ch);
  102. // echo "Error: ".curl_error($this->ch);
  103. // var_dump($data);
  104. // global $logfd;
  105. // if (!is_resource($logfd)) {
  106. // $logfd = fopen('php://stderr','w');
  107. if (!$this->quiet)
  108. echo 'POST: '.$url.' ('.(microtime(1) - $time).' s) ('.strlen($data)." b)\n";
  109. // }
  110. return $data;
  111. }
  112. function get ($url) {
  113. //echo 'GET: '.$url."\n";
  114. $time = microtime(1);
  115. curl_setopt($this->ch,CURLOPT_URL,$url);
  116. curl_setopt($this->ch,CURLOPT_USERAGENT,'php wikibot classes');
  117. /* Crappy hack to add extra cookies, should be cleaned up */
  118. $cookies = null;
  119. foreach ($this->cookie_jar as $name => $value) {
  120. if (empty($cookies))
  121. $cookies = "$name=$value";
  122. else
  123. $cookies .= "; $name=$value";
  124. }
  125. if ($cookies != null)
  126. curl_setopt($this->ch,CURLOPT_COOKIE,$cookies);
  127. curl_setopt($this->ch,CURLOPT_FOLLOWLOCATION,$this->getfollowredirs);
  128. curl_setopt($this->ch,CURLOPT_MAXREDIRS,10);
  129. curl_setopt($this->ch,CURLOPT_HEADER,0);
  130. curl_setopt($this->ch,CURLOPT_RETURNTRANSFER,1);
  131. curl_setopt($this->ch,CURLOPT_TIMEOUT,30);
  132. curl_setopt($this->ch,CURLOPT_CONNECTTIMEOUT,10);
  133. curl_setopt($this->ch,CURLOPT_HTTPGET,1);
  134. //curl_setopt($this->ch,CURLOPT_FAILONERROR,1);
  135. $data = curl_exec($this->ch);
  136. //echo "Error: ".curl_error($this->ch);
  137. //var_dump($data);
  138. //global $logfd;
  139. //if (!is_resource($logfd)) {
  140. // $logfd = fopen('php://stderr','w');
  141. if (!$this->quiet)
  142. echo 'GET: '.$url.' ('.(microtime(1) - $time).' s) ('.strlen($data)." b)\n";
  143. //}
  144. return $data;
  145. }
  146. function setHTTPcreds($uname,$pwd) {
  147. curl_setopt($this->ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
  148. curl_setopt($this->ch, CURLOPT_USERPWD, $uname.":".$pwd);
  149. }
  150. function __destruct () {
  151. curl_close($this->ch);
  152. @unlink('/tmp/cluewikibot.cookies.'.$this->uid.'.dat');
  153. }
  154. }
  155. /**
  156. * This class is interacts with wikipedia using api.php
  157. * @author Chris G and Cobi
  158. **/
  159. class wikipedia {
  160. private $http;
  161. private $token;
  162. private $ecTimestamp;
  163. public $url;
  164. /**
  165. * This is our constructor.
  166. * @return void
  167. **/
  168. function __construct ($url='http://en.wikipedia.org/w/api.php',$hu=null,$hp=null) {
  169. $this->http = new http;
  170. $this->token = null;
  171. $this->url = $url;
  172. $this->ecTimestamp = null;
  173. if ($hu!==null)
  174. $this->http->setHTTPcreds($hu,$hp);
  175. }
  176. function __set($var,$val) {
  177. switch($var) {
  178. case 'quiet':
  179. $this->http->quiet=$val;
  180. break;
  181. default:
  182. echo "WARNING: Unknown variable ($var)!\n";
  183. }
  184. }
  185. /**
  186. * Sends a query to the api.
  187. * @param $query The query string.
  188. * @param $post POST data if its a post request (optional).
  189. * @return The api result.
  190. **/
  191. function query ($query,$post=null) {
  192. if ($post==null)
  193. $ret = $this->http->get($this->url.$query);
  194. else
  195. $ret = $this->http->post($this->url.$query,$post);
  196. return unserialize($ret);
  197. }
  198. /**
  199. * Gets the content of a page. Returns false on error.
  200. * @param $page The wikipedia page to fetch.
  201. * @param $revid The revision id to fetch (optional)
  202. * @return The wikitext for the page.
  203. **/
  204. function getpage ($page,$revid=null,$detectEditConflict=false) {
  205. $append = '';
  206. if ($revid!=null)
  207. $append = '&rvstartid='.$revid;
  208. $x = $this->query('?action=query&format=php&prop=revisions&titles='.urlencode($page).'&rvlimit=1&rvprop=content|timestamp'.$append);
  209. foreach ($x['query']['pages'] as $ret) {
  210. if (isset($ret['revisions'][0]['*'])) {
  211. if ($detectEditConflict)
  212. $this->ecTimestamp = $ret['revisions'][0]['timestamp'];
  213. return $ret['revisions'][0]['*'];
  214. } else
  215. return false;
  216. }
  217. }
  218. /**
  219. * Gets the page id for a page.
  220. * @param $page The wikipedia page to get the id for.
  221. * @return The page id of the page.
  222. **/
  223. function getpageid ($page) {
  224. $x = $this->query('?action=query&format=php&prop=revisions&titles='.urlencode($page).'&rvlimit=1&rvprop=content');
  225. foreach ($x['query']['pages'] as $ret) {
  226. return $ret['pageid'];
  227. }
  228. }
  229. /**
  230. * Gets the number of contributions a user has.
  231. * @param $user The username for which to get the edit count.
  232. * @return The number of contributions the user has.
  233. **/
  234. function contribcount ($user) {
  235. $x = $this->query('?action=query&list=allusers&format=php&auprop=editcount&aulimit=1&aufrom='.urlencode($user));
  236. return $x['query']['allusers'][0]['editcount'];
  237. }
  238. /**
  239. * Returns an array with all the members of $category
  240. * @param $category The category to use.
  241. * @param $subcat (bool) Go into sub categories?
  242. * @return array
  243. **/
  244. function categorymembers ($category,$subcat=false) {
  245. $continue = '';
  246. $pages = array();
  247. while (true) {
  248. $res = $this->query('?action=query&list=categorymembers&cmtitle='.urlencode($category).'&format=php&cmlimit=500'.$continue);
  249. if (isset($x['error'])) {
  250. return false;
  251. }
  252. foreach ($res['query']['categorymembers'] as $x) {
  253. $pages[] = $x['title'];
  254. }
  255. if (empty($res['query-continue']['categorymembers']['cmcontinue'])) {
  256. if ($subcat) {
  257. foreach ($pages as $p) {
  258. if (substr($p,0,9)=='Category:') {
  259. $pages2 = $this->categorymembers($p,true);
  260. $pages = array_merge($pages,$pages2);
  261. }
  262. }
  263. }
  264. return $pages;
  265. } else {
  266. $continue = '&cmcontinue='.urlencode($res['query-continue']['categorymembers']['cmcontinue']);
  267. }
  268. }
  269. }
  270. /**
  271. * Returns a list of pages that link to $page.
  272. * @param $page
  273. * @param $extra (defaults to null)
  274. * @return array
  275. **/
  276. function whatlinkshere ($page,$extra=null) {
  277. $continue = '';
  278. $pages = array();
  279. while (true) {
  280. $res = $this->query('?action=query&list=backlinks&bltitle='.urlencode($page).'&bllimit=1000&format=php'.$continue.$extra);
  281. if (isset($res['error'])) {
  282. return false;
  283. }
  284. foreach ($res['query']['backlinks'] as $x) {
  285. $pages[] = $x['title'];
  286. }
  287. if (empty($res['query-continue']['backlinks']['blcontinue'])) {
  288. return $pages;
  289. } else {
  290. $continue = '&blcontinue='.urlencode($res['query-continue']['backlinks']['blcontinue']);
  291. }
  292. }
  293. }
  294. /**
  295. * Returns a list of pages that include the image.
  296. * @param $image
  297. * @param $extra (defaults to null)
  298. * @return array
  299. **/
  300. function whereisincluded ($image,$extre=null) {
  301. $continue = '';
  302. $pages = array();
  303. while (true) {
  304. $res = $this->query('?action=query&list=imageusage&iutitle='.urlencode($image).'&iulimit=500&format=php'.$continue.$extra);
  305. if (isset($res['error']))
  306. return false;
  307. foreach ($res['query']['imageusage'] as $x) {
  308. $pages[] = $x['title'];
  309. }
  310. if (empty($res['query-continue']['imageusage']['iucontinue']))
  311. return $pages;
  312. else
  313. $continue = '&iucontinue='.urlencode($res['query-continue']['imageusage']['iucontinue']);
  314. }
  315. }
  316. /**
  317. * Returns a list of pages that use the $template.
  318. * @param $template the template we are intereste into
  319. * @param $extra (defaults to null)
  320. * @return array
  321. **/
  322. function whatusethetemplate ($template,$extra=null) {
  323. $continue = '';
  324. $pages = array();
  325. while (true) {
  326. $res = $this->query('?action=query&list=embeddedin&eititle=Template:'.urlencode($template).'&eilimit=500&format=php'.$continue.$extra);
  327. if (isset($res['error'])) {
  328. return false;
  329. }
  330. foreach ($res['query']['embeddedin'] as $x) {
  331. $pages[] = $x['title'];
  332. }
  333. if (empty($res['query-continue']['embeddedin']['eicontinue'])) {
  334. return $pages;
  335. } else {
  336. $continue = '&eicontinue='.urlencode($res['query-continue']['embeddedin']['eicontinue']);
  337. }
  338. }
  339. }
  340. /**
  341. * Returns an array with all the subpages of $page
  342. * @param $page
  343. * @return array
  344. **/
  345. function subpages ($page) {
  346. /* Calculate all the namespace codes */
  347. $ret = $this->query('?action=query&meta=siteinfo&siprop=namespaces&format=php');
  348. foreach ($ret['query']['namespaces'] as $x) {
  349. $namespaces[$x['*']] = $x['id'];
  350. }
  351. $temp = explode(':',$page,2);
  352. $namespace = $namespaces[$temp[0]];
  353. $title = $temp[1];
  354. $continue = '';
  355. $subpages = array();
  356. while (true) {
  357. $res = $this->query('?action=query&format=php&list=allpages&apprefix='.urlencode($title).'&aplimit=500&apnamespace='.$namespace.$continue);
  358. if (isset($x[error])) {
  359. return false;
  360. }
  361. foreach ($res['query']['allpages'] as $p) {
  362. $subpages[] = $p['title'];
  363. }
  364. if (empty($res['query-continue']['allpages']['apfrom'])) {
  365. return $subpages;
  366. } else {
  367. $continue = '&apfrom='.urlencode($res['query-continue']['allpages']['apfrom']);
  368. }
  369. }
  370. }
  371. /**
  372. * This function takes a username and password and logs you into wikipedia.
  373. * @param $user Username to login as.
  374. * @param $pass Password that corrisponds to the username.
  375. * @return array
  376. **/
  377. function login ($user,$pass) {
  378. $post = array('lgname' => $user, 'lgpassword' => $pass);
  379. $ret = $this->query('?action=login&format=php',$post);
  380. /* This is now required - see https://bugzilla.wikimedia.org/show_bug.cgi?id=23076 */
  381. if ($ret['login']['result'] == 'NeedToken') {
  382. $post['lgtoken'] = $ret['login']['token'];
  383. $ret = $this->query( '?action=login&format=php', $post );
  384. }
  385. if ($ret['login']['result'] != 'Success') {
  386. echo "Login error: \n";
  387. print_r($ret);
  388. die();
  389. } else {
  390. return $ret;
  391. }
  392. }
  393. /* crappy hack to allow users to use cookies from old sessions */
  394. function setLogin($data) {
  395. $this->http->cookie_jar = array(
  396. $data['cookieprefix'].'UserName' => $data['lgusername'],
  397. $data['cookieprefix'].'UserID' => $data['lguserid'],
  398. $data['cookieprefix'].'Token' => $data['lgtoken'],
  399. $data['cookieprefix'].'_session' => $data['sessionid'],
  400. );
  401. }
  402. /**
  403. * Check if we're allowed to edit $page.
  404. * See http://en.wikipedia.org/wiki/Template:Bots
  405. * for more info.
  406. * @param $page The page we want to edit.
  407. * @param $user The bot's username.
  408. * @return bool
  409. **/
  410. function nobots ($page,$user=null,$text=null) {
  411. if ($text == null) {
  412. $text = $this->getpage($page);
  413. }
  414. if ($user != null) {
  415. if (preg_match('/\{\{(nobots|bots\|allow=none|bots\|deny=all|bots\|optout=all|bots\|deny=.*?'.preg_quote($user,'/').'.*?)\}\}/iS',$text)) {
  416. return false;
  417. }
  418. } else {
  419. if (preg_match('/\{\{(nobots|bots\|allow=none|bots\|deny=all|bots\|optout=all)\}\}/iS',$text)) {
  420. return false;
  421. }
  422. }
  423. return true;
  424. }
  425. /**
  426. * This function returns the edit token for the current user.
  427. * @return edit token.
  428. **/
  429. function getedittoken () {
  430. $x = $this->query('?action=query&prop=info&intoken=edit&titles=Main%20Page&format=php');
  431. foreach ($x['query']['pages'] as $ret) {
  432. return $ret['edittoken'];
  433. }
  434. }
  435. /**
  436. * Purges the cache of $page.
  437. * @param $page The page to purge.
  438. * @return Api result.
  439. **/
  440. function purgeCache($page) {
  441. return $this->query('?action=purge&titles='.urlencode($page).'&format=php');
  442. }
  443. /**
  444. * Checks if $user has email enabled.
  445. * Uses index.php.
  446. * @param $user The user to check.
  447. * @return bool.
  448. **/
  449. function checkEmail($user) {
  450. $x = $this->query('?action=query&meta=allmessages&ammessages=noemailtext|notargettext&amlang=en&format=php');
  451. $messages[0] = $x['query']['allmessages'][0]['*'];
  452. $messages[1] = $x['query']['allmessages'][1]['*'];
  453. $page = $this->http->get(str_replace('api.php','index.php',$this->url).'?title=Special:EmailUser&target='.urlencode($user));
  454. if (preg_match('/('.preg_quote($messages[0],'/').'|'.preg_quote($messages[1],'/').')/i',$page)) {
  455. return false;
  456. } else {
  457. return true;
  458. }
  459. }
  460. /**
  461. * Returns all the pages $page is transcluded on.
  462. * @param $page The page to get the transclusions from.
  463. * @param $sleep The time to sleep between requets (set to null to disable).
  464. * @return array.
  465. **/
  466. function getTransclusions($page,$sleep=null,$extra=null) {
  467. $continue = '';
  468. $pages = array();
  469. while (true) {
  470. $ret = $this->query('?action=query&list=embeddedin&eititle='.urlencode($page).$continue.$extra.'&eilimit=500&format=php');
  471. if ($sleep != null) {
  472. sleep($sleep);
  473. }
  474. foreach ($ret['query']['embeddedin'] as $x) {
  475. $pages[] = $x['title'];
  476. }
  477. if (isset($ret['query-continue']['embeddedin']['eicontinue'])) {
  478. $continue = '&eicontinue='.$ret['query-continue']['embeddedin']['eicontinue'];
  479. } else {
  480. return $pages;
  481. }
  482. }
  483. }
  484. /**
  485. * Edits a page.
  486. * @param $page Page name to edit.
  487. * @param $data Data to post to page.
  488. * @param $summary Edit summary to use.
  489. * @param $minor Whether or not to mark edit as minor. (Default false)
  490. * @param $bot Whether or not to mark edit as a bot edit. (Default true)
  491. * @return api result
  492. **/
  493. function edit ($page,$data,$summary = '',$minor = false,$bot = true,$section = null,$detectEC=false,$maxlag='') {
  494. if ($this->token==null) {
  495. $this->token = $this->getedittoken();
  496. }
  497. $params = array(
  498. 'title' => $page,
  499. 'text' => $data,
  500. 'token' => $this->token,
  501. 'summary' => $summary,
  502. ($minor?'minor':'notminor') => '1',
  503. ($bot?'bot':'notbot') => '1'
  504. );
  505. if ($section != null) {
  506. $params['section'] = $section;
  507. }
  508. if ($this->ecTimestamp != null && $detectEC == true) {
  509. $params['basetimestamp'] = $this->ecTimestamp;
  510. $this->ecTimestamp = null;
  511. }
  512. if ($maxlag!='') {
  513. $maxlag='&maxlag='.$maxlag;
  514. }
  515. return $this->query('?action=edit&format=php'.$maxlag,$params);
  516. }
  517. /**
  518. * Add a text at the bottom of a page
  519. * @param $page The page we're working with.
  520. * @param $text The text that you want to add.
  521. * @param $summary Edit summary to use.
  522. * @param $minor Whether or not to mark edit as minor. (Default false)
  523. * @param $bot Whether or not to mark edit as a bot edit. (Default true)
  524. * @return api result
  525. **/
  526. function addtext( $page, $text, $summary = '', $minor = false, $bot = true )
  527. {
  528. $data = $this->getpage( $page );
  529. $data.= "\n" . $text;
  530. return $this->edit( $page, $data, $summary, $minor, $bot );
  531. }
  532. /**
  533. * Moves a page.
  534. * @param $old Name of page to move.
  535. * @param $new New page title.
  536. * @param $reason Move summary to use.
  537. * @param $movetalk Move the page's talkpage as well.
  538. * @return api result
  539. **/
  540. function move ($old,$new,$reason,$options=null) {
  541. if ($this->token==null) {
  542. $this->token = $this->getedittoken();
  543. }
  544. $params = array(
  545. 'from' => $old,
  546. 'to' => $new,
  547. 'token' => $this->token,
  548. 'reason' => $reason
  549. );
  550. if ($options != null) {
  551. $option = explode('|',$options);
  552. foreach ($option as $o) {
  553. $params[$o] = true;
  554. }
  555. }
  556. return $this->query('?action=move&format=php',$params);
  557. }
  558. /**
  559. * Rollback an edit.
  560. * @param $title Title of page to rollback.
  561. * @param $user Username of last edit to the page to rollback.
  562. * @param $reason Edit summary to use for rollback.
  563. * @param $bot mark the rollback as bot.
  564. * @return api result
  565. **/
  566. function rollback ($title,$user,$reason=null,$bot=false) {
  567. $ret = $this->query('?action=query&prop=revisions&rvtoken=rollback&titles='.urlencode($title).'&format=php');
  568. foreach ($ret['query']['pages'] as $x) {
  569. $token = $x['revisions'][0]['rollbacktoken'];
  570. break;
  571. }
  572. $params = array(
  573. 'title' => $title,
  574. 'user' => $user,
  575. 'token' => $token
  576. );
  577. if ($bot) {
  578. $params['markbot'] = true;
  579. }
  580. if ($reason != null) { $params['summary'] = $reason; }
  581. return $this->query('?action=rollback&format=php',$params);
  582. }
  583. /**
  584. * Blocks a user.
  585. * @param $user The user to block.
  586. * @param $reason The block reason.
  587. * @param $expiry The block expiry.
  588. * @param $options a piped string containing the block options.
  589. * @return api result
  590. **/
  591. function block ($user,$reason='vand',$expiry='infinite',$options=null,$retry=true) {
  592. if ($this->token==null) {
  593. $this->token = $this->getedittoken();
  594. }
  595. $params = array(
  596. 'expiry' => $expiry,
  597. 'user' => $user,
  598. 'reason' => $reason,
  599. 'token' => $this->token
  600. );
  601. if ($options != null) {
  602. $option = explode('|',$options);
  603. foreach ($option as $o) {
  604. $params[$o] = true;
  605. }
  606. }
  607. $ret = $this->query('?action=block&format=php',$params);
  608. /* Retry on a failed token. */
  609. if ($retry and $ret['error']['code']=='badtoken') {
  610. $this->token = $this->getedittoken();
  611. return $this->block($user,$reason,$expiry,$options,false);
  612. }
  613. return $ret;
  614. }
  615. /**
  616. * Unblocks a user.
  617. * @param $user The user to unblock.
  618. * @param $reason The unblock reason.
  619. * @return api result
  620. **/
  621. function unblock ($user,$reason) {
  622. if ($this->token==null) {
  623. $this->token = $this->getedittoken();
  624. }
  625. $params = array(
  626. 'user' => $user,
  627. 'reason' => $reason,
  628. 'token' => $this->token
  629. );
  630. return $this->query('?action=unblock&format=php',$params);
  631. }
  632. /**
  633. * Emails a user.
  634. * @param $target The user to email.
  635. * @param $subject The email subject.
  636. * @param $text The body of the email.
  637. * @param $ccme Send a copy of the email to the user logged in.
  638. * @return api result
  639. **/
  640. function email ($target,$subject,$text,$ccme=false) {
  641. if ($this->token==null) {
  642. $this->token = $this->getedittoken();
  643. }
  644. $params = array(
  645. 'target' => $target,
  646. 'subject' => $subject,
  647. 'text' => $text,
  648. 'token' => $this->token
  649. );
  650. if ($ccme) {
  651. $params['ccme'] = true;
  652. }
  653. return $this->query('?action=emailuser&format=php',$params);
  654. }
  655. /**
  656. * Deletes a page.
  657. * @param $title The page to delete.
  658. * @param $reason The delete reason.
  659. * @return api result
  660. **/
  661. function delete ($title,$reason) {
  662. if ($this->token==null) {
  663. $this->token = $this->getedittoken();
  664. }
  665. $params = array(
  666. 'title' => $title,
  667. 'reason' => $reason,
  668. 'token' => $this->token
  669. );
  670. return $this->query('?action=delete&format=php',$params);
  671. }
  672. /**
  673. * Undeletes a page.
  674. * @param $title The page to undelete.
  675. * @param $reason The undelete reason.
  676. * @return api result
  677. **/
  678. function undelete ($title,$reason) {
  679. if ($this->token==null) {
  680. $this->token = $this->getedittoken();
  681. }
  682. $params = array(
  683. 'title' => $title,
  684. 'reason' => $reason,
  685. 'token' => $this->token
  686. );
  687. return $this->query('?action=undelete&format=php',$params);
  688. }
  689. /**
  690. * (Un)Protects a page.
  691. * @param $title The page to (un)protect.
  692. * @param $protections The protection levels (e.g. 'edit=autoconfirmed|move=sysop')
  693. * @param $expiry When the protection should expire (e.g. '1 day|infinite')
  694. * @param $reason The (un)protect reason.
  695. * @param $cascade Enable cascading protection? (defaults to false)
  696. * @return api result
  697. **/
  698. function protect ($title,$protections,$expiry,$reason,$cascade=false) {
  699. if ($this->token==null) {
  700. $this->token = $this->getedittoken();
  701. }
  702. $params = array(
  703. 'title' => $title,
  704. 'protections' => $protections,
  705. 'expiry' => $expiry,
  706. 'reason' => $reason,
  707. 'token' => $this->token
  708. );
  709. if ($cascade) {
  710. $params['cascade'] = true;
  711. }
  712. return $this->query('?action=protect&format=php',$params);
  713. }
  714. /**
  715. * Uploads an image.
  716. * @param $page The destination file name.
  717. * @param $file The local file path.
  718. * @param $desc The upload discrption (defaults to '').
  719. **/
  720. function upload ($page,$file,$desc='') {
  721. if ($this->token == null) {
  722. $this->token = $this->getedittoken();
  723. }
  724. $params = array(
  725. 'filename' => $page,
  726. 'comment' => $desc,
  727. 'text' => $desc,
  728. 'token' => $this->token,
  729. 'ignorewarnings' => '1',
  730. 'file' => '@'.$file
  731. );
  732. return $this->query('?action=upload&format=php',$params);
  733. }
  734. /*
  735. $page - page
  736. $revs - rev ids to delete (seperated with ,)
  737. $comment - delete comment
  738. */
  739. function revdel ($page,$revs,$comment) {
  740. if ($this->token==null) {
  741. $this->token = $this->getedittoken();
  742. }
  743. $post = array(
  744. 'wpEditToken' => $this->token,
  745. 'ids' => $revs,
  746. 'target' => $page,
  747. 'type' => 'revision',
  748. 'wpHidePrimary' => 1,
  749. 'wpHideComment' => 1,
  750. 'wpHideUser' => 0,
  751. 'wpRevDeleteReasonList' => 'other',
  752. 'wpReason' => $comment,
  753. 'wpSubmit' => 'Apply to selected revision(s)'
  754. );
  755. return $this->http->post(str_replace('api.php','index.php',$this->url).'?title=Special:RevisionDelete&action=submit',$post);
  756. }
  757. /**
  758. * Creates a new account.
  759. * Uses index.php as there is no api to create accounts yet :(
  760. * @param $username The username the new account will have.
  761. * @param $password The password the new account will have.
  762. * @param $email The email the new account will have.
  763. **/
  764. function createaccount ($username,$password,$email=null) {
  765. $post = array(
  766. 'wpName' => $username,
  767. 'wpPassword' => $password,
  768. 'wpRetype' => $password,
  769. 'wpEmail' => $email,
  770. 'wpRemember' => 0,
  771. 'wpIgnoreAntiSpoof' => 0,
  772. 'wpCreateaccount' => 'Create account',
  773. );
  774. return $this->http->post(str_replace('api.php','index.php',$this->url).'?title=Special:UserLogin&action=submitlogin&type=signup',$post);
  775. }
  776. /**
  777. * Changes a users rights.
  778. * @param $user The user we're working with.
  779. * @param $add A pipe-separated list of groups you want to add.
  780. * @param $remove A pipe-separated list of groups you want to remove.
  781. * @param $reason The reason for the change (defaults to '').
  782. **/
  783. function userrights ($user,$add,$remove,$reason='') {
  784. // get the userrights token
  785. $token = $this->query('?action=query&list=users&ususers='.urlencode($user).'&ustoken=userrights&format=php');
  786. $token = $token['query']['users'][0]['userrightstoken'];
  787. $params = array(
  788. 'user' => $user,
  789. 'token' => $token,
  790. 'add' => $add,
  791. 'remove' => $remove,
  792. 'reason' => $reason
  793. );
  794. return $this->query('?action=userrights&format=php',$params);
  795. }
  796. /**
  797. * Gets the number of images matching a particular sha1 hash.
  798. * @param $hash The sha1 hash for an image.
  799. * @return The number of images with the same sha1 hash.
  800. **/
  801. function imagematches ($hash) {
  802. $x = $this->query('?action=query&list=allimages&format=php&aisha1='.$hash);
  803. return count($x['query']['allimages']);
  804. }
  805. /** BMcN 2012-09-16
  806. * Retrieve a media file's actual location.
  807. * @param $page The "File:" page on the wiki which the URL of is desired.
  808. * @return The URL pointing directly to the media file (Eg http://upload.mediawiki.org/wikipedia/en/1/1/Example.jpg)
  809. **/
  810. function getfilelocation ($page) {
  811. $x = $this->query('?action=query&format=php&prop=imageinfo&titles='.urlencode($page).'&iilimit=1&iiprop=url');
  812. foreach ($x['query']['pages'] as $ret ) {
  813. if (isset($ret['imageinfo'][0]['url'])) {
  814. return $ret['imageinfo'][0]['url'];
  815. } else
  816. return false;
  817. }
  818. }
  819. /** BMcN 2012-09-16
  820. * Retrieve a media file's uploader.
  821. * @param $page The "File:" page
  822. * @return The user who uploaded the topmost version of the file.
  823. **/
  824. function getfileuploader ($page) {
  825. $x = $this->query('?action=query&format=php&prop=imageinfo&titles='.urlencode($page).'&iilimit=1&iiprop=user');
  826. foreach ($x['query']['pages'] as $ret ) {
  827. if (isset($ret['imageinfo'][0]['user'])) {
  828. return $ret['imageinfo'][0]['user'];
  829. } else
  830. return false;
  831. }
  832. }
  833. function lastedit ($user) {
  834. $x = $this->query('?action=query&list=usercontribs&uclimit=1&format=php&ucuser='.urlencode($user));
  835. return $x['query']['usercontribs'][0]['title'];
  836. }
  837. /**
  838. * Gets the time stamp of the last edit a user made on an article
  839. * @param $user The username for which to get the last edit
  840. * @param $page The page we want to check
  841. * @return The timestamp of the last edit e.g. 2012-02-28T13:10:12Z
  842. * @author Addshore
  843. **/
  844. function lasteditonpage ($user,$page) {
  845. $x = $this->query('?action=query&prop=revisions&format=php&titles='.urlencode($page).'&rvlimit=1&rvuser='.urlencode($user));
  846. return $x['query']['pages'][0]['revisions'][0]['timestamp'];
  847. }
  848. /**
  849. * Gets the date of the last edit the user has made
  850. * @param $user The username for which to get the first edit
  851. * @return The timestamp of the last edit e.g. 2012-02-28T13:10:12Z
  852. * @author Addshore
  853. **/
  854. function firstedit ($user) {
  855. $x = $this->query('?action=query&list=usercontribs&uclimit=1&format=php&acuser='.urlencode($user));
  856. return $x['query-continue'][0]['ucstart'];
  857. }
  858. /**
  859. * Gets the time stamp of the last edit a user made on an article
  860. * @param $user The username for which to get the last edit
  861. * @param $page The page we want to check
  862. * @return The timestamp of the last edit e.g. 2012-02-28T13:10:12Z
  863. * @author Addshore
  864. **//*
  865. function lasteditonpage ($user,$page) {
  866. $x = $this->query('?action=query&prop=revisions&format=php&titles='.urlencode($page).'&rvlimit=1&rvuser='.urlencode($user));
  867. return $x['query']['pages'][0]['revisions'][0]['timestamp'];
  868. }*/
  869. function last2edits ($page) {
  870. $x = $this->query('?action=query&prop=revisions&format=php&titles='.urlencode($page).'&rvlimit=2');
  871. foreach($x['query']['pages'] as $page)
  872. {
  873. return Array($page['revisions'][0]['revid'],$page['revisions'][1]['revid']);
  874. }
  875. }
  876. function wikidatasitelinks ($page){
  877. $x = $this->http->get("http://wikidata.org/w/api.php?action=wbgetentities&sites=enwiki&props=sitelinks&format=php&titles=".urlencode($page));
  878. $x = unserialize($x);
  879. if($x['success'] == 1)
  880. {
  881. return $x['entities'];
  882. }
  883. }
  884. }
  885. /**
  886. * This class extends the wiki class to provide an high level API for the most commons actions.
  887. * @author Fale
  888. **/
  889. class extended extends wikipedia
  890. {
  891. /**
  892. * Add a category to a page
  893. * @param $page The page we're working with.
  894. * @param $category The category that you want to add.
  895. * @param $summary Edit summary to use.
  896. * @param $minor Whether or not to mark edit as minor. (Default false)
  897. * @param $bot Whether or not to mark edit as a bot edit. (Default true)
  898. * @return api result
  899. **/
  900. function addcategory( $page, $category, $summary = '', $minor = false, $bot = true )
  901. {
  902. $data = $this->getpage( $page );
  903. $data.= "\n[[Category:" . $category . "]]";
  904. return $this->edit( $page, $data, $summary, $minor, $bot );
  905. }
  906. /**
  907. * Find a string
  908. * @param $page The page we're working with.
  909. * @param $string The string that you want to find.
  910. * @return bool value (1 found and 0 not-found)
  911. **/
  912. function findstring( $page, $string )
  913. {
  914. $data = $this->getpage( $page );
  915. if( strstr( $data, $string ) )
  916. return 1;
  917. else
  918. return 0;
  919. }
  920. /**
  921. * Replace a string
  922. * @param $page The page we're working with.
  923. * @param $string The string that you want to replace.
  924. * @param $newstring The string that will replace the present string.
  925. * @return the new text of page
  926. **/
  927. function replacestring( $page, $string, $newstring )
  928. {
  929. $data = $this->getpage( $page );
  930. return str_replace( $string, $newstring, $data );
  931. }
  932. /**
  933. * Get a template from a page
  934. * @param $page The page we're working with
  935. * @param $template The name of the template we are looking for
  936. * @return the searched (NULL if the template has not been found)
  937. **/
  938. function gettemplate( $page, $template ) {
  939. $data = $this->getpage( $page );
  940. $template = preg_quote( $template, " " );
  941. $r = "/{{" . $template . "(?:[^{}]*(?:{{[^}]*}})?)+(?:[^}]*}})?/i";
  942. preg_match_all( $r, $data, $matches );
  943. if( isset( $matches[0][0] ) )
  944. return $matches[0][0];
  945. else
  946. return NULL;
  947. }
  948. }
  949. /**
  950. * This class extends the wiki class to provide an high level API for the most commons actions.
  951. * @author Sean
  952. */
  953. class lyricwiki extends extended
  954. {
  955. /**
  956. * Constructor. Note that the parameters are in different order (primarily because it
  957. * is very unlikely the user will want to change the URL of LyricWiki, and fairly likely
  958. * that they may want to set a username/password).
  959. *
  960. * If not logging in, the caller can safely call this with no parameters.
  961. */
  962. function __construct ($hu=null, $hp=null, $url='http://lyrics.wikia.com/api.php') {
  963. parent::__construct($url,$hu,$hp);
  964. }
  965. /**
  966. * Returns basic info about a song as well as a fair-use snippet of
  967. * lyrics and a link to the LyricWiki page where the full lyrics can
  968. * be viewed (full lyrics are no longer available via the API because
  969. * of licensing issues - publishers won't allow that for free).
  970. *
  971. * @return associative array containing the song data. (TODO: Document what happens on No Match)
  972. */
  973. function getSong($artist, $song){
  974. return $this->query('?action=lyrics&func=getSong&fmt=php&artist='.urlencode($artist).'&song='.urlencode($song));
  975. } // end getSong()
  976. /**
  977. * Returns basic info about an artist as well as their
  978. * entire discography.
  979. *
  980. * @param - artist - a string containing the name of the artist (spaces or underscores are fine)
  981. * @return an associative array containing the artist data (TODO: Document what happens on No Match)
  982. */
  983. function getArtist($artist){
  984. return $this->query('?action=lyrics&func=getArtist&fmt=php&artist='.urlencode($artist));
  985. } // end getArtist()
  986. /**
  987. * Returns hometown information (country, state/province, hometown) for
  988. * the given artist if it can be found.
  989. *
  990. *
  991. * @param - artist - a string containing the name of the artist (spaces or underscores are fine)
  992. * @return an associative array whose keys are 'country', 'state', and 'hometown'. If the
  993. * artist's hometown could not be found, then the values corresponding to those keys will
  994. * be empty strings.
  995. */
  996. function getHometown($artist){
  997. return $this->query('?action=lyrics&func=getHometown&fmt=php&artist='.urlencode($artist));
  998. } // end getHometown()
  999. /**
  1000. * Gets information about the Song Of The Day (SOTD).
  1001. *
  1002. * @return an associative array representing the current Song of the Day. The
  1003. * fields returned include {artist, song, lyrics (just a snippet), url of song,
  1004. * page_namespace, page_id, isOnTakedownList, nominatedBy, reason}
  1005. */
  1006. function getSotd(){
  1007. return $this->query('?action=lyrics&func=getSotd&fmt=php');
  1008. } // end getSotd()
  1009. /**
  1010. * Returns information about the currently most-popular songs.
  1011. *
  1012. * @return an array containing associative arrays of the data for each top song.
  1013. */
  1014. function getTopSongs(){
  1015. return $this->query('?action=lyrics&func=getTopSongs&fmt=php');
  1016. } // end getTopSongs()
  1017. /**
  1018. * Allows easy submission of lyrics for a new song to LyricWiki.
  1019. *
  1020. * @param artist - the artist of the song
  1021. * @param song - the name of the song (following page naming conventions: http://lyrics.wikia.com/LW:PN ).
  1022. * @param lyrics - the full lyrics to submit
  1023. * @param language - optional string for the language (the language name should be in English - eg: "Swedish" not "Svenska").
  1024. * @param onAlbums - an array which contains strings which are album titles.
  1025. * @param overwriteIfExists - true means that this page data (the lyrics and onAlbums) will overwrite
  1026. * the page if it already exists. false means that nothing will be changed if the
  1027. * page already exists.
  1028. */
  1029. function postSong($artist, $song, $lyrics, $language="", $onAlbums=array(), $overwriteIfExists=false){
  1030. $params = array(
  1031. 'artist' => $artist,
  1032. 'song' => $song,
  1033. 'lyrics' => $lyrics,
  1034. 'overwriteIfExists' => ($overwriteIfExists ? "1" : "0"),
  1035. );
  1036. if(!empty($language)){
  1037. $params['language'] = $language;
  1038. }
  1039. if(count($onAlbums) > 0){
  1040. $params['onAlbums'] = implode("|", $onAlbums);
  1041. }
  1042. return $this->query('?action=lyrics&func=postSong&fmt=php',$params);
  1043. } // end postSong()
  1044. } // end class lyricwiki