1<?php 2/** 3 * Common DokuWiki functions 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Andreas Gohr <andi@splitbrain.org> 7 */ 8 9 if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/'); 10 require_once(DOKU_INC.'conf/dokuwiki.php'); 11 require_once(DOKU_INC.'inc/io.php'); 12 require_once(DOKU_INC.'inc/utf8.php'); 13 require_once(DOKU_INC.'inc/mail.php'); 14 15/** 16 * Return info about the current document as associative 17 * array. 18 * 19 * @author Andreas Gohr <andi@splitbrain.org> 20 */ 21function pageinfo(){ 22 global $ID; 23 global $REV; 24 global $USERINFO; 25 global $conf; 26 27 if($_SERVER['REMOTE_USER']){ 28 $info['user'] = $_SERVER['REMOTE_USER']; 29 $info['userinfo'] = $USERINFO; 30 $info['perm'] = auth_quickaclcheck($ID); 31 }else{ 32 $info['user'] = ''; 33 $info['perm'] = auth_aclcheck($ID,'',null); 34 } 35 36 $info['namespace'] = getNS($ID); 37 $info['locked'] = checklock($ID); 38 $info['filepath'] = realpath(wikiFN($ID,$REV)); 39 $info['exists'] = @file_exists($info['filepath']); 40 if($REV && !$info['exists']){ 41 //check if current revision was meant 42 $cur = wikiFN($ID); 43 if(@file_exists($cur) && (@filemtime($cur) == $REV)){ 44 $info['filepath'] = realpath($cur); 45 $info['exists'] = true; 46 $REV = ''; 47 } 48 } 49 if($info['exists']){ 50 $info['writable'] = (is_writable($info['filepath']) && 51 ($info['perm'] >= AUTH_EDIT)); 52 }else{ 53 $info['writable'] = ($info['perm'] >= AUTH_CREATE); 54 } 55 $info['editable'] = ($info['writable'] && empty($info['lock'])); 56 $info['lastmod'] = @filemtime($info['filepath']); 57 58 //who's the editor 59 if($REV){ 60 $revinfo = getRevisionInfo($ID,$REV); 61 }else{ 62 $revinfo = getRevisionInfo($ID,$info['lastmod']); 63 } 64 $info['ip'] = $revinfo['ip']; 65 $info['user'] = $revinfo['user']; 66 $info['sum'] = $revinfo['sum']; 67 $info['editor'] = $revinfo['ip']; 68 if($revinfo['user']) $info['editor'].= ' ('.$revinfo['user'].')'; 69 70 return $info; 71} 72 73/** 74 * print a message 75 * 76 * If HTTP headers were not sent yet the message is added 77 * to the global message array else it's printed directly 78 * using html_msgarea() 79 * 80 * 81 * Levels can be: 82 * 83 * -1 error 84 * 0 info 85 * 1 success 86 * 87 * @author Andreas Gohr <andi@splitbrain.org> 88 * @see html_msgarea 89 */ 90function msg($message,$lvl=0){ 91 global $MSG; 92 $errors[-1] = 'error'; 93 $errors[0] = 'info'; 94 $errors[1] = 'success'; 95 96 if(!headers_sent()){ 97 if(!isset($MSG)) $MSG = array(); 98 $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message); 99 }else{ 100 $MSG = array(); 101 $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message); 102 html_msgarea(); 103 } 104} 105 106/** 107 * This builds the breadcrumb trail and returns it as array 108 * 109 * @author Andreas Gohr <andi@splitbrain.org> 110 */ 111function breadcrumbs(){ 112 global $ID; 113 global $ACT; 114 global $conf; 115 $crumbs = $_SESSION[$conf['title']]['bc']; 116 117 //first visit? 118 if (!is_array($crumbs)){ 119 $crumbs = array(); 120 } 121 //we only save on show and existing wiki documents 122 $file = wikiFN($ID); 123 if($ACT != 'show' || !@file_exists($file)){ 124 $_SESSION[$conf['title']]['bc'] = $crumbs; 125 return $crumbs; 126 } 127 128 // page names 129 $name = noNS($ID); 130 if ($conf['useheading']) { 131 // get page title 132 $title = getFirstHeading(io_readFile($file)); 133 if ($title) { 134 $name = $title; 135 } 136 } 137 138 //remove ID from array 139 if (isset($crumbs[$ID])) { 140 unset($crumbs[$ID]); 141 } 142 143 //add to array 144 $crumbs[$ID] = $name; 145 //reduce size 146 while(count($crumbs) > $conf['breadcrumbs']){ 147 array_shift($crumbs); 148 } 149 //save to session 150 $_SESSION[$conf['title']]['bc'] = $crumbs; 151 return $crumbs; 152} 153 154/** 155 * Filter for page IDs 156 * 157 * This is run on a ID before it is outputted somewhere 158 * currently used to replace the colon with something else 159 * on Windows systems and to have proper URL encoding 160 * 161 * Urlencoding is ommitted when the second parameter is false 162 * 163 * @author Andreas Gohr <andi@splitbrain.org> 164 */ 165function idfilter($id,$ue=true){ 166 global $conf; 167 if ($conf['useslash'] && $conf['userewrite']){ 168 $id = strtr($id,':','/'); 169 }elseif (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && 170 $conf['userewrite']) { 171 $id = strtr($id,':',';'); 172 } 173 if($ue){ 174 $id = urlencode($id); 175 $id = str_replace('%3A',':',$id); //keep as colon 176 $id = str_replace('%2F','/',$id); //keep as slash 177 } 178 return $id; 179} 180 181/** 182 * This builds a link to a wikipage 183 * 184 * @author Andreas Gohr <andi@splitbrain.org> 185 */ 186function wl($id='',$more='',$abs=false){ 187 global $conf; 188 $more = str_replace(',','&',$more); 189 190 $id = idfilter($id); 191 if($abs){ 192 $xlink = DOKU_URL; 193 }else{ 194 $xlink = DOKU_BASE; 195 } 196 197 if(!$conf['userewrite']){ 198 $xlink .= DOKU_SCRIPT.'?id='.$id; 199 if($more) $xlink .= '&'.$more; 200 }else{ 201 $xlink .= $id; 202 if($more) $xlink .= '?'.$more; 203 } 204 205 return $xlink; 206} 207 208/** 209 * Just builds a link to a script 210 * 211 * @todo maybe obsolete 212 * @author Andreas Gohr <andi@splitbrain.org> 213 */ 214function script($script='doku.php'){ 215# $link = getBaseURL(); 216# $link .= $script; 217# return $link; 218 return DOKU_BASE.DOKU_SCRIPT; 219} 220 221/** 222 * Return namespacepart of a wiki ID 223 * 224 * @author Andreas Gohr <andi@splitbrain.org> 225 */ 226function getNS($id){ 227 if(strpos($id,':')!==false){ 228 return substr($id,0,strrpos($id,':')); 229 } 230 return false; 231} 232 233/** 234 * Returns the ID without the namespace 235 * 236 * @author Andreas Gohr <andi@splitbrain.org> 237 */ 238function noNS($id){ 239 return preg_replace('/.*:/','',$id); 240} 241 242/** 243 * Spamcheck against wordlist 244 * 245 * Checks the wikitext against a list of blocked expressions 246 * returns true if the text contains any bad words 247 * 248 * @author Andreas Gohr <andi@splitbrain.org> 249 */ 250function checkwordblock(){ 251 global $TEXT; 252 global $conf; 253 254 if(!$conf['usewordblock']) return false; 255 256 $blockfile = file('conf/wordblock.conf'); 257 //how many lines to read at once (to work around some PCRE limits) 258 if(version_compare(phpversion(),'4.3.0','<')){ 259 //old versions of PCRE define a maximum of parenthesises even if no 260 //backreferences are used - the maximum is 99 261 //this is very bad performancewise and may even be too high still 262 $chunksize = 40; 263 }else{ 264 //read file in chunks of 600 - this should work around the 265 //MAX_PATTERN_SIZE in modern PCRE 266 $chunksize = 600; 267 } 268 while($blocks = array_splice($blockfile,0,$chunksize)){ 269 $re = array(); 270 #build regexp from blocks 271 foreach($blocks as $block){ 272 $block = preg_replace('/#.*$/','',$block); 273 $block = trim($block); 274 if(empty($block)) continue; 275 $re[] = $block; 276 } 277 if(preg_match('#('.join('|',$re).')#si',$TEXT)) return true; 278 } 279 return false; 280} 281 282/** 283 * Return the IP of the client 284 * 285 * Honours X-Forwarded-For Proxy Headers 286 * 287 * @author Andreas Gohr <andi@splitbrain.org> 288 */ 289function clientIP(){ 290 $my = $_SERVER['REMOTE_ADDR']; 291 if($_SERVER['HTTP_X_FORWARDED_FOR']){ 292 $my .= ' ('.$_SERVER['HTTP_X_FORWARDED_FOR'].')'; 293 } 294 return $my; 295} 296 297/** 298 * Checks if a given page is currently locked. 299 * 300 * removes stale lockfiles 301 * 302 * @author Andreas Gohr <andi@splitbrain.org> 303 */ 304function checklock($id){ 305 global $conf; 306 $lock = wikiFN($id).'.lock'; 307 308 //no lockfile 309 if(!@file_exists($lock)) return false; 310 311 //lockfile expired 312 if((time() - filemtime($lock)) > $conf['locktime']){ 313 unlink($lock); 314 return false; 315 } 316 317 //my own lock 318 $ip = io_readFile($lock); 319 if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){ 320 return false; 321 } 322 323 return $ip; 324} 325 326/** 327 * Lock a page for editing 328 * 329 * @author Andreas Gohr <andi@splitbrain.org> 330 */ 331function lock($id){ 332 $lock = wikiFN($id).'.lock'; 333 if($_SERVER['REMOTE_USER']){ 334 io_saveFile($lock,$_SERVER['REMOTE_USER']); 335 }else{ 336 io_saveFile($lock,clientIP()); 337 } 338} 339 340/** 341 * Unlock a page if it was locked by the user 342 * 343 * @author Andreas Gohr <andi@splitbrain.org> 344 * @return bool true if a lock was removed 345 */ 346function unlock($id){ 347 $lock = wikiFN($id).'.lock'; 348 if(@file_exists($lock)){ 349 $ip = io_readFile($lock); 350 if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){ 351 @unlink($lock); 352 return true; 353 } 354 } 355 return false; 356} 357 358/** 359 * Remove unwanted chars from ID 360 * 361 * Cleans a given ID to only use allowed characters. Accented characters are 362 * converted to unaccented ones 363 * 364 * @author Andreas Gohr <andi@splitbrain.org> 365 */ 366function cleanID($id){ 367 global $conf; 368 global $lang; 369 $id = trim($id); 370 $id = utf8_strtolower($id); 371 372 //alternative namespace seperator 373 $id = strtr($id,';',':'); 374 if($conf['useslash']){ 375 $id = strtr($id,'/',':'); 376 }else{ 377 $id = strtr($id,'/','_'); 378 } 379 380 if($conf['deaccent']) $id = utf8_deaccent($id,-1); 381 382 //remove specials 383 $id = utf8_stripspecials($id,'_','_:.-'); 384 385 //clean up 386 $id = preg_replace('#__#','_',$id); 387 $id = preg_replace('#:+#',':',$id); 388 $id = trim($id,':._-'); 389 $id = preg_replace('#:[:\._\-]+#',':',$id); 390 391 return($id); 392} 393 394/** 395 * returns the full path to the datafile specified by ID and 396 * optional revision 397 * 398 * The filename is URL encoded to protect Unicode chars 399 * 400 * @author Andreas Gohr <andi@splitbrain.org> 401 */ 402function wikiFN($id,$rev=''){ 403 global $conf; 404 $id = cleanID($id); 405 $id = str_replace(':','/',$id); 406 if(empty($rev)){ 407 $fn = $conf['datadir'].'/'.utf8_encodeFN($id).'.txt'; 408 }else{ 409 $fn = $conf['olddir'].'/'.utf8_encodeFN($id).'.'.$rev.'.txt'; 410 if($conf['usegzip'] && !@file_exists($fn)){ 411 //return gzip if enabled and plaintext doesn't exist 412 $fn .= '.gz'; 413 } 414 } 415 return $fn; 416} 417 418/** 419 * Returns the full filepath to a localized textfile if local 420 * version isn't found the english one is returned 421 * 422 * @author Andreas Gohr <andi@splitbrain.org> 423 */ 424function localeFN($id){ 425 global $conf; 426 $file = './lang/'.$conf['lang'].'/'.$id.'.txt'; 427 if(!@file_exists($file)){ 428 //fall back to english 429 $file = './lang/en/'.$id.'.txt'; 430 } 431 return cleanText($file); 432} 433 434/** 435 * convert line ending to unix format 436 * 437 * @see formText() for 2crlf conversion 438 * @author Andreas Gohr <andi@splitbrain.org> 439 */ 440function cleanText($text){ 441 $text = preg_replace("/(\015\012)|(\015)/","\012",$text); 442 return $text; 443} 444 445/** 446 * Prepares text for print in Webforms by encoding special chars. 447 * It also converts line endings to Windows format which is 448 * pseudo standard for webforms. 449 * 450 * @see cleanText() for 2unix conversion 451 * @author Andreas Gohr <andi@splitbrain.org> 452 */ 453function formText($text){ 454 $text = preg_replace("/\012/","\015\012",$text); 455 return htmlspecialchars($text); 456} 457 458/** 459 * Returns the specified local text in parsed format 460 * 461 * @author Andreas Gohr <andi@splitbrain.org> 462 */ 463function parsedLocale($id){ 464 //disable section editing 465 global $parser; 466 $se = $parser['secedit']; 467 $parser['secedit'] = false; 468 //fetch parsed locale 469 $html = io_cacheParse(localeFN($id)); 470 //reset section editing 471 $parser['secedit'] = $se; 472 return $html; 473} 474 475/** 476 * Returns the specified local text in raw format 477 * 478 * @author Andreas Gohr <andi@splitbrain.org> 479 */ 480function rawLocale($id){ 481 return io_readFile(localeFN($id)); 482} 483 484 485/** 486 * Returns the parsed Wikitext for the given id and revision. 487 * 488 * If $excuse is true an explanation is returned if the file 489 * wasn't found 490 * 491 * @author Andreas Gohr <andi@splitbrain.org> 492 */ 493function parsedWiki($id,$rev='',$excuse=true){ 494 $file = wikiFN($id,$rev); 495 $ret = ''; 496 497 //ensure $id is in global $ID (needed for parsing) 498 global $ID; 499 $ID = $id; 500 501 if($rev){ 502 if(@file_exists($file)){ 503 $ret = parse(io_readFile($file)); 504 }elseif($excuse){ 505 $ret = parsedLocale('norev'); 506 } 507 }else{ 508 if(@file_exists($file)){ 509 $ret = io_cacheParse($file); 510 }elseif($excuse){ 511 $ret = parsedLocale('newpage'); 512 } 513 } 514 return $ret; 515} 516 517/** 518 * Returns the raw WikiText 519 * 520 * @author Andreas Gohr <andi@splitbrain.org> 521 */ 522function rawWiki($id,$rev=''){ 523 return io_readFile(wikiFN($id,$rev)); 524} 525 526/** 527 * Returns the raw Wiki Text in three slices. 528 * 529 * The range parameter needs to have the form "from-to" 530 * and gives the range of the section. 531 * The returned order is prefix, section and suffix. 532 * 533 * @author Andreas Gohr <andi@splitbrain.org> 534 */ 535function rawWikiSlices($range,$id,$rev=''){ 536 list($from,$to) = split('-',$range,2); 537 $text = io_readFile(wikiFN($id,$rev)); 538 $text = split("\n",$text); 539 if(!$from) $from = 0; 540 if(!$to) $to = count($text); 541 542 $slices[0] = join("\n",array_slice($text,0,$from)); 543 $slices[1] = join("\n",array_slice($text,$from,$to + 1 - $from)); 544 $slices[2] = join("\n",array_slice($text,$to+1)); 545 546 return $slices; 547} 548 549/** 550 * Joins wiki text slices 551 * 552 * function to join the text slices with correct lineendings again. 553 * When the pretty parameter is set to true it adds additional empty 554 * lines between sections if needed (used on saving). 555 * 556 * @author Andreas Gohr <andi@splitbrain.org> 557 */ 558function con($pre,$text,$suf,$pretty=false){ 559 560 if($pretty){ 561 if($pre && substr($pre,-1) != "\n") $pre .= "\n"; 562 if($suf && substr($text,-1) != "\n") $text .= "\n"; 563 } 564 565 if($pre) $pre .= "\n"; 566 if($suf) $text .= "\n"; 567 return $pre.$text.$suf; 568} 569 570/** 571 * print debug messages 572 * 573 * little function to print the content of a var 574 * 575 * @author Andreas Gohr <andi@splitbrain.org> 576 */ 577function dbg($msg,$hidden=false){ 578 (!$hidden) ? print '<pre class="dbg">' : print "<!--\n"; 579 print_r($msg); 580 (!$hidden) ? print '</pre>' : print "\n-->"; 581} 582 583/** 584 * Add's an entry to the changelog 585 * 586 * @author Andreas Gohr <andi@splitbrain.org> 587 */ 588function addLogEntry($date,$id,$summary=""){ 589 global $conf; 590 $id = cleanID($id);//FIXME not needed anymore? 591 592 if(!@is_writable($conf['changelog'])){ 593 msg($conf['changelog'].' is not writable!',-1); 594 return; 595 } 596 597 if(!$date) $date = time(); //use current time if none supplied 598 $remote = $_SERVER['REMOTE_ADDR']; 599 $user = $_SERVER['REMOTE_USER']; 600 601 $logline = join("\t",array($date,$remote,$id,$user,$summary))."\n"; 602 603 //FIXME: use adjusted io_saveFile instead 604 $fh = fopen($conf['changelog'],'a'); 605 if($fh){ 606 fwrite($fh,$logline); 607 fclose($fh); 608 } 609} 610 611/** 612 * returns an array of recently changed files using the 613 * changelog 614 * 615 * @author Andreas Gohr <andi@splitbrain.org> 616 */ 617function getRecents($num=0,$incdel=false){ 618 global $conf; 619 $recent = array(); 620 if(!$num) $num = $conf['recent']; 621 622 if(!@is_readable($conf['changelog'])){ 623 msg($conf['changelog'].' is not readable',-1); 624 return $recent; 625 } 626 627 $loglines = file($conf['changelog']); 628 rsort($loglines); //reverse sort on timestamp 629 630 foreach ($loglines as $line){ 631 $line = rtrim($line); //remove newline 632 if(empty($line)) continue; //skip empty lines 633 $info = split("\t",$line); //split into parts 634 //add id if not in yet and file still exists and is allowed to read 635 if(!$recent[$info[2]] && 636 (@file_exists(wikiFN($info[2])) || $incdel) && 637 (auth_quickaclcheck($info[2]) >= AUTH_READ) 638 ){ 639 $recent[$info[2]]['date'] = $info[0]; 640 $recent[$info[2]]['ip'] = $info[1]; 641 $recent[$info[2]]['user'] = $info[3]; 642 $recent[$info[2]]['sum'] = $info[4]; 643 $recent[$info[2]]['del'] = !@file_exists(wikiFN($info[2])); 644 } 645 if(count($recent) >= $num){ 646 break; //finish if enough items found 647 } 648 } 649 return $recent; 650} 651 652/** 653 * gets additonal informations for a certain pagerevison 654 * from the changelog 655 * 656 * @author Andreas Gohr <andi@splitbrain.org> 657 */ 658function getRevisionInfo($id,$rev){ 659 global $conf; 660 661 if(!$rev) return(null); 662 663 $info = array(); 664 if(!@is_readable($conf['changelog'])){ 665 msg($conf['changelog'].' is not readable',-1); 666 return $recent; 667 } 668 $loglines = file($conf['changelog']); 669 $loglines = preg_grep("/$rev\t\d+\.\d+\.\d+\.\d+\t$id\t/",$loglines); 670 rsort($loglines); //reverse sort on timestamp (shouldn't be needed) 671 $line = split("\t",$loglines[0]); 672 $info['date'] = $line[0]; 673 $info['ip'] = $line[1]; 674 $info['user'] = $line[3]; 675 $info['sum'] = $line[4]; 676 return $info; 677} 678 679/** 680 * Saves a wikitext by calling io_saveFile 681 * 682 * @author Andreas Gohr <andi@splitbrain.org> 683 */ 684function saveWikiText($id,$text,$summary){ 685 global $conf; 686 global $lang; 687 umask($conf['umask']); 688 // ignore if no changes were made 689 if($text == rawWiki($id,'')){ 690 return; 691 } 692 693 $file = wikiFN($id); 694 $old = saveOldRevision($id); 695 696 if (empty($text)){ 697 // remove empty files 698 @unlink($file); 699 $del = true; 700 //autoset summary on deletion 701 if(empty($summary)) $summary = $lang['deleted']; 702 //remove empty namespaces 703 io_sweepNS($id); 704 }else{ 705 // save file (datadir is created in io_saveFile) 706 io_saveFile($file,$text); 707 $del = false; 708 } 709 710 addLogEntry(@filemtime($file),$id,$summary); 711 notify($id,$old,$summary); 712 713 //purge cache on add by updating the purgefile 714 if($conf['purgeonadd'] && (!$old || $del)){ 715 io_saveFile($conf['datadir'].'/_cache/purgefile',time()); 716 } 717} 718 719/** 720 * moves the current version to the attic and returns its 721 * revision date 722 * 723 * @author Andreas Gohr <andi@splitbrain.org> 724 */ 725function saveOldRevision($id){ 726 global $conf; 727 umask($conf['umask']); 728 $oldf = wikiFN($id); 729 if(!@file_exists($oldf)) return ''; 730 $date = filemtime($oldf); 731 $newf = wikiFN($id,$date); 732 if(substr($newf,-3)=='.gz'){ 733 io_saveFile($newf,rawWiki($id)); 734 }else{ 735 io_makeFileDir($newf); 736 copy($oldf, $newf); 737 } 738 return $date; 739} 740 741/** 742 * Sends a notify mail to the wikiadmin when a page was 743 * changed 744 * 745 * @author Andreas Gohr <andi@splitbrain.org> 746 */ 747function notify($id,$rev="",$summary=""){ 748 global $lang; 749 global $conf; 750 $hdrs =''; 751 if(empty($conf['notify'])) return; //notify enabled? 752 753 $text = rawLocale('mailtext'); 754 $text = str_replace('@DATE@',date($conf['dformat']),$text); 755 $text = str_replace('@BROWSER@',$_SERVER['HTTP_USER_AGENT'],$text); 756 $text = str_replace('@IPADDRESS@',$_SERVER['REMOTE_ADDR'],$text); 757 $text = str_replace('@HOSTNAME@',gethostbyaddr($_SERVER['REMOTE_ADDR']),$text); 758 $text = str_replace('@NEWPAGE@',wl($id,'',true),$text); 759 $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text); 760 $text = str_replace('@SUMMARY@',$summary,$text); 761 $text = str_replace('@USER@',$_SERVER['REMOTE_USER'],$text); 762 763 if($rev){ 764 $subject = $lang['mail_changed'].' '.$id; 765 $text = str_replace('@OLDPAGE@',wl($id,"rev=$rev",true),$text); 766 require_once("inc/DifferenceEngine.php"); 767 $df = new Diff(split("\n",rawWiki($id,$rev)), 768 split("\n",rawWiki($id))); 769 $dformat = new UnifiedDiffFormatter(); 770 $diff = $dformat->format($df); 771 }else{ 772 $subject=$lang['mail_newpage'].' '.$id; 773 $text = str_replace('@OLDPAGE@','none',$text); 774 $diff = rawWiki($id); 775 } 776 $text = str_replace('@DIFF@',$diff,$text); 777 778 mail_send($conf['notify'],$subject,$text,$conf['mailfrom']); 779} 780 781/** 782 * Return a list of available page revisons 783 * 784 * @author Andreas Gohr <andi@splitbrain.org> 785 */ 786function getRevisions($id){ 787 $revd = dirname(wikiFN($id,'foo')); 788 $revs = array(); 789 $clid = cleanID($id); 790 if(strrpos($clid,':')) $clid = substr($clid,strrpos($clid,':')+1); //remove path 791 792 if (is_dir($revd) && $dh = opendir($revd)) { 793 while (($file = readdir($dh)) !== false) { 794 if (is_dir($revd.'/'.$file)) continue; 795 if (preg_match('/^'.$clid.'\.(\d+)\.txt(\.gz)?$/',$file,$match)){ 796 $revs[]=$match[1]; 797 } 798 } 799 closedir($dh); 800 } 801 rsort($revs); 802 return $revs; 803} 804 805/** 806 * downloads a file from the net and saves it to the given location 807 * 808 * @author Andreas Gohr <andi@splitbrain.org> 809 */ 810function download($url,$file){ 811 $fp = @fopen($url,"rb"); 812 if(!$fp) return false; 813 814 while(!feof($fp)){ 815 $cont.= fread($fp,1024); 816 } 817 fclose($fp); 818 819 $fp2 = @fopen($file,"w"); 820 if(!$fp2) return false; 821 fwrite($fp2,$cont); 822 fclose($fp2); 823 return true; 824} 825 826/** 827 * extracts the query from a google referer 828 * 829 * @todo should be more generic and support yahoo et al 830 * @author Andreas Gohr <andi@splitbrain.org> 831 */ 832function getGoogleQuery(){ 833 $url = parse_url($_SERVER['HTTP_REFERER']); 834 835 if(!preg_match("#google\.#i",$url['host'])) return ''; 836 $query = array(); 837 parse_str($url['query'],$query); 838 839 return $query['q']; 840} 841 842/** 843 * Try to set correct locale 844 * 845 * @deprecated No longer used 846 * @author Andreas Gohr <andi@splitbrain.org> 847 */ 848function setCorrectLocale(){ 849 global $conf; 850 global $lang; 851 852 $enc = strtoupper($lang['encoding']); 853 foreach ($lang['locales'] as $loc){ 854 //try locale 855 if(@setlocale(LC_ALL,$loc)) return; 856 //try loceale with encoding 857 if(@setlocale(LC_ALL,"$loc.$enc")) return; 858 } 859 //still here? try to set from environment 860 @setlocale(LC_ALL,""); 861} 862 863/** 864 * Return the human readable size of a file 865 * 866 * @param int $size A file size 867 * @param int $dec A number of decimal places 868 * @author Martin Benjamin <b.martin@cybernet.ch> 869 * @author Aidan Lister <aidan@php.net> 870 * @version 1.0.0 871 */ 872function filesize_h($size, $dec = 1){ 873 $sizes = array('B', 'KB', 'MB', 'GB'); 874 $count = count($sizes); 875 $i = 0; 876 877 while ($size >= 1024 && ($i < $count - 1)) { 878 $size /= 1024; 879 $i++; 880 } 881 882 return round($size, $dec) . ' ' . $sizes[$i]; 883} 884 885/** 886 * Run a few sanity checks 887 * 888 * @author Andreas Gohr <andi@splitbrain.org> 889 */ 890function getVersion(){ 891 //import version string 892 if(@file_exists('VERSION')){ 893 //official release 894 return 'Release '.io_readfile('VERSION'); 895 }elseif(is_dir('_darcs')){ 896 //darcs checkout 897 $inv = file('_darcs/inventory'); 898 $inv = preg_grep('#andi@splitbrain\.org\*\*\d{14}#',$inv); 899 $cur = array_pop($inv); 900 preg_match('#\*\*(\d{4})(\d{2})(\d{2})#',$cur,$matches); 901 return 'Darcs '.$matches[1].'-'.$matches[2].'-'.$matches[3]; 902 }else{ 903 return 'snapshot?'; 904 } 905} 906 907/** 908 * Run a few sanity checks 909 * 910 * @author Andreas Gohr <andi@splitbrain.org> 911 */ 912function check(){ 913 global $conf; 914 global $INFO; 915 916 msg('DokuWiki version: '.getVersion(),1); 917 918 if(version_compare(phpversion(),'4.3.0','<')){ 919 msg('Your PHP version is too old ('.phpversion().' vs. 4.3.+ recommended)',-1); 920 }elseif(version_compare(phpversion(),'4.3.10','<')){ 921 msg('Consider upgrading PHP to 4.3.10 or higher for security reasons (your version: '.phpversion().')',0); 922 }else{ 923 msg('PHP version '.phpversion(),1); 924 } 925 926 if(is_writable($conf['changelog'])){ 927 msg('Changelog is writable',1); 928 }else{ 929 msg('Changelog is not writable',-1); 930 } 931 932 if(is_writable($conf['datadir'])){ 933 msg('Datadir is writable',1); 934 }else{ 935 msg('Datadir is not writable',-1); 936 } 937 938 if(is_writable($conf['olddir'])){ 939 msg('Attic is writable',1); 940 }else{ 941 msg('Attic is not writable',-1); 942 } 943 944 if(is_writable($conf['mediadir'])){ 945 msg('Mediadir is writable',1); 946 }else{ 947 msg('Mediadir is not writable',-1); 948 } 949 950 if(is_writable('conf/users.auth')){ 951 msg('conf/users.auth is writable',1); 952 }else{ 953 msg('conf/users.auth is not writable',0); 954 } 955 956 if(function_exists('mb_strpos')){ 957 if(defined('UTF8_NOMBSTRING')){ 958 msg('mb_string extension is available but will not be used',0); 959 }else{ 960 msg('mb_string extension is available and will be used',1); 961 } 962 }else{ 963 msg('mb_string extension not available - PHP only replacements will be used',0); 964 } 965 966 msg('Your current permission for this page is '.$INFO['perm'],0); 967 968 if(is_writable($INFO['filepath'])){ 969 msg('The current page is writable by the webserver',0); 970 }else{ 971 msg('The current page is not writable by the webserver',0); 972 } 973 974 if($INFO['writable']){ 975 msg('The current page is writable by you',0); 976 }else{ 977 msg('The current page is not writable you',0); 978 } 979} 980?> 981