ChangesFeed.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <?php
  2. class ChangesFeed {
  3. public $format, $type, $titleMsg, $descMsg;
  4. public function __construct( $format, $type ) {
  5. $this->format = $format;
  6. $this->type = $type;
  7. }
  8. public function getFeedObject( $title, $description ) {
  9. global $wgSitename, $wgContLanguageCode, $wgFeedClasses, $wgTitle;
  10. $feedTitle = "$wgSitename - {$title} [$wgContLanguageCode]";
  11. if( !isset($wgFeedClasses[$this->format] ) )
  12. return false;
  13. return new $wgFeedClasses[$this->format](
  14. $feedTitle, htmlspecialchars( $description ), $wgTitle->getFullUrl() );
  15. }
  16. public function execute( $feed, $rows, $limit=0, $hideminor=false, $lastmod=false, $target='' ) {
  17. global $messageMemc, $wgFeedCacheTimeout;
  18. global $wgSitename, $wgContLanguageCode;
  19. if ( !FeedUtils::checkFeedOutput( $this->format ) ) {
  20. return;
  21. }
  22. $timekey = wfMemcKey( $this->type, $this->format, 'timestamp' );
  23. $key = wfMemcKey( $this->type, $this->format, $limit, $hideminor, $target );
  24. FeedUtils::checkPurge($timekey, $key);
  25. /*
  26. * Bumping around loading up diffs can be pretty slow, so where
  27. * possible we want to cache the feed output so the next visitor
  28. * gets it quick too.
  29. */
  30. $cachedFeed = $this->loadFromCache( $lastmod, $timekey, $key );
  31. if( is_string( $cachedFeed ) ) {
  32. wfDebug( "RC: Outputting cached feed\n" );
  33. $feed->httpHeaders();
  34. echo $cachedFeed;
  35. } else {
  36. wfDebug( "RC: rendering new feed and caching it\n" );
  37. ob_start();
  38. self::generateFeed( $rows, $feed );
  39. $cachedFeed = ob_get_contents();
  40. ob_end_flush();
  41. $this->saveToCache( $cachedFeed, $timekey, $key );
  42. }
  43. return true;
  44. }
  45. public function saveToCache( $feed, $timekey, $key ) {
  46. global $messageMemc;
  47. $expire = 3600 * 24; # One day
  48. $messageMemc->set( $key, $feed );
  49. $messageMemc->set( $timekey, wfTimestamp( TS_MW ), $expire );
  50. }
  51. public function loadFromCache( $lastmod, $timekey, $key ) {
  52. global $wgFeedCacheTimeout, $messageMemc;
  53. $feedLastmod = $messageMemc->get( $timekey );
  54. if( ( $wgFeedCacheTimeout > 0 ) && $feedLastmod ) {
  55. /*
  56. * If the cached feed was rendered very recently, we may
  57. * go ahead and use it even if there have been edits made
  58. * since it was rendered. This keeps a swarm of requests
  59. * from being too bad on a super-frequently edited wiki.
  60. */
  61. $feedAge = time() - wfTimestamp( TS_UNIX, $feedLastmod );
  62. $feedLastmodUnix = wfTimestamp( TS_UNIX, $feedLastmod );
  63. $lastmodUnix = wfTimestamp( TS_UNIX, $lastmod );
  64. if( $feedAge < $wgFeedCacheTimeout || $feedLastmodUnix > $lastmodUnix) {
  65. wfDebug( "RC: loading feed from cache ($key; $feedLastmod; $lastmod)...\n" );
  66. return $messageMemc->get( $key );
  67. } else {
  68. wfDebug( "RC: cached feed timestamp check failed ($feedLastmod; $lastmod)\n" );
  69. }
  70. }
  71. return false;
  72. }
  73. /**
  74. * Generate the feed items given a row from the database.
  75. * @param $rows Database resource with recentchanges rows
  76. * @param $feed Feed object
  77. */
  78. public static function generateFeed( $rows, &$feed ) {
  79. wfProfileIn( __METHOD__ );
  80. $feed->outHeader();
  81. # Merge adjacent edits by one user
  82. $sorted = array();
  83. $n = 0;
  84. foreach( $rows as $obj ) {
  85. if( $n > 0 &&
  86. $obj->rc_namespace >= 0 &&
  87. $obj->rc_cur_id == $sorted[$n-1]->rc_cur_id &&
  88. $obj->rc_user_text == $sorted[$n-1]->rc_user_text ) {
  89. $sorted[$n-1]->rc_last_oldid = $obj->rc_last_oldid;
  90. } else {
  91. $sorted[$n] = $obj;
  92. $n++;
  93. }
  94. }
  95. foreach( $sorted as $obj ) {
  96. $title = Title::makeTitle( $obj->rc_namespace, $obj->rc_title );
  97. $talkpage = $title->getTalkPage();
  98. $item = new FeedItem(
  99. $title->getPrefixedText(),
  100. FeedUtils::formatDiff( $obj ),
  101. $title->getFullURL( 'diff=' . $obj->rc_this_oldid . '&oldid=prev' ),
  102. $obj->rc_timestamp,
  103. ($obj->rc_deleted & Revision::DELETED_USER) ? wfMsgHtml('rev-deleted-user') : $obj->rc_user_text,
  104. $talkpage->getFullURL()
  105. );
  106. $feed->outItem( $item );
  107. }
  108. $feed->outFooter();
  109. wfProfileOut( __METHOD__ );
  110. }
  111. }