/** * Checks if the current page version is newer than the last entry in the page's * changelog. If so, we assume it has been an external edit and we create an * attic copy and add a proper changelog line. * * This check is only executed when the page is about to be saved again from the * wiki, triggered in @see saveWikiText() * * @param string $id the page ID */ function detectExternalEdit($id) { global $lang; $fileLastMod = wikiFN($id); $lastMod = @filemtime($fileLastMod); // from page $pagelog = new PageChangeLog($id, 1024); $lastRev = $pagelog->getRevisions(-1, 1); // from changelog $lastRev = (int) (empty($lastRev) ? 0 : $lastRev[0]); if (!file_exists(wikiFN($id, $lastMod)) && file_exists($fileLastMod) && $lastMod >= $lastRev) { // add old revision to the attic if missing saveOldRevision($id); // add a changelog entry if this edit came from outside dokuwiki if ($lastMod > $lastRev) { $fileLastRev = wikiFN($id, $lastRev); $revinfo = $pagelog->getRevisionInfo($lastRev); if (empty($lastRev) || !file_exists($fileLastRev) || $revinfo['type'] == DOKU_CHANGE_TYPE_DELETE) { $filesize_old = 0; } else { $filesize_old = io_getSizeFile($fileLastRev); } $filesize_new = filesize($fileLastMod); $sizechange = $filesize_new - $filesize_old; addLogEntry($lastMod, $id, DOKU_CHANGE_TYPE_EDIT, $lang['external_edit'], '', array('ExternalEdit' => true), $sizechange); // remove soon to be stale instructions $cache = new cache_instructions($id, $fileLastMod); $cache->removeCache(); } } }
/** * Create html for revision navigation * * @param PageChangeLog $pagelog changelog object of current page * @param string $type inline vs sidebyside * @param int $l_rev left revision timestamp * @param int $r_rev right revision timestamp * @return string[] html of left and right navigation elements */ function html_diff_navigation($pagelog, $type, $l_rev, $r_rev) { global $INFO, $ID; // last timestamp is not in changelog, retrieve timestamp from metadata // note: when page is removed, the metadata timestamp is zero if (!$r_rev) { if (isset($INFO['meta']['last_change']['date'])) { $r_rev = $INFO['meta']['last_change']['date']; } else { $r_rev = 0; } } //retrieve revisions with additional info list($l_revs, $r_revs) = $pagelog->getRevisionsAround($l_rev, $r_rev); $l_revisions = array(); if (!$l_rev) { $l_revisions[0] = array(0, "", false); //no left revision given, add dummy } foreach ($l_revs as $rev) { $info = $pagelog->getRevisionInfo($rev); $l_revisions[$rev] = array($rev, dformat($info['date']) . ' ' . editorinfo($info['user'], true) . ' ' . $info['sum'], $r_rev ? $rev >= $r_rev : false); } $r_revisions = array(); if (!$r_rev) { $r_revisions[0] = array(0, "", false); //no right revision given, add dummy } foreach ($r_revs as $rev) { $info = $pagelog->getRevisionInfo($rev); $r_revisions[$rev] = array($rev, dformat($info['date']) . ' ' . editorinfo($info['user'], true) . ' ' . $info['sum'], $rev <= $l_rev); } //determine previous/next revisions $l_index = array_search($l_rev, $l_revs); $l_prev = $l_revs[$l_index + 1]; $l_next = $l_revs[$l_index - 1]; if ($r_rev) { $r_index = array_search($r_rev, $r_revs); $r_prev = $r_revs[$r_index + 1]; $r_next = $r_revs[$r_index - 1]; } else { //removed page if ($l_next) { $r_prev = $r_revs[0]; } else { $r_prev = null; } $r_next = null; } /* * Left side: */ $l_nav = ''; //move back if ($l_prev) { $l_nav .= html_diff_navigationlink($type, 'diffbothprevrev', $l_prev, $r_prev); $l_nav .= html_diff_navigationlink($type, 'diffprevrev', $l_prev, $r_rev); } //dropdown $form = new Doku_Form(array('action' => wl())); $form->addHidden('id', $ID); $form->addHidden('difftype', $type); $form->addHidden('rev2[1]', $r_rev); $form->addHidden('do', 'diff'); $form->addElement(form_makeListboxField('rev2[0]', $l_revisions, $l_rev, '', '', '', array('class' => 'quickselect'))); $form->addElement(form_makeButton('submit', 'diff', 'Go')); $l_nav .= $form->getForm(); //move forward if ($l_next && ($l_next < $r_rev || !$r_rev)) { $l_nav .= html_diff_navigationlink($type, 'diffnextrev', $l_next, $r_rev); } /* * Right side: */ $r_nav = ''; //move back if ($l_rev < $r_prev) { $r_nav .= html_diff_navigationlink($type, 'diffprevrev', $l_rev, $r_prev); } //dropdown $form = new Doku_Form(array('action' => wl())); $form->addHidden('id', $ID); $form->addHidden('rev2[0]', $l_rev); $form->addHidden('difftype', $type); $form->addHidden('do', 'diff'); $form->addElement(form_makeListboxField('rev2[1]', $r_revisions, $r_rev, '', '', '', array('class' => 'quickselect'))); $form->addElement(form_makeButton('submit', 'diff', 'Go')); $r_nav .= $form->getForm(); //move forward if ($r_next) { if ($pagelog->isCurrentRevision($r_next)) { $r_nav .= html_diff_navigationlink($type, 'difflastrev', $l_rev); //last revision is diff with current page } else { $r_nav .= html_diff_navigationlink($type, 'diffnextrev', $l_rev, $r_next); } $r_nav .= html_diff_navigationlink($type, 'diffbothnextrev', $l_next, $r_next); } return array($l_nav, $r_nav); }
/** * Return info about the current document as associative * array. * * @author Andreas Gohr <*****@*****.**> * * @return array with info about current document */ function pageinfo() { global $ID; global $REV; global $RANGE; global $lang; /* @var Input $INPUT */ global $INPUT; $info = basicinfo($ID); // include ID & REV not redundant, as some parts of DokuWiki may temporarily change $ID, e.g. p_wiki_xhtml // FIXME ... perhaps it would be better to ensure the temporary changes weren't necessary $info['id'] = $ID; $info['rev'] = $REV; if ($INPUT->server->has('REMOTE_USER')) { $sub = new Subscription(); $info['subscribed'] = $sub->user_subscription(); } else { $info['subscribed'] = false; } $info['locked'] = checklock($ID); $info['filepath'] = fullpath(wikiFN($ID)); $info['exists'] = file_exists($info['filepath']); $info['currentrev'] = @filemtime($info['filepath']); if ($REV) { //check if current revision was meant if ($info['exists'] && $info['currentrev'] == $REV) { $REV = ''; } elseif ($RANGE) { //section editing does not work with old revisions! $REV = ''; $RANGE = ''; msg($lang['nosecedit'], 0); } else { //really use old revision $info['filepath'] = fullpath(wikiFN($ID, $REV)); $info['exists'] = file_exists($info['filepath']); } } $info['rev'] = $REV; if ($info['exists']) { $info['writable'] = is_writable($info['filepath']) && $info['perm'] >= AUTH_EDIT; } else { $info['writable'] = $info['perm'] >= AUTH_CREATE; } $info['editable'] = $info['writable'] && empty($info['locked']); $info['lastmod'] = @filemtime($info['filepath']); //load page meta data $info['meta'] = p_get_metadata($ID); //who's the editor $pagelog = new PageChangeLog($ID, 1024); if ($REV) { $revinfo = $pagelog->getRevisionInfo($REV); } else { if (!empty($info['meta']['last_change']) && is_array($info['meta']['last_change'])) { $revinfo = $info['meta']['last_change']; } else { $revinfo = $pagelog->getRevisionInfo($info['lastmod']); // cache most recent changelog line in metadata if missing and still valid if ($revinfo !== false) { $info['meta']['last_change'] = $revinfo; p_set_metadata($ID, array('last_change' => $revinfo)); } } } //and check for an external edit if ($revinfo !== false && $revinfo['date'] != $info['lastmod']) { // cached changelog line no longer valid $revinfo = false; $info['meta']['last_change'] = $revinfo; p_set_metadata($ID, array('last_change' => $revinfo)); } $info['ip'] = $revinfo['ip']; $info['user'] = $revinfo['user']; $info['sum'] = $revinfo['sum']; // See also $INFO['meta']['last_change'] which is the most recent log line for page $ID. // Use $INFO['meta']['last_change']['type']===DOKU_CHANGE_TYPE_MINOR_EDIT in place of $info['minor']. if ($revinfo['user']) { $info['editor'] = $revinfo['user']; } else { $info['editor'] = $revinfo['ip']; } // draft $draft = getCacheName($info['client'] . $ID, '.draft'); if (file_exists($draft)) { if (@filemtime($draft) < @filemtime(wikiFN($ID))) { // remove stale draft @unlink($draft); } else { $info['draft'] = $draft; } } return $info; }
/** * sometimes chuncksize is set to true */ function test_chuncksizetrue() { $rev = 1362525899; $infoexpected = parseChangelogLine($this->logline); $pagelog = new PageChangeLog($this->pageid, true); $info = $pagelog->getRevisionInfo($rev); $this->assertEquals($infoexpected, $info); }
/** * Returns a list of available revisions of a given wiki page * * @author Michael Klier <*****@*****.**> * * @param string $id page id * @param int $first skip the first n changelog lines * @return array * @throws RemoteAccessDeniedException no read access for page * @throws RemoteException empty id */ function pageVersions($id, $first) { $id = $this->resolvePageId($id); if (auth_quickaclcheck($id) < AUTH_READ) { throw new RemoteAccessDeniedException('You are not allowed to read this page', 111); } global $conf; $versions = array(); if (empty($id)) { throw new RemoteException('Empty page ID', 131); } $pagelog = new PageChangeLog($id); $revisions = $pagelog->getRevisions($first, $conf['recent'] + 1); if (count($revisions) == 0 && $first != 0) { $first = 0; $revisions = $pagelog->getRevisions($first, $conf['recent'] + 1); } if (count($revisions) > 0 && $first == 0) { array_unshift($revisions, ''); // include current revision if (count($revisions) > $conf['recent']) { array_pop($revisions); // remove extra log entry } } if (count($revisions) > $conf['recent']) { array_pop($revisions); // remove extra log entry } if (!empty($revisions)) { foreach ($revisions as $rev) { $file = wikiFN($id, $rev); $time = @filemtime($file); // we check if the page actually exists, if this is not the // case this can lead to less pages being returned than // specified via $conf['recent'] if ($time) { $pagelog->setChunkSize(1024); $info = $pagelog->getRevisionInfo($time); if (!empty($info)) { $data = array(); $data['user'] = $info['user']; $data['ip'] = $info['ip']; $data['type'] = $info['type']; $data['sum'] = $info['sum']; $data['modified'] = $this->api->toDate($info['date']); $data['version'] = $info['date']; array_push($versions, $data); } } } return $versions; } else { return array(); } }
/** * Get the changelog information for a specific page id * and revision (timestamp). Adjacent changelog lines * are optimistically parsed and cached to speed up * consecutive calls to getRevisionInfo. For large * changelog files, only the chunk containing the * requested changelog line is read. * * @deprecated 2013-11-20 * * @author Ben Coburn <*****@*****.**> * @author Kate Arzamastseva <*****@*****.**> */ function getRevisionInfo($id, $rev, $chunk_size = 8192, $media = false) { dbg_deprecated('class PageChangeLog or class MediaChangelog'); if ($media) { $changelog = new MediaChangeLog($id, $chunk_size); } else { $changelog = new PageChangeLog($id, $chunk_size); } return $changelog->getRevisionInfo($rev); }
function handle_display_banner(&$event, $param) { global $ID, $REV, $INFO; if ($event->data != 'show') { return; } if (!$INFO['exists']) { return; } $m = p_get_metadata($ID); $changelog = new PageChangeLog($ID); //sprawdź status aktualnej strony if ($REV != 0) { $ch = $changelog->getRevisionInfo($REV); $sum = $ch['sum']; } else { $sum = $m['last_change']['sum']; } if ($sum != APPRVOED) { $class = 'approved_no'; $last_approved_rev = $this->find_lastest_approved(); } ptln('<div class="approval ' . ($sum == APPROVED ? 'approved_yes' : 'approved_no') . '">'); tpl_pageinfo(); ptln(' | '); if ($sum == APPROVED) { ptln('<span>' . $this->getLang('approved') . '</span>'); if ($REV != 0 && auth_quickaclcheck($ID) > AUTH_READ) { ptln('<a href="' . wl($ID) . '">'); ptln($this->getLang($m['last_change']['sum'] == APPROVED ? 'newest_approved' : 'newest_draft')); ptln('</a>'); } else { if ($REV != 0 && $REV != $last_approved_rev) { ptln('<a href="' . wl($ID) . '">'); ptln($this->getLang('newest_approved')); ptln('</a>'); } } } else { ptln('<span>' . $this->getLang('draft') . '</span>'); if (isset($last_approved_rev)) { if ($last_approved_rev != 0) { ptln('<a href="' . wl($ID, array('rev' => $last_approved_rev)) . '">'); } else { ptln('<a href="' . wl($ID) . '">'); } ptln($this->getLang('newest_approved')); ptln('</a>'); } else { ptln('<a href="' . wl($ID) . '">'); ptln($this->getLang('newest_draft')); ptln('</a>'); } //można zatwierdzać tylko najnowsze strony if ($REV == 0 && $this->can_approve()) { ptln('<a href="' . wl($ID, array('rev' => $last_approved_rev, 'do' => 'diff', 'approve' => 'approve')) . '">'); ptln($this->getLang('approve')); ptln('</a>'); } } ptln('</div>'); }
/** * request existing rev and check cache */ function test_requestrev_checkcache() { $rev = 1362525359; $dir = 1; $revexpected = 1362525899; $infoexpected = parseChangelogLine($this->logline); $pagelog = new PageChangeLog($this->pageid, $chunk_size = 8192); $revfound = $pagelog->getRelativeRevision($rev, $dir); $this->assertEquals($revexpected, $revfound); //checked info returned from cache $info = $pagelog->getRevisionInfo($revfound); $this->assertEquals($infoexpected, $info); }
/** * Get the changelog information for a specific page id * and revision (timestamp). Adjacent changelog lines * are optimistically parsed and cached to speed up * consecutive calls to getRevisionInfo. For large * changelog files, only the chunk containing the * requested changelog line is read. * * @deprecated 20-11-2013 * * @author Ben Coburn <*****@*****.**> * @author Kate Arzamastseva <*****@*****.**> */ function getRevisionInfo($id, $rev, $chunk_size = 8192, $media = false) { if ($media) { $changelog = new MediaChangeLog($id, $chunk_size); } else { $changelog = new PageChangeLog($id, $chunk_size); } return $changelog->getRevisionInfo($rev); }