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