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