Completed
Push — master ( 724970...8458d4 )
by Andreas
12:51 queued 08:20
created

infoutils.php ➔ dbg_deprecated()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 33
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 24
nc 4
nop 1
dl 0
loc 33
rs 8.439
c 0
b 0
f 0
1
<?php
2
/**
3
 * Information and debugging functions
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Andreas Gohr <[email protected]>
7
 */
8
if(!defined('DOKU_INC')) die('meh.');
9
10
if(!defined('DOKU_MESSAGEURL')){
11
    if(in_array('ssl', stream_get_transports())) {
12
        define('DOKU_MESSAGEURL','https://update.dokuwiki.org/check/');
13
    }else{
14
        define('DOKU_MESSAGEURL','http://update.dokuwiki.org/check/');
15
    }
16
}
17
18
/**
19
 * Check for new messages from upstream
20
 *
21
 * @author Andreas Gohr <[email protected]>
22
 */
23
function checkUpdateMessages(){
24
    global $conf;
25
    global $INFO;
26
    global $updateVersion;
27
    if(!$conf['updatecheck']) return;
28
    if($conf['useacl'] && !$INFO['ismanager']) return;
29
30
    $cf = getCacheName($updateVersion, '.updmsg');
31
    $lm = @filemtime($cf);
32
    $is_http = substr(DOKU_MESSAGEURL, 0, 5) != 'https';
33
34
    // check if new messages needs to be fetched
35
    if($lm < time()-(60*60*24) || $lm < @filemtime(DOKU_INC.DOKU_SCRIPT)){
36
        @touch($cf);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
37
        dbglog("checkUpdateMessages(): downloading messages to ".$cf.($is_http?' (without SSL)':' (with SSL)'));
38
        $http = new DokuHTTPClient();
39
        $http->timeout = 12;
40
        $resp = $http->get(DOKU_MESSAGEURL.$updateVersion);
41
        if(is_string($resp) && ($resp == "" || substr(trim($resp), -1) == '%')) {
42
            // basic sanity check that this is either an empty string response (ie "no messages")
43
            // or it looks like one of our messages, not WiFi login or other interposed response
44
            io_saveFile($cf,$resp);
45
        } else {
46
            dbglog("checkUpdateMessages(): unexpected HTTP response received");
47
        }
48
    }else{
49
        dbglog("checkUpdateMessages(): messages up to date");
50
    }
51
52
    $data = io_readFile($cf);
53
    // show messages through the usual message mechanism
54
    $msgs = explode("\n%\n",$data);
55
    foreach($msgs as $msg){
56
        if($msg) msg($msg,2);
57
    }
58
}
59
60
61
/**
62
 * Return DokuWiki's version (split up in date and type)
63
 *
64
 * @author Andreas Gohr <[email protected]>
65
 */
66
function getVersionData(){
67
    $version = array();
68
    //import version string
69
    if(file_exists(DOKU_INC.'VERSION')){
70
        //official release
71
        $version['date'] = trim(io_readFile(DOKU_INC.'VERSION'));
72
        $version['type'] = 'Release';
73
    }elseif(is_dir(DOKU_INC.'.git')){
74
        $version['type'] = 'Git';
75
        $version['date'] = 'unknown';
76
77
        $inventory = DOKU_INC.'.git/logs/HEAD';
78
        if(is_file($inventory)){
79
            $sz   = filesize($inventory);
80
            $seek = max(0,$sz-2000); // read from back of the file
81
            $fh   = fopen($inventory,'rb');
82
            fseek($fh,$seek);
83
            $chunk = fread($fh,2000);
84
            fclose($fh);
85
            $chunk = trim($chunk);
86
            $chunk = @array_pop(explode("\n",$chunk));   //last log line
0 ignored issues
show
Bug introduced by
explode(' ', $chunk) cannot be passed to array_pop() as the parameter $array expects a reference.
Loading history...
87
            $chunk = @array_shift(explode("\t",$chunk)); //strip commit msg
0 ignored issues
show
Bug introduced by
explode(' ', $chunk) cannot be passed to array_shift() as the parameter $array expects a reference.
Loading history...
88
            $chunk = explode(" ",$chunk);
89
            array_pop($chunk); //strip timezone
90
            $date = date('Y-m-d',array_pop($chunk));
91
            if($date) $version['date'] = $date;
92
        }
93
    }else{
94
        global $updateVersion;
95
        $version['date'] = 'update version '.$updateVersion;
96
        $version['type'] = 'snapshot?';
97
    }
98
    return $version;
99
}
100
101
/**
102
 * Return DokuWiki's version (as a string)
103
 *
104
 * @author Anika Henke <[email protected]>
105
 */
