1<?php 2/** 3 * Information and debugging functions 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Andreas Gohr <andi@splitbrain.org> 7 */ 8if(!defined('DOKU_INC')) die('meh.'); 9if(!defined('DOKU_MESSAGEURL')) define('DOKU_MESSAGEURL','http://update.dokuwiki.org/check/'); 10require_once(DOKU_INC.'inc/HTTPClient.php'); 11 12/** 13 * Check for new messages from upstream 14 * 15 * @author Andreas Gohr <andi@splitbrain.org> 16 */ 17function checkUpdateMessages(){ 18 global $conf; 19 global $INFO; 20 if(!$conf['updatecheck']) return; 21 if($conf['useacl'] && !$INFO['ismanager']) return; 22 23 $cf = $conf['cachedir'].'/messages.txt'; 24 $lm = @filemtime($cf); 25 26 // check if new messages needs to be fetched 27 if($lm < time()-(60*60*24) || $lm < @filemtime(DOKU_CONF.'msg')){ 28 $num = @file(DOKU_CONF.'msg'); 29 $num = is_array($num) ? (int) $num[0] : 0; 30 $http = new DokuHTTPClient(); 31 $http->timeout = 8; 32 $data = $http->get(DOKU_MESSAGEURL.$num); 33 io_saveFile($cf,$data); 34 }else{ 35 $data = io_readFile($cf); 36 } 37 38 // show messages through the usual message mechanism 39 $msgs = explode("\n%\n",$data); 40 foreach($msgs as $msg){ 41 if($msg) msg($msg,2); 42 } 43} 44 45 46/** 47 * Return DokuWikis version 48 * 49 * @author Andreas Gohr <andi@splitbrain.org> 50 */ 51function getVersion(){ 52 //import version string 53 if(@file_exists(DOKU_INC.'VERSION')){ 54 //official release 55 return 'Release '.trim(io_readfile(DOKU_INC.'VERSION')); 56 }elseif(is_dir(DOKU_INC.'_darcs')){ 57 if(is_file(DOKU_INC.'_darcs/inventory')){ 58 $inventory = DOKU_INC.'_darcs/inventory'; 59 }elseif(is_file(DOKU_INC.'_darcs/hashed_inventory')){ 60 $inventory = DOKU_INC.'_darcs/hashed_inventory'; 61 }else{ 62 return 'Darcs unknown'; 63 } 64 65 //darcs checkout - read last 2000 bytes of inventory 66 $sz = filesize($inventory); 67 $seek = max(0,$sz-2000); 68 $fh = fopen($inventory,'rb'); 69 fseek($fh,$seek); 70 $chunk = fread($fh,2000); 71 fclose($fh); 72 $inv = preg_grep('#\*\*\d{14}[\]$]#',explode("\n",$chunk)); 73 $cur = array_pop($inv); 74 preg_match('#\*\*(\d{4})(\d{2})(\d{2})#',$cur,$matches); 75 return 'Darcs '.$matches[1].'-'.$matches[2].'-'.$matches[3]; 76 }else{ 77 return 'snapshot?'; 78 } 79} 80 81/** 82 * Run a few sanity checks 83 * 84 * @author Andreas Gohr <andi@splitbrain.org> 85 */ 86function check(){ 87 global $conf; 88 global $INFO; 89 90 msg('DokuWiki version: '.getVersion(),1); 91 92 if(version_compare(phpversion(),'5.1.2','<')){ 93 msg('Your PHP version is too old ('.phpversion().' vs. 5.1.2+ needed)',-1); 94 }else{ 95 msg('PHP version '.phpversion(),1); 96 } 97 98 $mem = (int) php_to_byte(ini_get('memory_limit')); 99 if($mem){ 100 if($mem < 16777216){ 101 msg('PHP is limited to less than 16MB RAM ('.$mem.' bytes). Increase memory_limit in php.ini',-1); 102 }elseif($mem < 20971520){ 103 msg('PHP is limited to less than 20MB RAM ('.$mem.' bytes), you might encounter problems with bigger pages. Increase memory_limit in php.ini',-1); 104 }elseif($mem < 33554432){ 105 msg('PHP is limited to less than 32MB RAM ('.$mem.' bytes), but that should be enough in most cases. If not, increase memory_limit in php.ini',0); 106 }else{ 107 msg('More than 32MB RAM ('.$mem.' bytes) available.',1); 108 } 109 } 110 111 if(is_writable($conf['changelog'])){ 112 msg('Changelog is writable',1); 113 }else{ 114 if (@file_exists($conf['changelog'])) { 115 msg('Changelog is not writable',-1); 116 } 117 } 118 119 if (isset($conf['changelog_old']) && @file_exists($conf['changelog_old'])) { 120 msg('Old changelog exists', 0); 121 } 122 123 if (@file_exists($conf['changelog'].'_failed')) { 124 msg('Importing old changelog failed', -1); 125 } else if (@file_exists($conf['changelog'].'_importing')) { 126 msg('Importing old changelog now.', 0); 127 } else if (@file_exists($conf['changelog'].'_import_ok')) { 128 msg('Old changelog imported', 1); 129 if (!plugin_isdisabled('importoldchangelog')) { 130 msg('Importoldchangelog plugin not disabled after import', -1); 131 } 132 } 133 134 if(is_writable($conf['datadir'])){ 135 msg('Datadir is writable',1); 136 }else{ 137 msg('Datadir is not writable',-1); 138 } 139 140 if(is_writable($conf['olddir'])){ 141 msg('Attic is writable',1); 142 }else{ 143 msg('Attic is not writable',-1); 144 } 145 146 if(is_writable($conf['mediadir'])){ 147 msg('Mediadir is writable',1); 148 }else{ 149 msg('Mediadir is not writable',-1); 150 } 151 152 if(is_writable($conf['cachedir'])){ 153 msg('Cachedir is writable',1); 154 }else{ 155 msg('Cachedir is not writable',-1); 156 } 157 158 if(is_writable($conf['lockdir'])){ 159 msg('Lockdir is writable',1); 160 }else{ 161 msg('Lockdir is not writable',-1); 162 } 163 164 if($conf['authtype'] == 'plain'){ 165 if(is_writable(DOKU_CONF.'users.auth.php')){ 166 msg('conf/users.auth.php is writable',1); 167 }else{ 168 msg('conf/users.auth.php is not writable',0); 169 } 170 } 171 172 if(function_exists('mb_strpos')){ 173 if(defined('UTF8_NOMBSTRING')){ 174 msg('mb_string extension is available but will not be used',0); 175 }else{ 176 msg('mb_string extension is available and will be used',1); 177 if(ini_get('mbstring.func_overload') != 0){ 178 msg('mb_string function overloading is enabled, this will cause problems and should be disabled',-1); 179 } 180 } 181 }else{ 182 msg('mb_string extension not available - PHP only replacements will be used',0); 183 } 184 185 if($conf['allowdebug']){ 186 msg('Debugging support is enabled. If you don\'t need it you should set $conf[\'allowdebug\'] = 0',-1); 187 }else{ 188 msg('Debugging support is disabled',1); 189 } 190 191 if($INFO['userinfo']['name']){ 192 msg('You are currently logged in as '.$_SERVER['REMOTE_USER'].' ('.$INFO['userinfo']['name'].')',0); 193 msg('You are part of the groups '.join($INFO['userinfo']['grps'],', '),0); 194 }else{ 195 msg('You are currently not logged in',0); 196 } 197 198 msg('Your current permission for this page is '.$INFO['perm'],0); 199 200 if(is_writable($INFO['filepath'])){ 201 msg('The current page is writable by the webserver',0); 202 }else{ 203 msg('The current page is not writable by the webserver',0); 204 } 205 206 if($INFO['writable']){ 207 msg('The current page is writable by you',0); 208 }else{ 209 msg('The current page is not writable by you',0); 210 } 211 212 require_once(DOKU_INC.'inc/HTTPClient.php'); 213 $check = wl('','',true).'data/_dummy'; 214 $http = new DokuHTTPClient(); 215 $http->timeout = 6; 216 $res = $http->get($check); 217 if(strpos($res,'data directory') !== false){ 218 msg('It seems like the data directory is accessible from the web. 219 Make sure this directory is properly protected 220 (See <a href="http://www.dokuwiki.org/security">security</a>)',-1); 221 }elseif($http->status == 404 || $http->status == 403){ 222 msg('The data directory seems to be properly protected',1); 223 }else{ 224 msg('Failed to check if the data directory is accessible from the web. 225 Make sure this directory is properly protected 226 (See <a href="http://www.dokuwiki.org/security">security</a>)',-1); 227 } 228} 229 230/** 231 * print a message 232 * 233 * If HTTP headers were not sent yet the message is added 234 * to the global message array else it's printed directly 235 * using html_msgarea() 236 * 237 * 238 * Levels can be: 239 * 240 * -1 error 241 * 0 info 242 * 1 success 243 * 244 * @author Andreas Gohr <andi@splitbrain.org> 245 * @see html_msgarea 246 */ 247function msg($message,$lvl=0,$line='',$file=''){ 248 global $MSG; 249 $errors[-1] = 'error'; 250 $errors[0] = 'info'; 251 $errors[1] = 'success'; 252 $errors[2] = 'notify'; 253 254 if($line || $file) $message.=' ['.basename($file).':'.$line.']'; 255 256 if(!headers_sent()){ 257 if(!isset($MSG)) $MSG = array(); 258 $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message); 259 }else{ 260 $MSG = array(); 261 $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message); 262 if(function_exists('html_msgarea')){ 263 html_msgarea(); 264 }else{ 265 print "ERROR($lvl) $message"; 266 } 267 } 268} 269 270/** 271 * print debug messages 272 * 273 * little function to print the content of a var 274 * 275 * @author Andreas Gohr <andi@splitbrain.org> 276 */ 277function dbg($msg,$hidden=false){ 278 (!$hidden) ? print '<pre class="dbg">' : print "<!--\n"; 279 print_r($msg); 280 (!$hidden) ? print '</pre>' : print "\n-->"; 281} 282 283/** 284 * Print info to a log file 285 * 286 * @author Andreas Gohr <andi@splitbrain.org> 287 */ 288function dbglog($msg,$header=''){ 289 global $conf; 290 if(is_object($msg) || is_array($msg)){ 291 $msg = print_r($msg,true); 292 } 293 294 if($header) $msg = "$header\n$msg"; 295 296 $file = $conf['cachedir'].'/debug.log'; 297 $fh = fopen($file,'a'); 298 if($fh){ 299 fwrite($fh,date('H:i:s ').$_SERVER['REMOTE_ADDR'].': '.$msg."\n"); 300 fclose($fh); 301 } 302} 303 304/** 305 * Print a reversed, prettyprinted backtrace 306 * 307 * @author Gary Owen <gary_owen@bigfoot.com> 308 */ 309function dbg_backtrace(){ 310 // Get backtrace 311 $backtrace = debug_backtrace(); 312 313 // Unset call to debug_print_backtrace 314 array_shift($backtrace); 315 316 // Iterate backtrace 317 $calls = array(); 318 $depth = count($backtrace) - 1; 319 foreach ($backtrace as $i => $call) { 320 $location = $call['file'] . ':' . $call['line']; 321 $function = (isset($call['class'])) ? 322 $call['class'] . $call['type'] . $call['function'] : $call['function']; 323 324 $params = array(); 325 if (isset($call['args'])){ 326 foreach($call['args'] as $arg){ 327 if(is_object($arg)){ 328 $params[] = '[Object '.get_class($arg).']'; 329 }elseif(is_array($arg)){ 330 $params[] = '[Array]'; 331 }elseif(is_null($arg)){ 332 $param[] = '[NULL]'; 333 }else{ 334 $params[] = (string) '"'.$arg.'"'; 335 } 336 } 337 } 338 $params = implode(', ',$params); 339 340 $calls[$depth - $i] = sprintf('%s(%s) called at %s', 341 $function, 342 str_replace("\n", '\n', $params), 343 $location); 344 } 345 ksort($calls); 346 347 return implode("\n", $calls); 348} 349 350/** 351 * Remove all data from an array where the key seems to point to sensitive data 352 * 353 * This is used to remove passwords, mail addresses and similar data from the 354 * debug output 355 * 356 * @author Andreas Gohr <andi@splitbrain.org> 357 */ 358function debug_guard(&$data){ 359 foreach($data as $key => $value){ 360 if(preg_match('/(notify|pass|auth|secret|ftp|userinfo|token|buid|mail|proxy)/i',$key)){ 361 $data[$key] = '***'; 362 continue; 363 } 364 if(is_array($value)) debug_guard($data[$key]); 365 } 366} 367