These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * DokuWiki search functions |
||
4 | * |
||
5 | * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) |
||
6 | * @author Andreas Gohr <[email protected]> |
||
7 | */ |
||
8 | |||
9 | use dokuwiki\Utf8\Sort; |
||
10 | |||
11 | /** |
||
12 | * Recurse directory |
||
13 | * |
||
14 | * This function recurses into a given base directory |
||
15 | * and calls the supplied function for each file and directory |
||
16 | * |
||
17 | * @param array &$data The results of the search are stored here |
||
18 | * @param string $base Where to start the search |
||
19 | * @param callback $func Callback (function name or array with object,method) |
||
20 | * @param array $opts option array will be given to the Callback |
||
21 | * @param string $dir Current directory beyond $base |
||
22 | * @param int $lvl Recursion Level |
||
23 | * @param mixed $sort 'natural' to use natural order sorting (default); |
||
24 | * 'date' to sort by filemtime; leave empty to skip sorting. |
||
25 | * @author Andreas Gohr <[email protected]> |
||
26 | */ |
||
27 | function search(&$data,$base,$func,$opts,$dir='',$lvl=1,$sort='natural'){ |
||
28 | $dirs = array(); |
||
29 | $files = array(); |
||
30 | $filepaths = array(); |
||
31 | |||
32 | // safeguard against runaways #1452 |
||
33 | if($base == '' || $base == '/') { |
||
34 | throw new RuntimeException('No valid $base passed to search() - possible misconfiguration or bug'); |
||
35 | } |
||
36 | |||
37 | //read in directories and files |
||
38 | $dh = @opendir($base.'/'.$dir); |
||
39 | if(!$dh) return; |
||
40 | while(($file = readdir($dh)) !== false){ |
||
41 | if(preg_match('/^[\._]/',$file)) continue; //skip hidden files and upper dirs |
||
42 | if(is_dir($base.'/'.$dir.'/'.$file)){ |
||
43 | $dirs[] = $dir.'/'.$file; |
||
44 | continue; |
||
45 | } |
||
46 | $files[] = $dir.'/'.$file; |
||
47 | $filepaths[] = $base.'/'.$dir.'/'.$file; |
||
48 | } |
||
49 | closedir($dh); |
||
50 | if (!empty($sort)) { |
||
51 | if ($sort == 'date') { |
||
52 | @array_multisort(array_map('filemtime', $filepaths), SORT_NUMERIC, SORT_DESC, $files); |
||
53 | } else /* natural */ { |
||
54 | Sort::asortFN($files); |
||
55 | } |
||
56 | Sort::asortFN($dirs); |
||
57 | } |
||
58 | |||
59 | //give directories to userfunction then recurse |
||
60 | foreach($dirs as $dir){ |
||
61 | if (call_user_func_array($func, array(&$data,$base,$dir,'d',$lvl,$opts))){ |
||
62 | search($data,$base,$func,$opts,$dir,$lvl+1,$sort); |
||
63 | } |
||
64 | } |
||
65 | //now handle the files |
||
66 | foreach($files as $file){ |
||
67 | call_user_func_array($func, array(&$data,$base,$file,'f',$lvl,$opts)); |
||
68 | } |
||
69 | } |
||
70 | |||
71 | /** |
||
72 | * The following functions are userfunctions to use with the search |
||
73 | * function above. This function is called for every found file or |
||
74 | * directory. When a directory is given to the function it has to |
||
75 | * decide if this directory should be traversed (true) or not (false) |
||
76 | * The function has to accept the following parameters: |
||
77 | * |
||
78 | * array &$data - Reference to the result data structure |
||
79 | * string $base - Base usually $conf['datadir'] |
||
80 | * string $file - current file or directory relative to $base |
||
81 | * string $type - Type either 'd' for directory or 'f' for file |
||
82 | * int $lvl - Current recursion depht |
||
83 | * array $opts - option array as given to search() |
||
84 | * |
||
85 | * return values for files are ignored |
||
86 | * |
||
87 | * All functions should check the ACL for document READ rights |
||
88 | * namespaces (directories) are NOT checked (when sneaky_index is 0) as this |
||
89 | * would break the recursion (You can have an nonreadable dir over a readable |
||
90 | * one deeper nested) also make sure to check the file type (for example |
||
91 | * in case of lockfiles). |
||
92 | */ |
||
93 | |||
94 | /** |
||
95 | * Searches for pages beginning with the given query |
||
96 | * |
||
97 | * @author Andreas Gohr <[email protected]> |
||
98 | * |
||
99 | * @param array $data |
||
100 | * @param string $base |
||
101 | * @param string $file |
||
102 | * @param string $type |
||
103 | * @param integer $lvl |
||
104 | * @param array $opts |
||
105 | * |
||
106 | * @return bool |
||
107 | */ |
||
108 | function search_qsearch(&$data,$base,$file,$type,$lvl,$opts){ |
||
109 | $opts = array( |
||
110 | 'idmatch' => '(^|:)'.preg_quote($opts['query'],'/').'/', |
||
111 | 'listfiles' => true, |
||
112 | 'pagesonly' => true, |
||
113 | ); |
||
114 | return search_universal($data,$base,$file,$type,$lvl,$opts); |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * Build the browsable index of pages |
||
119 | * |
||
120 | * $opts['ns'] is the currently viewed namespace |
||
121 | * |
||
122 | * @author Andreas Gohr <[email protected]> |
||
123 | * |
||
124 | * @param array $data |
||
125 | * @param string $base |
||
126 | * @param string $file |
||
127 | * @param string $type |
||
128 | * @param integer $lvl |
||
129 | * @param array $opts |
||
130 | * |
||
131 | * @return bool |
||
132 | */ |
||
133 | function search_index(&$data,$base,$file,$type,$lvl,$opts){ |
||
134 | global $conf; |
||
135 | $ns = isset($opts['ns']) ? $opts['ns'] : ''; |
||
136 | $opts = array( |
||
137 | 'pagesonly' => true, |
||
138 | 'listdirs' => true, |
||
139 | 'listfiles' => empty($opts['nofiles']), |
||
140 | 'sneakyacl' => $conf['sneaky_index'], |
||
141 | // Hacky, should rather use recmatch |
||
142 | 'depth' => preg_match('#^'.preg_quote($file, '#').'(/|$)#','/'.$ns) ? 0 : -1 |
||
143 | ); |
||
144 | |||
145 | return search_universal($data, $base, $file, $type, $lvl, $opts); |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * List all namespaces |
||
150 | * |
||
151 | * @author Andreas Gohr <[email protected]> |
||
152 | * |
||
153 | * @param array $data |
||
154 | * @param string $base |
||
155 | * @param string $file |
||
156 | * @param string $type |
||
157 | * @param integer $lvl |
||
158 | * @param array $opts |
||
159 | * |
||
160 | * @return bool |
||
161 | */ |
||
162 | function search_namespaces(&$data,$base,$file,$type,$lvl,$opts){ |
||
163 | $opts = array( |
||
164 | 'listdirs' => true, |
||
165 | ); |
||
166 | return search_universal($data,$base,$file,$type,$lvl,$opts); |
||
167 | } |
||
168 | |||
169 | /** |
||
170 | * List all mediafiles in a namespace |
||
171 | * $opts['depth'] recursion level, 0 for all |
||
172 | * $opts['showmsg'] shows message if invalid media id is used |
||
173 | * $opts['skipacl'] skip acl checking |
||
174 | * $opts['pattern'] check given pattern |
||
175 | * $opts['hash'] add hashes to result list |
||
176 | * |
||
177 | * @author Andreas Gohr <[email protected]> |
||
178 | * |
||
179 | * @param array $data |
||
180 | * @param string $base |
||
181 | * @param string $file |
||
182 | * @param string $type |
||
183 | * @param integer $lvl |
||
184 | * @param array $opts |
||
185 | * |
||
186 | * @return bool |
||
187 | */ |
||
188 | function search_media(&$data,$base,$file,$type,$lvl,$opts){ |
||
189 | |||
190 | //we do nothing with directories |
||
191 | if($type == 'd') { |
||
192 | if(empty($opts['depth'])) return true; // recurse forever |
||
193 | $depth = substr_count($file,'/'); |
||
194 | if($depth >= $opts['depth']) return false; // depth reached |
||
195 | return true; |
||
196 | } |
||
197 | |||
198 | $info = array(); |
||
199 | $info['id'] = pathID($file,true); |
||
200 | if($info['id'] != cleanID($info['id'])){ |
||
201 | if($opts['showmsg']) |
||
202 | msg(hsc($info['id']).' is not a valid file name for DokuWiki - skipped',-1); |
||
203 | return false; // skip non-valid files |
||
204 | } |
||
205 | |||
206 | //check ACL for namespace (we have no ACL for mediafiles) |
||
207 | $info['perm'] = auth_quickaclcheck(getNS($info['id']).':*'); |
||
208 | if(empty($opts['skipacl']) && $info['perm'] < AUTH_READ){ |
||
209 | return false; |
||
210 | } |
||
211 | |||
212 | //check pattern filter |
||
213 | if(!empty($opts['pattern']) && !@preg_match($opts['pattern'], $info['id'])){ |
||
214 | return false; |
||
215 | } |
||
216 | |||
217 | $info['file'] = \dokuwiki\Utf8\PhpString::basename($file); |
||
218 | $info['size'] = filesize($base.'/'.$file); |
||
219 | $info['mtime'] = filemtime($base.'/'.$file); |
||
220 | $info['writable'] = is_writable($base.'/'.$file); |
||
221 | if(preg_match("/\.(jpe?g|gif|png)$/",$file)){ |
||
222 | $info['isimg'] = true; |
||
223 | $info['meta'] = new JpegMeta($base.'/'.$file); |
||
224 | }else{ |
||
225 | $info['isimg'] = false; |
||
226 | } |
||
227 | if(!empty($opts['hash'])){ |
||
228 | $info['hash'] = md5(io_readFile(mediaFN($info['id']),false)); |
||
229 | } |
||
230 | |||
231 | $data[] = $info; |
||
232 | |||
233 | return false; |
||
234 | } |
||
235 | |||
236 | /** |
||
237 | * List all mediafiles in a namespace |
||
238 | * $opts['depth'] recursion level, 0 for all |
||
239 | * $opts['showmsg'] shows message if invalid media id is used |
||
240 | * $opts['skipacl'] skip acl checking |
||
241 | * $opts['pattern'] check given pattern |
||
242 | * $opts['hash'] add hashes to result list |
||
243 | * |
||
244 | * @todo This is a temporary copy of search_media returning a list of MediaFile intances |
||
245 | * |
||
246 | * @param array $data |
||
247 | * @param string $base |
||
248 | * @param string $file |
||
249 | * @param string $type |
||
250 | * @param integer $lvl |
||
251 | * @param array $opts |
||
252 | * |
||
253 | * @return bool |
||
254 | */ |
||
255 | function search_mediafiles(&$data,$base,$file,$type,$lvl,$opts){ |
||
0 ignored issues
–
show
|
|||
256 | |||
257 | //we do nothing with directories |
||
258 | if($type == 'd') { |
||
259 | if(empty($opts['depth'])) return true; // recurse forever |
||
260 | $depth = substr_count($file,'/'); |
||
261 | if($depth >= $opts['depth']) return false; // depth reached |
||
262 | return true; |
||
263 | } |
||
264 | |||
265 | $id = pathID($file,true); |
||
266 | if($id != cleanID($id)){ |
||
267 | if($opts['showmsg']) |
||
268 | msg(hsc($id).' is not a valid file name for DokuWiki - skipped',-1); |
||
269 | return false; // skip non-valid files |
||
270 | } |
||
271 | |||
272 | //check ACL for namespace (we have no ACL for mediafiles) |
||
273 | $info['perm'] = auth_quickaclcheck(getNS($id).':*'); |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$info was never initialized. Although not strictly required by PHP, it is generally a good practice to add $info = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
274 | if(empty($opts['skipacl']) && $info['perm'] < AUTH_READ){ |
||
275 | return false; |
||
276 | } |
||
277 | |||
278 | //check pattern filter |
||
279 | if(!empty($opts['pattern']) && !@preg_match($opts['pattern'], $id)){ |
||
280 | return false; |
||
281 | } |
||
282 | |||
283 | $data[] = new \dokuwiki\File\MediaFile($id); |
||
284 | return false; |
||
285 | } |
||
286 | |||
287 | |||
288 | /** |
||
289 | * This function just lists documents (for RSS namespace export) |
||
290 | * |
||
291 | * @author Andreas Gohr <[email protected]> |
||
292 | * |
||
293 | * @param array $data |
||
294 | * @param string $base |
||
295 | * @param string $file |
||
296 | * @param string $type |
||
297 | * @param integer $lvl |
||
298 | * @param array $opts |
||
299 | * |
||
300 | * @return bool |
||
301 | */ |
||
302 | function search_list(&$data,$base,$file,$type,$lvl,$opts){ |
||
303 | //we do nothing with directories |
||
304 | if($type == 'd') return false; |
||
305 | //only search txt files |
||
306 | if(substr($file,-4) == '.txt'){ |
||
307 | //check ACL |
||
308 | $id = pathID($file); |
||
309 | if(auth_quickaclcheck($id) < AUTH_READ){ |
||
310 | return false; |
||
311 | } |
||
312 | $data[]['id'] = $id; |
||
313 | } |
||
314 | return false; |
||
315 | } |
||
316 | |||
317 | /** |
||
318 | * Quicksearch for searching matching pagenames |
||
319 | * |
||
320 | * $opts['query'] is the search query |
||
321 | * |
||
322 | * @author Andreas Gohr <[email protected]> |
||
323 | * |
||
324 | * @param array $data |
||
325 | * @param string $base |
||
326 | * @param string $file |
||
327 | * @param string $type |
||
328 | * @param integer $lvl |
||
329 | * @param array $opts |
||
330 | * |
||
331 | * @return bool |
||
332 | */ |
||
333 | function search_pagename(&$data,$base,$file,$type,$lvl,$opts){ |
||
334 | //we do nothing with directories |
||
335 | if($type == 'd') return true; |
||
336 | //only search txt files |
||
337 | if(substr($file,-4) != '.txt') return true; |
||
338 | |||
339 | //simple stringmatching |
||
340 | if (!empty($opts['query'])){ |
||
341 | if(strpos($file,$opts['query']) !== false){ |
||
342 | //check ACL |
||
343 | $id = pathID($file); |
||
344 | if(auth_quickaclcheck($id) < AUTH_READ){ |
||
345 | return false; |
||
346 | } |
||
347 | $data[]['id'] = $id; |
||
348 | } |
||
349 | } |
||
350 | return true; |
||
351 | } |
||
352 | |||
353 | /** |
||
354 | * Just lists all documents |
||
355 | * |
||
356 | * $opts['depth'] recursion level, 0 for all |
||
357 | * $opts['hash'] do md5 sum of content? |
||
358 | * $opts['skipacl'] list everything regardless of ACL |
||
359 | * |
||
360 | * @author Andreas Gohr <[email protected]> |
||
361 | * |
||
362 | * @param array $data |
||
363 | * @param string $base |
||
364 | * @param string $file |
||
365 | * @param string $type |
||
366 | * @param integer $lvl |
||
367 | * @param array $opts |
||
368 | * |
||
369 | * @return bool |
||
370 | */ |
||
371 | function search_allpages(&$data,$base,$file,$type,$lvl,$opts){ |
||
372 | if(isset($opts['depth']) && $opts['depth']){ |
||
373 | $parts = explode('/',ltrim($file,'/')); |
||
374 | if(($type == 'd' && count($parts) >= $opts['depth']) |
||
375 | || ($type != 'd' && count($parts) > $opts['depth'])){ |
||
376 | return false; // depth reached |
||
377 | } |
||
378 | } |
||
379 | |||
380 | //we do nothing with directories |
||
381 | if($type == 'd'){ |
||
382 | return true; |
||
383 | } |
||
384 | |||
385 | //only search txt files |
||
386 | if(substr($file,-4) != '.txt') return true; |
||
387 | |||
388 | $item = array(); |
||
389 | $item['id'] = pathID($file); |
||
390 | if(empty($opts['skipacl']) && auth_quickaclcheck($item['id']) < AUTH_READ){ |
||
391 | return false; |
||
392 | } |
||
393 | |||
394 | $item['rev'] = filemtime($base.'/'.$file); |
||
395 | $item['mtime'] = $item['rev']; |
||
396 | $item['size'] = filesize($base.'/'.$file); |
||
397 | if(!empty($opts['hash'])){ |
||
398 | $item['hash'] = md5(trim(rawWiki($item['id']))); |
||
399 | } |
||
400 | |||
401 | $data[] = $item; |
||
402 | return true; |
||
403 | } |
||
404 | |||
405 | /* ------------- helper functions below -------------- */ |
||
406 | |||
407 | /** |
||
408 | * fulltext sort |
||
409 | * |
||
410 | * Callback sort function for use with usort to sort the data |
||
411 | * structure created by search_fulltext. Sorts descending by count |
||
412 | * |
||
413 | * @author Andreas Gohr <[email protected]> |
||
414 | * |
||
415 | * @param array $a |
||
416 | * @param array $b |
||
417 | * |
||
418 | * @return int |
||
419 | */ |
||
420 | function sort_search_fulltext($a,$b){ |
||
421 | if($a['count'] > $b['count']){ |
||
422 | return -1; |
||
423 | }elseif($a['count'] < $b['count']){ |
||
424 | return 1; |
||
425 | }else{ |
||
426 | return Sort::strcmp($a['id'],$b['id']); |
||
427 | } |
||
428 | } |
||
429 | |||
430 | /** |
||
431 | * translates a document path to an ID |
||
432 | * |
||
433 | * @author Andreas Gohr <[email protected]> |
||
434 | * @todo move to pageutils |
||
435 | * |
||
436 | * @param string $path |
||
437 | * @param bool $keeptxt |
||
438 | * |
||
439 | * @return mixed|string |
||
440 | */ |
||
441 | function pathID($path,$keeptxt=false){ |
||
442 | $id = utf8_decodeFN($path); |
||
443 | $id = str_replace('/',':',$id); |
||
444 | if(!$keeptxt) $id = preg_replace('#\.txt$#','',$id); |
||
445 | $id = trim($id, ':'); |
||
446 | return $id; |
||
447 | } |
||
448 | |||
449 | |||
450 | /** |
||
451 | * This is a very universal callback for the search() function, replacing |
||
452 | * many of the former individual functions at the cost of a more complex |
||
453 | * setup. |
||
454 | * |
||
455 | * How the function behaves, depends on the options passed in the $opts |
||
456 | * array, where the following settings can be used. |
||
457 | * |
||
458 | * depth int recursion depth. 0 for unlimited (default: 0) |
||
459 | * keeptxt bool keep .txt extension for IDs (default: false) |
||
460 | * listfiles bool include files in listing (default: false) |
||
461 | * listdirs bool include namespaces in listing (default: false) |
||
462 | * pagesonly bool restrict files to pages (default: false) |
||
463 | * skipacl bool do not check for READ permission (default: false) |
||
464 | * sneakyacl bool don't recurse into nonreadable dirs (default: false) |
||
465 | * hash bool create MD5 hash for files (default: false) |
||
466 | * meta bool return file metadata (default: false) |
||
467 | * filematch string match files against this regexp (default: '', so accept everything) |
||
468 | * idmatch string match full ID against this regexp (default: '', so accept everything) |
||
469 | * dirmatch string match directory against this regexp when adding (default: '', so accept everything) |
||
470 | * nsmatch string match namespace against this regexp when adding (default: '', so accept everything) |
||
471 | * recmatch string match directory against this regexp when recursing (default: '', so accept everything) |
||
472 | * showmsg bool warn about non-ID files (default: false) |
||
473 | * showhidden bool show hidden files(e.g. by hidepages config) too (default: false) |
||
474 | * firsthead bool return first heading for pages (default: false) |
||
475 | * |
||
476 | * @param array &$data - Reference to the result data structure |
||
477 | * @param string $base - Base usually $conf['datadir'] |
||
478 | * @param string $file - current file or directory relative to $base |
||
479 | * @param string $type - Type either 'd' for directory or 'f' for file |
||
480 | * @param int $lvl - Current recursion depht |
||
481 | * @param array $opts - option array as given to search() |
||
482 | * @return bool if this directory should be traversed (true) or not (false) |
||
483 | * return value is ignored for files |
||
484 | * |
||
485 | * @author Andreas Gohr <[email protected]> |
||
486 | */ |
||
487 | function search_universal(&$data,$base,$file,$type,$lvl,$opts){ |
||
488 | $item = array(); |
||
489 | $return = true; |
||
490 | |||
491 | // get ID and check if it is a valid one |
||
492 | $item['id'] = pathID($file,($type == 'd' || !empty($opts['keeptxt']))); |
||
493 | if($item['id'] != cleanID($item['id'])){ |
||
494 | if(!empty($opts['showmsg'])){ |
||
495 | msg(hsc($item['id']).' is not a valid file name for DokuWiki - skipped',-1); |
||
496 | } |
||
497 | return false; // skip non-valid files |
||
498 | } |
||
499 | $item['ns'] = getNS($item['id']); |
||
500 | |||
501 | if($type == 'd') { |
||
502 | // decide if to recursion into this directory is wanted |
||
503 | if(empty($opts['depth'])){ |
||
504 | $return = true; // recurse forever |
||
505 | }else{ |
||
506 | $depth = substr_count($file,'/'); |
||
507 | if($depth >= $opts['depth']){ |
||
508 | $return = false; // depth reached |
||
509 | }else{ |
||
510 | $return = true; |
||
511 | } |
||
512 | } |
||
513 | |||
514 | if ($return) { |
||
515 | $match = empty($opts['recmatch']) || preg_match('/'.$opts['recmatch'].'/',$file); |
||
516 | if (!$match) { |
||
517 | return false; // doesn't match |
||
518 | } |
||
519 | } |
||
520 | } |
||
521 | |||
522 | // check ACL |
||
523 | if(empty($opts['skipacl'])){ |
||
524 | if($type == 'd'){ |
||
525 | $item['perm'] = auth_quickaclcheck($item['id'].':*'); |
||
526 | }else{ |
||
527 | $item['perm'] = auth_quickaclcheck($item['id']); //FIXME check namespace for media files |
||
528 | } |
||
529 | }else{ |
||
530 | $item['perm'] = AUTH_DELETE; |
||
531 | } |
||
532 | |||
533 | // are we done here maybe? |
||
534 | if($type == 'd'){ |
||
535 | if(empty($opts['listdirs'])) return $return; |
||
536 | //neither list nor recurse forbidden items: |
||
537 | if(empty($opts['skipacl']) && !empty($opts['sneakyacl']) && $item['perm'] < AUTH_READ) return false; |
||
538 | if(!empty($opts['dirmatch']) && !preg_match('/'.$opts['dirmatch'].'/',$file)) return $return; |
||
539 | if(!empty($opts['nsmatch']) && !preg_match('/'.$opts['nsmatch'].'/',$item['ns'])) return $return; |
||
540 | }else{ |
||
541 | if(empty($opts['listfiles'])) return $return; |
||
542 | if(empty($opts['skipacl']) && $item['perm'] < AUTH_READ) return $return; |
||
543 | if(!empty($opts['pagesonly']) && (substr($file,-4) != '.txt')) return $return; |
||
544 | if(empty($opts['showhidden']) && isHiddenPage($item['id'])) return $return; |
||
545 | if(!empty($opts['filematch']) && !preg_match('/'.$opts['filematch'].'/',$file)) return $return; |
||
546 | if(!empty($opts['idmatch']) && !preg_match('/'.$opts['idmatch'].'/',$item['id'])) return $return; |
||
547 | } |
||
548 | |||
549 | // still here? prepare the item |
||
550 | $item['type'] = $type; |
||
551 | $item['level'] = $lvl; |
||
552 | $item['open'] = $return; |
||
553 | |||
554 | if(!empty($opts['meta'])){ |
||
555 | $item['file'] = \dokuwiki\Utf8\PhpString::basename($file); |
||
556 | $item['size'] = filesize($base.'/'.$file); |
||
557 | $item['mtime'] = filemtime($base.'/'.$file); |
||
558 | $item['rev'] = $item['mtime']; |
||
559 | $item['writable'] = is_writable($base.'/'.$file); |
||
560 | $item['executable'] = is_executable($base.'/'.$file); |
||
561 | } |
||
562 | |||
563 | if($type == 'f'){ |
||
564 | if(!empty($opts['hash'])) $item['hash'] = md5(io_readFile($base.'/'.$file,false)); |
||
565 | if(!empty($opts['firsthead'])) $item['title'] = p_get_first_heading($item['id'],METADATA_DONT_RENDER); |
||
566 | } |
||
567 | |||
568 | // finally add the item |
||
569 | $data[] = $item; |
||
570 | return $return; |
||
571 | } |
||
572 | |||
573 | //Setup VIM: ex: et ts=4 : |
||
574 |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.