Completed
Push — remoteapiGetversions ( b2f4ab...f28a57 )
by Gerrit
12:56 queued 07:54
created

pageutils.php ➔ cleanID()   C

Complexity

Conditions 11
Paths 65

Size

Total Lines 44
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 27
c 1
b 0
f 0
nc 65
nop 2
dl 0
loc 44
rs 5.2653

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Utilities for handling pagenames
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Andreas Gohr <[email protected]>
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 <[email protected]>
20
 *
21
 * @param string $param  the $_REQUEST variable name, default 'id'
22
 * @param bool   $clean  if true, ID is cleaned
23
 * @return string
24
 */
25
function getID($param='id',$clean=true){
26
    /** @var Input $INPUT */
27
    global $INPUT;
28
    global $conf;
29
    global $ACT;
30
31
    $id = $INPUT->str($param);
32
33
    //construct page id from request URI
34
    if(empty($id) && $conf['userewrite'] == 2){
35
        $request = $INPUT->server->str('REQUEST_URI');
36
        $script = '';
37
38
        //get the script URL
39
        if($conf['basedir']){
40
            $relpath = '';
41
            if($param != 'id') {
42
                $relpath = 'lib/exe/';
43
            }
44
            $script = $conf['basedir'].$relpath.utf8_basename($INPUT->server->str('SCRIPT_FILENAME'));
45
46
        }elseif($INPUT->server->str('PATH_INFO')){
47
            $request = $INPUT->server->str('PATH_INFO');
48
        }elseif($INPUT->server->str('SCRIPT_NAME')){
49
            $script = $INPUT->server->str('SCRIPT_NAME');
50
        }elseif($INPUT->server->str('DOCUMENT_ROOT') && $INPUT->server->str('SCRIPT_FILENAME')){
51
            $script = preg_replace ('/^'.preg_quote($INPUT->server->str('DOCUMENT_ROOT'),'/').'/','',
52
                    $INPUT->server->str('SCRIPT_FILENAME'));
53
            $script = '/'.$script;
54
        }
55
56
        //clean script and request (fixes a windows problem)
57
        $script  = preg_replace('/\/\/+/','/',$script);
58
        $request = preg_replace('/\/\/+/','/',$request);
59
60
        //remove script URL and Querystring to gain the id
61
        if(preg_match('/^'.preg_quote($script,'/').'(.*)/',$request, $match)){
62
            $id = preg_replace ('/\?.*/','',$match[1]);
63
        }
64
        $id = urldecode($id);
65
        //strip leading slashes
66
        $id = preg_replace('!^/+!','',$id);
67
    }
68
69
    // Namespace autolinking from URL
70
    if(substr($id,-1) == ':' || ($conf['useslash'] && substr($id,-1) == '/')){
71
        if(page_exists($id.$conf['start'])){
72
            // start page inside namespace
73
            $id = $id.$conf['start'];
74
        }elseif(page_exists($id.noNS(cleanID($id)))){
75
            // page named like the NS inside the NS
76
            $id = $id.noNS(cleanID($id));
77
        }elseif(page_exists($id)){
78
            // page like namespace exists
79
            $id = substr($id,0,-1);
80
        }else{
81
            // fall back to default
82
            $id = $id.$conf['start'];
83
        }
84
        if (isset($ACT) && $ACT === 'show') send_redirect(wl($id,'',true));
85
    }
86
87
    if($clean) $id = cleanID($id);
88
    if(empty($id) && $param=='id') $id = $conf['start'];
89
90
    return $id;
91
}
92
93
/**
94
 * Remove unwanted chars from ID
95
 *
96
 * Cleans a given ID to only use allowed characters. Accented characters are
97
 * converted to unaccented ones
98
 *
99
 * @author Andreas Gohr <[email protected]>
100
 *
101
 * @param  string  $raw_id    The pageid to clean
102
 * @param  boolean $ascii     Force ASCII
103
 * @return string cleaned id
104
 */
