17d559c7fSBen Coburn<?php 27d559c7fSBen Coburn/** 37d559c7fSBen Coburn * Changelog handling functions 47d559c7fSBen Coburn * 57d559c7fSBen Coburn * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 67d559c7fSBen Coburn * @author Andreas Gohr <andi@splitbrain.org> 77d559c7fSBen Coburn */ 87d559c7fSBen Coburn 9*1d11f1d3SSatoshi Saharause dokuwiki\ChangeLog\ChangeLog; 10*1d11f1d3SSatoshi Sahara 117d559c7fSBen Coburn/** 127d559c7fSBen Coburn * parses a changelog line into it's components 137d559c7fSBen Coburn * 147d559c7fSBen Coburn * @author Ben Coburn <btcoburn@silicodon.net> 154f1e2cb3SGerrit Uitslag * 164f1e2cb3SGerrit Uitslag * @param string $line changelog line 174f1e2cb3SGerrit Uitslag * @return array|bool parsed line or false 187d559c7fSBen Coburn */ 197d559c7fSBen Coburnfunction parseChangelogLine($line) { 20*1d11f1d3SSatoshi Sahara return ChangeLog::parseLogLine($line); 217d559c7fSBen Coburn} 227d559c7fSBen Coburn 237d559c7fSBen Coburn/** 2463f13cadSDamien Regad * Adds an entry to the changelog and saves the metadata for the page 257d559c7fSBen Coburn * 266527839fSSatoshi Sahara * Note: timestamp of the change might not be unique especially after very quick 276527839fSSatoshi Sahara * repeated edits (e.g. change checkbox via do plugin) 286527839fSSatoshi Sahara * 296527839fSSatoshi Sahara * @param int $date Timestamp of the change 30a365baeeSDominik Eckelmann * @param String $id Name of the affected page 31a365baeeSDominik Eckelmann * @param String $type Type of the change see DOKU_CHANGE_TYPE_* 32a365baeeSDominik Eckelmann * @param String $summary Summary of the change 33a365baeeSDominik Eckelmann * @param mixed $extra In case of a revert the revision (timestmp) of the reverted page 34a365baeeSDominik Eckelmann * @param array $flags Additional flags in a key value array. 354f1e2cb3SGerrit Uitslag * Available flags: 36a365baeeSDominik Eckelmann * - ExternalEdit - mark as an external edit. 37ac3ed4afSGerrit Uitslag * @param null|int $sizechange Change of filesize 38a365baeeSDominik Eckelmann * 397d559c7fSBen Coburn * @author Andreas Gohr <andi@splitbrain.org> 407d559c7fSBen Coburn * @author Esther Brunner <wikidesign@gmail.com> 417d559c7fSBen Coburn * @author Ben Coburn <btcoburn@silicodon.net> 427d559c7fSBen Coburn */ 435d9428a0SSatoshi Saharafunction addLogEntry( 445d9428a0SSatoshi Sahara $date, 455d9428a0SSatoshi Sahara $id, 465d9428a0SSatoshi Sahara $type = DOKU_CHANGE_TYPE_EDIT, 475d9428a0SSatoshi Sahara $summary = '', 485d9428a0SSatoshi Sahara $extra = '', 495d9428a0SSatoshi Sahara $flags = null, 505d9428a0SSatoshi Sahara $sizechange = null) 515d9428a0SSatoshi Sahara{ 527d559c7fSBen Coburn global $conf, $INFO; 53585bf44eSChristopher Smith /** @var Input $INPUT */ 54585bf44eSChristopher Smith global $INPUT; 557d559c7fSBen Coburn 565aa52fafSBen Coburn // check for special flags as keys 57252acce3SSatoshi Sahara if (!is_array($flags)) $flags = array(); 585aa52fafSBen Coburn $flagExternalEdit = isset($flags['ExternalEdit']); 595aa52fafSBen Coburn 607d559c7fSBen Coburn $id = cleanid($id); 617d559c7fSBen Coburn $file = wikiFN($id); 627d559c7fSBen Coburn $created = @filectime($file); 63ebf1501fSBen Coburn $minor = ($type === DOKU_CHANGE_TYPE_MINOR_EDIT); 64ebf1501fSBen Coburn $wasRemoved = ($type === DOKU_CHANGE_TYPE_DELETE); 65c7192766SSatoshi Sahara $wasCreated = ($type === DOKU_CHANGE_TYPE_CREATE); 66c7192766SSatoshi Sahara $wasReverted = ($type === DOKU_CHANGE_TYPE_REVERT); 677d559c7fSBen Coburn 687d559c7fSBen Coburn if (!$date) $date = time(); //use current time if none supplied 692f9daf16SAndreas Gohr $remote = (!$flagExternalEdit) ? clientIP(true) : '127.0.0.1'; 70585bf44eSChristopher Smith $user = (!$flagExternalEdit) ? $INPUT->server->str('REMOTE_USER') : ''; 71*1d11f1d3SSatoshi Sahara $sizechange = ($sizechange === null) ? '' : (int)$sizechange; 727d559c7fSBen Coburn 73*1d11f1d3SSatoshi Sahara // update changelog file and get the added entry that is also to be stored in metadata 74*1d11f1d3SSatoshi Sahara $logEntry = (new PageChangeLog($id, 1024))->addLogEntry([ 757d559c7fSBen Coburn 'date' => $date, 767d559c7fSBen Coburn 'ip' => $remote, 77c7192766SSatoshi Sahara 'type' => $type, 787d559c7fSBen Coburn 'id' => $id, 797d559c7fSBen Coburn 'user' => $user, 80c7192766SSatoshi Sahara 'sum' => $summary, 81c7192766SSatoshi Sahara 'extra' => $extra, 82c7192766SSatoshi Sahara 'sizechange' => $sizechange, 83*1d11f1d3SSatoshi Sahara ]); 847d559c7fSBen Coburn 857d559c7fSBen Coburn // update metadata 867d559c7fSBen Coburn if (!$wasRemoved) { 8763f13cadSDamien Regad $oldmeta = p_read_metadata($id)['persistent']; 887d559c7fSBen Coburn $meta = array(); 89*1d11f1d3SSatoshi Sahara if ($wasCreated && 90*1d11f1d3SSatoshi Sahara (empty($oldmeta['date']['created']) || $oldmeta['date']['created'] === $created) 91bba3d825SAndreas Gohr ) { 9264159a61SAndreas Gohr // newly created 937d559c7fSBen Coburn $meta['date']['created'] = $created; 94a8e72133SAndreas Gohr if ($user) { 95aac83cd4SPhy $meta['creator'] = isset($INFO) ? $INFO['userinfo']['name'] : null; 96a8e72133SAndreas Gohr $meta['user'] = $user; 97a8e72133SAndreas Gohr } 9863f13cadSDamien Regad } elseif (($wasCreated || $wasReverted) && !empty($oldmeta['date']['created'])) { 9964159a61SAndreas Gohr // re-created / restored 10063f13cadSDamien Regad $meta['date']['created'] = $oldmeta['date']['created']; 1013d1f9ec3SMichael Klier $meta['date']['modified'] = $created; // use the files ctime here 10263f13cadSDamien Regad $meta['creator'] = isset($oldmeta['creator']) ? $oldmeta['creator'] : null; 103aac83cd4SPhy if ($user) $meta['contributor'][$user] = isset($INFO) ? $INFO['userinfo']['name'] : null; 1047d559c7fSBen Coburn } elseif (!$minor) { // non-minor modification 1057d559c7fSBen Coburn $meta['date']['modified'] = $date; 106aac83cd4SPhy if ($user) $meta['contributor'][$user] = isset($INFO) ? $INFO['userinfo']['name'] : null; 1077d559c7fSBen Coburn } 108*1d11f1d3SSatoshi Sahara $meta['last_change'] = $logEntry; 109ee4d22e0SChristopher Smith p_set_metadata($id, $meta); 1107d559c7fSBen Coburn } 1117d559c7fSBen Coburn} 1127d559c7fSBen Coburn 1137d559c7fSBen Coburn/** 11499c8d7f2Smichael * Add's an entry to the media changelog 11599c8d7f2Smichael * 11699c8d7f2Smichael * @author Michael Hamann <michael@content-space.de> 11799c8d7f2Smichael * @author Andreas Gohr <andi@splitbrain.org> 11899c8d7f2Smichael * @author Esther Brunner <wikidesign@gmail.com> 11999c8d7f2Smichael * @author Ben Coburn <btcoburn@silicodon.net> 1204f1e2cb3SGerrit Uitslag * 1214f1e2cb3SGerrit Uitslag * @param int $date Timestamp of the change 1224f1e2cb3SGerrit Uitslag * @param String $id Name of the affected page 1234f1e2cb3SGerrit Uitslag * @param String $type Type of the change see DOKU_CHANGE_TYPE_* 1244f1e2cb3SGerrit Uitslag * @param String $summary Summary of the change 1254f1e2cb3SGerrit Uitslag * @param mixed $extra In case of a revert the revision (timestmp) of the reverted page 1264f1e2cb3SGerrit Uitslag * @param array $flags Additional flags in a key value array. 1274f1e2cb3SGerrit Uitslag * Available flags: 1284f1e2cb3SGerrit Uitslag * - (none, so far) 129ac3ed4afSGerrit Uitslag * @param null|int $sizechange Change of filesize 13099c8d7f2Smichael */ 13164159a61SAndreas Gohrfunction addMediaLogEntry( 13264159a61SAndreas Gohr $date, 13364159a61SAndreas Gohr $id, 13464159a61SAndreas Gohr $type = DOKU_CHANGE_TYPE_EDIT, 13564159a61SAndreas Gohr $summary = '', 13664159a61SAndreas Gohr $extra = '', 13764159a61SAndreas Gohr $flags = null, 13864159a61SAndreas Gohr $sizechange = null) 13964159a61SAndreas Gohr{ 140de3eb1d7SAdrian Lang global $conf; 141585bf44eSChristopher Smith /** @var Input $INPUT */ 142585bf44eSChristopher Smith global $INPUT; 14399c8d7f2Smichael 144facfe250SSatoshi Sahara // check for special flags as keys 145facfe250SSatoshi Sahara if (!is_array($flags)) $flags = array(); 146facfe250SSatoshi Sahara $flagExternalEdit = isset($flags['ExternalEdit']); 147facfe250SSatoshi Sahara 14899c8d7f2Smichael $id = cleanid($id); 14999c8d7f2Smichael 15099c8d7f2Smichael if (!$date) $date = time(); //use current time if none supplied 151facfe250SSatoshi Sahara $remote = (!$flagExternalEdit) ? clientIP(true) : '127.0.0.1'; 152facfe250SSatoshi Sahara $user = (!$flagExternalEdit) ? $INPUT->server->str('REMOTE_USER') : ''; 153*1d11f1d3SSatoshi Sahara $sizechange = ($sizechange === null) ? '' : (int)$sizechange; 15499c8d7f2Smichael 155*1d11f1d3SSatoshi Sahara // update changelog file and get the added entry 156*1d11f1d3SSatoshi Sahara $logEntry = (new MediaChangeLog($id, 1024))->addLogEntry([ 15799c8d7f2Smichael 'date' => $date, 15899c8d7f2Smichael 'ip' => $remote, 159c7192766SSatoshi Sahara 'type' => $type, 16099c8d7f2Smichael 'id' => $id, 16199c8d7f2Smichael 'user' => $user, 162c7192766SSatoshi Sahara 'sum' => $summary, 163c7192766SSatoshi Sahara 'extra' => $extra, 164c7192766SSatoshi Sahara 'sizechange' => $sizechange, 165*1d11f1d3SSatoshi Sahara ]); 16699c8d7f2Smichael} 16799c8d7f2Smichael 16899c8d7f2Smichael/** 169252acce3SSatoshi Sahara * returns an array of recently changed files using the changelog 1707d559c7fSBen Coburn * 1717d559c7fSBen Coburn * The following constants can be used to control which changes are 1727d559c7fSBen Coburn * included. Add them together as needed. 1737d559c7fSBen Coburn * 1747d559c7fSBen Coburn * RECENTS_SKIP_DELETED - don't include deleted pages 1757d559c7fSBen Coburn * RECENTS_SKIP_MINORS - don't include minor changes 17608e9b52fSPhy * RECENTS_ONLY_CREATION - only include new created pages and media 1777d559c7fSBen Coburn * RECENTS_SKIP_SUBSPACES - don't include subspaces 1780b926329SKate Arzamastseva * RECENTS_MEDIA_CHANGES - return media changes instead of page changes 1790b926329SKate Arzamastseva * RECENTS_MEDIA_PAGES_MIXED - return both media changes and page changes 1807d559c7fSBen Coburn * 1817d559c7fSBen Coburn * @param int $first number of first entry returned (for paginating 1827d559c7fSBen Coburn * @param int $num return $num entries 1837d559c7fSBen Coburn * @param string $ns restrict to given namespace 18459f20ea3SMichael Hamann * @param int $flags see above 18559f20ea3SMichael Hamann * @return array recently changed files 1867d559c7fSBen Coburn * 1877d559c7fSBen Coburn * @author Ben Coburn <btcoburn@silicodon.net> 18829778747SKate Arzamastseva * @author Kate Arzamastseva <pshns@ukr.net> 1897d559c7fSBen Coburn */ 1907d559c7fSBen Coburnfunction getRecents($first, $num, $ns = '', $flags = 0) { 1917d559c7fSBen Coburn global $conf; 1927d559c7fSBen Coburn $recent = array(); 1937d559c7fSBen Coburn $count = 0; 1947d559c7fSBen Coburn 1957d559c7fSBen Coburn if (!$num) 1967d559c7fSBen Coburn return $recent; 1977d559c7fSBen Coburn 1987d559c7fSBen Coburn // read all recent changes. (kept short) 1990b926329SKate Arzamastseva if ($flags & RECENTS_MEDIA_CHANGES) { 2008e3e8693SAndreas Gohr $lines = @file($conf['media_changelog']) ?: []; 20199c8d7f2Smichael } else { 2028e3e8693SAndreas Gohr $lines = @file($conf['changelog']) ?: []; 20399c8d7f2Smichael } 2041b266025SPhy if (!is_array($lines)) { 2051b266025SPhy $lines = array(); 2061b266025SPhy } 20729778747SKate Arzamastseva $lines_position = count($lines) - 1; 20859f20ea3SMichael Hamann $media_lines_position = 0; 20959f20ea3SMichael Hamann $media_lines = array(); 21029778747SKate Arzamastseva 2110b926329SKate Arzamastseva if ($flags & RECENTS_MEDIA_PAGES_MIXED) { 2128e3e8693SAndreas Gohr $media_lines = @file($conf['media_changelog']) ?: []; 2131b266025SPhy if (!is_array($media_lines)) { 2141b266025SPhy $media_lines = array(); 2151b266025SPhy } 21629778747SKate Arzamastseva $media_lines_position = count($media_lines) - 1; 21729778747SKate Arzamastseva } 21829778747SKate Arzamastseva 21929778747SKate Arzamastseva $seen = array(); // caches seen lines, _handleRecent() skips them 2207d559c7fSBen Coburn 2217d559c7fSBen Coburn // handle lines 2220b926329SKate Arzamastseva while ($lines_position >= 0 || (($flags & RECENTS_MEDIA_PAGES_MIXED) && $media_lines_position >= 0)) { 22329778747SKate Arzamastseva if (empty($rec) && $lines_position >= 0) { 2241d901ab2SAndreas Gohr $rec = _handleRecent(@$lines[$lines_position], $ns, $flags, $seen); 22529778747SKate Arzamastseva if (!$rec) { 22629778747SKate Arzamastseva $lines_position --; 22729778747SKate Arzamastseva continue; 22829778747SKate Arzamastseva } 22929778747SKate Arzamastseva } 2300b926329SKate Arzamastseva if (($flags & RECENTS_MEDIA_PAGES_MIXED) && empty($media_rec) && $media_lines_position >= 0) { 23164159a61SAndreas Gohr $media_rec = _handleRecent( 23264159a61SAndreas Gohr @$media_lines[$media_lines_position], 23364159a61SAndreas Gohr $ns, 23464159a61SAndreas Gohr $flags | RECENTS_MEDIA_CHANGES, 23564159a61SAndreas Gohr $seen 23664159a61SAndreas Gohr ); 23729778747SKate Arzamastseva if (!$media_rec) { 23829778747SKate Arzamastseva $media_lines_position --; 23929778747SKate Arzamastseva continue; 24029778747SKate Arzamastseva } 24129778747SKate Arzamastseva } 2420b926329SKate Arzamastseva if (($flags & RECENTS_MEDIA_PAGES_MIXED) && @$media_rec['date'] >= @$rec['date']) { 24329778747SKate Arzamastseva $media_lines_position--; 24429778747SKate Arzamastseva $x = $media_rec; 245b5941dfaSKate Arzamastseva $x['media'] = true; 24629778747SKate Arzamastseva $media_rec = false; 24729778747SKate Arzamastseva } else { 24829778747SKate Arzamastseva $lines_position--; 24929778747SKate Arzamastseva $x = $rec; 250421ec38eSKate Arzamastseva if ($flags & RECENTS_MEDIA_CHANGES) $x['media'] = true; 25129778747SKate Arzamastseva $rec = false; 25229778747SKate Arzamastseva } 2537d559c7fSBen Coburn if (--$first >= 0) continue; // skip first entries 25429778747SKate Arzamastseva $recent[] = $x; 2557d559c7fSBen Coburn $count++; 2567d559c7fSBen Coburn // break when we have enough entries 2577d559c7fSBen Coburn if ($count >= $num) { break; } 2587d559c7fSBen Coburn } 2597d559c7fSBen Coburn return $recent; 2607d559c7fSBen Coburn} 2617d559c7fSBen Coburn 2627d559c7fSBen Coburn/** 26399c8d7f2Smichael * returns an array of files changed since a given time using the 26499c8d7f2Smichael * changelog 26599c8d7f2Smichael * 26699c8d7f2Smichael * The following constants can be used to control which changes are 26799c8d7f2Smichael * included. Add them together as needed. 26899c8d7f2Smichael * 26999c8d7f2Smichael * RECENTS_SKIP_DELETED - don't include deleted pages 27099c8d7f2Smichael * RECENTS_SKIP_MINORS - don't include minor changes 27108e9b52fSPhy * RECENTS_ONLY_CREATION - only include new created pages and media 27299c8d7f2Smichael * RECENTS_SKIP_SUBSPACES - don't include subspaces 2730b926329SKate Arzamastseva * RECENTS_MEDIA_CHANGES - return media changes instead of page changes 27499c8d7f2Smichael * 27599c8d7f2Smichael * @param int $from date of the oldest entry to return 27699c8d7f2Smichael * @param int $to date of the newest entry to return (for pagination, optional) 27799c8d7f2Smichael * @param string $ns restrict to given namespace (optional) 27859f20ea3SMichael Hamann * @param int $flags see above (optional) 27959f20ea3SMichael Hamann * @return array of files 28099c8d7f2Smichael * 28199c8d7f2Smichael * @author Michael Hamann <michael@content-space.de> 28299c8d7f2Smichael * @author Ben Coburn <btcoburn@silicodon.net> 28399c8d7f2Smichael */ 28499c8d7f2Smichaelfunction getRecentsSince($from, $to = null, $ns = '', $flags = 0) { 28599c8d7f2Smichael global $conf; 28699c8d7f2Smichael $recent = array(); 28799c8d7f2Smichael 28899c8d7f2Smichael if ($to && $to < $from) 28999c8d7f2Smichael return $recent; 29099c8d7f2Smichael 29199c8d7f2Smichael // read all recent changes. (kept short) 2920b926329SKate Arzamastseva if ($flags & RECENTS_MEDIA_CHANGES) { 29399c8d7f2Smichael $lines = @file($conf['media_changelog']); 29499c8d7f2Smichael } else { 29599c8d7f2Smichael $lines = @file($conf['changelog']); 29699c8d7f2Smichael } 297e920a0a1SAndreas Gohr if (!$lines) return $recent; 29899c8d7f2Smichael 29999c8d7f2Smichael // we start searching at the end of the list 30099c8d7f2Smichael $lines = array_reverse($lines); 30199c8d7f2Smichael 30299c8d7f2Smichael // handle lines 30399c8d7f2Smichael $seen = array(); // caches seen lines, _handleRecent() skips them 30499c8d7f2Smichael 30599c8d7f2Smichael foreach ($lines as $line) { 30699c8d7f2Smichael $rec = _handleRecent($line, $ns, $flags, $seen); 30799c8d7f2Smichael if ($rec !== false) { 30899c8d7f2Smichael if ($rec['date'] >= $from) { 30999c8d7f2Smichael if (!$to || $rec['date'] <= $to) { 31099c8d7f2Smichael $recent[] = $rec; 31199c8d7f2Smichael } 31299c8d7f2Smichael } else { 31399c8d7f2Smichael break; 31499c8d7f2Smichael } 31599c8d7f2Smichael } 31699c8d7f2Smichael } 31799c8d7f2Smichael 31899c8d7f2Smichael return array_reverse($recent); 31999c8d7f2Smichael} 32099c8d7f2Smichael 32199c8d7f2Smichael/** 3227d559c7fSBen Coburn * Internal function used by getRecents 3237d559c7fSBen Coburn * 3247d559c7fSBen Coburn * don't call directly 3257d559c7fSBen Coburn * 3267d559c7fSBen Coburn * @see getRecents() 3277d559c7fSBen Coburn * @author Andreas Gohr <andi@splitbrain.org> 3287d559c7fSBen Coburn * @author Ben Coburn <btcoburn@silicodon.net> 3294f1e2cb3SGerrit Uitslag * 3304f1e2cb3SGerrit Uitslag * @param string $line changelog line 3314f1e2cb3SGerrit Uitslag * @param string $ns restrict to given namespace 3324f1e2cb3SGerrit Uitslag * @param int $flags flags to control which changes are included 3334f1e2cb3SGerrit Uitslag * @param array $seen listing of seen pages 3344f1e2cb3SGerrit Uitslag * @return array|bool false or array with info about a change 3357d559c7fSBen Coburn */ 33699c8d7f2Smichaelfunction _handleRecent($line, $ns, $flags, &$seen) { 3377d559c7fSBen Coburn if (empty($line)) return false; //skip empty lines 3387d559c7fSBen Coburn 3397d559c7fSBen Coburn // split the line into parts 340*1d11f1d3SSatoshi Sahara $recent = ChangeLog::parseLogLine($line); 341252acce3SSatoshi Sahara if ($recent === false) return false; 3427d559c7fSBen Coburn 3437d559c7fSBen Coburn // skip seen ones 3447d559c7fSBen Coburn if (isset($seen[$recent['id']])) return false; 3457d559c7fSBen Coburn 34608e9b52fSPhy // skip changes, of only new items are requested 34708e9b52fSPhy if ($recent['type'] !== DOKU_CHANGE_TYPE_CREATE && ($flags & RECENTS_ONLY_CREATION)) return false; 34868f43bcfSTero Kivinen 3497d559c7fSBen Coburn // skip minors 350ebf1501fSBen Coburn if ($recent['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT && ($flags & RECENTS_SKIP_MINORS)) return false; 3517d559c7fSBen Coburn 3527d559c7fSBen Coburn // remember in seen to skip additional sights 3537d559c7fSBen Coburn $seen[$recent['id']] = 1; 3547d559c7fSBen Coburn 3557d559c7fSBen Coburn // check if it's a hidden page 3567d559c7fSBen Coburn if (isHiddenPage($recent['id'])) return false; 3577d559c7fSBen Coburn 3587d559c7fSBen Coburn // filter namespace 3597d559c7fSBen Coburn if (($ns) && (strpos($recent['id'], $ns.':') !== 0)) return false; 3607d559c7fSBen Coburn 3617d559c7fSBen Coburn // exclude subnamespaces 3627d559c7fSBen Coburn if (($flags & RECENTS_SKIP_SUBSPACES) && (getNS($recent['id']) != $ns)) return false; 3637d559c7fSBen Coburn 3647d559c7fSBen Coburn // check ACL 36542025dfdSMichael Hamann if ($flags & RECENTS_MEDIA_CHANGES) { 36642025dfdSMichael Hamann $recent['perms'] = auth_quickaclcheck(getNS($recent['id']).':*'); 36742025dfdSMichael Hamann } else { 36899c8d7f2Smichael $recent['perms'] = auth_quickaclcheck($recent['id']); 36942025dfdSMichael Hamann } 37099c8d7f2Smichael if ($recent['perms'] < AUTH_READ) return false; 3717d559c7fSBen Coburn 3727d559c7fSBen Coburn // check existance 3731d901ab2SAndreas Gohr if ($flags & RECENTS_SKIP_DELETED) { 37442025dfdSMichael Hamann $fn = (($flags & RECENTS_MEDIA_CHANGES) ? mediaFN($recent['id']) : wikiFN($recent['id'])); 37579e79377SAndreas Gohr if (!file_exists($fn)) return false; 3761d901ab2SAndreas Gohr } 3777d559c7fSBen Coburn 3787d559c7fSBen Coburn return $recent; 3797d559c7fSBen Coburn} 3805d9428a0SSatoshi Sahara