106
function getVersion(){
107
    $version = getVersionData();
108
    return $version['type'].' '.$version['date'];
109
}
110
111
/**
112
 * Run a few sanity checks
113
 *
114
 * @author Andreas Gohr <[email protected]>
115
 */
116
function check(){
117
    global $conf;
118
    global $INFO;
119
    /* @var Input $INPUT */
120
    global $INPUT;
121
122
    if ($INFO['isadmin'] || $INFO['ismanager']){
123
        msg('DokuWiki version: '.getVersion(),1);
124
125
        if(version_compare(phpversion(),'5.6.0','<')){
126
            msg('Your PHP version is too old ('.phpversion().' vs. 5.6.0+ needed)',-1);
127
        }else{
128
            msg('PHP version '.phpversion(),1);
129
        }
130
    } else {
131
        if(version_compare(phpversion(),'5.6.0','<')){
132
            msg('Your PHP version is too old',-1);
133
        }
134
    }
135
136
    $mem = (int) php_to_byte(ini_get('memory_limit'));
137
    if($mem){
138
        if($mem < 16777216){
139
            msg('PHP is limited to less than 16MB RAM ('.$mem.' bytes). Increase memory_limit in php.ini',-1);
140
        }elseif($mem < 20971520){
141
            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);
142
        }elseif($mem < 33554432){
143
            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);
144
        }else{
145
            msg('More than 32MB RAM ('.$mem.' bytes) available.',1);
146
        }
147
    }
148
149
    if(is_writable($conf['changelog'])){
150
        msg('Changelog is writable',1);
151
    }else{
152
        if (file_exists($conf['changelog'])) {
153
            msg('Changelog is not writable',-1);
154
        }
155
    }
156
157
    if (isset($conf['changelog_old']) && file_exists($conf['changelog_old'])) {
158
        msg('Old changelog exists', 0);
159
    }
160
161
    if (file_exists($conf['changelog'].'_failed')) {
162
        msg('Importing old changelog failed', -1);
163
    } else if (file_exists($conf['changelog'].'_importing')) {
164
        msg('Importing old changelog now.', 0);
165
    } else if (file_exists($conf['changelog'].'_import_ok')) {
166
        msg('Old changelog imported', 1);
167
        if (!plugin_isdisabled('importoldchangelog')) {
168
            msg('Importoldchangelog plugin not disabled after import', -1);
169
        }
170
    }
171
172
    if(is_writable(DOKU_CONF)){
173
        msg('conf directory is writable',1);
174
    }else{
175
        msg('conf directory is not writable',-1);
176
    }
177
178
    if($conf['authtype'] == 'plain'){
179
        global $config_cascade;
180
        if(is_writable($config_cascade['plainauth.users']['default'])){
181
            msg('conf/users.auth.php is writable',1);
182
        }else{
183
            msg('conf/users.auth.php is not writable',0);
184
        }
185
    }
186
187
    if(function_exists('mb_strpos')){
188
        if(defined('UTF8_NOMBSTRING')){
189
            msg('mb_string extension is available but will not be used',0);
190
        }else{
191
            msg('mb_string extension is available and will be used',1);
192
            if(ini_get('mbstring.func_overload') != 0){
193
                msg('mb_string function overloading is enabled, this will cause problems and should be disabled',-1);
194
            }
195
        }
196
    }else{
197
        msg('mb_string extension not available - PHP only replacements will be used',0);
198
    }
199
200
    if (!UTF8_PREGSUPPORT) {
201
        msg('PHP is missing UTF-8 support in Perl-Compatible Regular Expressions (PCRE)', -1);
202
    }
