xref: /dokuwiki/inc/pageutils.php (revision 0868021bf5712da12fd19903d02210f25a573f5d)
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 */
69function cleanID($id){
70  global $conf;
71  global $lang;
72  static $sepcharpat = null;
73
74  $sepchar = $conf['sepchar'];
75  if($sepcharpat == null) // build string only once to save clock cycles
76    $sepcharpat = '#\\'.$sepchar.'+#';
77
78  $id = trim($id);
79  $id = utf8_strtolower($id);
80
81  //alternative namespace seperator
82  $id = strtr($id,';',':');
83  if($conf['useslash']){
84    $id = strtr($id,'/',':');
85  }else{
86    $id = strtr($id,'/',$sepchar);
87  }
88
89  if($conf['deaccent']) $id = utf8_deaccent($id,-1);
90
91  //remove specials
92  $id = utf8_stripspecials($id,$sepchar,'\*');
93
94  //clean up
95  $id = preg_replace($sepcharpat,$sepchar,$id);
96  $id = preg_replace('#:+#',':',$id);
97  $id = trim($id,':._-');
98  $id = preg_replace('#:[:\._\-]+#',':',$id);
99
100  return($id);
101}
102
103/**
104 * Return namespacepart of a wiki ID
105 *
106 * @author Andreas Gohr <andi@splitbrain.org>
107 */
108function getNS($id){
109 if(strpos($id,':')!==false){
110   return substr($id,0,strrpos($id,':'));
111 }
112 return false;
113}
114
115/**
116 * Returns the ID without the namespace
117 *
118 * @author Andreas Gohr <andi@splitbrain.org>
119 */
120function noNS($id){
121  return preg_replace('/.*:/','',$id);
122}
123
124/**
125 * returns the full path to the datafile specified by ID and
126 * optional revision
127 *
128 * The filename is URL encoded to protect Unicode chars
129 *
130 * @author Andreas Gohr <andi@splitbrain.org>
131 */
132function wikiFN($id,$rev=''){
133  global $conf;
134  $id = cleanID($id);
135  $id = str_replace(':','/',$id);
136  if(empty($rev)){
137    $fn = $conf['datadir'].'/'.utf8_encodeFN($id).'.txt';
138  }else{
139    $fn = $conf['olddir'].'/'.utf8_encodeFN($id).'.'.$rev.'.txt';
140    if($conf['usegzip'] && !@file_exists($fn)){
141      //return gzip if enabled and plaintext doesn't exist
142      $fn .= '.gz';
143    }
144  }
145  return $fn;
146}
147
148/**
149 * returns the full path to the meta file specified by ID and extension
150 *
151 * The filename is URL encoded to protect Unicode chars
152 *
153 * @author Steven Danz <steven-danz@kc.rr.com>
154 */
155function metaFN($id,$ext){
156  global $conf;
157  $id = cleanID($id);
158  $id = str_replace(':','/',$id);
159  $fn = $conf['metadir'].'/'.utf8_encodeFN($id).$ext;
160  return $fn;
161}
162
163/**
164 * returns an array of full paths to all metafiles of a given ID
165 *
166 * @author Esther Brunner <esther@kaffeehaus.ch>
167 */
168function metaFiles($id){
169   $name   = noNS($id);
170   $dir    = metaFN(getNS($id),'');
171   $files  = array();
172
173   $dh = @opendir($dir);
174   if(!$dh) return $files;
175   while(($file = readdir($dh)) !== false){
176     if(strpos($file,$name.'.') === 0 && !is_dir($dir.$file))
177       $files[] = $dir.$file;
178   }
179   closedir($dh);
180
181   return $files;
182}
183
184/**
185 * returns the full path to the mediafile specified by ID
186 *
187 * The filename is URL encoded to protect Unicode chars
188 *
189 * @author Andreas Gohr <andi@splitbrain.org>
190 */
191function mediaFN($id){
192  global $conf;
193  $id = cleanID($id);
194  $id = str_replace(':','/',$id);
195    $fn = $conf['mediadir'].'/'.utf8_encodeFN($id);
196  return $fn;
197}
198
199/**
200 * Returns the full filepath to a localized textfile if local
201 * version isn't found the english one is returned
202 *
203 * @author Andreas Gohr <andi@splitbrain.org>
204 */
205function localeFN($id){
206  global $conf;
207  $file = DOKU_INC.'inc/lang/'.$conf['lang'].'/'.$id.'.txt';
208  if(!@file_exists($file)){
209    //fall back to english
210    $file = DOKU_INC.'inc/lang/en/'.$id.'.txt';
211  }
212  return $file;
213}
214
215/**
216 * Returns a full media id
217 *
218 * @author Andreas Gohr <andi@splitbrain.org>
219 */
220function resolve_mediaid($ns,&$page,&$exists){
221  global $conf;
222
223  //if links starts with . add current namespace
224  if($page{0} == '.'){
225    $page = $ns.':'.substr($page,1);
226  }
227
228  //if link contains no namespace. add current namespace (if any)
229  if($ns !== false && strpos($page,':') === false){
230    $page = $ns.':'.$page;
231  }
232
233  $page   = cleanID($page);
234  $file   = mediaFN($page);
235  $exists = @file_exists($file);
236}
237
238/**
239 * Returns a full page id
240 *
241 * @author Andreas Gohr <andi@splitbrain.org>
242 */
243function resolve_pageid($ns,&$page,&$exists){
244  global $conf;
245  $exists = false;
246
247  //if links starts with . add current namespace
248  if($page{0} == '.'){
249    $page = $ns.':'.substr($page,1);
250  }
251
252  //if link contains no namespace. add current namespace (if any)
253  if($ns !== false && strpos($page,':') === false){
254    $page = $ns.':'.$page;
255  }
256
257  //keep hashlink if exists then clean both parts
258  list($page,$hash) = split('#',$page,2);
259  $page = cleanID($page);
260  $hash = cleanID($hash);
261
262  $file = wikiFN($page);
263
264  //check alternative plural/nonplural form
265  if(!@file_exists($file)){
266    if( $conf['autoplural'] ){
267      if(substr($page,-1) == 's'){
268        $try = substr($page,0,-1);
269      }else{
270        $try = $page.'s';
271      }
272      if(@file_exists(wikiFN($try))){
273        $page   = $try;
274        $exists = true;
275      }
276    }
277  }else{
278    $exists = true;
279  }
280
281  //add hash if any
282  if(!empty($hash)) $page .= '#'.$hash;
283}
284
285/**
286 * Returns the name of a cachefile from given data
287 *
288 * The needed directory is created by this function!
289 *
290 * @author Andreas Gohr <andi@splitbrain.org>
291 *
292 * @param string $data  This data is used to create a unique md5 name
293 * @param string $ext   This is appended to the filename if given
294 * @return string       The filename of the cachefile
295 */
296function getCacheName($data,$ext=''){
297  global $conf;
298  $md5  = md5($data);
299  $file = $conf['cachedir'].'/'.$md5{0}.'/'.$md5.$ext;
300  io_makeFileDir($file);
301  return $file;
302}
303
304/**
305 * Checks a pageid against $conf['hidepages']
306 *
307 * @author Andreas Gohr <gohr@cosmocode.de>
308 */
309function isHiddenPage($id){
310  global $conf;
311  if(empty($conf['hidepages'])) return false;
312
313  if(preg_match('/'.$conf['hidepages'].'/ui',':'.$id)){
314    return true;
315  }
316  return false;
317}
318
319/**
320 * Reverse of isHiddenPage
321 *
322 * @author Andreas Gohr <gohr@cosmocode.de>
323 */
324function isVisiblePage($id){
325  return !isHiddenPage($id);
326}
327
328//Setup VIM: ex: et ts=2 enc=utf-8 :
329