Failed Conditions
Push — refactorCachePSR2 ( 0db577 )
by Michael
05:36 queued 02:56
created

lib/exe/js.php (1 issue)

Labels
Severity

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
 * DokuWiki JavaScript creator
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Andreas Gohr <[email protected]>
7
 */
8
9
use dokuwiki\Cache\Cache;
0 ignored issues
show
This use statement conflicts with another class in this namespace, Cache.

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_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
12
if(!defined('NOSESSION')) define('NOSESSION',true); // we do not use a session or authentication here (better caching)
13
if(!defined('NL')) define('NL',"\n");
14
if(!defined('DOKU_DISABLE_GZIP_OUTPUT')) define('DOKU_DISABLE_GZIP_OUTPUT',1); // we gzip ourself here
15
require_once(DOKU_INC.'inc/init.php');
16
17
// Main (don't run when UNIT test)
18
if(!defined('SIMPLE_TEST')){
19
    header('Content-Type: application/javascript; charset=utf-8');
20
    js_out();
21
}
22
23
24
// ---------------------- functions ------------------------------
25
26
/**
27
 * Output all needed JavaScript
28
 *
29
 * @author Andreas Gohr <[email protected]>
30
 */
31
function js_out(){
32
    global $conf;
33
    global $lang;
34
    global $config_cascade;
35
    global $INPUT;
36
37
    // decide from where to get the template
38
    $tpl = trim(preg_replace('/[^\w-]+/','',$INPUT->str('t')));
39
    if(!$tpl) $tpl = $conf['template'];
40
41
    // array of core files
42
    $files = array(
43
                DOKU_INC.'lib/scripts/jquery/jquery.cookie.js',
44
                DOKU_INC.'inc/lang/'.$conf['lang'].'/jquery.ui.datepicker.js',
45
                DOKU_INC."lib/scripts/fileuploader.js",
46
                DOKU_INC."lib/scripts/fileuploaderextended.js",
47
                DOKU_INC.'lib/scripts/helpers.js',
48
                DOKU_INC.'lib/scripts/delay.js',
49
                DOKU_INC.'lib/scripts/cookie.js',
50
                DOKU_INC.'lib/scripts/script.js',
51
                DOKU_INC.'lib/scripts/qsearch.js',
52
                DOKU_INC.'lib/scripts/search.js',
53
                DOKU_INC.'lib/scripts/tree.js',
54
                DOKU_INC.'lib/scripts/index.js',
55
                DOKU_INC.'lib/scripts/textselection.js',
56
                DOKU_INC.'lib/scripts/toolbar.js',
57
                DOKU_INC.'lib/scripts/edit.js',
58
                DOKU_INC.'lib/scripts/editor.js',
59
                DOKU_INC.'lib/scripts/locktimer.js',
60
                DOKU_INC.'lib/scripts/linkwiz.js',
61
                DOKU_INC.'lib/scripts/media.js',
62
                DOKU_INC.'lib/scripts/compatibility.js',
63
# disabled for FS#1958                DOKU_INC.'lib/scripts/hotkeys.js',
64
                DOKU_INC.'lib/scripts/behaviour.js',
65
                DOKU_INC.'lib/scripts/page.js',
66
                tpl_incdir($tpl).'script.js',
67
            );
68
69
    // add possible plugin scripts and userscript
70
    $files   = array_merge($files,js_pluginscripts());
71
    if(!empty($config_cascade['userscript']['default'])) {
72
        foreach($config_cascade['userscript']['default'] as $userscript) {
73
            $files[] = $userscript;
74
        }
75
    }
76
77
    // Let plugins decide to either put more scripts here or to remove some
78
    trigger_event('JS_SCRIPT_LIST', $files);
79
80
    // The generated script depends on some dynamic options
81
    $cache = new Cache('scripts'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'].md5(serialize($files)),'.js');
82
    $cache->_event = 'JS_CACHE_USE';
83
84
    $cache_files = array_merge($files, getConfigFiles('main'));
85
    $cache_files[] = __FILE__;
86
87
    // check cache age & handle conditional request
88
    // This may exit if a cache can be used
89
    $cache_ok = $cache->useCache(array('files' => $cache_files));
90
    http_cached($cache->cache, $cache_ok);
91
92
    // start output buffering and build the script
93
    ob_start();
94
95
    // add some global variables
96
    print "var DOKU_BASE   = '".DOKU_BASE."';";
97
    print "var DOKU_TPL    = '".tpl_basedir($tpl)."';";
98
    print "var DOKU_COOKIE_PARAM = " . json_encode(
99
            array(
100
                 'path' => empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir'],
101
                 'secure' => $conf['securecookie'] && is_ssl()
102
            )).";";
103
    // FIXME: Move those to JSINFO
104
    print "Object.defineProperty(window, 'DOKU_UHN', { get: function() {".
105
          "console.warn('Using DOKU_UHN is deprecated. Please use JSINFO.useHeadingNavigation instead');".
106
          "return JSINFO.useHeadingNavigation; } });";
107
    print "Object.defineProperty(window, 'DOKU_UHC', { get: function() {".
108
          "console.warn('Using DOKU_UHC is deprecated. Please use JSINFO.useHeadingContent instead');".
109
          "return JSINFO.useHeadingContent; } });";
110
111
    // load JS specific translations
112
    $lang['js']['plugins'] = js_pluginstrings();
113
    $templatestrings = js_templatestrings($tpl);
114
    if(!empty($templatestrings)) {
115
        $lang['js']['template'] = $templatestrings;
116
    }
117
    echo 'LANG = '.json_encode($lang['js']).";\n";
118
119
    // load toolbar
120
    toolbar_JSdefines('toolbar');
121
122
    // load files
123
    foreach($files as $file){
124
        if(!file_exists($file)) continue;
125
        $ismin = (substr($file,-7) == '.min.js');
126
        $debugjs = ($conf['allowdebug'] && strpos($file, DOKU_INC.'lib/scripts/') !== 0);
127
128
        echo "\n\n/* XXXXXXXXXX begin of ".str_replace(DOKU_INC, '', $file) ." XXXXXXXXXX */\n\n";
129
        if($ismin) echo "\n/* BEGIN NOCOMPRESS */\n";
130
        if ($debugjs) echo "\ntry {\n";
131
        js_load($file);
132
        if ($debugjs) echo "\n} catch (e) {\n   logError(e, '".str_replace(DOKU_INC, '', $file)."');\n}\n";
133
        if($ismin) echo "\n/* END NOCOMPRESS */\n";
134
        echo "\n\n/* XXXXXXXXXX end of " . str_replace(DOKU_INC, '', $file) . " XXXXXXXXXX */\n\n";
135
    }
136
137
    // init stuff
138
    if($conf['locktime'] != 0){
139
        js_runonstart("dw_locktimer.init(".($conf['locktime'] - 60).",".$conf['usedraft'].")");
140
    }
141
    // init hotkeys - must have been done after init of toolbar
142
# disabled for FS#1958    js_runonstart('initializeHotkeys()');
143
144
    // end output buffering and get contents
145
    $js = ob_get_contents();
146
    ob_end_clean();
147
148
    // strip any source maps
149
    stripsourcemaps($js);
150
151
    // compress whitespace and comments
152
    if($conf['compress']){
153
        $js = js_compress($js);
154
    }
155
156
    $js .= "\n"; // https://bugzilla.mozilla.org/show_bug.cgi?id=316033
157
158
    http_cached_finish($cache->cache, $js);
159
}
160
161
/**
162
 * Load the given file, handle include calls and print it
163
 *
164
 * @author Andreas Gohr <[email protected]>
165
 *
166
 * @param string $file filename path to file
167
 */
168
function js_load($file){
169
    if(!file_exists($file)) return;
170
    static $loaded = array();
171
172
    $data = io_readFile($file);
173
    while(preg_match('#/\*\s*DOKUWIKI:include(_once)?\s+([\w\.\-_/]+)\s*\*/#',$data,$match)){
174
        $ifile = $match[2];
175
176
        // is it a include_once?
177
        if($match[1]){
178
            $base = utf8_basename($ifile);
179
            if(array_key_exists($base, $loaded) && $loaded[$base] === true){
180
                $data  = str_replace($match[0], '' ,$data);
181
                continue;
182
            }
183
            $loaded[$base] = true;
184
        }
185
186
        if($ifile{0} != '/') $ifile = dirname($file).'/'.$ifile;
187
188
        if(file_exists($ifile)){
189
            $idata = io_readFile($ifile);
190
        }else{
191
            $idata = '';
192
        }
193
        $data  = str_replace($match[0],$idata,$data);
194
    }
195
    echo "$data\n";
196
}
197
198
/**
199
 * Returns a list of possible Plugin Scripts (no existance check here)
200
 *
201
 * @author Andreas Gohr <[email protected]>
202
 *
203
 * @return array
204
 */
205
function js_pluginscripts(){
206
    $list = array();
207
    $plugins = plugin_list();
208
    foreach ($plugins as $p){
209
        $list[] = DOKU_PLUGIN."$p/script.js";
210
    }
211
    return $list;
212
}
213
214
/**
215
 * Return an two-dimensional array with strings from the language file of each plugin.
216
 *
217
 * - $lang['js'] must be an array.
218
 * - Nothing is returned for plugins without an entry for $lang['js']
219
 *
220
 * @author Gabriel Birke <[email protected]>
221
 *
222
 * @return array
223
 */
224
function js_pluginstrings() {
225
    global $conf, $config_cascade;
226
    $pluginstrings = array();
227
    $plugins = plugin_list();
228
    foreach($plugins as $p) {
229
        $path = DOKU_PLUGIN . $p . '/lang/';
230
231
        if(isset($lang)) unset($lang);
232
        if(file_exists($path . "en/lang.php")) {
233
            include $path . "en/lang.php";
234
        }
235
        foreach($config_cascade['lang']['plugin'] as $config_file) {
236
            if(file_exists($config_file . $p . '/en/lang.php')) {
237
                include($config_file . $p . '/en/lang.php');
238
            }
239
        }
240
        if(isset($conf['lang']) && $conf['lang'] != 'en') {
241
            if(file_exists($path . $conf['lang'] . "/lang.php")) {
242
                include($path . $conf['lang'] . '/lang.php');
243
            }
244
            foreach($config_cascade['lang']['plugin'] as $config_file) {
245
                if(file_exists($config_file . $p . '/' . $conf['lang'] . '/lang.php')) {
246
                    include($config_file . $p . '/' . $conf['lang'] . '/lang.php');
247
                }
248
            }
249
        }
250
251
        if(isset($lang['js'])) {
252
            $pluginstrings[$p] = $lang['js'];
253
        }
254
    }
255
    return $pluginstrings;
256
}
257
258
/**
259
 * Return an two-dimensional array with strings from the language file of current active template.
260
 *
261
 * - $lang['js'] must be an array.
262
 * - Nothing is returned for template without an entry for $lang['js']
263
 *
264
 * @param string $tpl
265
 * @return array
266
 */
267
function js_templatestrings($tpl) {
268
    global $conf, $config_cascade;
269
270
    $path = tpl_incdir() . 'lang/';
271
272
    $templatestrings = array();
273
    if(file_exists($path . "en/lang.php")) {
274
        include $path . "en/lang.php";
275
    }
276
    foreach($config_cascade['lang']['template'] as $config_file) {
277
        if(file_exists($config_file . $conf['template'] . '/en/lang.php')) {
278
            include($config_file . $conf['template'] . '/en/lang.php');
279
        }
280
    }
281
    if(isset($conf['lang']) && $conf['lang'] != 'en' && file_exists($path . $conf['lang'] . "/lang.php")) {
282
        include $path . $conf['lang'] . "/lang.php";
283
    }
284
    if(isset($conf['lang']) && $conf['lang'] != 'en') {
285
        if(file_exists($path . $conf['lang'] . "/lang.php")) {
286
            include $path . $conf['lang'] . "/lang.php";
287
        }
288
        foreach($config_cascade['lang']['template'] as $config_file) {
289
            if(file_exists($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php')) {
290
                include($config_file . $conf['template'] . '/' . $conf['lang'] . '/lang.php');
291
            }
292
        }
293
    }
294
295
    if(isset($lang['js'])) {
296
        $templatestrings[$tpl] = $lang['js'];
297
    }
298
    return $templatestrings;
299
}
300
301
/**
302
 * Escapes a String to be embedded in a JavaScript call, keeps \n
303
 * as newline
304
 *
305
 * @author Andreas Gohr <[email protected]>
306
 *
307
 * @param string $string
308
 * @return string
309
 */
310
function js_escape($string){
311
    return str_replace('\\\\n','\\n',addslashes($string));
312
}
313
314
/**
315
 * Adds the given JavaScript code to the window.onload() event
316
 *
317
 * @author Andreas Gohr <[email protected]>
318
 *
319
 * @param string $func
320
 */
321
function js_runonstart($func){
322
    echo "jQuery(function(){ $func; });".NL;
323
}
324
325
/**
326
 * Strip comments and whitespaces from given JavaScript Code
327
 *
328
 * This is a port of Nick Galbreath's python tool jsstrip.py which is
329
 * released under BSD license. See link for original code.
330
 *
331
 * @author Nick Galbreath <[email protected]>
332
 * @author Andreas Gohr <[email protected]>
333
 * @link   http://code.google.com/p/jsstrip/
334
 *
335
 * @param string $s
336
 * @return string
337
 */
338
function js_compress($s){
339
    $s = ltrim($s);     // strip all initial whitespace
340
    $s .= "\n";
341
    $i = 0;             // char index for input string
342
    $j = 0;             // char forward index for input string
343
    $line = 0;          // line number of file (close to it anyways)
344
    $slen = strlen($s); // size of input string
345
    $lch  = '';         // last char added
346
    $result = '';       // we store the final result here
347
348
    // items that don't need spaces next to them
349
    $chars = "^&|!+\-*\/%=\?:;,{}()<>% \t\n\r'\"[]";
350
351
    // items which need a space if the sign before and after whitespace is equal.
352
    // E.g. '+ ++' may not be compressed to '+++' --> syntax error.
353
    $ops = "+-";
354
355
    $regex_starters = array("(", "=", "[", "," , ":", "!", "&", "|");
356
357
    $whitespaces_chars = array(" ", "\t", "\n", "\r", "\0", "\x0B");
358
359
    while($i < $slen){
360
        // skip all "boring" characters.  This is either
361
        // reserved word (e.g. "for", "else", "if") or a
362
        // variable/object/method (e.g. "foo.color")
363
        while ($i < $slen && (strpos($chars,$s[$i]) === false) ){
364
            $result .= $s{$i};
365
            $i = $i + 1;
366
        }
367
368
        $ch = $s{$i};
369
        // multiline comments (keeping IE conditionals)
370
        if($ch == '/' && $s{$i+1} == '*' && $s{$i+2} != '@'){
371
            $endC = strpos($s,'*/',$i+2);
372
            if($endC === false) trigger_error('Found invalid /*..*/ comment', E_USER_ERROR);
373
374
            // check if this is a NOCOMPRESS comment
375
            if(substr($s, $i, $endC+2-$i) == '/* BEGIN NOCOMPRESS */'){
376
                $endNC = strpos($s, '/* END NOCOMPRESS */', $endC+2);
377
                if($endNC === false) trigger_error('Found invalid NOCOMPRESS comment', E_USER_ERROR);
378
379
                // verbatim copy contents, trimming but putting it on its own line
380
                $result .= "\n".trim(substr($s, $i + 22, $endNC - ($i + 22)))."\n"; // BEGIN comment = 22 chars
381
                $i = $endNC + 20; // END comment = 20 chars
382
            }else{
383
                $i = $endC + 2;
384
            }
385
            continue;
386
        }
387
388
        // singleline
389
        if($ch == '/' && $s{$i+1} == '/'){
390
            $endC = strpos($s,"\n",$i+2);
391
            if($endC === false) trigger_error('Invalid comment', E_USER_ERROR);
392
            $i = $endC;
393
            continue;
394
        }
395
396
        // tricky.  might be an RE
397
        if($ch == '/'){
398
            // rewind, skip white space
399
            $j = 1;
400
            while(in_array($s{$i-$j}, $whitespaces_chars)){
401
                $j = $j + 1;
402
            }
403
            if( in_array($s{$i-$j}, $regex_starters) ){
404
                // yes, this is an re
405
                // now move forward and find the end of it
406
                $j = 1;
407
                while($s{$i+$j} != '/'){
408
                    if($s{$i+$j} == '\\') $j = $j + 2;
409
                    else $j++;
410
                }
411
                $result .= substr($s,$i,$j+1);
412
                $i = $i + $j + 1;
413
                continue;
414
            }
415
        }
416
417
        // double quote strings
418
        if($ch == '"'){
419
            $j = 1;
420
            while( $s{$i+$j} != '"' && ($i+$j < $slen)){
421
                if( $s{$i+$j} == '\\' && ($s{$i+$j+1} == '"' || $s{$i+$j+1} == '\\') ){
422
                    $j += 2;
423
                }else{
424
                    $j += 1;
425
                }
426
            }
427
            $string  = substr($s,$i,$j+1);
428
            // remove multiline markers:
429
            $string  = str_replace("\\\n",'',$string);
430
            $result .= $string;
431
            $i = $i + $j + 1;
432
            continue;
433
        }
434
435
        // single quote strings
436
        if($ch == "'"){
437
            $j = 1;
438
            while( $s{$i+$j} != "'" && ($i+$j < $slen)){
439
                if( $s{$i+$j} == '\\' && ($s{$i+$j+1} == "'" || $s{$i+$j+1} == '\\') ){
440
                    $j += 2;
441
                }else{
442
                    $j += 1;
443
                }
444
            }
445
            $string = substr($s,$i,$j+1);
446
            // remove multiline markers:
447
            $string  = str_replace("\\\n",'',$string);
448
            $result .= $string;
449
            $i = $i + $j + 1;
450
            continue;
451
        }
452
453
        // whitespaces
454
        if( $ch == ' ' || $ch == "\r" || $ch == "\n" || $ch == "\t" ){
455
            $lch = substr($result,-1);
456
457
            // Only consider deleting whitespace if the signs before and after
458
            // are not equal and are not an operator which may not follow itself.
459
            if ($i+1 < $slen && ((!$lch || $s[$i+1] == ' ')
460
                || $lch != $s[$i+1]
461
                || strpos($ops,$s[$i+1]) === false)) {
462
                // leading spaces
463
                if($i+1 < $slen && (strpos($chars,$s[$i+1]) !== false)){
464
                    $i = $i + 1;
465
                    continue;
466
                }
467
                // trailing spaces
468
                //  if this ch is space AND the last char processed
469
                //  is special, then skip the space
470
                if($lch && (strpos($chars,$lch) !== false)){
471
                    $i = $i + 1;
472
                    continue;
473
                }
474
            }
475
476
            // else after all of this convert the "whitespace" to
477
            // a single space.  It will get appended below
478
            $ch = ' ';
479
        }
480
481
        // other chars
482
        $result .= $ch;
483
        $i = $i + 1;
484
    }
485
486
    return trim($result);
487
}
488
489
//Setup VIM: ex: et ts=4 :
490