203
    if (!UTF8_PROPERTYSUPPORT) {
204
        msg('PHP is missing Unicode properties support in Perl-Compatible Regular Expressions (PCRE)', -1);
205
    }
206
207
    $loc = setlocale(LC_ALL, 0);
208
    if(!$loc){
209
        msg('No valid locale is set for your PHP setup. You should fix this',-1);
210
    }elseif(stripos($loc,'utf') === false){
211
        msg('Your locale <code>'.hsc($loc).'</code> seems not to be a UTF-8 locale, you should fix this if you encounter problems.',0);
212
    }else{
213
        msg('Valid locale '.hsc($loc).' found.', 1);
214
    }
215
216
    if($conf['allowdebug']){
217
        msg('Debugging support is enabled. If you don\'t need it you should set $conf[\'allowdebug\'] = 0',-1);
218
    }else{
219
        msg('Debugging support is disabled',1);
220
    }
221
222
    if($INFO['userinfo']['name']){
223
        msg('You are currently logged in as '.$INPUT->server->str('REMOTE_USER').' ('.$INFO['userinfo']['name'].')',0);
224
        msg('You are part of the groups '.join($INFO['userinfo']['grps'],', '),0);
225
    }else{
226
        msg('You are currently not logged in',0);
227
    }
228
229
    msg('Your current permission for this page is '.$INFO['perm'],0);
230
231
    if(is_writable($INFO['filepath'])){
232
        msg('The current page is writable by the webserver',0);
233
    }else{
234
        msg('The current page is not writable by the webserver',0);
235
    }
236
237
    if($INFO['writable']){
238
        msg('The current page is writable by you',0);
239
    }else{
240
        msg('The current page is not writable by you',0);
241
    }
242
243
    // Check for corrupted search index
244
    $lengths = idx_listIndexLengths();
245
    $index_corrupted = false;
246
    foreach ($lengths as $length) {
247
        if (count(idx_getIndex('w', $length)) != count(idx_getIndex('i', $length))) {
248
            $index_corrupted = true;
249
            break;
250
        }
251
    }
252
253
    foreach (idx_getIndex('metadata', '') as $index) {
254
        if (count(idx_getIndex($index.'_w', '')) != count(idx_getIndex($index.'_i', ''))) {
255
            $index_corrupted = true;
256
            break;
257
        }
258
    }
259
260
    if($index_corrupted) {
261
        msg(
262
            'The search index is corrupted. It might produce wrong results and most
263
                probably needs to be rebuilt. See
264
                <a href="http://www.dokuwiki.org/faq:searchindex">faq:searchindex</a>
265
                for ways to rebuild the search index.', -1
266
        );
267
    } elseif(!empty($lengths)) {
268
        msg('The search index seems to be working', 1);
269
    } else {
270
        msg(
271
            'The search index is empty. See
272
                <a href="http://www.dokuwiki.org/faq:searchindex">faq:searchindex</a>
273
                for help on how to fix the search index. If the default indexer
274
                isn\'t used or the wiki is actually empty this is normal.'
275
        );
276
    }
277
278
    // rough time check
279
    $http = new DokuHTTPClient();
280
    $http->max_redirect = 0;
281
    $http->timeout = 3;
282
    $http->sendRequest('http://www.dokuwiki.org', '', 'HEAD');
283
    $now = time();
284
    if(isset($http->resp_headers['date'])) {
285
        $time = strtotime($http->resp_headers['date']);
286
        $diff = $time - $now;
287
288
        if(abs($diff) < 4) {
289
            msg("Server time seems to be okay. Diff: {$diff}s", 1);
290
        } else {
291
            msg("Your server's clock seems to be out of sync! Consider configuring a sync with a NTP server.  Diff: {$diff}s");
292
        }
293
    }
294
295
}
296
297
/**
298
 * print a message
299
 *
300
 * If HTTP headers were not sent yet the message is added
301
 * to the global message array else it's printed directly
302
 * using html_msgarea()
303
 *
304
 *
305
 * Levels can be:
306
 *
307
 * -1 error
308
 *  0 info
309
 *  1 success
310
 *
311
 * @author Andreas Gohr <[email protected]>
312
 * @see    html_msgarea
313
 */
