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