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