1<?php 2 3namespace dokuwiki; 4 5use Doku_Event; 6use Sitemapper; 7use Subscription; 8 9class TaskRunner 10{ 11 public function run() 12 { 13 // run one of the jobs 14 $tmp = []; // No event data 15 $evt = new Doku_Event('INDEXER_TASKS_RUN', $tmp); 16 if ($evt->advise_before()) { 17 $this->runIndexer() or 18 $this->runSitemapper() or 19 $this->sendDigest() or 20 $this->runTrimRecentChanges() or 21 $this->runTrimRecentChanges(true) or 22 $evt->advise_after(); 23 } 24 } 25 26 /** 27 * Trims the recent changes cache (or imports the old changelog) as needed. 28 * 29 * @param bool $media_changes If the media changelog shall be trimmed instead of 30 * the page changelog 31 * @return bool 32 * 33 * @author Ben Coburn <btcoburn@silicodon.net> 34 */ 35 protected function runTrimRecentChanges($media_changes = false) { 36 global $conf; 37 38 echo "runTrimRecentChanges($media_changes): started".NL; 39 40 $fn = ($media_changes ? $conf['media_changelog'] : $conf['changelog']); 41 42 // Trim the Recent Changes 43 // Trims the recent changes cache to the last $conf['changes_days'] recent 44 // changes or $conf['recent'] items, which ever is larger. 45 // The trimming is only done once a day. 46 if (file_exists($fn) && 47 (@filemtime($fn.'.trimmed')+86400)<time() && 48 !file_exists($fn.'_tmp')) { 49 @touch($fn.'.trimmed'); 50 io_lock($fn); 51 $lines = file($fn); 52 if (count($lines)<=$conf['recent']) { 53 // nothing to trim 54 io_unlock($fn); 55 echo "runTrimRecentChanges($media_changes): finished".NL; 56 return false; 57 } 58 59 io_saveFile($fn.'_tmp', ''); // presave tmp as 2nd lock 60 $trim_time = time() - $conf['recent_days']*86400; 61 $out_lines = array(); 62 $old_lines = array(); 63 for ($i=0; $i<count($lines); $i++) { 64 $log = parseChangelogLine($lines[$i]); 65 if ($log === false) continue; // discard junk 66 if ($log['date'] < $trim_time) { 67 $old_lines[$log['date'].".$i"] = $lines[$i]; // keep old lines for now (append .$i to prevent key collisions) 68 } else { 69 $out_lines[$log['date'].".$i"] = $lines[$i]; // definitely keep these lines 70 } 71 } 72 73 if (count($lines)==count($out_lines)) { 74 // nothing to trim 75 @unlink($fn.'_tmp'); 76 io_unlock($fn); 77 echo "runTrimRecentChanges($media_changes): finished".NL; 78 return false; 79 } 80 81 // sort the final result, it shouldn't be necessary, 82 // however the extra robustness in making the changelog cache self-correcting is worth it 83 ksort($out_lines); 84 $extra = $conf['recent'] - count($out_lines); // do we need extra lines do bring us up to minimum 85 if ($extra > 0) { 86 ksort($old_lines); 87 $out_lines = array_merge(array_slice($old_lines,-$extra),$out_lines); 88 } 89 90 // save trimmed changelog 91 io_saveFile($fn.'_tmp', implode('', $out_lines)); 92 @unlink($fn); 93 if (!rename($fn.'_tmp', $fn)) { 94 // rename failed so try another way... 95 io_unlock($fn); 96 io_saveFile($fn, implode('', $out_lines)); 97 @unlink($fn.'_tmp'); 98 } else { 99 io_unlock($fn); 100 } 101 echo "runTrimRecentChanges($media_changes): finished".NL; 102 return true; 103 } 104 105 // nothing done 106 echo "runTrimRecentChanges($media_changes): finished".NL; 107 return false; 108 } 109 110 111 /** 112 * Runs the indexer for the current page 113 * 114 * @author Andreas Gohr <andi@splitbrain.org> 115 */ 116 protected function runIndexer(){ 117 global $ID; 118 global $conf; 119 print "runIndexer(): started".NL; 120 121 if(!$ID) return false; 122 123 // do the work 124 return idx_addPage($ID, true); 125 } 126 127 /** 128 * Builds a Google Sitemap of all public pages known to the indexer 129 * 130 * The map is placed in the root directory named sitemap.xml.gz - This 131 * file needs to be writable! 132 * 133 * @author Andreas Gohr 134 * @link https://www.google.com/webmasters/sitemaps/docs/en/about.html 135 */ 136 protected function runSitemapper(){ 137 print "runSitemapper(): started".NL; 138 $result = Sitemapper::generate() && Sitemapper::pingSearchEngines(); 139 print 'runSitemapper(): finished'.NL; 140 return $result; 141 } 142 143 /** 144 * Send digest and list mails for all subscriptions which are in effect for the 145 * current page 146 * 147 * @author Adrian Lang <lang@cosmocode.de> 148 */ 149 protected function sendDigest() { 150 global $conf; 151 global $ID; 152 153 echo 'sendDigest(): started'.NL; 154 if(!actionOK('subscribe')) { 155 echo 'sendDigest(): disabled'.NL; 156 return false; 157 } 158 $sub = new Subscription(); 159 $sent = $sub->send_bulk($ID); 160 161 echo "sendDigest(): sent $sent mails".NL; 162 echo 'sendDigest(): finished'.NL; 163 return (bool) $sent; 164 } 165} 166