diff options
Diffstat (limited to 'vendors/dokuwiki/inc/pageutils.php')
| -rw-r--r-- | vendors/dokuwiki/inc/pageutils.php | 537 | 
1 files changed, 537 insertions, 0 deletions
diff --git a/vendors/dokuwiki/inc/pageutils.php b/vendors/dokuwiki/inc/pageutils.php new file mode 100644 index 000000000..9c192e5e6 --- /dev/null +++ b/vendors/dokuwiki/inc/pageutils.php @@ -0,0 +1,537 @@ +<?php +/** + * Utilities for handling pagenames + * + * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author     Andreas Gohr <andi@splitbrain.org> + * @todo       Combine similar functions like {wiki,media,meta}FN() + */ + +/** + * Fetch the an ID from request + * + * Uses either standard $_REQUEST variable or extracts it from + * the full request URI when userewrite is set to 2 + * + * For $param='id' $conf['start'] is returned if no id was found. + * If the second parameter is true (default) the ID is cleaned. + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function getID($param='id',$clean=true){ +    global $conf; + +    $id = isset($_REQUEST[$param]) ? $_REQUEST[$param] : null; + +    $request = $_SERVER['REQUEST_URI']; + +    //construct page id from request URI +    if(empty($id) && $conf['userewrite'] == 2){ +        //get the script URL +        if($conf['basedir']){ +            $relpath = ''; +            if($param != 'id') { +                $relpath = 'lib/exe/'; +            } +            $script = $conf['basedir'].$relpath.basename($_SERVER['SCRIPT_FILENAME']); + +        }elseif($_SERVER['DOCUMENT_ROOT'] && $_SERVER['PATH_TRANSLATED']){ +            $request = preg_replace ('/^'.preg_quote($_SERVER['DOCUMENT_ROOT'],'/').'/','', +                    $_SERVER['PATH_TRANSLATED']); +        }elseif($_SERVER['DOCUMENT_ROOT'] && $_SERVER['SCRIPT_FILENAME']){ +            $script = preg_replace ('/^'.preg_quote($_SERVER['DOCUMENT_ROOT'],'/').'/','', +                    $_SERVER['SCRIPT_FILENAME']); +            $script = '/'.$script; +        }else{ +            $script = $_SERVER['SCRIPT_NAME']; +        } + +        //clean script and request (fixes a windows problem) +        $script  = preg_replace('/\/\/+/','/',$script); +        $request = preg_replace('/\/\/+/','/',$request); + +        //remove script URL and Querystring to gain the id +        if(preg_match('/^'.preg_quote($script,'/').'(.*)/',$request, $match)){ +            $id = preg_replace ('/\?.*/','',$match[1]); +        } +        $id = urldecode($id); +        //strip leading slashes +        $id = preg_replace('!^/+!','',$id); +    } + +    // Namespace autolinking from URL +    if(substr($id,-1) == ':' || ($conf['useslash'] && substr($id,-1) == '/')){ +        if(page_exists($id.$conf['start'])){ +            // start page inside namespace +            $id = $id.$conf['start']; +        }elseif(page_exists($id.noNS(cleanID($id)))){ +            // page named like the NS inside the NS +            $id = $id.noNS(cleanID($id)); +        }elseif(page_exists($id)){ +            // page like namespace exists +            $id = substr($id,0,-1); +        }else{ +            // fall back to default +            $id = $id.$conf['start']; +        } +        send_redirect(wl($id,'',true)); +    } + +    if($clean) $id = cleanID($id); +    if(empty($id) && $param=='id') $id = $conf['start']; + +    return $id; +} + +/** + * Remove unwanted chars from ID + * + * Cleans a given ID to only use allowed characters. Accented characters are + * converted to unaccented ones + * + * @author Andreas Gohr <andi@splitbrain.org> + * @param  string  $raw_id    The pageid to clean + * @param  boolean $ascii     Force ASCII + * @param  boolean $media     Allow leading or trailing _ for media files + */ +function cleanID($raw_id,$ascii=false,$media=false){ +    global $conf; +    global $lang; +    static $sepcharpat = null; + +    global $cache_cleanid; +    $cache = & $cache_cleanid; + +    // check if it's already in the memory cache +    if (isset($cache[(string)$raw_id])) { +        return $cache[(string)$raw_id]; +    } + +    $sepchar = $conf['sepchar']; +    if($sepcharpat == null) // build string only once to save clock cycles +        $sepcharpat = '#\\'.$sepchar.'+#'; + +    $id = trim((string)$raw_id); +    $id = utf8_strtolower($id); + +    //alternative namespace seperator +    $id = strtr($id,';',':'); +    if($conf['useslash']){ +        $id = strtr($id,'/',':'); +    }else{ +        $id = strtr($id,'/',$sepchar); +    } + +    if($conf['deaccent'] == 2 || $ascii) $id = utf8_romanize($id); +    if($conf['deaccent'] || $ascii) $id = utf8_deaccent($id,-1); + +    //remove specials +    $id = utf8_stripspecials($id,$sepchar,'\*'); + +    if($ascii) $id = utf8_strip($id); + +    //clean up +    $id = preg_replace($sepcharpat,$sepchar,$id); +    $id = preg_replace('#:+#',':',$id); +    $id = ($media ? trim($id,':.-') : trim($id,':._-')); +    $id = preg_replace('#:[:\._\-]+#',':',$id); + +    $cache[(string)$raw_id] = $id; +    return($id); +} + +/** + * Return namespacepart of a wiki ID + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function getNS($id){ +    $pos = strrpos((string)$id,':'); +    if($pos!==false){ +        return substr((string)$id,0,$pos); +    } +    return false; +} + +/** + * Returns the ID without the namespace + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function noNS($id) { +    $pos = strrpos($id, ':'); +    if ($pos!==false) { +        return substr($id, $pos+1); +    } else { +        return $id; +    } +} + +/** + * Returns the current namespace + * + * @author Nathan Fritz <fritzn@crown.edu> + */ +function curNS($id) { +    return noNS(getNS($id)); +} + +/** + * Returns the ID without the namespace or current namespace for 'start' pages + * + * @author Nathan Fritz <fritzn@crown.edu> + */ +function noNSorNS($id) { +    global $conf; + +    $p = noNS($id); +    if ($p == $conf['start']) { +        $p = curNS($id); +        if ($p == false) { +            return noNS($id); +        } +    } +    return $p; +} + +/** + * Creates a XHTML valid linkid from a given headline title + * + * @param string  $title   The headline title + * @param array   $check   List of existing IDs + * @author Andreas Gohr <andi@splitbrain.org> + */ +function sectionID($title,&$check) { +    $title = str_replace(array(':','.'),'',cleanID($title)); +    $new = ltrim($title,'0123456789_-'); +    if(empty($new)){ +        $title = 'section'.preg_replace('/[^0-9]+/','',$title); //keep numbers from headline +    }else{ +        $title = $new; +    } + +    if(is_array($check)){ +        // make sure tiles are unique +        $num = ''; +        while(in_array($title.$num,$check)){ +            ($num) ? $num++ : $num = 1; +        } +        $title = $title.$num; +        $check[] = $title; +    } + +    return $title; +} + + +/** + * Wiki page existence check + * + * parameters as for wikiFN + * + * @author Chris Smith <chris@jalakai.co.uk> + */ +function page_exists($id,$rev='',$clean=true) { +    return @file_exists(wikiFN($id,$rev,$clean)); +} + +/** + * returns the full path to the datafile specified by ID and optional revision + * + * The filename is URL encoded to protect Unicode chars + * + * @param  $raw_id  string   id of wikipage + * @param  $rev     string   page revision, empty string for current + * @param  $clean   bool     flag indicating that $raw_id should be cleaned.  Only set to false + *                           when $id is guaranteed to have been cleaned already. + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function wikiFN($raw_id,$rev='',$clean=true){ +    global $conf; + +    global $cache_wikifn; +    $cache = & $cache_wikifn; + +    if (isset($cache[$raw_id]) && isset($cache[$raw_id][$rev])) { +        return $cache[$raw_id][$rev]; +    } + +    $id = $raw_id; + +    if ($clean) $id = cleanID($id); +    $id = str_replace(':','/',$id); +    if(empty($rev)){ +        $fn = $conf['datadir'].'/'.utf8_encodeFN($id).'.txt'; +    }else{ +        $fn = $conf['olddir'].'/'.utf8_encodeFN($id).'.'.$rev.'.txt'; +        if($conf['compression']){ +            //test for extensions here, we want to read both compressions +            if (@file_exists($fn . '.gz')){ +                $fn .= '.gz'; +            }else if(@file_exists($fn . '.bz2')){ +                $fn .= '.bz2'; +            }else{ +                //file doesnt exist yet, so we take the configured extension +                $fn .= '.' . $conf['compression']; +            } +        } +    } + +    if (!isset($cache[$raw_id])) { $cache[$raw_id] = array(); } +    $cache[$raw_id][$rev] = $fn; +    return $fn; +} + +/** + * Returns the full path to the file for locking the page while editing. + * + * @author Ben Coburn <btcoburn@silicodon.net> + */ +function wikiLockFN($id) { +    global $conf; +    return $conf['lockdir'].'/'.md5(cleanID($id)).'.lock'; +} + + +/** + * returns the full path to the meta file specified by ID and extension + * + * The filename is URL encoded to protect Unicode chars + * + * @author Steven Danz <steven-danz@kc.rr.com> + */ +function metaFN($id,$ext){ +    global $conf; +    $id = cleanID($id); +    $id = str_replace(':','/',$id); +    $fn = $conf['metadir'].'/'.utf8_encodeFN($id).$ext; +    return $fn; +} + +/** + * returns an array of full paths to all metafiles of a given ID + * + * @author Esther Brunner <esther@kaffeehaus.ch> + */ +function metaFiles($id){ +    $name   = noNS($id); +    $ns     = getNS($id); +    $dir    = ($ns) ? metaFN($ns,'').'/' : metaFN($ns,''); +    $files  = array(); + +    $dh = @opendir($dir); +    if(!$dh) return $files; +    while(($file = readdir($dh)) !== false){ +        if(strpos($file,$name.'.') === 0 && !is_dir($dir.$file)) +            $files[] = $dir.$file; +    } +    closedir($dh); + +    return $files; +} + +/** + * returns the full path to the mediafile specified by ID + * + * The filename is URL encoded to protect Unicode chars + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function mediaFN($id){ +    global $conf; +    $id = cleanID($id); +    $id = str_replace(':','/',$id); +    $fn = $conf['mediadir'].'/'.utf8_encodeFN($id); +    return $fn; +} + +/** + * Returns the full filepath to a localized textfile if local + * version isn't found the english one is returned + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function localeFN($id){ +    global $conf; +    $file = DOKU_INC.'inc/lang/'.$conf['lang'].'/'.$id.'.txt'; +    if(!@file_exists($file)){ +        //fall back to english +        $file = DOKU_INC.'inc/lang/en/'.$id.'.txt'; +    } +    return $file; +} + +/** + * Resolve relative paths in IDs + * + * Do not call directly use resolve_mediaid or resolve_pageid + * instead + * + * Partyly based on a cleanPath function found at + * http://www.php.net/manual/en/function.realpath.php#57016 + * + * @author <bart at mediawave dot nl> + */ +function resolve_id($ns,$id,$clean=true){ +    global $conf; + +    // some pre cleaning for useslash: +    if($conf['useslash']) $id = str_replace('/',':',$id); + +    // if the id starts with a dot we need to handle the +    // relative stuff +    if($id{0} == '.'){ +        // normalize initial dots without a colon +        $id = preg_replace('/^(\.+)(?=[^:\.])/','\1:',$id); +        // prepend the current namespace +        $id = $ns.':'.$id; + +        // cleanup relatives +        $result = array(); +        $pathA  = explode(':', $id); +        if (!$pathA[0]) $result[] = ''; +        foreach ($pathA AS $key => $dir) { +            if ($dir == '..') { +                if (end($result) == '..') { +                    $result[] = '..'; +                } elseif (!array_pop($result)) { +                    $result[] = '..'; +                } +            } elseif ($dir && $dir != '.') { +                $result[] = $dir; +            } +        } +        if (!end($pathA)) $result[] = ''; +        $id = implode(':', $result); +    }elseif($ns !== false && strpos($id,':') === false){ +        //if link contains no namespace. add current namespace (if any) +        $id = $ns.':'.$id; +    } + +    if($clean) $id = cleanID($id); +    return $id; +} + +/** + * Returns a full media id + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function resolve_mediaid($ns,&$page,&$exists){ +    $page   = resolve_id($ns,$page); +    $file   = mediaFN($page); +    $exists = @file_exists($file); +} + +/** + * Returns a full page id + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function resolve_pageid($ns,&$page,&$exists){ +    global $conf; +    $exists = false; + +    //keep hashlink if exists then clean both parts +    if (strpos($page,'#')) { +        list($page,$hash) = explode('#',$page,2); +    } else { +        $hash = ''; +    } +    $hash = cleanID($hash); +    $page = resolve_id($ns,$page,false); // resolve but don't clean, yet + +    // get filename (calls clean itself) +    $file = wikiFN($page); + +    // if ends with colon or slash we have a namespace link +    if(substr($page,-1) == ':' || ($conf['useslash'] && substr($page,-1) == '/')){ +        if(page_exists($page.$conf['start'])){ +            // start page inside namespace +            $page = $page.$conf['start']; +            $exists = true; +        }elseif(page_exists($page.noNS(cleanID($page)))){ +            // page named like the NS inside the NS +            $page = $page.noNS(cleanID($page)); +            $exists = true; +        }elseif(page_exists($page)){ +            // page like namespace exists +            $page = $page; +            $exists = true; +        }else{ +            // fall back to default +            $page = $page.$conf['start']; +        } +    }else{ +        //check alternative plural/nonplural form +        if(!@file_exists($file)){ +            if( $conf['autoplural'] ){ +                if(substr($page,-1) == 's'){ +                    $try = substr($page,0,-1); +                }else{ +                    $try = $page.'s'; +                } +                if(page_exists($try)){ +                    $page   = $try; +                    $exists = true; +                } +            } +        }else{ +            $exists = true; +        } +    } + +    // now make sure we have a clean page +    $page = cleanID($page); + +    //add hash if any +    if(!empty($hash)) $page .= '#'.$hash; +} + +/** + * Returns the name of a cachefile from given data + * + * The needed directory is created by this function! + * + * @author Andreas Gohr <andi@splitbrain.org> + * + * @param string $data  This data is used to create a unique md5 name + * @param string $ext   This is appended to the filename if given + * @return string       The filename of the cachefile + */ +function getCacheName($data,$ext=''){ +    global $conf; +    $md5  = md5($data); +    $file = $conf['cachedir'].'/'.$md5{0}.'/'.$md5.$ext; +    io_makeFileDir($file); +    return $file; +} + +/** + * Checks a pageid against $conf['hidepages'] + * + * @author Andreas Gohr <gohr@cosmocode.de> + */ +function isHiddenPage($id){ +    global $conf; +    global $ACT; +    if(empty($conf['hidepages'])) return false; +    if($ACT == 'admin') return false; + +    if(preg_match('/'.$conf['hidepages'].'/ui',':'.$id)){ +        return true; +    } +    return false; +} + +/** + * Reverse of isHiddenPage + * + * @author Andreas Gohr <gohr@cosmocode.de> + */ +function isVisiblePage($id){ +    return !isHiddenPage($id); +} + +  | 
