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