PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/extensions/DPLforum/DPLforum_body.php

https://github.com/ChuguluGames/mediawiki-svn
PHP | 540 lines | 441 code | 62 blank | 37 comment | 123 complexity | 91b54b41ee68f2cd82f7e4f70a234ce0 MD5 | raw file
  1. <?php
  2. /**
  3. DPLforum v3.2 -- DynamicPageList-based forum extension
  4. Author: Ross McClure
  5. http://www.mediawiki.org/wiki/User:Algorithm
  6. DynamicPageList written by: n:en:User:IlyaHaykinson n:en:User:Amgine
  7. http://en.wikinews.org/wiki/User:Amgine
  8. http://en.wikinews.org/wiki/User:IlyaHaykinson
  9. This program is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation; either version 2 of the License, or
  12. (at your option) any later version.
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. GNU General Public License for more details.
  17. You should have received a copy of the GNU General Public License along
  18. with this program; if not, write to the Free Software Foundation, Inc.,
  19. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. http://www.gnu.org/copyleft/gpl.html
  21. * @file
  22. * @ingroup Extensions
  23. */
  24. if ( !defined( 'MEDIAWIKI' ) ) {
  25. echo( "This file is an extension to the MediaWiki software and is not a valid access point" );
  26. die( 1 );
  27. }
  28. class DPLForum {
  29. var $minCategories = 1; // Minimum number of categories to look for
  30. var $maxCategories = 6; // Maximum number of categories to look for
  31. var $maxResultCount = 50; // Maximum number of results to allow
  32. var $unlimitedResults = true; // Allow unlimited results
  33. var $unlimitedCategories = false; // Allow unlimited categories
  34. var $requireCache = false; // Only clear the cache on purge
  35. // Restricted namespaces cannot be searched for page author or creation time.
  36. // Unless this array is empty, namespace-free searches are also restricted.
  37. // Note: Only integers in this array are checked.
  38. var $restrictNamespace = array(); // No restrictions
  39. var $bTableMode;
  40. var $bTimestamp;
  41. var $bLinkHistory;
  42. var $bEmbedHistory;
  43. var $bShowNamespace;
  44. var $bAddAuthor;
  45. var $bAddCreationDate;
  46. var $bAddLastEdit;
  47. var $bAddLastEditor;
  48. var $bCompactAuthor;
  49. var $bCompactEdit;
  50. var $sInput;
  51. var $sOmit;
  52. var $vMarkNew;
  53. var $sCreationDateFormat;
  54. var $sLastEditFormat;
  55. function cat( &$parser, $name ) {
  56. $cats = array();
  57. if ( preg_match_all( "/^\s*$name\s*=\s*(.*)/mi", $this->sInput, $matches ) ) {
  58. foreach ( $matches[1] as $cat ) {
  59. $title = Title::newFromText( $parser->replaceVariables( trim( $cat ) ) );
  60. if ( !is_null( $title ) ) {
  61. $cats[] = $title;
  62. }
  63. }
  64. }
  65. return $cats;
  66. }
  67. function get( $name, $value = null, $parser = null ) {
  68. if ( preg_match( "/^\s*$name\s*=\s*(.*)/mi", $this->sInput, $matches ) ) {
  69. $arg = trim( $matches[1] );
  70. if ( is_int( $value ) ) {
  71. return intval( $arg );
  72. } elseif ( is_null( $parser ) ) {
  73. return htmlspecialchars( $arg );
  74. } else {
  75. return $parser->replaceVariables( $arg );
  76. }
  77. }
  78. return $value;
  79. }
  80. function link( &$parser, $count, $page = '', $text = '' ) {
  81. $count = intval( $count );
  82. if ( $count < 1 ) {
  83. return '';
  84. }
  85. if ( $this->requireCache ) {
  86. $offset = 0;
  87. } else {
  88. global $wgRequest;
  89. $parser->disableCache();
  90. $offset = intval( $wgRequest->getVal( 'offset', '' ) );
  91. }
  92. $i = intval( $page );
  93. if ( ( $i != 0 ) && ctype_digit( $page[0] ) ) {
  94. $i -= 1;
  95. } else {
  96. $i += intval( $offset / $count );
  97. }
  98. if ( $this->link_test( $i, $page ) ) {
  99. return '';
  100. }
  101. if ( $text === '' ) {
  102. $text = ( $i + 1 );
  103. }
  104. $page = ( $count * $i );
  105. if ( $page == $offset ) {
  106. return $text;
  107. }
  108. return '[' . $parser->replaceVariables( '{{fullurl:{{FULLPAGENAME}}|offset=' . $page . '}} ' ) . $text . ']';
  109. }
  110. function link_test( $page, $cond ) {
  111. if ( preg_match( "/\\d+(\\D+)(\\d+)/", $cond, $m ) ) {
  112. $m[1] = strtr( $m[1], array( ( '&l' . 't;' ) => '<', ( '&g' . 't;' ) => '>' ) );
  113. $m[2] = intval( $m[2] ) - 1;
  114. switch( $m[1] ) {
  115. case '<':
  116. return ( $page >= $m[2] );
  117. case '>':
  118. return ( $page <= $m[2] );
  119. case '<=':
  120. return ( $page > $m[2] );
  121. case '>=':
  122. return ( $page < $m[2] );
  123. }
  124. }
  125. return ( $page < 0 );
  126. }
  127. function msg( $type, $error = null ) {
  128. if ( $error && ( $this->get( 'suppresserrors' ) == 'true' ) ) {
  129. return '';
  130. }
  131. return htmlspecialchars( wfMsg( $type ) );
  132. }
  133. function date( $ts, $type = 'date', $df = false ) { // based on Language::date()
  134. global $wgLang;
  135. $ts = wfTimestamp( TS_MW, $ts );
  136. $ts = $wgLang->userAdjust( $ts );
  137. if ( $df === false ) {
  138. $df = $wgLang->getDateFormatString( $type, $wgLang->dateFormat( true ) );
  139. }
  140. return $wgLang->sprintfDate( $df, $ts );
  141. }
  142. function parse( &$input, &$parser ) {
  143. global $wgContLang;
  144. $this->sInput =& $input;
  145. $sPrefix = $this->get( 'prefix', '', $parser );
  146. $this->sOmit = $this->get( 'omit', $sPrefix, $parser );
  147. $this->bAddAuthor = ( $this->get( 'addauthor' ) == 'true' );
  148. $this->bTimestamp = ( $this->get( 'timestamp' ) != 'false' );
  149. $this->bAddLastEdit = ( $this->get( 'addlastedit' ) != 'false' );
  150. $this->sLastEditFormat = $this->get( 'lasteditformat', false );
  151. $this->bAddLastEditor = ( $this->get( 'addlasteditor' ) == 'true' );
  152. $this->bAddCreationDate = ( $this->get( 'addcreationdate' ) == 'true' );
  153. $this->sCreationDateFormat = $this->get( 'creationdateformat', false );
  154. switch( $this->get( 'historylink' ) ) {
  155. case 'embed':
  156. case 'true':
  157. $this->bEmbedHistory = true;
  158. case 'append':
  159. case 'show':
  160. $this->bLinkHistory = true;
  161. }
  162. $sOrder = 'rev_timestamp';
  163. switch( $this->get( 'ordermethod' ) ) {
  164. case 'categoryadd':
  165. case 'created':
  166. $sOrder = 'first_time';
  167. break;
  168. case 'pageid':
  169. $sOrder = 'page_id';
  170. }
  171. $arg = $this->get( 'compact' );
  172. if ( $arg == 'all' || strpos( $arg, 'edit' ) === 0 ) {
  173. $this->bCompactEdit = $this->bAddLastEdit;
  174. }
  175. $this->bCompactAuthor = ( $arg == 'author' || $arg == 'all' );
  176. $arg = $this->get( 'namespace', '', $parser );
  177. $iNamespace = $wgContLang->getNsIndex( $arg );
  178. if ( !$iNamespace ) {
  179. if ( ( $arg ) || ( $arg === '0' ) ) {
  180. $iNamespace = intval( $arg );
  181. } else {
  182. $iNamespace = -1;
  183. }
  184. }
  185. if ( $iNamespace < 0 ) {
  186. $this->bShowNamespace = ( $this->get( 'shownamespace' ) != 'false' );
  187. } else {
  188. $this->bShowNamespace = ( $this->get( 'shownamespace' ) == 'true' );
  189. }
  190. $this->bTableMode = false;
  191. $sStartItem = $sEndItem = '';
  192. $bCountMode = false;
  193. $arg = $this->get( 'mode' );
  194. switch( $arg ) {
  195. case 'none':
  196. $sEndItem = '<br />';
  197. break;
  198. case 'count':
  199. $bCountMode = true;
  200. break;
  201. case 'list':
  202. case 'ordered':
  203. case 'unordered':
  204. $sStartItem = '<li>';
  205. $sEndItem = '</li>';
  206. break;
  207. case 'table':
  208. default:
  209. $this->bTableMode = true;
  210. $sStartItem = '<tr>';
  211. $sEndItem = '</tr>';
  212. }
  213. $aCategories = $this->cat( $parser, 'category' );
  214. $aExcludeCategories = $this->cat( $parser, 'notcategory' );
  215. $cats = count( $aCategories );
  216. $nocats = count( $aExcludeCategories );
  217. $total = $cats + $nocats;
  218. $output = '';
  219. if ( $sPrefix === '' && ( ( $cats < 1 && $iNamespace < 0 ) ||
  220. ( $total < $this->minCategories ) ) ) {
  221. return $this->msg( 'dplforum-toofew', 1 );
  222. }
  223. if ( ( $total > $this->maxCategories ) && ( !$this->unlimitedCategories ) ) {
  224. return $this->msg( 'dplforum-toomany', 1 );
  225. }
  226. $count = 1;
  227. $start = $this->get( 'start', 0 );
  228. $title = Title::newFromText( $parser->replaceVariables(
  229. trim( $this->get( 'title' ) ) ) );
  230. if ( !( $bCountMode || $this->requireCache || $this->get( 'cache' ) == 'true' ) ) {
  231. $parser->disableCache();
  232. if ( is_null( $title ) ) {
  233. global $wgRequest;
  234. $start += intval( $wgRequest->getVal( 'offset' ) );
  235. }
  236. }
  237. if ( $start < 0 ) {
  238. $start = 0;
  239. }
  240. if ( is_null( $title ) ) {
  241. $count = $this->get( 'count', 0 );
  242. if ( $count > 0 ) {
  243. if ( $count > $this->maxResultCount ) {
  244. $count = $this->maxResultCount;
  245. }
  246. } elseif ( $this->unlimitedResults ) {
  247. $count = 0x7FFFFFFF; // maximum integer value
  248. } else {
  249. $count = $this->maxResultCount;
  250. }
  251. }
  252. // build the SQL query
  253. $dbr = wfGetDB( DB_SLAVE );
  254. $sPageTable = $dbr->tableName( 'page' );
  255. $sRevTable = $dbr->tableName( 'revision' );
  256. $categorylinks = $dbr->tableName( 'categorylinks' );
  257. $sSqlSelectFrom = "SELECT page_namespace, page_title,"
  258. . " r.rev_user_text, r.rev_timestamp";
  259. $arg = " FROM $sPageTable INNER JOIN $sRevTable"
  260. . " AS r ON page_latest = r.rev_id";
  261. if ( $bCountMode ) {
  262. $sSqlSelectFrom = "SELECT COUNT(*) AS num_rows FROM $sPageTable";
  263. } elseif ( ( $this->bAddAuthor || $this->bAddCreationDate ||
  264. ( $sOrder == 'first_time' ) ) && ( ( !$this->restrictNamespace ) ||
  265. ( $iNamespace >= 0 && !in_array( $iNamespace, $this->restrictNamespace ) ) ) ) {
  266. $sSqlSelectFrom .= ", o.rev_user_text AS first_user, o.rev_timestamp AS"
  267. . " first_time" . $arg . " INNER JOIN $sRevTable AS o"
  268. . " ON o.rev_id =( SELECT MIN(q.rev_id) FROM $sRevTable"
  269. . " AS q WHERE q.rev_page = page_id )";
  270. } else {
  271. if ( $sOrder == 'first_time' )
  272. $sOrder = 'page_id';
  273. $sSqlSelectFrom .= $arg;
  274. }
  275. $sSqlWhere = ' WHERE 1=1';
  276. if ( $iNamespace >= 0 )
  277. $sSqlWhere = ' WHERE page_namespace=' . $iNamespace;
  278. if ( $sPrefix !== '' ) {
  279. // Escape SQL special characters
  280. $sPrefix = strtr( $sPrefix, array( '\\' => '\\\\\\\\',
  281. ' ' => '\\_', '_' => '\\_', '%' => '\\%', '\'' => '\\\'' ) );
  282. $sSqlWhere .= " AND page_title LIKE BINARY '" . $sPrefix . "%'";
  283. }
  284. switch( $this->get( 'redirects' ) ) {
  285. case 'only':
  286. $sSqlWhere .= ' AND page_is_redirect = 1';
  287. case 'include':
  288. break;
  289. case 'exclude':
  290. default:
  291. $sSqlWhere .= ' AND page_is_redirect = 0';
  292. break;
  293. }
  294. $n = 1;
  295. for ( $i = 0; $i < $cats; $i++ ) {
  296. $sSqlSelectFrom .= " INNER JOIN $categorylinks AS" .
  297. " c{$n} ON page_id = c{$n}.cl_from AND c{$n}.cl_to=" .
  298. $dbr->addQuotes( $aCategories[$i]->getDBkey() );
  299. $n++;
  300. }
  301. for ( $i = 0; $i < $nocats; $i++ ) {
  302. $sSqlSelectFrom .= " LEFT OUTER JOIN $categorylinks AS" .
  303. " c{$n} ON page_id = c{$n}.cl_from AND c{$n}.cl_to=" .
  304. $dbr->addQuotes( $aExcludeCategories[$i]->getDBkey() );
  305. $sSqlWhere .= " AND c{$n}.cl_to IS NULL";
  306. $n++;
  307. }
  308. if ( !$bCountMode ) {
  309. $sSqlWhere .= " ORDER BY $sOrder ";
  310. if ( $this->get( 'order' ) == 'ascending' ) {
  311. $sSqlWhere .= 'ASC';
  312. } else {
  313. $sSqlWhere .= 'DESC';
  314. }
  315. }
  316. $sSqlWhere .= " LIMIT $start, $count";
  317. // DEBUG: output SQL query
  318. // $output .= 'QUERY: [' . $sSqlSelectFrom . $sSqlWhere . "]<br />";
  319. // process the query
  320. $res = $dbr->query( $sSqlSelectFrom . $sSqlWhere, __METHOD__ );
  321. $this->vMarkNew = $dbr->timestamp( time() -
  322. intval( $this->get( 'newdays', 7 ) * 86400 ) );
  323. if ( $bCountMode ) {
  324. if ( $row = $dbr->fetchObject( $res ) ) {
  325. $output .= $row->num_rows;
  326. } else {
  327. $output .= '0';
  328. }
  329. } elseif ( is_null( $title ) ) {
  330. while ( $row = $dbr->fetchObject( $res ) ) {
  331. if( isset( $row->first_time ) ) {
  332. $first_time = $row->first_time;
  333. } else {
  334. $first_time = '';
  335. }
  336. if( isset( $row->first_user ) ) {
  337. $first_user = $row->first_user;
  338. } else {
  339. $first_user = '';
  340. }
  341. $title = Title::makeTitle( $row->page_namespace, $row->page_title );
  342. $output .= $sStartItem;
  343. $output .= $this->buildOutput( $title, $title, $row->rev_timestamp,
  344. $row->rev_user_text, $first_user, $first_time );
  345. $output .= $sEndItem . "\n";
  346. }
  347. } else {
  348. $output .= $sStartItem;
  349. if ( $row = $dbr->fetchObject( $res ) ) {
  350. $output .= $this->buildOutput( Title::makeTitle( $row->page_namespace,
  351. $row->page_title ), $title, $row->rev_timestamp, $row->rev_user_text );
  352. } else {
  353. $output .= $this->buildOutput( null, $title, $this->msg( 'dplforum-never' ) );
  354. }
  355. $output .= $sEndItem . "\n";
  356. }
  357. return $output;
  358. }
  359. // Generates a single line of output.
  360. function buildOutput( $page, $title, $time, $user = '', $author = '', $made = '' ) {
  361. global $wgUser;
  362. $sk = $wgUser->getSkin();
  363. $tm =& $this->bTableMode;
  364. $output = '';
  365. if ( $this->bAddCreationDate ) {
  366. if ( is_numeric( $made ) ) {
  367. $made = $this->date( $made, 'date', $this->sCreationDateFormat );
  368. }
  369. if ( $page && $this->bLinkHistory && !$this->bAddLastEdit ) {
  370. if ( $this->bEmbedHistory ) {
  371. $made = $sk->makeKnownLinkObj( $page, $made, 'action=history' );
  372. } else {
  373. $made .= ' (' . $sk->makeKnownLinkObj( $page,
  374. wfMsg( 'hist' ), 'action=history' ) . ')';
  375. }
  376. }
  377. if ( $tm ) {
  378. $output .= "<td class='forum_created'>$made</td>";
  379. } elseif ( $made ) {
  380. $output = "{$made}: ";
  381. }
  382. }
  383. if ( $tm ) {
  384. $output .= '<td class="forum_title">';
  385. }
  386. $text = $query = $props = '';
  387. if ( $this->bShowNamespace == true ) {
  388. $text = $title->getEscapedText();
  389. } else {
  390. $text = htmlspecialchars( $title->getText() );
  391. }
  392. if ( ( $this->sOmit ) && strpos( $text, $this->sOmit ) === 0 ) {
  393. $text = substr( $text, strlen( $this->sOmit ) );
  394. }
  395. if ( is_numeric( $time ) ) {
  396. if ( $this->bTimestamp ) {
  397. $query = 't=' . $time;
  398. }
  399. if ( $time > $this->vMarkNew ) {
  400. $props = " class='forum_new'";
  401. }
  402. }
  403. $output .= $sk->makeKnownLinkObj( $title, $text, $query, '', '', $props );
  404. $text = '';
  405. if ( $this->bAddAuthor ) {
  406. $author = Title::newFromText( $author, NS_USER );
  407. if ( $author ) {
  408. $author = $sk->makeKnownLinkObj( $author, $author->getText() );
  409. }
  410. if ( $tm ) {
  411. if ( $this->bCompactAuthor ) {
  412. if ( $author ) {
  413. $byAuthor = wfMsg( 'word-separator' ) . wfMsgHtml( 'dplforum-by', $author );
  414. $output .= " <span class='forum_author'>$byAuthor</span>";
  415. } else {
  416. $output .= " <span class='forum_author'>&nb" . "sp;</span>";
  417. }
  418. } else {
  419. $output .= "</td><td class='forum_author'>$author";
  420. }
  421. } elseif ( $author ) {
  422. $byAuthor = wfMsg( 'word-separator' ) . wfMsgHtml( 'dplforum-by', $author );
  423. $output .= $byAuthor;
  424. }
  425. }
  426. if ( $this->bAddLastEdit ) {
  427. if ( is_numeric( $time ) ) {
  428. $time = $this->date( $time, 'both', $this->sLastEditFormat );
  429. }
  430. if ( $page && $this->bLinkHistory ) {
  431. if ( $this->bEmbedHistory ) {
  432. $time = $sk->makeKnownLinkObj( $page, $time, 'action=history' );
  433. } else {
  434. $time .= ' (' . $sk->makeKnownLinkObj( $page,
  435. wfMsg( 'hist' ), 'action=history' ) . ')';
  436. }
  437. }
  438. if ( $tm ) {
  439. $output .= "</td><td class='forum_edited'>$time";
  440. } else {
  441. $text .= "$time ";
  442. }
  443. }
  444. if ( $this->bAddLastEditor ) {
  445. $user = Title::newFromText( $user, NS_USER );
  446. if ( $user ) {
  447. $user = $sk->makeKnownLinkObj( $user, $user->getText() );
  448. }
  449. if ( $tm ) {
  450. if ( $this->bCompactEdit ) {
  451. if ( $user ) {
  452. $byUser = wfMsgHtml( 'dplforum-by', $user );
  453. $output .= " <span class='forum_editor'>$byUser</span>";
  454. } else {
  455. $output .= " <span class='forum_editor'>&nb" . "sp;</span>";
  456. }
  457. } else {
  458. $output .= "</td><td class='forum_editor'>$user";
  459. }
  460. } elseif ( $user ) {
  461. $byUser = wfMsgHtml( 'dplforum-by', $user );
  462. $text .= $byUser;
  463. }
  464. }
  465. if ( $tm ) {
  466. $output .= '</td>';
  467. } elseif ( $text ) {
  468. $output .= wfMsg( 'word-separator' ) . $this->msg( 'dplforum-edited' ) . " $text";
  469. }
  470. return $output;
  471. }
  472. }