314
315
define('MSG_PUBLIC', 0);
316
define('MSG_USERS_ONLY', 1);
317
define('MSG_MANAGERS_ONLY',2);
318
define('MSG_ADMINS_ONLY',4);
319
320
/**
321
 * Display a message to the user
322
 *
323
 * @param string $message
324
 * @param int    $lvl   -1 = error, 0 = info, 1 = success, 2 = notify
325
 * @param string $line  line number
326
 * @param string $file  file number
327
 * @param int    $allow who's allowed to see the message, see MSG_* constants
328
 */
329
function msg($message,$lvl=0,$line='',$file='',$allow=MSG_PUBLIC){
330
    global $MSG, $MSG_shown;
331
    $errors = array();
332
    $errors[-1] = 'error';
333
    $errors[0]  = 'info';
334
    $errors[1]  = 'success';
335
    $errors[2]  = 'notify';
336
337
    if($line || $file) $message.=' ['.utf8_basename($file).':'.$line.']';
338
339
    if(!isset($MSG)) $MSG = array();
340
    $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message, 'allow' => $allow);
341
    if(isset($MSG_shown) || headers_sent()){
342
        if(function_exists('html_msgarea')){
343
            html_msgarea();
344
        }else{
345
            print "ERROR($lvl) $message";
346
        }
347
        unset($GLOBALS['MSG']);
348
    }
349
}
350
/**
351
 * Determine whether the current user is allowed to view the message
352
 * in the $msg data structure
353
 *
354
 * @param  $msg   array    dokuwiki msg structure
355
 *                         msg   => string, the message
356
 *                         lvl   => int, level of the message (see msg() function)
357
 *                         allow => int, flag used to determine who is allowed to see the message
358
 *                                       see MSG_* constants
359
 * @return bool
360
 */
361
function info_msg_allowed($msg){
362
    global $INFO, $auth;
363
364
    // is the message public? - everyone and anyone can see it
365
    if (empty($msg['allow']) || ($msg['allow'] == MSG_PUBLIC)) return true;
366
367
    // restricted msg, but no authentication
368
    if (empty($auth)) return false;
369
370
    switch ($msg['allow']){
371
        case MSG_USERS_ONLY:
372
            return !empty($INFO['userinfo']);
373
374
        case MSG_MANAGERS_ONLY:
375
            return $INFO['ismanager'];
376
377
        case MSG_ADMINS_ONLY:
378
            return $INFO['isadmin'];
379
380
        default:
381
            trigger_error('invalid msg allow restriction.  msg="'.$msg['msg'].'" allow='.$msg['allow'].'"', E_USER_WARNING);
382
            return $INFO['isadmin'];
383
    }
384
385
    return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
386
}
387
388
/**
389
 * print debug messages
390
 *
391
 * little function to print the content of a var
392
 *
393
 * @author Andreas Gohr <[email protected]>
394
 *
395
 * @param string $msg
396
 * @param bool $hidden
397
 */
398
function dbg($msg,$hidden=false){
399
    if($hidden){
400
        echo "<!--\n";
401
        print_r($msg);
402
        echo "\n-->";
403
    }else{
404
        echo '<pre class="dbg">';
405
        echo hsc(print_r($msg,true));
406
        echo '</pre>';
407
    }
408
}
409
410
/**
411
 * Print info to a log file
412
 *
413
 * @author Andreas Gohr <[email protected]>
414
 *
415
 * @param string $msg
416
 * @param string $header
417
 */