105
function cleanID($raw_id,$ascii=false){
106
    global $conf;
107
    static $sepcharpat = null;
108
109
    global $cache_cleanid;
110
    $cache = & $cache_cleanid;
111
112
    // check if it's already in the memory cache
113
    if (!$ascii && isset($cache[(string)$raw_id])) {
114
        return $cache[(string)$raw_id];
115
    }
116
117
    $sepchar = $conf['sepchar'];
118
    if($sepcharpat == null) // build string only once to save clock cycles
119
        $sepcharpat = '#\\'.$sepchar.'+#';
120
121
    $id = trim((string)$raw_id);
122
    $id = utf8_strtolower($id);
123
124
    //alternative namespace seperator
125
    if($conf['useslash']){
126
        $id = strtr($id,';/','::');
127
    }else{
128
        $id = strtr($id,';/',':'.$sepchar);
129
    }
130
131
    if($conf['deaccent'] == 2 || $ascii) $id = utf8_romanize($id);
132
    if($conf['deaccent'] || $ascii) $id = utf8_deaccent($id,-1);
133
134
    //remove specials
135
    $id = utf8_stripspecials($id,$sepchar,'\*');
136
137
    if($ascii) $id = utf8_strip($id);
138
139
    //clean up
140
    $id = preg_replace($sepcharpat,$sepchar,$id);
141
    $id = preg_replace('#:+#',':',$id);
142
    $id = trim($id,':._-');
143
    $id = preg_replace('#:[:\._\-]+#',':',$id);
144
    $id = preg_replace('#[:\._\-]+:#',':',$id);
145
146
    if (!$ascii) $cache[(string)$raw_id] = $id;
147
    return($id);
148
}
149
150
/**
151
 * Return namespacepart of a wiki ID
152
 *
153
 * @author Andreas Gohr <[email protected]>
154
 *
155
 * @param string $id
156
 * @return string|false the namespace part or false if the given ID has no namespace (root)
157
 */
158
function getNS($id){
159
    $pos = strrpos((string)$id,':');
160
    if($pos!==false){
161
        return substr((string)$id,0,$pos);
162
    }
163
    return false;
164
}
165
166
/**
167
 * Returns the ID without the namespace
168
 *
169
 * @author Andreas Gohr <[email protected]>
170
 *
171
 * @param string $id
172
 * @return string
173
 */
174
function noNS($id) {
175
    $pos = strrpos($id, ':');
176
    if ($pos!==false) {
177
        return substr($id, $pos+1);
178
    } else {
179
        return $id;
180
    }
181
}
182
183
/**
184
 * Returns the current namespace
185
 *
186
 * @author Nathan Fritz <[email protected]>
187
 *
188
 * @param string $id
189
 * @return string
190
 */
191
function curNS($id) {
192
    return noNS(getNS($id));
0 ignored issues
show
Security Bug introduced by
It seems like getNS($id) targeting getNS() can also be of type false; however, noNS() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
193
}
194
195
/**
196
 * Returns the ID without the namespace or current namespace for 'start' pages
197
 *
198
 * @author Nathan Fritz <[email protected]>
199
 *
200
 * @param string $id
201
 * @return string
202
 */
203
function noNSorNS($id) {
204
    global $conf;
205
206
    $p = noNS($id);
207
    if ($p == $conf['start'] || $p == false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $p of type string to the boolean false. If you are specifically checking for an empty string, consider using the more explicit === '' instead.
Loading history...
208
        $p = curNS($id);
209
        if ($p == false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $p of type string to the boolean false. If you are specifically checking for an empty string, consider using the more explicit === '' instead.
Loading history...
210
            return $conf['start'];
211
        }
212
    }
213
    return $p;
214
}
215
216
/**
217
 * Creates a XHTML valid linkid from a given headline title
218
 *
219
 * @param string  $title   The headline title
220
 * @param array|bool   $check   Existing IDs (title => number)
221
 * @return string the title
222
 *
223
 * @author Andreas Gohr <[email protected]>
224
 */
225
function sectionID($title,&$check) {
226
    $title = str_replace(array(':','.'),'',cleanID($title));
227
    $new = ltrim($title,'0123456789_-');
228
    if(empty($new)){
229
        $title = 'section'.preg_replace('/[^0-9]+/','',$title); //keep numbers from headline
230
    }else{
231
        $title = $new;
232
    }
233
234
    if(is_array($check)){
235
        // make sure tiles are unique
236
        if (!array_key_exists ($title,$check)) {
237
            $check[$title] = 0;
238
        } else {
239
            $title .= ++ $check[$title];
240
        }
241
    }
242
243
    return $title;
244
}
245
246
/**
247
 * Wiki page existence check
248
 *
249
 * parameters as for wikiFN
250
 *
251
 * @author Chris Smith <[email protected]>
252
 *
253
 * @param string $id page id
254
 * @param string|int $rev empty or revision timestamp
255
 * @param bool $clean flag indicating that $id should be cleaned (see wikiFN as well)
256
 * @param bool $date_at
257
 * @return bool exists?
258
 */
