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