Failed Conditions
Push — logging ( 0ecde6 )
by Andreas
02:50
created

inc/infoutils.php (3 issues)

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
9
use dokuwiki\HTTP\DokuHTTPClient;
10
11
if(!defined('DOKU_MESSAGEURL')){
12
    if(in_array('ssl', stream_get_transports())) {
13
        define('DOKU_MESSAGEURL','https://update.dokuwiki.org/check/');
14
    }else{
15
        define('DOKU_MESSAGEURL','http://update.dokuwiki.org/check/');
16
    }
17
}
18
19
/**
20
 * Check for new messages from upstream
21
 *
22
 * @author Andreas Gohr <[email protected]>
23
 */
24
function checkUpdateMessages(){
25
    global $conf;
26
    global $INFO;
27
    global $updateVersion;
28
    if(!$conf['updatecheck']) return;
29
    if($conf['useacl'] && !$INFO['ismanager']) return;
30
31
    $cf = getCacheName($updateVersion, '.updmsg');
32
    $lm = @filemtime($cf);
33
    $is_http = substr(DOKU_MESSAGEURL, 0, 5) != 'https';
34
35
    // check if new messages needs to be fetched
36
    if($lm < time()-(60*60*24) || $lm < @filemtime(DOKU_INC.DOKU_SCRIPT)){
37
        @touch($cf);
38
        dbglog("checkUpdateMessages(): downloading messages to ".$cf.($is_http?' (without SSL)':' (with SSL)'));
0 ignored issues
show
Deprecated Code introduced by
The function dbglog() has been deprecated with message: 2020-08-13

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...
39
        $http = new DokuHTTPClient();
40
        $http->timeout = 12;
41
        $resp = $http->get(DOKU_MESSAGEURL.$updateVersion);
42
        if(is_string($resp) && ($resp == "" || substr(trim($resp), -1) == '%')) {
43
            // basic sanity check that this is either an empty string response (ie "no messages")
44
            // or it looks like one of our messages, not WiFi login or other interposed response
45
            io_saveFile($cf,$resp);
46
        } else {
47
            dbglog("checkUpdateMessages(): unexpected HTTP response received");
0 ignored issues
show
Deprecated Code introduced by
The function dbglog() has been deprecated with message: 2020-08-13

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...
48
        }
49
    }else{
50
        dbglog("checkUpdateMessages(): messages up to date");
0 ignored issues
show
Deprecated Code introduced by
The function dbglog() has been deprecated with message: 2020-08-13

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...
51
    }
52
53
    $data = io_readFile($cf);
54
    // show messages through the usual message mechanism
55
    $msgs = explode("\n%\n",$data);
56
    foreach($msgs as $msg){
57
        if($msg) msg($msg,2);
58
    }
59
}
60
61
62
/**
63
 * Return DokuWiki's version (split up in date and type)
64
 *
65
 * @author Andreas Gohr <[email protected]>
66
 */
67
function getVersionData(){
68
    $version = array();
69
    //import version string
70
    if(file_exists(DOKU_INC.'VERSION')){
71
        //official release
72
        $version['date'] = trim(io_readFile(DOKU_INC.'VERSION'));
73
        $version['type'] = 'Release';
74
    }elseif(is_dir(DOKU_INC.'.git')){
75
        $version['type'] = 'Git';
76
        $version['date'] = 'unknown';
77
78
        $inventory = DOKU_INC.'.git/logs/HEAD';
79
        if(is_file($inventory)){
80
            $sz   = filesize($inventory);
81
            $seek = max(0,$sz-2000); // read from back of the file
82
            $fh   = fopen($inventory,'rb');
83
            fseek($fh,$seek);
84
            $chunk = fread($fh,2000);
85
            fclose($fh);
86
            $chunk = trim($chunk);
87
            $chunk = @array_pop(explode("\n",$chunk));   //last log line
88
            $chunk = @array_shift(explode("\t",$chunk)); //strip commit msg
89
            $chunk = explode(" ",$chunk);
90
            array_pop($chunk); //strip timezone
91
            $date = date('Y-m-d',array_pop($chunk));
92
            if($date) $version['date'] = $date;
93
        }
94
    }else{
95
        global $updateVersion;
96
        $version['date'] = 'update version '.$updateVersion;
97
        $version['type'] = 'snapshot?';
98
    }
99
    return $version;
100
}
101
102
/**
103
 * Return DokuWiki's version (as a string)
104
 *
105
 * @author Anika Henke <[email protected]>
106
 */
