xref: /dokuwiki/inc/pageutils.php (revision 98c868589ee0757f176239cf289cbd007bb74852)
1<?php
2/**
3 * Utilities for handling pagenames
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Andreas Gohr <andi@splitbrain.org>
7 * @todo       Combine similar functions like {wiki,media,meta}FN()
8 */
9
10/**
11 * Fetch the an ID from request
12 *
13 * Uses either standard $_REQUEST variable or extracts it from
14 * the full request URI when userewrite is set to 2
15 *
16 * For $param='id' $conf['start'] is returned if no id was found.
17 * If the second parameter is true (default) the ID is cleaned.
18 *
19 * @author Andreas Gohr <andi@splitbrain.org>
20 */
21function getID($param='id',$clean=true){
22  global $conf;
23
24  $id = $_REQUEST[$param];
25
26  //construct page id from request URI
27  if(empty($id) && $conf['userewrite'] == 2){
28    //get the script URL
29    if($conf['basedir']){
30      $relpath = '';
31      if($param != 'id') {
32        $relpath = 'lib/exe/';
33      }
34      $script = $conf['basedir'].$relpath.basename($_SERVER['SCRIPT_FILENAME']);
35    }elseif($_SERVER['DOCUMENT_ROOT'] && $_SERVER['SCRIPT_FILENAME']){
36      $script = preg_replace ('/^'.preg_quote($_SERVER['DOCUMENT_ROOT'],'/').'/','',
37                              $_SERVER['SCRIPT_FILENAME']);
38      $script = '/'.$script;
39    }else{
40      $script = $_SERVER['SCRIPT_NAME'];
41    }
42
43    //clean script and request (fixes a windows problem)
44    $script  = preg_replace('/\/\/+/','/',$script);
45    $request = preg_replace('/\/\/+/','/',$_SERVER['REQUEST_URI']);
46
47    //remove script URL and Querystring to gain the id
48    if(preg_match('/^'.preg_quote($script,'/').'(.*)/',$request, $match)){
49      $id = preg_replace ('/\?.*/','',$match[1]);
50    }
51    $id = urldecode($id);
52    //strip leading slashes
53    $id = preg_replace('!^/+!','',$id);
54  }
55  if($clean) $id = cleanID($id);
56  if(empty($id) && $param=='id') $id = $conf['start'];
57
58  return $id;
59}
60
61/**
62 * Remove unwanted chars from ID
63 *
64 * Cleans a given ID to only use allowed characters. Accented characters are
65 * converted to unaccented ones
66 *
67 * @author Andreas Gohr <andi@splitbrain.org>
68 * @param  string  $id    The pageid to clean
69 * @param  boolean $ascii Force ASCII
70 */
71function cleanID($id,$ascii=false){
72  global $conf;
73  global $lang;
74  static $sepcharpat = null;
75
76  $sepchar = $conf['sepchar'];
77  if($sepcharpat == null) // build string only once to save clock cycles
78    $sepcharpat = '#\\'.$sepchar.'+#';
79
80  $id = trim($id);
81  $id = utf8_strtolower($id);
82
83  //alternative namespace seperator
84  $id = strtr($id,';',':');
85  if($conf['useslash']){
86    $id = strtr($id,'/',':');
87  }else{
88    $id = strtr($id,'/',$sepchar);
89  }
90
91  if($conf['deaccent'] == 2 || $ascii) $id = utf8_romanize($id);
92  if($conf['deaccent'] || $ascii) $id = utf8_deaccent($id,-1);
93
94  //remove specials
95  $id = utf8_stripspecials($id,$sepchar,'\*');
96
97  if($ascii) $id = utf8_strip($id);
98
99  //clean up
100  $id = preg_replace($sepcharpat,$sepchar,$id);
101  $id = preg_replace('#:+#',':',$id);
102  $id = trim($id,':._-');
103  $id = preg_replace('#:[:\._\-]+#',':',$id);
104
105  return($id);
106}
107
108/**
109 * Return namespacepart of a wiki ID
110 *
111 * @author Andreas Gohr <andi@splitbrain.org>
112 */
113function getNS($id){
114 if(strpos($id,':')!==false){
115   return substr($id,0,strrpos($id,':'));
116 }
117 return false;
118}
119
120/**
121 * Returns the ID without the namespace
122 *
123 * @author Andreas Gohr <andi@splitbrain.org>
124 */
125function noNS($id){
126  return preg_replace('/.*:/','',$id);
127}
128
129/**
130 * returns the full path to the datafile specified by ID and
131 * optional revision
132 *
133 * The filename is URL encoded to protect Unicode chars
134 *
135 * @author Andreas Gohr <andi@splitbrain.org>
136 */
137function wikiFN($id,$rev=''){
138  global $conf;
139  $id = cleanID($id);
140  $id = str_replace(':','/',$id);
141  if(empty($rev)){
142    $fn = $conf['datadir'].'/'.utf8_encodeFN($id).'.txt';
143  }else{
144    $fn = $conf['olddir'].'/'.utf8_encodeFN($id).'.'.$rev.'.txt';
145    if($conf['usegzip'] && !@file_exists($fn)){
146      //return gzip if enabled and plaintext doesn't exist
147      $fn .= '.gz';
148    }
149  }
150  return $fn;
151}
152
153/**
154 * returns the full path to the meta file specified by ID and extension
155 *
156 * The filename is URL encoded to protect Unicode chars
157 *
158 * @author Steven Danz <steven-danz@kc.rr.com>
159 */
160function metaFN($id,$ext){
161  global $conf;
162  $id = cleanID($id);
163  $id = str_replace(':','/',$id);
164  $fn = $conf['metadir'].'/'.utf8_encodeFN($id).$ext;
165  return $fn;
166}
167
168/**
169 * returns an array of full paths to all metafiles of a given ID
170 *
171 * @author Esther Brunner <esther@kaffeehaus.ch>
172 */
173function metaFiles($id){
174   $name   = noNS($id);
175   $dir    = metaFN(getNS($id),'');
176   $files  = array();
177
178   $dh = @opendir($dir);
179   if(!$dh) return $files;
180   while(($file = readdir($dh)) !== false){
181     if(strpos($file,$name.'.') === 0 && !is_dir($dir.$file))
182       $files[] = $dir.$file;
183   }
184   closedir($dh);
185
186   return $files;
187}
188
189/**
190 * returns the full path to the mediafile specified by ID
191 *
192 * The filename is URL encoded to protect Unicode chars
193 *
194 * @author Andreas Gohr <andi@splitbrain.org>
195 */
196function mediaFN($id){
197  global $conf;
198  $id = cleanID($id);
199  $id = str_replace(':','/',$id);
200    $fn = $conf['mediadir'].'/'.utf8_encodeFN($id);
201  return $fn;
202}
203
204/**
205 * Returns the full filepath to a localized textfile if local
206 * version isn't found the english one is returned
207 *
208 * @author Andreas Gohr <andi@splitbrain.org>
209 */
210function localeFN($id){
211  global $conf;
212  $file = DOKU_INC.'inc/lang/'.$conf['lang'].'/'.$id.'.txt';
213  if(!@file_exists($file)){
214    //fall back to english
215    $file = DOKU_INC.'inc/lang/en/'.$id.'.txt';
216  }
217  return $file;
218}
219
220/**
221 * Returns a full media id
222 *
223 * @author Andreas Gohr <andi@splitbrain.org>
224 */
225function resolve_mediaid($ns,&$page,&$exists){
226  global $conf;
227
228  //if links starts with . add current namespace
229  if($page{0} == '.'){
230    $page = $ns.':'.substr($page,1);
231  }
232
233  //if link contains no namespace. add current namespace (if any)
234  if($ns !== false && strpos($page,':') === false){
235    $page = $ns.':'.$page;
236  }
237
238  $page   = cleanID($page);
239  $file   = mediaFN($page);
240  $exists = @file_exists($file);
241}
242
243/**
244 * Returns a full page id
245 *
246 * @author Andreas Gohr <andi@splitbrain.org>
247 */
248function resolve_pageid($ns,&$page,&$exists){
249  global $conf;
250  $exists = false;
251
252  //if links starts with . add current namespace
253  if($page{0} == '.'){
254    $page = $ns.':'.substr($page,1);
255  }
256
257  //if link contains no namespace. add current namespace (if any)
258  if($ns !== false && strpos($page,':') === false){
259    $page = $ns.':'.$page;
260  }
261
262  //keep hashlink if exists then clean both parts
263  list($page,$hash) = split('#',$page,2);
264  $page = cleanID($page);
265  $hash = cleanID($hash);
266
267  $file = wikiFN($page);
268
269  //check alternative plural/nonplural form
270  if(!@file_exists($file)){
271    if( $conf['autoplural'] ){
272      if(substr($page,-1) == 's'){
273        $try = substr($page,0,-1);
274      }else{
275        $try = $page.'s';
276      }
277      if(@file_exists(wikiFN($try))){
278        $page   = $try;
279        $exists = true;
280      }
281    }
282  }else{
283    $exists = true;
284  }
285
286  //add hash if any
287  if(!empty($hash)) $page .= '#'.$hash;
288}
289
290/**
291 * Returns the name of a cachefile from given data
292 *
293 * The needed directory is created by this function!
294 *
295 * @author Andreas Gohr <andi@splitbrain.org>
296 *
297 * @param string $data  This data is used to create a unique md5 name
298 * @param string $ext   This is appended to the filename if given
299 * @return string       The filename of the cachefile
300 */
301function getCacheName($data,$ext=''){
302  global $conf;
303  $md5  = md5($data);
304  $file = $conf['cachedir'].'/'.$md5{0}.'/'.$md5.$ext;
305  io_makeFileDir($file);
306  return $file;
307}
308
309/**
310 * Checks a pageid against $conf['hidepages']
311 *
312 * @author Andreas Gohr <gohr@cosmocode.de>
313 */
314function isHiddenPage($id){
315  global $conf;
316  if(empty($conf['hidepages'])) return false;
317
318  if(preg_match('/'.$conf['hidepages'].'/ui',':'.$id)){
319    return true;
320  }
321  return false;
322}
323
324/**
325 * Reverse of isHiddenPage
326 *
327 * @author Andreas Gohr <gohr@cosmocode.de>
328 */
329function isVisiblePage($id){
330  return !isHiddenPage($id);
331}
332
333//Setup VIM: ex: et ts=2 enc=utf-8 :
334