418
function dbglog($msg,$header=''){
419
    global $conf;
420
    /* @var Input $INPUT */
421
    global $INPUT;
422
423
    // The debug log isn't automatically cleaned thus only write it when
424
    // debugging has been enabled by the user.
425
    if($conf['allowdebug'] !== 1) return;
426
    if(is_object($msg) || is_array($msg)){
427
        $msg = print_r($msg,true);
428
    }
429
430
    if($header) $msg = "$header\n$msg";
431
432
    $file = $conf['cachedir'].'/debug.log';
433
    $fh = fopen($file,'a');
434
    if($fh){
435
        fwrite($fh,date('H:i:s ').$INPUT->server->str('REMOTE_ADDR').': '.$msg."\n");
436
        fclose($fh);
437
    }
438
}
439
440
/**
441
 * Log accesses to deprecated fucntions to the debug log
442
 *
443
 * @param string $alternative The function or method that should be used instead
444
 * @triggers INFO_DEPRECATION_LOG
445
 */
446
function dbg_deprecated($alternative = '') {
447
    global $conf;
448
    global $EVENT_HANDLER;
449
    if(!$conf['allowdebug'] && !$EVENT_HANDLER->hasHandlerForEvent('INFO_DEPRECATION_LOG')) {
450
        // avoid any work if no one cares
451
        return;
452
    }
453
454
    $backtrace = debug_backtrace();
455
    array_shift($backtrace);
456
    $self = $backtrace[0];
457
    $call = $backtrace[1];
458
459
    $data = [
460
        'trace' => $backtrace,
461
        'alternative' => $alternative,
462
        'called' => trim($self['class'] . '::' . $self['function'] . '()', ':'),
463
        'caller' => trim($call['class'] . '::' . $call['function'] . '()', ':'),
464
        'file' => $call['file'],
465
        'line' => $call['line'],
466
    ];
467
468
    $event = new Doku_Event('INFO_DEPRECATION_LOG', $data);
469
    if($event->advise_before()) {
470
        $msg = $event->data['called'] . ' is deprecated. It was called from ';
471
        $msg .= $event->data['caller'] . ' in ' . $event->data['file'] . ':' . $event->data['line'];
472
        if($event->data['alternative']) {
473
            $msg .= ' ' . $event->data['alternative'] . ' should be used instead!';
474
        }
475
        dbglog($msg);
476
    }
477
    $event->advise_after();
478
}
479
480
/**
481
 * Print a reversed, prettyprinted backtrace
482
 *
483
 * @author Gary Owen <[email protected]>
484
 */
485
function dbg_backtrace(){
486
    // Get backtrace
487
    $backtrace = debug_backtrace();
488
489
    // Unset call to debug_print_backtrace
490
    array_shift($backtrace);
491
492
    // Iterate backtrace
493
    $calls = array();
494
    $depth = count($backtrace) - 1;
495
    foreach ($backtrace as $i => $call) {
496
        $location = $call['file'] . ':' . $call['line'];
497
        $function = (isset($call['class'])) ?
498
            $call['class'] . $call['type'] . $call['function'] : $call['function'];
499
500
        $params = array();
501
        if (isset($call['args'])){
502
            foreach($call['args'] as $arg){
503
                if(is_object($arg)){
504
                    $params[] = '[Object '.get_class($arg).']';
505
                }elseif(is_array($arg)){
506
                    $params[] = '[Array]';
507
                }elseif(is_null($arg)){
508
                    $params[] = '[NULL]';
509
                }else{
510
                    $params[] = (string) '"'.$arg.'"';
511
                }
512
            }
513
        }
514
        $params = implode(', ',$params);
515
516
        $calls[$depth - $i] = sprintf('%s(%s) called at %s',
517
                $function,
518
                str_replace("\n", '\n', $params),
519
                $location);
520
    }
521
    ksort($calls);
522
523
    return implode("\n", $calls);
524
}
525
526
/**
527
 * Remove all data from an array where the key seems to point to sensitive data
528
 *
529
 * This is used to remove passwords, mail addresses and similar data from the
530
 * debug output
531
 *
532
 * @author Andreas Gohr <[email protected]>
533
 *
534
 * @param array $data
535
 */
536
function debug_guard(&$data){
537
    foreach($data as $key => $value){
538
        if(preg_match('/(notify|pass|auth|secret|ftp|userinfo|token|buid|mail|proxy)/i',$key)){
539
            $data[$key] = '***';
540
            continue;
541
        }
542
        if(is_array($value)) debug_guard($data[$key]);
543
    }
544
}
545