259
function page_exists($id,$rev='',$clean=true, $date_at=false) {
260
    if($rev !== '' && $date_at) {
261
        $pagelog = new PageChangeLog($id);
262
        $pagelog_rev = $pagelog->getLastRevisionAt($rev);
263
        if($pagelog_rev !== false)
264
            $rev = $pagelog_rev;
265
    }
266
    return file_exists(wikiFN($id,$rev,$clean));
267
}
268
269
/**
270
 * returns the full path to the datafile specified by ID and optional revision
271
 *
272
 * The filename is URL encoded to protect Unicode chars
273
 *
274
 * @param  $raw_id  string   id of wikipage
275
 * @param  $rev     int|string   page revision, empty string for current
276
 * @param  $clean   bool     flag indicating that $raw_id should be cleaned.  Only set to false
277
 *                           when $id is guaranteed to have been cleaned already.
278
 * @return string full path
279
 *
280
 * @author Andreas Gohr <[email protected]>
281
 */
282
function wikiFN($raw_id,$rev='',$clean=true){
283
    global $conf;
284
285
    global $cache_wikifn;
286
    $cache = & $cache_wikifn;
287
288
    $id = $raw_id;
289
290
    if ($clean) $id = cleanID($id);
291
    $id = str_replace(':','/',$id);
292
293
    if (isset($cache[$id]) && isset($cache[$id][$rev])) {
294
        return $cache[$id][$rev];
295
    }
296
297
    if(empty($rev)){
298
        $fn = $conf['datadir'].'/'.utf8_encodeFN($id).'.txt';
299
    }else{
300
        $fn = $conf['olddir'].'/'.utf8_encodeFN($id).'.'.$rev.'.txt';
301
        if($conf['compression']){
302
            //test for extensions here, we want to read both compressions
303
            if (file_exists($fn . '.gz')){
304
                $fn .= '.gz';
305
            }else if(file_exists($fn . '.bz2')){
306
                $fn .= '.bz2';
307
            }else{
308
                //file doesnt exist yet, so we take the configured extension
309
                $fn .= '.' . $conf['compression'];
310
            }
311
        }
312
    }
313
314
    if (!isset($cache[$id])) { $cache[$id] = array(); }
315
    $cache[$id][$rev] = $fn;
316
    return $fn;
317
}
318
319
/**
320
 * Returns the full path to the file for locking the page while editing.
321
 *
322
 * @author Ben Coburn <[email protected]>
323
 *
324
 * @param string $id page id
325
 * @return string full path
326
 */
327
function wikiLockFN($id) {
328
    global $conf;
329
    return $conf['lockdir'].'/'.md5(cleanID($id)).'.lock';
330
}
331
332
333
/**
334
 * returns the full path to the meta file specified by ID and extension
335
 *
336
 * @author Steven Danz <[email protected]>
337
 *
338
 * @param string $id   page id
339
 * @param string $ext  file extension
340
 * @return string full path
341
 */
342
function metaFN($id,$ext){
343
    global $conf;
344
    $id = cleanID($id);
345
    $id = str_replace(':','/',$id);
346
    $fn = $conf['metadir'].'/'.utf8_encodeFN($id).$ext;
347
    return $fn;
348
}
349
350
/**
351
 * returns the full path to the media's meta file specified by ID and extension
352
 *
353
 * @author Kate Arzamastseva <[email protected]>
354
 *
355
 * @param string $id   media id
356
 * @param string $ext  extension of media
357
 * @return string
358
 */
359
function mediaMetaFN($id,$ext){
360
    global $conf;
361
    $id = cleanID($id);
362
    $id = str_replace(':','/',$id);
363
    $fn = $conf['mediametadir'].'/'.utf8_encodeFN($id).$ext;
364
    return $fn;
365
}
366
367
/**
368
 * returns an array of full paths to all metafiles of a given ID
369
 *
370
 * @author Esther Brunner <[email protected]>
371
 * @author Michael Hamann <[email protected]>
372
 *
373
 * @param string $id page id
374
 * @return array
375
 */
