Completed
Push — master ( 206d3a...96da53 )
by Andreas
06:49 queued 04:18
created

infoutils.php ➔ getVersionData()   B

Complexity

Conditions 10
Paths 10

Size

Total Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
nc 10
nop 0
dl 0
loc 42
rs 7.6666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, DokuHTTPClient.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

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