Completed
Push — manifest ( 10b4c8...c90718 )
by Michael
03:59
created

confutils.php ➔ jsonToArray()   C

Complexity

Conditions 13
Paths 12

Size

Total Lines 50
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 41
nc 12
nop 1
dl 0
loc 50
rs 5.3808
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
 * Utilities for collecting data from config files
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Harry Fuecks <[email protected]>
7
 */
8
9
/*
10
 * line prefix used to negate single value config items
11
 * (scheme.conf & stopwords.conf), e.g.
12
 * !gopher
13
 */
14
const DOKU_CONF_NEGATION = '!';
15
16
/**
17
 * Returns the (known) extension and mimetype of a given filename
18
 *
19
 * If $knownonly is true (the default), then only known extensions
20
 * are returned.
21
 *
22
 * @author Andreas Gohr <[email protected]>
23
 *
24
 * @param string $file file name
25
 * @param bool   $knownonly
26
 * @return array with extension, mimetype and if it should be downloaded
27
 */
28
function mimetype($file, $knownonly=true){
29
    $mtypes = getMimeTypes();     // known mimetypes
30
    $ext    = strrpos($file, '.');
31
    if ($ext === false) {
32
        return array(false, false, false);
33
    }
34
    $ext = strtolower(substr($file, $ext + 1));
35
    if (!isset($mtypes[$ext])){
36
        if ($knownonly) {
37
            return array(false, false, false);
38
        } else {
39
            return array($ext, 'application/octet-stream', true);
40
        }
41
    }
42
    if($mtypes[$ext][0] == '!'){
43
        return array($ext, substr($mtypes[$ext],1), true);
44
    }else{
45
        return array($ext, $mtypes[$ext], false);
46
    }
47
}
48
49
/**
50
 * returns a hash of mimetypes
51
 *
52
 * @author Andreas Gohr <[email protected]>
53
 */
54
function getMimeTypes() {
55
    static $mime = null;
56
    if ( !$mime ) {
57
        $mime = retrieveConfig('mime','confToHash');
58
        $mime = array_filter($mime);
59
    }
60
    return $mime;
61
}
62
63
/**
64
 * returns a hash of acronyms
65
 *
66
 * @author Harry Fuecks <[email protected]>
67
 */
68
function getAcronyms() {
69
    static $acronyms = null;
70
    if ( !$acronyms ) {
71
        $acronyms = retrieveConfig('acronyms','confToHash');
72
        $acronyms = array_filter($acronyms, 'strlen');
73
    }
74
    return $acronyms;
75
}
76
77
/**
78
 * returns a hash of smileys
79
 *
80
 * @author Harry Fuecks <[email protected]>
81
 */
82
function getSmileys() {
83
    static $smileys = null;
84
    if ( !$smileys ) {
85
        $smileys = retrieveConfig('smileys','confToHash');
86
        $smileys = array_filter($smileys, 'strlen');
87
    }
88
    return $smileys;
89
}
90
91
/**
92
 * returns a hash of entities
93
 *
94
 * @author Harry Fuecks <[email protected]>
95
 */
96
function getEntities() {
97
    static $entities = null;
98
    if ( !$entities ) {
99
        $entities = retrieveConfig('entities','confToHash');
100
        $entities = array_filter($entities, 'strlen');
101
    }
102
    return $entities;
103
}
104
105
/**
106
 * returns a hash of interwikilinks
107
 *
108
 * @author Harry Fuecks <[email protected]>
109
 */
110
function getInterwiki() {
111
    static $wikis = null;
112
    if ( !$wikis ) {
113
        $wikis = retrieveConfig('interwiki','confToHash',array(true));
114
        $wikis = array_filter($wikis, 'strlen');
115
116
        //add sepecial case 'this'
117
        $wikis['this'] = DOKU_URL.'{NAME}';
118
    }
119
    return $wikis;
120
}
121
122
/**
123
 * Returns the jquery script URLs for the versions defined in lib/scripts/jquery/versions
124
 *
125
 * @trigger CONFUTIL_CDN_SELECT
126
 * @return array
127
 */