376
function metaFiles($id){
377
    $basename = metaFN($id, '');
378
    $files    = glob($basename.'.*', GLOB_MARK);
379
    // filter files like foo.bar.meta when $id == 'foo'
380
    return    $files ? preg_grep('/^'.preg_quote($basename, '/').'\.[^.\/]*$/u', $files) : array();
381
}
382
383
/**
384
 * returns the full path to the mediafile specified by ID
385
 *
386
 * The filename is URL encoded to protect Unicode chars
387
 *
388
 * @author Andreas Gohr <[email protected]>
389
 * @author Kate Arzamastseva <[email protected]>
390
 *
391
 * @param string     $id  media id
392
 * @param string|int $rev empty string or revision timestamp
393
 * @return string full path
394
 */
395
function mediaFN($id, $rev='', $clean=true){
396
    global $conf;
397
    if ($clean) $id = cleanID($id);
398
    $id = str_replace(':','/',$id);
399
    if(empty($rev)){
400
        $fn = $conf['mediadir'].'/'.utf8_encodeFN($id);
401
    }else{
402
        $ext = mimetype($id);
403
        $name = substr($id,0, -1*strlen($ext[0])-1);
404
        $fn = $conf['mediaolddir'].'/'.utf8_encodeFN($name .'.'.( (int) $rev ).'.'.$ext[0]);
405
    }
406
    return $fn;
407
}
408
409
/**
410
 * Returns the full filepath to a localized file if local
411
 * version isn't found the english one is returned
412
 *
413
 * @param  string $id  The id of the local file
414
 * @param  string $ext The file extension (usually txt)
415
 * @return string full filepath to localized file
416
 *
417
 * @author Andreas Gohr <[email protected]>
418
 */
419
function localeFN($id,$ext='txt'){
420
    global $conf;
421
    $file = DOKU_CONF.'lang/'.$conf['lang'].'/'.$id.'.'.$ext;
422
    if(!file_exists($file)){
423
        $file = DOKU_INC.'inc/lang/'.$conf['lang'].'/'.$id.'.'.$ext;
424
        if(!file_exists($file)){
425
            //fall back to english
426
            $file = DOKU_INC.'inc/lang/en/'.$id.'.'.$ext;
427
        }
428
    }
429
    return $file;
430
}
431
432
/**
433
 * Resolve relative paths in IDs
434
 *
435
 * Do not call directly use resolve_mediaid or resolve_pageid
436
 * instead
437
 *
438
 * Partyly based on a cleanPath function found at
439
 * http://www.php.net/manual/en/function.realpath.php#57016
440
 *
441
 * @author <bart at mediawave dot nl>
442
 *
443
 * @param string $ns     namespace which is context of id
444
 * @param string $id     relative id
445
 * @param bool   $clean  flag indicating that id should be cleaned
446
 * @return string
447
 */
448
function resolve_id($ns,$id,$clean=true){
449
    global $conf;
450
451
    // some pre cleaning for useslash:
452
    if($conf['useslash']) $id = str_replace('/',':',$id);
453
454
    // if the id starts with a dot we need to handle the
455
    // relative stuff
456
    if($id && $id{0} == '.'){
457
        // normalize initial dots without a colon
458
        $id = preg_replace('/^(\.+)(?=[^:\.])/','\1:',$id);
459
        // prepend the current namespace
460
        $id = $ns.':'.$id;
461
462
        // cleanup relatives
463
        $result = array();
464
        $pathA  = explode(':', $id);
465
        if (!$pathA[0]) $result[] = '';
466
        foreach ($pathA AS $key => $dir) {
467
            if ($dir == '..') {
468
                if (end($result) == '..') {
469
                    $result[] = '..';
470
                } elseif (!array_pop($result)) {
471
                    $result[] = '..';
472
                }
473
            } elseif ($dir && $dir != '.') {
474
                $result[] = $dir;
475
            }
476
        }
477
        if (!end($pathA)) $result[] = '';
478
        $id = implode(':', $result);
479
    }elseif($ns !== false && strpos($id,':') === false){
480
        //if link contains no namespace. add current namespace (if any)
481
        $id = $ns.':'.$id;
482
    }
483
484
    if($clean) $id = cleanID($id);
485
    return $id;
486
}
487
488
/**
489
 * Returns a full media id
490
 *
491
 * @author Andreas Gohr <[email protected]>
492
 *
493
 * @param string $ns namespace which is context of id
494
 * @param string &$page (reference) relative media id, updated to resolved id
495
 * @param bool &$exists (reference) updated with existance of media
496
 * @param int|string $rev
497
 * @param bool $date_at
498
 */
