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