128
function getCdnUrls() {
129
    global $conf;
130
131
    // load version info
132
    $versions = array();
133
    $lines = file(DOKU_INC . 'lib/scripts/jquery/versions');
134
    foreach($lines as $line) {
135
        $line = trim(preg_replace('/#.*$/', '', $line));
136
        if($line === '') continue;
137
        list($key, $val) = explode('=', $line, 2);
138
        $key = trim($key);
139
        $val = trim($val);
140
        $versions[$key] = $val;
141
    }
142
143
    $src = array();
144
    $data = array(
145
        'versions' => $versions,
146
        'src' => &$src
147
    );
148
    $event = new Doku_Event('CONFUTIL_CDN_SELECT', $data);
149
    if($event->advise_before()) {
150
        if(!$conf['jquerycdn']) {
151
            $jqmod = md5(join('-', $versions));
152
            $src[] = DOKU_BASE . 'lib/exe/jquery.php' . '?tseed=' . $jqmod;
153
        } elseif($conf['jquerycdn'] == 'jquery') {
154
            $src[] = sprintf('https://code.jquery.com/jquery-%s.min.js', $versions['JQ_VERSION']);
155
            $src[] = sprintf('https://code.jquery.com/jquery-migrate-%s.min.js', $versions['JQM_VERSION']);
156
            $src[] = sprintf('https://code.jquery.com/ui/%s/jquery-ui.min.js', $versions['JQUI_VERSION']);
157
        } elseif($conf['jquerycdn'] == 'cdnjs') {
158
            $src[] = sprintf('https://cdnjs.cloudflare.com/ajax/libs/jquery/%s/jquery.min.js', $versions['JQ_VERSION']);
159
            $src[] = sprintf('https://cdnjs.cloudflare.com/ajax/libs/jquery-migrate/%s/jquery-migrate.min.js', $versions['JQM_VERSION']);
160
            $src[] = sprintf('https://cdnjs.cloudflare.com/ajax/libs/jqueryui/%s/jquery-ui.min.js', $versions['JQUI_VERSION']);
161
        }
162
    }
163
    $event->advise_after();
164
165
    return $src;
166
}
167
168
/**
169
 * returns array of wordblock patterns
170
 *
171
 */
172
function getWordblocks() {
173
    static $wordblocks = null;
174
    if ( !$wordblocks ) {
175
        $wordblocks = retrieveConfig('wordblock','file',null,'array_merge_with_removal');
176
    }
177
    return $wordblocks;
178
}
179
180
/**
181
 * Gets the list of configured schemes
182
 *
183
 * @return array the schemes
184
 */
185
function getSchemes() {
186
    static $schemes = null;
187
    if ( !$schemes ) {
188
        $schemes = retrieveConfig('scheme','file',null,'array_merge_with_removal');
189
        $schemes = array_map('trim', $schemes);
190
        $schemes = preg_replace('/^#.*/', '', $schemes);
191
        $schemes = array_filter($schemes);
192
    }
193
    return $schemes;
194
}
195
196
/**
197
 * Builds a hash from an array of lines
198
 *
199
 * If $lower is set to true all hash keys are converted to
200
 * lower case.
201
 *
202
 * @author Harry Fuecks <[email protected]>
203
 * @author Andreas Gohr <[email protected]>
204
 * @author Gina Haeussge <[email protected]>
205
 *
206
 * @param array $lines
207
 * @param bool $lower
208
 *
209
 * @return array
210
 */
211
function linesToHash($lines, $lower = false) {
212
    $conf = array();
213
    // remove BOM
214
    if(isset($lines[0]) && substr($lines[0], 0, 3) == pack('CCC', 0xef, 0xbb, 0xbf))
215
        $lines[0] = substr($lines[0], 3);
216
    foreach($lines as $line) {
217
        //ignore comments (except escaped ones)
218
        $line = preg_replace('/(?<![&\\\\])#.*$/', '', $line);
219
        $line = str_replace('\\#', '#', $line);
220
        $line = trim($line);
221
        if($line === '') continue;
222
        $line = preg_split('/\s+/', $line, 2);
223
        $line = array_pad($line, 2, '');
224
        // Build the associative array
225
        if($lower) {
226
            $conf[strtolower($line[0])] = $line[1];
227
        } else {
228
            $conf[$line[0]] = $line[1];
229
        }
230
    }
231
232
    return $conf;
233
}
234
235
/**
236
 * Builds a hash from a configfile
237
 *
238
 * If $lower is set to true all hash keys are converted to
239
 * lower case.
240
 *
241
 * @author Harry Fuecks <[email protected]>
242
 * @author Andreas Gohr <[email protected]>
243
 * @author Gina Haeussge <[email protected]>
244
 *
245
 * @param string $file
246
 * @param bool $lower
247
 *
248
 * @return array
249
 */
250
function confToHash($file,$lower=false) {
251
    $conf = array();
252
    $lines = @file( $file );
253
    if ( !$lines ) return $conf;
254
255
    return linesToHash($lines, $lower);
256
}
257
258
/**
259
 * Read a json config file into an array
260
 *
261
 * @param string $file
262
 * @return array
263
 */
