function dw_get_pages($dir) { static $trunclen = null; if (!$trunclen) { global $conf; $trunclen = strlen($conf['datadir'] . ':'); } if (!is_dir($dir)) { fwrite(STDERR, "Unable to read directory {$dir}\n"); exit(1); } $pages = array(); $dh = opendir($dir); while (false !== ($entry = readdir($dh))) { $status = dw_dir_filter($entry, $dir); if ($status == DW_DIR_CONTINUE) { continue; } else { if ($status == DW_DIR_NS) { $pages = array_merge($pages, dw_get_pages($dir . '/' . $entry)); } else { $page = array('id' => pathID(substr($dir . '/' . $entry, $trunclen)), 'file' => $dir . '/' . $entry); $pages[] = $page; } } } closedir($dh); return $pages; }
/** * Search for internal wiki links in page $file */ function orph_Check_InternalLinks(&$data, $base, $file, $type, $lvl, $opts) { global $conf; define('LINK_PATTERN', '%\\[\\[([^\\]|#]*)(#[^\\]|]*)?\\|?([^\\]]*)]]%'); if (!preg_match("/.*\\.txt\$/", $file)) { return; } $currentID = pathID($file); $currentNS = getNS($currentID); if ($conf['allowdebug']) { echo sprintf("<p><b>%s</b>: %s</p>\n", $file, $currentID); } // echo " <!-- checking file: $file -->\n"; $body = @file_get_contents($conf['datadir'] . $file); // ignores entries in <nowiki>, %%, <code> and emails with @ foreach (array('/<nowiki>.*?<\\/nowiki>/', '/%%.*?%%/', '@<code[^>]*?>.*?<\\/code>@siu', '@<file[^>]*?>.*?<\\/file>@siu') as $ignored) { $body = preg_replace($ignored, '', $body); } $links = array(); preg_match_all(LINK_PATTERN, $body, $links); foreach ($links[1] as $link) { if ($conf['allowdebug']) { echo sprintf("--- Checking %s<br />\n", $link); } if (0 < strlen(ltrim($link)) and !preg_match('/^[a-zA-Z0-9\\.]+>{1}.*$/u', $link) and !preg_match('/^\\\\\\\\[\\w.:?\\-;,]+?\\\\/u', $link) and !preg_match('#^([a-z0-9\\-\\.+]+?)://#i', $link) and !preg_match('<' . PREG_PATTERN_VALID_EMAIL . '>', $link) and !preg_match('!^#.+!', $link)) { $pageExists = false; resolve_pageid($currentNS, $link, $pageExists); if ($conf['allowdebug']) { echo sprintf("---- link='%s' %s ", $link, $pageExists ? 'EXISTS' : 'MISS'); } if (strlen(ltrim($link)) > 0 and !auth_quickaclcheck($link) < AUTH_READ) { // should be visible to user //echo " <!-- adding $link -->\n"; if ($conf['allowdebug']) { echo ' A_LINK'; } $link = utf8_strtolower($link); $this->orph_handle_link($data, $link); } else { if ($conf['allowdebug']) { echo ' EMPTY_OR_FORBIDDEN'; } } } else { if ($conf['allowdebug']) { echo ' NOT_INTERNAL'; } } if ($conf['allowdebug']) { echo "<br />\n"; } } // end of foreach link }
function indexmenu_search_index(&$data, $base, $file, $type, $lvl, $opts) { global $conf; $ret = true; $item = array(); if ($type == 'f' && !preg_match('#\\.txt$#', $file)) { // don't add return false; } // get page id by filename $id = pathID($file); // check hiddens if ($type == 'f' && isHiddenPage($id)) { return false; } // bugfix for the // /ns/ // /<ns>.txt // case, need to force the 'directory' type if ($type == 'f' && file_exists(dirname(wikiFN($id . ":" . noNS($id))))) { $type = 'd'; } // page target id = global id $target = $id; if ($type == 'd') { // this will check 3 kinds of headpage: // 1. /<ns>/<ns>.txt // 2. /<ns>/ // /<ns>.txt // 3. /<ns>/ // /<ns>/<start_page> $nsa = array($id . ":" . noNS($id), $id, $id . ":" . $conf['start']); $nspage = false; foreach ($nsa as $nsp) { if (@file_exists(wikiFN($nsp)) && auth_quickaclcheck($nsp) >= AUTH_READ) { $nspage = $nsp; break; } } //headpage exists if ($nspage) { $target = $nspage; } else { // open namespace index, if headpage does not exists $target = $target . ':'; } } $data[] = array('id' => $id, 'date' => @filectime(wikiFN($target)), 'type' => $type, 'target' => $target, 'title' => $conf['useheading'] && ($title = p_get_first_heading($target)) ? $title : $id, 'level' => $lvl); if (substr_count($id, ":") > 2) { $ret = 0; } return $ret; }
/** * function for the search callback */ function search_discussionpages(&$data, $base, $file, $type, $lvl, $opts) { global $conf; if ($type == 'd') { return true; } // recurse into directories if (!preg_match('#' . preg_quote('/' . DISCUSSION_NS . '/', '#') . '#u', $file)) { return false; } if (!preg_match('#\\.txt$#', $file)) { return false; } $id = pathID(str_replace(DISCUSSION_NS . '/', '', $file)); $data[] = array('id' => $id, 'old' => $conf['datadir'] . $file, 'new' => metaFN($id, '.comments')); return true; }
/** * This is a very universal callback for the search() function, replacing * many of the former individual functions at the cost of a more complex * setup. * * How the function behaves, depends on the options passed in the $opts * array, where the following settings can be used. * * depth int recursion depth. 0 for unlimited * keeptxt bool keep .txt extension for IDs * listfiles bool include files in listing * listdirs bool include namespaces in listing * pagesonly bool restrict files to pages * skipacl bool do not check for READ permission * sneakyacl bool don't recurse into nonreadable dirs * hash bool create MD5 hash for files * meta bool return file metadata * filematch string match files against this regexp * idmatch string match full ID against this regexp * dirmatch string match directory against this regexp when adding * nsmatch string match namespace against this regexp when adding * recmatch string match directory against this regexp when recursing * showmsg bool warn about non-ID files * showhidden bool show hidden files too * firsthead bool return first heading for pages * * @author Andreas Gohr <*****@*****.**> */ function search_universal(&$data, $base, $file, $type, $lvl, $opts) { $item = array(); $return = true; // get ID and check if it is a valid one $item['id'] = pathID($file); if ($item['id'] != cleanID($item['id'])) { if ($opts['showmsg']) { msg(hsc($item['id']) . ' is not a valid file name for DokuWiki - skipped', -1); } return false; // skip non-valid files } $item['ns'] = getNS($item['id']); if ($type == 'd') { // decide if to recursion into this directory is wanted if (!$opts['depth']) { $return = true; // recurse forever } else { $depth = substr_count($file, '/'); if ($depth >= $opts['depth']) { $return = false; // depth reached } else { $return = true; } } if ($return && !preg_match('/' . $opts['recmatch'] . '/', $file)) { $return = false; // doesn't match } } // check ACL if (!$opts['skipacl']) { if ($type == 'd') { $item['perm'] = auth_quickaclcheck($item['id'] . ':*'); } else { $item['perm'] = auth_quickaclcheck($item['id']); //FIXME check namespace for media files } } else { $item['perm'] = AUTH_DELETE; } // are we done here maybe? if ($type == 'd') { if (!$opts['listdirs']) { return $return; } if (!$opts['skipacl'] && $opts['sneakyacl'] && $item['perm'] < AUTH_READ) { return false; } //neither list nor recurse if ($opts['dirmatch'] && !preg_match('/' . $opts['dirmatch'] . '/', $file)) { return $return; } if ($opts['nsmatch'] && !preg_match('/' . $opts['nsmatch'] . '/', $item['ns'])) { return $return; } } else { if (!$opts['listfiles']) { return $return; } if (!$opts['skipacl'] && $item['perm'] < AUTH_READ) { return $return; } if ($opts['pagesonly'] && substr($file, -4) != '.txt') { return $return; } if (!$conf['showhidden'] && isHiddenPage($id)) { return $return; } if ($opts['filematch'] && !preg_match('/' . $opts['filematch'] . '/', $file)) { return $return; } if ($opts['idmatch'] && !preg_match('/' . $opts['idmatch'] . '/', $item['id'])) { return $return; } } // still here? prepare the item $item['type'] = $type; $item['level'] = $lvl; $item['open'] = $return; if ($opts['meta']) { $item['file'] = basename($file); $item['size'] = filesize($base . '/' . $file); $item['mtime'] = filemtime($base . '/' . $file); $item['rev'] = $item['mtime']; $item['writable'] = is_writable($base . '/' . $file); $item['executable'] = is_executable($base . '/' . $file); } if ($type == 'f') { if ($opts['hash']) { $item['hash'] = md5(io_readFile($base . '/' . $file, false)); } if ($opts['firsthead']) { $item['title'] = p_get_first_heading($item['id'], false); } } // finally add the item $data[] = $item; return $return; }
function orph_search_wanted(&$data, $base, $file, $type, $lvl, $opts) { if ($type == 'd') { return true; // recurse all directories, but we don't store namespaces } if (!preg_match("/.*\\.txt\$/", $file)) { // Ignore everything but TXT return true; } // search the body of the file for links // dae mod // orph_Check_InternalLinks(&$data,$base,$file,$type,$lvl,$opts); orph_Check_InternalLinks($data, $base, $file, $type, $lvl, $opts); // get id of this file $id = pathID($file); //check ACL if (auth_quickaclcheck($id) < AUTH_READ) { return false; } // try to avoid making duplicate entries for forms and pages $item =& $data["{$id}"]; if (isset($item)) { // This item already has a member in the array // Note that the file search found it $item['exists'] = true; } else { // Create a new entry $data["{$id}"] = array('exists' => true, 'links' => 0); } return true; }
/** * fulltext search helper * searches a text file with a given regular expression * no ACL checks are performed. This have to be done by * the caller if necessary. * * @param array $data reference to array for results * @param string $base base directory * @param string $file file name to search in * @param string $reg regular expression to search for * @param array $words words that should be marked in the results * * @author Andreas Gohr <*****@*****.**> * @author Matthias Grimm <*****@*****.**> * * @deprecated - fulltext indexer is used instead */ function search_regex(&$data, $base, $file, $reg, $words) { //get text $text = io_readfile($base . '/' . $file); //lowercase text (u modifier does not help with case) $lctext = utf8_strtolower($text); //do the fulltext search $matches = array(); if ($cnt = preg_match_all('#' . $reg . '#usi', $lctext, $matches)) { //this is not the best way for snippet generation but the fastest I could find $q = $words[0]; //use first word for snippet creation $p = utf8_strpos($lctext, $q); $f = $p - 100; $l = utf8_strlen($q) + 200; if ($f < 0) { $f = 0; } $snippet = '<span class="search_sep"> ... </span>' . htmlspecialchars(utf8_substr($text, $f, $l)) . '<span class="search_sep"> ... </span>'; $mark = '(' . join('|', $words) . ')'; $snippet = preg_replace('#' . $mark . '#si', '<strong class="search_hit">\\1</strong>', $snippet); $data[] = array('id' => pathID($file), 'count' => preg_match_all('#' . $mark . '#usi', $lctext, $matches), 'poswords' => join(' ', $words), 'snippet' => $snippet); } return true; }
/** * Expire the renderer cache of archive pages whenever a page is updated or a comment or linkback is added * * @author Michael Hamann <*****@*****.**> */ function handle_cache(Doku_Event $event, $params) { global $conf; /** @var cache_parser $cache */ $cache = $event->data; if (!in_array($cache->mode, array('xhtml', 'metadata'))) { return; } $page = $cache->page; // try to extract the page id from the file if possible if (empty($page)) { if (strpos($cache->file, $conf['datadir']) === 0) { $page = pathID(substr($cache->file, strlen($conf['datadir']) + 1)); } else { return; } } $meta = p_get_metadata($page, 'plugin_blog'); if ($meta === null) { return; } if (isset($meta['purgefile_cache'])) { $cache->depends['files'][] = $conf['cachedir'] . '/purgefile'; $cache->depends['files'][] = $conf['metadir'] . '/_comments.changes'; $cache->depends['files'][] = $conf['metadir'] . '/_linkbacks.changes'; } // purge the cache when a page is listed that the current user can't access if (isset($meta['archive_pages'])) { foreach ($meta['archive_pages'] as $page) { if (auth_quickaclcheck($page) < AUTH_READ) { $cache->depends['purge'] = true; return; } } } }
/** * Build the browsable index of pages * * $opts['ns'] is the current namespace * * @author Andreas Gohr <*****@*****.**> * modified by Samuele Tognini <*****@*****.**> */ function _search_index(&$data, $base, $file, $type, $lvl, $opts) { global $conf; $hns = false; $return = false; $isopen = false; $skip_index = $opts['skip_index']; $skip_file = $opts['skip_file']; $headpage = $opts['headpage']; $id = pathID($file); if ($type == 'd') { // Skip folders in plugin conf if (!empty($skip_index) && preg_match($skip_index, $id)) { return false; } //check ACL (for sneaky_index namespaces too). if ($this->getConf('sneaky_index') && auth_quickaclcheck($id . ':') < AUTH_READ) { return false; } //Open requested level if ($opts['level'] > $lvl || $opts['level'] == -1) { $isopen = true; } //Search optional namespaces if (!empty($opts['nss'])) { $nss = $opts['nss']; for ($a = 0; $a < count($nss); $a++) { if (preg_match("/^" . $id . "(\$|:.+)/i", $nss[$a][0], $match)) { //It contains an optional namespace $isopen = true; } elseif (preg_match("/^" . $nss[$a][0] . "(:.*)/i", $id, $match)) { //It's inside an optional namespace if ($nss[$a][1] == -1 || substr_count($match[1], ":") < $nss[$a][1]) { $isopen = true; } else { $isopen = false; } } } } if ($opts['nons']) { return $isopen; } elseif ($opts['max'] > 0 && !$isopen && $lvl >= $opts['max']) { $isopen = false; //Stop recursive searching $return = false; //change type $type = "l"; } elseif ($opts['js']) { $return = true; } else { $return = $isopen; } //Set title and headpage $title = $this->_getTitle($id, $headpage, $hns); if (!$hns && $opts['nopg']) { $hns = $id . ":" . $conf['start']; } } else { //Nopg.Dont show pages if ($opts['nopg']) { return false; } $return = true; //Nons.Set all pages at first level if ($opts['nons']) { $lvl = 1; } //don't add if (substr($file, -4) != '.txt') { return false; } //check hiddens and acl if (isHiddenPage($id) || auth_quickaclcheck($id) < AUTH_READ) { return false; } //Skip files in plugin conf if (!empty($skip_file) && preg_match($skip_file, $id)) { return false; } //Skip headpages to hide if (!$opts['nons'] && !empty($headpage) && $opts['hide_headpage']) { if ($id == $conf['start']) { return false; } $ahp = explode(",", $headpage); foreach ($ahp as $hp) { switch ($hp) { case ":inside:": if (noNS($id) == noNS(getNS($id))) { return false; } break; case ":same:": if (@is_dir(dirname(wikiFN($id)) . "/" . utf8_encodeFN(noNS($id)))) { return false; } break; //it' s an inside start //it' s an inside start case ":start:": if (noNS($id) == $conf['start']) { return false; } break; default: if (noNS($id) == cleanID($hp)) { return false; } } } } //Set title if (!$conf['useheading'] || !($title = p_get_first_heading($id, FALSE))) { $title = noNS($id); } $title = htmlspecialchars($title, ENT_QUOTES); } $item = array('id' => $id, 'type' => $type, 'level' => $lvl, 'open' => $isopen, 'title' => $title, 'hns' => $hns, 'file' => $file, 'return' => $return); $item['sort'] = $this->_setorder($item); $data[] = $item; return $return; }
/** * Handle the cache events, it looks if a page needs to be rewritten so it can expire the cache of the page * * @param Doku_Event $event The even object * @param mixed $param Optional parameters (not used) */ function handle_cache(Doku_Event $event, $param) { global $conf; /** @var $cache cache_parser */ $cache = $event->data; $id = $cache->page; if (!$id) { // try to reconstruct the id from the filename $path = $cache->file; if (strpos($path, $conf['datadir']) === 0) { $path = substr($path, strlen($conf['datadir']) + 1); $id = pathID($path); } } if ($id) { /** @var helper_plugin_move_rewrite $helper */ $helper = $this->loadHelper('move_rewrite'); if (!is_null($helper)) { $meta = $helper->getMoveMeta($id); if ($meta && ($meta['pages'] || $meta['media'])) { $file = wikiFN($id, '', false); if (is_writable($file)) { $cache->depends['purge'] = true; } else { // FIXME: print error here or fail silently? msg('Error: Page ' . hsc($id) . ' needs to be rewritten because of page renames but is not writable.', -1); } } } } }
protected function get_pages($dir) { static $trunclen = null; if (!$trunclen) { global $conf; $trunclen = strlen($conf['datadir'] . ':'); } if (!is_dir($dir)) { throw new DokuCLI_Exception("Unable to read directory {$dir}"); } $pages = array(); $dh = opendir($dir); while (false !== ($entry = readdir($dh))) { $status = $this->dir_filter($entry, $dir); if ($status == WantedPagesCLI::DIR_CONTINUE) { continue; } else { if ($status == WantedPagesCLI::DIR_NS) { $pages = array_merge($pages, $this->get_pages($dir . '/' . $entry)); } else { $page = array('id' => pathID(substr($dir . '/' . $entry, $trunclen)), 'file' => $dir . '/' . $entry); $pages[] = $page; } } } closedir($dh); return $pages; }
/** * Handle the cache events, it looks if a page needs to be rewritten so it can expire the cache of the page * * @param Doku_Event $event The even object * @param mixed $param Optional parameters (not used) */ function handle_cache(Doku_Event $event, $param) { global $conf; /** @var $cache cache_parser */ $cache = $event->data; $id = $cache->page; if (!$id) { // try to reconstruct the id from the filename $path = $cache->file; if (strpos($path, $conf['datadir']) === 0) { $path = substr($path, strlen($conf['datadir'])+1); $id = pathID($path); } } if ($id) { $meta = p_get_metadata($id, 'plugin_move', METADATA_DONT_RENDER); if ($meta && (isset($meta['moves']) || isset($meta['media_moves']))) { $file = wikiFN($id, '', false); if (is_writable($file)) $cache->depends['purge'] = true; else // FIXME: print error here or fail silently? msg('Error: Page '.hsc($id).' needs to be rewritten because of page renames but is not writable.', -1); } } }
/** * search callback function * * filter out pages which can't be approved by the current user * then check if they need approving */ function _search_helper(&$data, $base, $file, $type, $lvl, $opts) { $ns = $opts[0]; $valid_ns = $opts[1]; $invalid_ns = $opts[2]; if ($type == 'd') { return $this->hlp->in_sub_namespace($valid_ns, $ns . ':' . str_replace('/', ':', $file)); } if (!preg_match('#\\.txt$#', $file)) { return false; } $id = pathID($ns . $file); if (!$this->hlp->in_namespace($valid_ns, $id)) { return false; } if ($this->hlp->in_namespace($invalid_ns, $id)) { return false; } if (auth_quickaclcheck($id) < AUTH_DELETE) { return false; } $meta = $this->hlp->getMeta($id); if ($this->hlp->isCurrentRevisionApproved($id)) { // Already approved return false; } $data[] = array($id, $meta['approval'], $meta['last_change']['date']); return false; }
/** * Just lists all documents * * $opts['depth'] recursion level, 0 for all * $opts['hash'] do md5 sum of content? * $opts['skipacl'] list everything regardless of ACL * * @param $data * @param $base * @param $file * @param $type * @param $lvl * @param $opts * @return bool */ public static function save_search_allpages(&$data, $base, $file, $type, $lvl, $opts) { if (!empty($opts['depth'])) { $parts = explode('/', ltrim($file, '/')); if ($type == 'd' && count($parts) >= $opts['depth'] || $type != 'd' && count($parts) > $opts['depth']) { return false; // depth reached } } //we do nothing with directories if ($type == 'd') { return true; } //only search txt files if (substr($file, -4) != '.txt') { return true; } $pathId = pathID($file); if (!$opts['skipacl'] && auth_quickaclcheck($pathId) < AUTH_READ) { return false; } file_put_contents(self::$tempFileName, "{$pathId}\n", FILE_APPEND); self::$totalPagesToIndex++; return true; }