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