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