264
function jsonToArray($file)
265
{
266
    $json = file_get_contents($file);
267
268
    $conf = json_decode($json, true);
269
270
    $jsonError = json_last_error();
271
    if (!is_array($conf) && $jsonError !== JSON_ERROR_NONE) {
272
273
        switch ($jsonError) {
274
            case JSON_ERROR_DEPTH:
275
                $jsonErrorText = 'The maximum stack depth has been exceeded';
276
                break;
277
            case JSON_ERROR_STATE_MISMATCH:
278
                $jsonErrorText = 'Invalid or malformed JSON';
279
                break;
280
            case JSON_ERROR_CTRL_CHAR:
281
                $jsonErrorText = 'Control character error, possibly incorrectly encoded';
282
                break;
283
            case JSON_ERROR_SYNTAX:
284
                $jsonErrorText = 'Syntax error';
285
                break;
286
            case JSON_ERROR_UTF8:
287
                $jsonErrorText = 'Malformed UTF-8 characters, possibly incorrectly encoded';
288
                break;
289
            case JSON_ERROR_RECURSION:
290
                $jsonErrorText = 'One or more recursive references in the value to be encoded';
291
                break;
292
            case JSON_ERROR_INF_OR_NAN:
293
                $jsonErrorText = 'One or more NAN or INF values in the value to be encoded';
294
                break;
295
            case JSON_ERROR_UNSUPPORTED_TYPE:
296
                $jsonErrorText = 'A value of a type that cannot be encoded was given';
297
                break;
298
            case JSON_ERROR_INVALID_PROPERTY_NAME:
299
                $jsonErrorText = 'A property name that cannot be encoded was given';
300
                break;
301
            case JSON_ERROR_UTF16:
302
                $jsonErrorText = 'Malformed UTF-16 characters, possibly incorrectly encoded';
303
                break;
304
            default:
305
                $jsonErrorText = 'Unknown Error Code';
306
        }
307
308
        trigger_error('JSON decoding error "' . $jsonErrorText . '" for file ' . $file, E_USER_WARNING);
309
        return [];
310
    }
311
312
    return $conf;
313
}
314
315
/**
316
 * Retrieve the requested configuration information
317
 *
318
 * @author Chris Smith <[email protected]>
319
 *
320
 * @param  string   $type     the configuration settings to be read, must correspond to a key/array in $config_cascade
321
 * @param  callback $fn       the function used to process the configuration file into an array
322
 * @param  array    $params   optional additional params to pass to the callback
323
 * @param  callback $combine  the function used to combine arrays of values read from different configuration files;
324
 *                            the function takes two parameters,
325
 *                               $combined - the already read & merged configuration values
326
 *                               $new - array of config values from the config cascade file being currently processed
327
 *                            and returns an array of the merged configuration values.
328
 * @return array    configuration values
329
 */
330
function retrieveConfig($type,$fn,$params=null,$combine='array_merge') {
331
    global $config_cascade;
332
333
    if(!is_array($params)) $params = array();
334
335
    $combined = array();
336
    if (!is_array($config_cascade[$type])) trigger_error('Missing config cascade for "'.$type.'"',E_USER_WARNING);
337
    foreach (array('default','local','protected') as $config_group) {
338
        if (empty($config_cascade[$type][$config_group])) continue;
339
        foreach ($config_cascade[$type][$config_group] as $file) {
340
            if (file_exists($file)) {
341
                $config = call_user_func_array($fn,array_merge(array($file),$params));
342
                $combined = $combine($combined, $config);
343
            }
344
        }
345
    }
346
347
    return $combined;
348
}
349
350
/**
351
 * Include the requested configuration information
352
 *
353
 * @author Chris Smith <[email protected]>
354
 *
355
 * @param  string   $type     the configuration settings to be read, must correspond to a key/array in $config_cascade
356
 * @return array              list of files, default before local before protected
357
 */
358
function getConfigFiles($type) {
359
    global $config_cascade;
360
    $files = array();
361
362
    if (!is_array($config_cascade[$type])) trigger_error('Missing config cascade for "'.$type.'"',E_USER_WARNING);
363
    foreach (array('default','local','protected') as $config_group) {
364
        if (empty($config_cascade[$type][$config_group])) continue;
365
        $files = array_merge($files, $config_cascade[$type][$config_group]);
366
    }
367
368
    return $files;
369
}
370
371
/**
372
 * check if the given action was disabled in config
373
 *
374
 * @author Andreas Gohr <[email protected]>
375
 * @param string $action
376
 * @returns boolean true if enabled, false if disabled
377
 */