499
function resolve_mediaid($ns,&$page,&$exists,$rev='',$date_at=false){
500
    $page   = resolve_id($ns,$page);
501
    if($rev !== '' &&  $date_at){
502
        $medialog = new MediaChangeLog($page);
503
        $medialog_rev = $medialog->getLastRevisionAt($rev);
504
        if($medialog_rev !== false) {
505
            $rev = $medialog_rev;
506
        }
507
    }
508
509
    $file   = mediaFN($page,$rev);
510
    $exists = file_exists($file);
511
}
512
513
/**
514
 * Returns a full page id
515
 *
516
 * @author Andreas Gohr <[email protected]>
517
 *
518
 * @param string $ns namespace which is context of id
519
 * @param string &$page (reference) relative page id, updated to resolved id
520
 * @param bool &$exists (reference) updated with existance of media
521
 * @param string $rev
522
 * @param bool $date_at
523
 */
524
function resolve_pageid($ns,&$page,&$exists,$rev='',$date_at=false ){
525
    global $conf;
526
    global $ID;
527
    $exists = false;
528
529
    //empty address should point to current page
530
    if ($page === "") {
531
        $page = $ID;
532
    }
533
534
    //keep hashlink if exists then clean both parts
535
    if (strpos($page,'#')) {
536
        list($page,$hash) = explode('#',$page,2);
537
    } else {
538
        $hash = '';
539
    }
540
    $hash = cleanID($hash);
541
    $page = resolve_id($ns,$page,false); // resolve but don't clean, yet
542
543
    // get filename (calls clean itself)
544
    if($rev !== '' && $date_at) {
545
        $pagelog = new PageChangeLog($page);
546
        $pagelog_rev = $pagelog->getLastRevisionAt($rev);
547
        if($pagelog_rev !== false)//something found
548
           $rev  = $pagelog_rev;
549
    }
550
    $file = wikiFN($page,$rev);
551
552
    // if ends with colon or slash we have a namespace link
553
    if(in_array(substr($page,-1), array(':', ';')) ||
554
       ($conf['useslash'] && substr($page,-1) == '/')){
555
        if(page_exists($page.$conf['start'],$rev,true,$date_at)){
556
            // start page inside namespace
557
            $page = $page.$conf['start'];
558
            $exists = true;
559
        }elseif(page_exists($page.noNS(cleanID($page)),$rev,true,$date_at)){
560
            // page named like the NS inside the NS
561
            $page = $page.noNS(cleanID($page));
562
            $exists = true;
563
        }elseif(page_exists($page,$rev,true,$date_at)){
564
            // page like namespace exists
565
            $page = $page;
0 ignored issues
show
Bug introduced by
Why assign $page to itself?

This checks looks for cases where a variable has been assigned to itself.

This assignement can be removed without consequences.

Loading history...
566
            $exists = true;
567
        }else{
568
            // fall back to default
569
            $page = $page.$conf['start'];
570
        }
571
    }else{
572
        //check alternative plural/nonplural form
573
        if(!file_exists($file)){
574
            if( $conf['autoplural'] ){
575
                if(substr($page,-1) == 's'){
576
                    $try = substr($page,0,-1);
577
                }else{
578
                    $try = $page.'s';
579
                }
580
                if(page_exists($try,$rev,true,$date_at)){
581
                    $page   = $try;
582
                    $exists = true;
583
                }
584
            }
585
        }else{
586
            $exists = true;
587
        }
588
    }
589
590
    // now make sure we have a clean page
591
    $page = cleanID($page);
592
593
    //add hash if any
594
    if(!empty($hash)) $page .= '#'.$hash;
595
}
596
597
/**
598
 * Returns the name of a cachefile from given data
599
 *
600
 * The needed directory is created by this function!
601
 *
602
 * @author Andreas Gohr <[email protected]>
603
 *
604
 * @param string $data  This data is used to create a unique md5 name
605
 * @param string $ext   This is appended to the filename if given
606
 * @return string       The filename of the cachefile
607
 */
608
function getCacheName($data,$ext=''){
609
    global $conf;
610
    $md5  = md5($data);
611
    $file = $conf['cachedir'].'/'.$md5{0}.'/'.$md5.$ext;
612
    io_makeFileDir($file);
613
    return $file;
614
}
615
616
/**
617
 * Checks a pageid against $conf['hidepages']
618
 *
619
 * @author Andreas Gohr <[email protected]>
620
 *
621
 * @param string $id page id
622
 * @return bool
623
 */
