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