378
function actionOK($action){
379
    static $disabled = null;
380
    if(is_null($disabled) || defined('SIMPLE_TEST')){
381
        global $conf;
382
        /** @var DokuWiki_Auth_Plugin $auth */
383
        global $auth;
384
385
        // prepare disabled actions array and handle legacy options
386
        $disabled = explode(',',$conf['disableactions']);
387
        $disabled = array_map('trim',$disabled);
388
        if((isset($conf['openregister']) && !$conf['openregister']) || is_null($auth) || !$auth->canDo('addUser')) {
389
            $disabled[] = 'register';
390
        }
391
        if((isset($conf['resendpasswd']) && !$conf['resendpasswd']) || is_null($auth) || !$auth->canDo('modPass')) {
392
            $disabled[] = 'resendpwd';
393
        }
394
        if((isset($conf['subscribers']) && !$conf['subscribers']) || is_null($auth)) {
395
            $disabled[] = 'subscribe';
396
        }
397
        if (is_null($auth) || !$auth->canDo('Profile')) {
398
            $disabled[] = 'profile';
399
        }
400
        if (is_null($auth) || !$auth->canDo('delUser')) {
401
            $disabled[] = 'profile_delete';
402
        }
403
        if (is_null($auth)) {
404
            $disabled[] = 'login';
405
        }
406
        if (is_null($auth) || !$auth->canDo('logout')) {
407
            $disabled[] = 'logout';
408
        }
409
        $disabled = array_unique($disabled);
410
    }
411
412
    return !in_array($action,$disabled);
413
}
414
415
/**
416
 * check if headings should be used as link text for the specified link type
417
 *
418
 * @author Chris Smith <[email protected]>
419
 *
420
 * @param   string  $linktype   'content'|'navigation', content applies to links in wiki text
421
 *                                                      navigation applies to all other links
422
 * @return  boolean             true if headings should be used for $linktype, false otherwise
423
 */
424
function useHeading($linktype) {
425
    static $useHeading = null;
426
    if(defined('DOKU_UNITTEST')) $useHeading = null; // don't cache during unit tests
427
428
    if (is_null($useHeading)) {
429
        global $conf;
430
431
        if (!empty($conf['useheading'])) {
432
            switch ($conf['useheading']) {
433
                case 'content':
434
                    $useHeading['content'] = true;
435
                    break;
436
437
                case 'navigation':
438
                    $useHeading['navigation'] = true;
439
                    break;
440
                default:
441
                    $useHeading['content'] = true;
442
                    $useHeading['navigation'] = true;
443
            }
444
        } else {
445
            $useHeading = array();
446
        }
447
    }
448
449
    return (!empty($useHeading[$linktype]));
450
}
451
452
/**
453
 * obscure config data so information isn't plain text
454
 *
455
 * @param string       $str     data to be encoded
456
 * @param string       $code    encoding method, values: plain, base64, uuencode.
457
 * @return string               the encoded value
458
 */
459
function conf_encodeString($str,$code) {
460
    switch ($code) {
461
        case 'base64'   : return '<b>'.base64_encode($str);
462
        case 'uuencode' : return '<u>'.convert_uuencode($str);
463
        case 'plain':
464
        default:
465
                          return $str;
466
    }
467
}
468
/**
469
 * return obscured data as plain text
470
 *
471
 * @param  string      $str   encoded data
472
 * @return string             plain text
473
 */
474
function conf_decodeString($str) {
475
    switch (substr($str,0,3)) {
476
        case '<b>' : return base64_decode(substr($str,3));
477
        case '<u>' : return convert_uudecode(substr($str,3));
478
        default:  // not encoded (or unknown)
479
                     return $str;
480
    }
481
}
482
483
/**
484
 * array combination function to remove negated values (prefixed by !)
485
 *
486
 * @param  array $current
487
 * @param  array $new
488
 *
489
 * @return array the combined array, numeric keys reset
490
 */
491
function array_merge_with_removal($current, $new) {
492
    foreach ($new as $val) {
493
        if (substr($val,0,1) == DOKU_CONF_NEGATION) {
494
            $idx = array_search(trim(substr($val,1)),$current);
495
            if ($idx !== false) {
496
                unset($current[$idx]);
497
            }
498
        } else {
499
            $current[] = trim($val);
500
        }
501
    }
502
503
    return array_slice($current,0);
504
}
505
//Setup VIM: ex: et ts=4 :
506