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