Failed Conditions
Pull Request — psr2 (#2426)
by Andreas
09:22 queued 06:07
created

inc/infoutils.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
use dokuwiki\Extension\Event;if(!defined('DOKU_MESSAGEURL')){
9
    if(in_array('ssl', stream_get_transports())) {
10
        define('DOKU_MESSAGEURL','https://update.dokuwiki.org/check/');
11
    }else{
12
        define('DOKU_MESSAGEURL','http://update.dokuwiki.org/check/');
13
    }
14
}
15
16
/**
17
 * Check for new messages from upstream
18
 *
19
 * @author Andreas Gohr <[email protected]>
20
 */
21
function checkUpdateMessages(){
22
    global $conf;
23
    global $INFO;
24
    global $updateVersion;
25
    if(!$conf['updatecheck']) return;
26
    if($conf['useacl'] && !$INFO['ismanager']) return;
27
28
    $cf = getCacheName($updateVersion, '.updmsg');
29
    $lm = @filemtime($cf);
30
    $is_http = substr(DOKU_MESSAGEURL, 0, 5) != 'https';
31
32
    // check if new messages needs to be fetched
33
    if($lm < time()-(60*60*24) || $lm < @filemtime(DOKU_INC.DOKU_SCRIPT)){
34
        @touch($cf);
35
        dbglog("checkUpdateMessages(): downloading messages to ".$cf.($is_http?' (without SSL)':' (with SSL)'));
36
        $http = new DokuHTTPClient();
37
        $http->timeout = 12;
38
        $resp = $http->get(DOKU_MESSAGEURL.$updateVersion);
39
        if(is_string($resp) && ($resp == "" || substr(trim($resp), -1) == '%')) {
40
            // basic sanity check that this is either an empty string response (ie "no messages")
41
            // or it looks like one of our messages, not WiFi login or other interposed response
42
            io_saveFile($cf,$resp);
43
        } else {
44
            dbglog("checkUpdateMessages(): unexpected HTTP response received");
45
        }
46
    }else{
47
        dbglog("checkUpdateMessages(): messages up to date");
48
    }
49
50
    $data = io_readFile($cf);
51
    // show messages through the usual message mechanism
52
    $msgs = explode("\n%\n",$data);
53
    foreach($msgs as $msg){
54
        if($msg) msg($msg,2);
55
    }
56
}
57
58
59
/**
60
 * Return DokuWiki's version (split up in date and type)
61
 *
62
 * @author Andreas Gohr <[email protected]>
63
 */
64
function getVersionData(){
65
    $version = array();
66
    //import version string
67
    if(file_exists(DOKU_INC.'VERSION')){
68
        //official release
69
        $version['date'] = trim(io_readFile(DOKU_INC.'VERSION'));
70
        $version['type'] = 'Release';
71
    }elseif(is_dir(DOKU_INC.'.git')){
72
        $version['type'] = 'Git';
73
        $version['date'] = 'unknown';
74
75
        $inventory = DOKU_INC.'.git/logs/HEAD';
76
        if(is_file($inventory)){
77
            $sz   = filesize($inventory);
78
            $seek = max(0,$sz-2000); // read from back of the file
79
            $fh   = fopen($inventory,'rb');
80
            fseek($fh,$seek);
81
            $chunk = fread($fh,2000);
82
            fclose($fh);
83
            $chunk = trim($chunk);
84
            $chunk = @array_pop(explode("\n",$chunk));   //last log line
85
            $chunk = @array_shift(explode("\t",$chunk)); //strip commit msg
86
            $chunk = explode(" ",$chunk);
87
            array_pop($chunk); //strip timezone
88
            $date = date('Y-m-d',array_pop($chunk));
89
            if($date) $version['date'] = $date;
90
        }
91
    }else{
92
        global $updateVersion;
93
        $version['date'] = 'update version '.$updateVersion;
94
        $version['type'] = 'snapshot?';
95
    }
96
    return $version;
97
}
98
99
/**
100
 * Return DokuWiki's version (as a string)
101
 *
102
 * @author Anika Henke <[email protected]>
103
 */
104
function getVersion(){
105
    $version = getVersionData();
106
    return $version['type'].' '.$version['date'];
107
}
108
109
/**
110
 * Run a few sanity checks
111
 *
112
 * @author Andreas Gohr <[email protected]>
113
 */
114
function check(){
115
    global $conf;
116
    global $INFO;
117
    /* @var Input $INPUT */
118
    global $INPUT;
119
120
    if ($INFO['isadmin'] || $INFO['ismanager']){
121
        msg('DokuWiki version: '.getVersion(),1);
122
123
        if(version_compare(phpversion(),'5.6.0','<')){
124
            msg('Your PHP version is too old ('.phpversion().' vs. 5.6.0+ needed)',-1);
125
        }else{
126
            msg('PHP version '.phpversion(),1);
127
        }
128
    } else {
129
        if(version_compare(phpversion(),'5.6.0','<')){
130
            msg('Your PHP version is too old',-1);
131
        }
132
    }
133
134
    $mem = (int) php_to_byte(ini_get('memory_limit'));
135
    if($mem){
136
        if($mem < 16777216){
137
            msg('PHP is limited to less than 16MB RAM ('.$mem.' bytes). Increase memory_limit in php.ini',-1);
138
        }elseif($mem < 20971520){
139
            msg('PHP is limited to less than 20MB RAM ('.$mem.' bytes), 
140
                 you might encounter problems with bigger pages. Increase memory_limit in php.ini',-1);
141
        }elseif($mem < 33554432){
142
            msg('PHP is limited to less than 32MB RAM ('.$mem.' bytes), 
143
                 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')) {
0 ignored issues
show
Deprecated Code introduced by
The function plugin_isdisabled() has been deprecated with message: 2018-07-20

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
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,
212
             you should fix this if you encounter problems.',0);
213
    }else{
214
        msg('Valid locale '.hsc($loc).' found.', 1);
215
    }
216
217
    if($conf['allowdebug']){
218
        msg('Debugging support is enabled. If you don\'t need it you should set $conf[\'allowdebug\'] = 0',-1);
219
    }else{
220
        msg('Debugging support is disabled',1);
221
    }
222
223
    if($INFO['userinfo']['name']){
224
        msg('You are currently logged in as '.$INPUT->server->str('REMOTE_USER').' ('.$INFO['userinfo']['name'].')',0);
225
        msg('You are part of the groups '.join($INFO['userinfo']['grps'],', '),0);
226
    }else{
227
        msg('You are currently not logged in',0);
228
    }
229
230
    msg('Your current permission for this page is '.$INFO['perm'],0);
231
232
    if(is_writable($INFO['filepath'])){
233
        msg('The current page is writable by the webserver',0);
234
    }else{
235
        msg('The current page is not writable by the webserver',0);
236
    }
237
238
    if($INFO['writable']){
239
        msg('The current page is writable by you',0);
240
    }else{
241
        msg('The current page is not writable by you',0);
242
    }
243
244
    // Check for corrupted search index
245
    $lengths = idx_listIndexLengths();
246
    $index_corrupted = false;
247
    foreach ($lengths as $length) {
248
        if (count(idx_getIndex('w', $length)) != count(idx_getIndex('i', $length))) {
249
            $index_corrupted = true;
250
            break;
251
        }
252
    }
253
254
    foreach (idx_getIndex('metadata', '') as $index) {
255
        if (count(idx_getIndex($index.'_w', '')) != count(idx_getIndex($index.'_i', ''))) {
256
            $index_corrupted = true;
257
            break;
258
        }
259
    }
260
261
    if($index_corrupted) {
262
        msg(
263
            'The search index is corrupted. It might produce wrong results and most
264
                probably needs to be rebuilt. See
265
                <a href="http://www.dokuwiki.org/faq:searchindex">faq:searchindex</a>
266
                for ways to rebuild the search index.', -1
267
        );
268
    } elseif(!empty($lengths)) {
269
        msg('The search index seems to be working', 1);
270
    } else {
271
        msg(
272
            'The search index is empty. See
273
                <a href="http://www.dokuwiki.org/faq:searchindex">faq:searchindex</a>
274
                for help on how to fix the search index. If the default indexer
275
                isn\'t used or the wiki is actually empty this is normal.'
276
        );
277
    }
278
279
    // rough time check
280
    $http = new DokuHTTPClient();
281
    $http->max_redirect = 0;
282
    $http->timeout = 3;
283
    $http->sendRequest('http://www.dokuwiki.org', '', 'HEAD');
284
    $now = time();
285
    if(isset($http->resp_headers['date'])) {
286
        $time = strtotime($http->resp_headers['date']);
287
        $diff = $time - $now;
288
289
        if(abs($diff) < 4) {
290
            msg("Server time seems to be okay. Diff: {$diff}s", 1);
291
        } else {
292
            msg("Your server's clock seems to be out of sync!
293
                 Consider configuring a sync with a NTP server.  Diff: {$diff}s");
294
        }
295
    }
296
297
}
298
299
/**
300
 * print a message
301
 *
302
 * If HTTP headers were not sent yet the message is added
303
 * to the global message array else it's printed directly
304
 * using html_msgarea()
305
 *
306
 *
307
 * Levels can be:
308
 *
309
 * -1 error
310
 *  0 info
311
 *  1 success
312
 *
313
 * @author Andreas Gohr <[email protected]>
314
 * @see    html_msgarea
315
 */
316
317
define('MSG_PUBLIC', 0);
318
define('MSG_USERS_ONLY', 1);
319
define('MSG_MANAGERS_ONLY',2);
320
define('MSG_ADMINS_ONLY',4);
321
322
/**
323
 * Display a message to the user
324
 *
325
 * @param string $message
326
 * @param int    $lvl   -1 = error, 0 = info, 1 = success, 2 = notify
327
 * @param string $line  line number
328
 * @param string $file  file number
329
 * @param int    $allow who's allowed to see the message, see MSG_* constants
330
 */
331
function msg($message,$lvl=0,$line='',$file='',$allow=MSG_PUBLIC){
332
    global $MSG, $MSG_shown;
333
    $errors = array();
334
    $errors[-1] = 'error';
335
    $errors[0]  = 'info';
336
    $errors[1]  = 'success';
337
    $errors[2]  = 'notify';
338
339
    if($line || $file) $message.=' ['.utf8_basename($file).':'.$line.']';
340
341
    if(!isset($MSG)) $MSG = array();
342
    $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message, 'allow' => $allow);
343
    if(isset($MSG_shown) || headers_sent()){
344
        if(function_exists('html_msgarea')){
345
            html_msgarea();
346
        }else{
347
            print "ERROR($lvl) $message";
348
        }
349
        unset($GLOBALS['MSG']);
350
    }
351
}
352
/**
353
 * Determine whether the current user is allowed to view the message
354
 * in the $msg data structure
355
 *
356
 * @param  $msg   array    dokuwiki msg structure
357
 *                         msg   => string, the message
358
 *                         lvl   => int, level of the message (see msg() function)
359
 *                         allow => int, flag used to determine who is allowed to see the message
360
 *                                       see MSG_* constants
361
 * @return bool
362
 */
363
function info_msg_allowed($msg){
364
    global $INFO, $auth;
365
366
    // is the message public? - everyone and anyone can see it
367
    if (empty($msg['allow']) || ($msg['allow'] == MSG_PUBLIC)) return true;
368
369
    // restricted msg, but no authentication
370
    if (empty($auth)) return false;
371
372
    switch ($msg['allow']){
373
        case MSG_USERS_ONLY:
374
            return !empty($INFO['userinfo']);
375
376
        case MSG_MANAGERS_ONLY:
377
            return $INFO['ismanager'];
378
379
        case MSG_ADMINS_ONLY:
380
            return $INFO['isadmin'];
381
382
        default:
383
            trigger_error('invalid msg allow restriction.  msg="'.$msg['msg'].'" allow='.$msg['allow'].'"',
384
                          E_USER_WARNING);
385
            return $INFO['isadmin'];
386
    }
387
388
    return false;
389
}
390
391
/**
392
 * print debug messages
393
 *
394
 * little function to print the content of a var
395
 *
396
 * @author Andreas Gohr <[email protected]>
397
 *
398
 * @param string $msg
399
 * @param bool $hidden
400
 */
401
function dbg($msg,$hidden=false){
402
    if($hidden){
403
        echo "<!--\n";
404
        print_r($msg);
405
        echo "\n-->";
406
    }else{
407
        echo '<pre class="dbg">';
408
        echo hsc(print_r($msg,true));
409
        echo '</pre>';
410
    }
411
}
412
413
/**
414
 * Print info to a log file
415
 *
416
 * @author Andreas Gohr <[email protected]>
417
 *
418
 * @param string $msg
419
 * @param string $header
420
 */
421
function dbglog($msg,$header=''){
422
    global $conf;
423
    /* @var Input $INPUT */
424
    global $INPUT;
425
426
    // The debug log isn't automatically cleaned thus only write it when
427
    // debugging has been enabled by the user.
428
    if($conf['allowdebug'] !== 1) return;
429
    if(is_object($msg) || is_array($msg)){
430
        $msg = print_r($msg,true);
431
    }
432
433
    if($header) $msg = "$header\n$msg";
434
435
    $file = $conf['cachedir'].'/debug.log';
436
    $fh = fopen($file,'a');
437
    if($fh){
438
        fwrite($fh,date('H:i:s ').$INPUT->server->str('REMOTE_ADDR').': '.$msg."\n");
439
        fclose($fh);
440
    }
441
}
442
443
/**
444
 * Log accesses to deprecated fucntions to the debug log
445
 *
446
 * @param string $alternative The function or method that should be used instead
447
 * @triggers INFO_DEPRECATION_LOG
448
 */
449
function dbg_deprecated($alternative = '') {
450
    global $conf;
451
    global $EVENT_HANDLER;
452
    if(
453
        !$conf['allowdebug'] &&
454
        ($EVENT_HANDLER === null || !$EVENT_HANDLER->hasHandlerForEvent('INFO_DEPRECATION_LOG'))
455
    ) {
456
        // avoid any work if no one cares
457
        return;
458
    }
459
460
    $backtrace = debug_backtrace();
461
    array_shift($backtrace);
462
    $self = $backtrace[0];
463
    $call = $backtrace[1];
464
465
    $data = [
466
        'trace' => $backtrace,
467
        'alternative' => $alternative,
468
        'called' => trim($self['class'] . '::' . $self['function'] . '()', ':'),
469
        'caller' => trim($call['class'] . '::' . $call['function'] . '()', ':'),
470
        'file' => $call['file'],
471
        'line' => $call['line'],
472
    ];
473
474
    $event = new Event('INFO_DEPRECATION_LOG', $data);
475
    if($event->advise_before()) {
476
        $msg = $event->data['called'] . ' is deprecated. It was called from ';
477
        $msg .= $event->data['caller'] . ' in ' . $event->data['file'] . ':' . $event->data['line'];
478
        if($event->data['alternative']) {
479
            $msg .= ' ' . $event->data['alternative'] . ' should be used instead!';
480
        }
481
        dbglog($msg);
482
    }
483
    $event->advise_after();
484
}
485
486
/**
487
 * Print a reversed, prettyprinted backtrace
488
 *
489
 * @author Gary Owen <[email protected]>
490
 */
491
function dbg_backtrace(){
492
    // Get backtrace
493
    $backtrace = debug_backtrace();
494
495
    // Unset call to debug_print_backtrace
496
    array_shift($backtrace);
497
498
    // Iterate backtrace
499
    $calls = array();
500
    $depth = count($backtrace) - 1;
501
    foreach ($backtrace as $i => $call) {
502
        $location = $call['file'] . ':' . $call['line'];
503
        $function = (isset($call['class'])) ?
504
            $call['class'] . $call['type'] . $call['function'] : $call['function'];
505
506
        $params = array();
507
        if (isset($call['args'])){
508
            foreach($call['args'] as $arg){
509
                if(is_object($arg)){
510
                    $params[] = '[Object '.get_class($arg).']';
511
                }elseif(is_array($arg)){
512
                    $params[] = '[Array]';
513
                }elseif(is_null($arg)){
514
                    $params[] = '[NULL]';
515
                }else{
516
                    $params[] = (string) '"'.$arg.'"';
517
                }
518
            }
519
        }
520
        $params = implode(', ',$params);
521
522
        $calls[$depth - $i] = sprintf('%s(%s) called at %s',
523
                $function,
524
                str_replace("\n", '\n', $params),
525
                $location);
526
    }
527
    ksort($calls);
528
529
    return implode("\n", $calls);
530
}
531
532
/**
533
 * Remove all data from an array where the key seems to point to sensitive data
534
 *
535
 * This is used to remove passwords, mail addresses and similar data from the
536
 * debug output
537
 *
538
 * @author Andreas Gohr <[email protected]>
539
 *
540
 * @param array $data
541
 */
542
function debug_guard(&$data){
543
    foreach($data as $key => $value){
544
        if(preg_match('/(notify|pass|auth|secret|ftp|userinfo|token|buid|mail|proxy)/i',$key)){
545
            $data[$key] = '***';
546
            continue;
547
        }
548
        if(is_array($value)) debug_guard($data[$key]);
549
    }
550
}
551