107
function getVersion(){
108
    $version = getVersionData();
109
    return $version['type'].' '.$version['date'];
110
}
111
112
/**
113
 * Run a few sanity checks
114
 *
115
 * @author Andreas Gohr <[email protected]>
116
 */
117
function check(){
118
    global $conf;
119
    global $INFO;
120
    /* @var Input $INPUT */
121
    global $INPUT;
122
123
    if ($INFO['isadmin'] || $INFO['ismanager']){
124
        msg('DokuWiki version: '.getVersion(),1);
125
126
        if(version_compare(phpversion(),'7.2.0','<')){
127
            msg('Your PHP version is too old ('.phpversion().' vs. 7.2+ needed)',-1);
128
        }else{
129
            msg('PHP version '.phpversion(),1);
130
        }
131
    } else {
132
        if(version_compare(phpversion(),'7.2.0','<')){
133
            msg('Your PHP version is too old',-1);
134
        }
135
    }
136
137
    $mem = (int) php_to_byte(ini_get('memory_limit'));
138
    if($mem){
139
        if ($mem === -1) {
140
            msg('PHP memory is unlimited', 1);
141
        } else if ($mem < 16777216) {
142
            msg('PHP is limited to less than 16MB RAM (' . filesize_h($mem) . ').
143
            Increase memory_limit in php.ini', -1);
144
        } else if ($mem < 20971520) {
145
            msg('PHP is limited to less than 20MB RAM (' . filesize_h($mem) . '),
146
                you might encounter problems with bigger pages. Increase memory_limit in php.ini', -1);
147
        } else if ($mem < 33554432) {
148
            msg('PHP is limited to less than 32MB RAM (' . filesize_h($mem) . '),
149
                but that should be enough in most cases. If not, increase memory_limit in php.ini', 0);
150
        } else {
151
            msg('More than 32MB RAM (' . filesize_h($mem) . ') available.', 1);
152
        }
153
    }
154
155
    if(is_writable($conf['changelog'])){
156
        msg('Changelog is writable',1);
157
    }else{
158
        if (file_exists($conf['changelog'])) {
159
            msg('Changelog is not writable',-1);
160
        }
161
    }
162
163
    if (isset($conf['changelog_old']) && file_exists($conf['changelog_old'])) {
164
        msg('Old changelog exists', 0);
165
    }
166
167
    if (file_exists($conf['changelog'].'_failed')) {
168
        msg('Importing old changelog failed', -1);
169
    } else if (file_exists($conf['changelog'].'_importing')) {
170
        msg('Importing old changelog now.', 0);
171
    } else if (file_exists($conf['changelog'].'_import_ok')) {
172
        msg('Old changelog imported', 1);
173
        if (!plugin_isdisabled('importoldchangelog')) {
174
            msg('Importoldchangelog plugin not disabled after import', -1);
175
        }
176
    }
177
178
    if(is_writable(DOKU_CONF)){
179
        msg('conf directory is writable',1);
180
    }else{
181
        msg('conf directory is not writable',-1);
182
    }
183
184
    if($conf['authtype'] == 'plain'){
185
        global $config_cascade;
186
        if(is_writable($config_cascade['plainauth.users']['default'])){
187
            msg('conf/users.auth.php is writable',1);
188
        }else{
189
            msg('conf/users.auth.php is not writable',0);
190
        }
191
    }
192
193
    if(function_exists('mb_strpos')){
194
        if(defined('UTF8_NOMBSTRING')){
195
            msg('mb_string extension is available but will not be used',0);
196
        }else{
197
            msg('mb_string extension is available and will be used',1);
198
            if(ini_get('mbstring.func_overload') != 0){
199
                msg('mb_string function overloading is enabled, this will cause problems and should be disabled',-1);
200
            }
201
        }
202
    }else{
203
        msg('mb_string extension not available - PHP only replacements will be used',0);
204
    }
205
206
    if (!UTF8_PREGSUPPORT) {
207
        msg('PHP is missing UTF-8 support in Perl-Compatible Regular Expressions (PCRE)', -1);
208
    }
209
    if (!UTF8_PROPERTYSUPPORT) {
210
        msg('PHP is missing Unicode properties support in Perl-Compatible Regular Expressions (PCRE)', -1);
211
    }
212
213
    $loc = setlocale(LC_ALL, 0);
214
    if(!$loc){
215
        msg('No valid locale is set for your PHP setup. You should fix this',-1);
216
    }elseif(stripos($loc,'utf') === false){
217
        msg('Your locale <code>'.hsc($loc).'</code> seems not to be a UTF-8 locale,
218
             you should fix this if you encounter problems.',0);
219
    }else{
220
        msg('Valid locale '.hsc($loc).' found.', 1);
221
    }
222
223
    if($conf['allowdebug']){
224
        msg('Debugging support is enabled. If you don\'t need it you should set $conf[\'allowdebug\'] = 0',-1);
225
    }else{
226
        msg('Debugging support is disabled',1);
227
    }
228
229
    if($INFO['userinfo']['name']){
230
        msg('You are currently logged in as '.$INPUT->server->str('REMOTE_USER').' ('.$INFO['userinfo']['name'].')',0);
231
        msg('You are part of the groups '.join($INFO['userinfo']['grps'],', '),0);
232
    }else{
233
        msg('You are currently not logged in',0);
234
    }
235
236
    msg('Your current permission for this page is '.$INFO['perm'],0);
237
238
    if (file_exists($INFO['filepath']) && is_writable($INFO['filepath'])) {
239
        msg('The current page is writable by the webserver', 1);
240
    } elseif (!file_exists($INFO['filepath']) && is_writable(dirname($INFO['filepath']))) {
241
        msg('The current page can be created by the webserver', 1);
242
    } else {
243
        msg('The current page is not writable by the webserver', -1);
244
    }
245
246
    if ($INFO['writable']) {
247
        msg('The current page is writable by you', 1);
248
    } else {
249
        msg('The current page is not writable by you', -1);
250
    }
251
252
    // Check for corrupted search index
253
    $lengths = idx_listIndexLengths();
254
    $index_corrupted = false;
255
    foreach ($lengths as $length) {
256
        if (count(idx_getIndex('w', $length)) != count(idx_getIndex('i', $length))) {
257
            $index_corrupted = true;
258
            break;
259
        }
260
    }
261
262
    foreach (idx_getIndex('metadata', '') as $index) {
263
        if (count(idx_getIndex($index.'_w', '')) != count(idx_getIndex($index.'_i', ''))) {
264
            $index_corrupted = true;
265
            break;
266
        }
267
    }
268
269
    if($index_corrupted) {
270
        msg(
271
            'The search index is corrupted. It might produce wrong results and most
272
                probably needs to be rebuilt. See
273
                <a href="http://www.dokuwiki.org/faq:searchindex">faq:searchindex</a>
274
                for ways to rebuild the search index.', -1
275
        );
276
    } elseif(!empty($lengths)) {
277
        msg('The search index seems to be working', 1);
278
    } else {
279
        msg(
280
            'The search index is empty. See
281
                <a href="http://www.dokuwiki.org/faq:searchindex">faq:searchindex</a>
282
                for help on how to fix the search index. If the default indexer
283
                isn\'t used or the wiki is actually empty this is normal.'
284
        );
285
    }
286
287
    // rough time check
288
    $http = new DokuHTTPClient();
289
    $http->max_redirect = 0;
290
    $http->timeout = 3;
291
    $http->sendRequest('http://www.dokuwiki.org', '', 'HEAD');
292
    $now = time();
293
    if(isset($http->resp_headers['date'])) {
294
        $time = strtotime($http->resp_headers['date']);
295
        $diff = $time - $now;
296
297
        if(abs($diff) < 4) {
298
            msg("Server time seems to be okay. Diff: {$diff}s", 1);
299
        } else {
300
            msg("Your server's clock seems to be out of sync!
301
                 Consider configuring a sync with a NTP server.  Diff: {$diff}s");
302
        }
303
    }
304
305
}
306
307
/**
308
 * Display a message to the user
309
 *
310
 * If HTTP headers were not sent yet the message is added
311
 * to the global message array else it's printed directly
312
 * using html_msgarea()
313
 *
314
 * Triggers INFOUTIL_MSG_SHOW
315
 *
316
 * @see    html_msgarea()
317
 * @param string $message
318
 * @param int    $lvl   -1 = error, 0 = info, 1 = success, 2 = notify
319
 * @param string $line  line number
320
 * @param string $file  file number
321
 * @param int    $allow who's allowed to see the message, see MSG_* constants
322
 */
323
function msg($message,$lvl=0,$line='',$file='',$allow=MSG_PUBLIC){
324
    global $MSG, $MSG_shown;
325
    static $errors = [
326
        -1 => 'error',
327
        0 => 'info',
328
        1 => 'success',
329
        2 => 'notify',
330
    ];
331
332
    $msgdata = [
333
        'msg' => $message,
334
        'lvl' => $errors[$lvl],
335
        'allow' => $allow,
336
        'line' => $line,
337
        'file' => $file,
338
    ];
339
340
    $evt = new \dokuwiki\Extension\Event('INFOUTIL_MSG_SHOW', $msgdata);
341
    if ($evt->advise_before()) {
342
        /* Show msg normally - event could suppress message show */
343
        if($msgdata['line'] || $msgdata['file']) {
344
            $basename = \dokuwiki\Utf8\PhpString::basename($msgdata['file']);
345
            $msgdata['msg'] .=' ['.$basename.':'.$msgdata['line'].']';
346
        }
347
348
        if(!isset($MSG)) $MSG = array();
349
        $MSG[] = $msgdata;
350
        if(isset($MSG_shown) || headers_sent()){
351
            if(function_exists('html_msgarea')){
352
                html_msgarea();
353
            }else{
354
                print "ERROR(".$msgdata['lvl'].") ".$msgdata['msg']."\n";
355
            }
356
            unset($GLOBALS['MSG']);
357
        }
358
    }
359
    $evt->advise_after();
360
    unset($evt);
361
}
362
/**
363
 * Determine whether the current user is allowed to view the message
364
 * in the $msg data structure
365
 *
366
 * @param  $msg   array    dokuwiki msg structure
367
 *                         msg   => string, the message
368
 *                         lvl   => int, level of the message (see msg() function)
369
 *                         allow => int, flag used to determine who is allowed to see the message
370
 *                                       see MSG_* constants
371
 * @return bool
372
 */
373
function info_msg_allowed($msg){
374
    global $INFO, $auth;
375
376
    // is the message public? - everyone and anyone can see it
377
    if (empty($msg['allow']) || ($msg['allow'] == MSG_PUBLIC)) return true;
378
379
    // restricted msg, but no authentication
380
    if (empty($auth)) return false;
381
382
    switch ($msg['allow']){
383
        case MSG_USERS_ONLY:
384
            return !empty($INFO['userinfo']);
385
386
        case MSG_MANAGERS_ONLY:
387
            return $INFO['ismanager'];
388
389
        case MSG_ADMINS_ONLY:
390
            return $INFO['isadmin'];
391
392
        default:
393
            trigger_error('invalid msg allow restriction.  msg="'.$msg['msg'].'" allow='.$msg['allow'].'"',
394
                          E_USER_WARNING);
395
            return $INFO['isadmin'];
396
    }
397
398
    return false;
399
}
400
401
/**
402
 * print debug messages
403
 *
404
 * little function to print the content of a var
405
 *
406
 * @author Andreas Gohr <[email protected]>
407
 *
408
 * @param string $msg
409
 * @param bool $hidden
410
 */
411
function dbg($msg,$hidden=false){
412
    if($hidden){
413
        echo "<!--\n";
414
        print_r($msg);
415
        echo "\n-->";
416
    }else{
417
        echo '<pre class="dbg">';
418
        echo hsc(print_r($msg,true));
419
        echo '</pre>';
420
    }
421
}
422
423
/**
424
 * Print info to a log file
425
 *
426
 * @author Andreas Gohr <[email protected]>
427
 * @deprecated 2020-08-13
428
 * @param string $msg
429
 * @param string $header
430
 */
431
function dbglog($msg,$header=''){
432
    global $conf;
433
    dbg_deprecated('\\dokuwiki\\Logger');
434
435
    // The debug log isn't automatically cleaned thus only write it when
436
    // debugging has been enabled by the user.
437
    if($conf['allowdebug'] !== 1) return;
438
    if(is_object($msg) || is_array($msg)){
439
        $msg = print_r($msg,true);
440
    }
441
442
    // was the msg as single line string? use it as header
443
    if($header === '' && strpos($msg, "\n") === false) {
444
        $header = $msg;
445
        $msg = '';
446
    }
447
448
    \dokuwiki\Logger::getInstance(\dokuwiki\Logger::LOG_DEBUG)->log(
449
        $header, $msg
450
    );
451
}
452
453
/**
454
 * Log accesses to deprecated fucntions to the debug log
455
 *
456
 * @param string $alternative The function or method that should be used instead
457
 * @triggers INFO_DEPRECATION_LOG
458
 */
459
function dbg_deprecated($alternative = '') {
460
    \dokuwiki\Debug\DebugHelper::dbgDeprecatedFunction($alternative, 2);
461
}
462
463
/**
464
 * Print a reversed, prettyprinted backtrace
465
 *
466
 * @author Gary Owen <[email protected]>
467
 */
468
function dbg_backtrace(){
469
    // Get backtrace
470
    $backtrace = debug_backtrace();
471
472
    // Unset call to debug_print_backtrace
473
    array_shift($backtrace);
474
475
    // Iterate backtrace
476
    $calls = array();
477
    $depth = count($backtrace) - 1;
478
    foreach ($backtrace as $i => $call) {
479
        $location = $call['file'] . ':' . $call['line'];
480
        $function = (isset($call['class'])) ?
481
            $call['class'] . $call['type'] . $call['function'] : $call['function'];
482
483
        $params = array();
484
        if (isset($call['args'])){
485
            foreach($call['args'] as $arg){
486
                if(is_object($arg)){
487
                    $params[] = '[Object '.get_class($arg).']';
488
                }elseif(is_array($arg)){
489
                    $params[] = '[Array]';
490
                }elseif(is_null($arg)){
491
                    $params[] = '[NULL]';
492
                }else{
493
                    $params[] = (string) '"'.$arg.'"';
494
                }
495
            }
496
        }
497
        $params = implode(', ',$params);
498
499
        $calls[$depth - $i] = sprintf('%s(%s) called at %s',
500
                $function,
501
                str_replace("\n", '\n', $params),
502
                $location);
503
    }
504
    ksort($calls);
505
506
    return implode("\n", $calls);
507
}
508
509
/**
510
 * Remove all data from an array where the key seems to point to sensitive data
511
 *
512
 * This is used to remove passwords, mail addresses and similar data from the
513
 * debug output
514
 *
515
 * @author Andreas Gohr <[email protected]>
516
 *
517
 * @param array $data
518
 */
519
function debug_guard(&$data){
520
    foreach($data as $key => $value){
521
        if(preg_match('/(notify|pass|auth|secret|ftp|userinfo|token|buid|mail|proxy)/i',$key)){
522
            $data[$key] = '***';
523
            continue;
524
        }
525
        if(is_array($value)) debug_guard($data[$key]);
526
    }
527
}
528