624
function isHiddenPage($id){
625
    $data = array(
626
        'id' => $id,
627
        'hidden' => false
628
    );
629
    trigger_event('PAGEUTILS_ID_HIDEPAGE', $data, '_isHiddenPage');
630
    return $data['hidden'];
631
}
632
633
/**
634
 * callback checks if page is hidden
635
 *
636
 * @param array $data event data    - see isHiddenPage()
637
 */
638
function _isHiddenPage(&$data) {
639
    global $conf;
640
    global $ACT;
641
642
    if ($data['hidden']) return;
643
    if(empty($conf['hidepages'])) return;
644
    if($ACT == 'admin') return;
645
646
    if(preg_match('/'.$conf['hidepages'].'/ui',':'.$data['id'])){
647
        $data['hidden'] = true;
648
    }
649
}
650
651
/**
652
 * Reverse of isHiddenPage
653
 *
654
 * @author Andreas Gohr <[email protected]>
655
 *
656
 * @param string $id page id
657
 * @return bool
658
 */
659
function isVisiblePage($id){
660
    return !isHiddenPage($id);
661
}
662
663
/**
664
 * Format an id for output to a user
665
 *
666
 * Namespaces are denoted by a trailing “:*”. The root namespace is
667
 * “*”. Output is escaped.
668
 *
669
 * @author Adrian Lang <[email protected]>
670
 *
671
 * @param string $id page id
672
 * @return string
673
 */
674
function prettyprint_id($id) {
675
    if (!$id || $id === ':') {
676
        return '*';
677
    }
678
    if ((substr($id, -1, 1) === ':')) {
679
        $id .= '*';
680
    }
681
    return hsc($id);
682
}
683
684
/**
685
 * Encode a UTF-8 filename to use on any filesystem
686
 *
687
 * Uses the 'fnencode' option to determine encoding
688
 *
689
 * When the second parameter is true the string will
690
 * be encoded only if non ASCII characters are detected -
691
 * This makes it safe to run it multiple times on the
692
 * same string (default is true)
693
 *
694
 * @author Andreas Gohr <[email protected]>
695
 * @see    urlencode
696
 *
697
 * @param string $file file name
698
 * @param bool   $safe if true, only encoded when non ASCII characters detected
699
 * @return string
700
 */
701
function utf8_encodeFN($file,$safe=true){
702
    global $conf;
703
    if($conf['fnencode'] == 'utf-8') return $file;
704
705
    if($safe && preg_match('#^[a-zA-Z0-9/_\-\.%]+$#',$file)){
706
        return $file;
707
    }
708
709
    if($conf['fnencode'] == 'safe'){
710
        return SafeFN::encode($file);
711
    }
712
713
    $file = urlencode($file);
714
    $file = str_replace('%2F','/',$file);
715
    return $file;
716
}
717
718
/**
719
 * Decode a filename back to UTF-8
720
 *
721
 * Uses the 'fnencode' option to determine encoding
722
 *
723
 * @author Andreas Gohr <[email protected]>
724
 * @see    urldecode
725
 *
726
 * @param string $file file name
727
 * @return string
728
 */
729
function utf8_decodeFN($file){
730
    global $conf;
731
    if($conf['fnencode'] == 'utf-8') return $file;
732
733
    if($conf['fnencode'] == 'safe'){
734
        return SafeFN::decode($file);
735
    }
736
737
    return urldecode($file);
738
}
739
740
/**
741
 * Find a page in the current namespace (determined from $ID) or any
742
 * higher namespace that can be accessed by the current user,
743
 * this condition can be overriden by an optional parameter.
744
 *
745
 * Used for sidebars, but can be used other stuff as well
746
 *
747
 * @todo   add event hook
748
 *
749
 * @param  string $page the pagename you're looking for
750
 * @param bool $useacl only return pages readable by the current user, false to ignore ACLs
751
 * @return false|string the full page id of the found page, false if any
752
 */
753
function page_findnearest($page, $useacl = true){
754
    if (!$page) return false;
755
    global $ID;
756
757
    $ns = $ID;
758
    do {
759
        $ns = getNS($ns);
760
        $pageid = cleanID("$ns:$page");
761
        if(page_exists($pageid) && (!$useacl || auth_quickaclcheck($pageid) >= AUTH_READ)){
762
            return $pageid;
763
        }
764
    } while($ns);
0 ignored issues
show
Bug Best Practice introduced by
The expression $ns of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
765
766
    return false;
767
}
768