Completed
Pull Request — master (#662)
by
unknown
01:33
created

PrettyPageHandler::addCustomJs()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
/**
3
 * Whoops - php errors for cool kids
4
 * @author Filipe Dobreira <http://github.com/filp>
5
 */
6
7
namespace Whoops\Handler;
8
9
use InvalidArgumentException;
10
use RuntimeException;
11
use Symfony\Component\VarDumper\Cloner\AbstractCloner;
12
use Symfony\Component\VarDumper\Cloner\VarCloner;
13
use UnexpectedValueException;
14
use Whoops\Exception\Formatter;
15
use Whoops\Util\Misc;
16
use Whoops\Util\TemplateHelper;
17
18
class PrettyPageHandler extends Handler
19
{
20
    const EDITOR_SUBLIME = "sublime";
21
    const EDITOR_TEXTMATE = "textmate";
22
    const EDITOR_EMACS = "emacs";
23
    const EDITOR_MACVIM = "macvim";
24
    const EDITOR_PHPSTORM = "phpstorm";
25
    const EDITOR_IDEA = "idea";
26
    const EDITOR_VSCODE = "vscode";
27
    const EDITOR_ATOM = "atom";
28
    const EDITOR_ESPRESSO = "espresso";
29
    const EDITOR_XDEBUG = "xdebug";
30
31
    /**
32
     * Search paths to be scanned for resources, in the reverse
33
     * order they're declared.
34
     *
35
     * @var array
36
     */
37
    private $searchPaths = [];
38
39
    /**
40
     * Fast lookup cache for known resource locations.
41
     *
42
     * @var array
43
     */
44
    private $resourceCache = [];
45
46
    /**
47
     * The name of the custom css file.
48
     *
49
     * @var string
50
     */
51
    private $customCss = null;
52
53
    /**
54
     * The name of the custom js file.
55
     *
56
     * @var string
57
     */
58
    private $customJs = null;
59
60
    /**
61
     * @var array[]
62
     */
63
    private $extraTables = [];
64
65
    /**
66
     * @var bool
67
     */
68
    private $handleUnconditionally = false;
69
70
    /**
71
     * @var string
72
     */
73
    private $pageTitle = "Whoops! There was an error.";
74
75
    /**
76
     * @var array[]
77
     */
78
    private $applicationPaths;
79
80
    /**
81
     * @var array[]
82
     */
83
    private $blacklist = [
84
        '_GET' => [],
85
        '_POST' => [],
86
        '_FILES' => [],
87
        '_COOKIE' => [],
88
        '_SESSION' => [],
89
        '_SERVER' => [],
90
        '_ENV' => [],
91
    ];
92
93
    /**
94
     * A string identifier for a known IDE/text editor, or a closure
95
     * that resolves a string that can be used to open a given file
96
     * in an editor. If the string contains the special substrings
97
     * %file or %line, they will be replaced with the correct data.
98
     *
99
     * @example
100
     *  "txmt://open?url=%file&line=%line"
101
     * @var mixed $editor
102
     */
103
    protected $editor;
104
105
    /**
106
     * A list of known editor strings
107
     * @var array
108
     */
109
    protected $editors = [
110
        "sublime"  => "subl://open?url=file://%file&line=%line",
111
        "textmate" => "txmt://open?url=file://%file&line=%line",
112
        "emacs"    => "emacs://open?url=file://%file&line=%line",
113
        "macvim"   => "mvim://open/?url=file://%file&line=%line",
114
        "phpstorm" => "phpstorm://open?file=%file&line=%line",
115
        "idea"     => "idea://open?file=%file&line=%line",
116
        "vscode"   => "vscode://file/%file:%line",
117
        "atom"     => "atom://core/open/file?filename=%file&line=%line",
118
        "espresso" => "x-espresso://open?filepath=%file&lines=%line",
119
    ];
120
121
    /**
122
     * @var TemplateHelper
123
     */
124
    private $templateHelper;
125
126
    /**
127
     * Constructor.
128
     */
129 1
    public function __construct()
130
    {
131 1
        if (ini_get('xdebug.file_link_format') || extension_loaded('xdebug')) {
132
            // Register editor using xdebug's file_link_format option.
133
            $this->editors['xdebug'] = function ($file, $line) {
134 1
                return str_replace(['%f', '%l'], [$file, $line], ini_get('xdebug.file_link_format'));
135
            };
136
137
            // If xdebug is available, use it as default editor.
138 1
            $this->setEditor('xdebug');
139 1
        }
140
141
        // Add the default, local resource search path:
142 1
        $this->searchPaths[] = __DIR__ . "/../Resources";
143
144
        // blacklist php provided auth based values
145 1
        $this->blacklist('_SERVER', 'PHP_AUTH_PW');
146
147 1
        $this->templateHelper = new TemplateHelper();
148
149 1
        if (class_exists('Symfony\Component\VarDumper\Cloner\VarCloner')) {
150 1
            $cloner = new VarCloner();
151
            // Only dump object internals if a custom caster exists for performance reasons
152
            // https://github.com/filp/whoops/pull/404
153
            $cloner->addCasters(['*' => function ($obj, $a, $stub, $isNested, $filter = 0) {
0 ignored issues
show
Unused Code introduced by
The parameter $isNested is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $filter is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
154
                $class = $stub->class;
155
                $classes = [$class => $class] + class_parents($obj) + class_implements($obj);
156
157
                foreach ($classes as $class) {
158
                    if (isset(AbstractCloner::$defaultCasters[$class])) {
159
                        return $a;
160
                    }
161
                }
162
163
                // Remove all internals
164
                return [];
165 1
            }]);
166 1
            $this->templateHelper->setCloner($cloner);
167 1
        }
168 1
    }
169
170
    /**
171
     * @return int|null
172
     */
173 1
    public function handle()
174
    {
175 1
        if (!$this->handleUnconditionally()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->handleUnconditionally() of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
176
            // Check conditions for outputting HTML:
177
            // @todo: Make this more robust
178 1
            if (PHP_SAPI === 'cli') {
179
                // Help users who have been relying on an internal test value
180
                // fix their code to the proper method
181 1
                if (isset($_ENV['whoops-test'])) {
182
                    throw new \Exception(
183
                        'Use handleUnconditionally instead of whoops-test'
184
                        .' environment variable'
185
                    );
186
                }
187
188 1
                return Handler::DONE;
189
            }
190
        }
191
192
        $templateFile = $this->getResource("views/layout.html.php");
193
        $cssFile      = $this->getResource("css/whoops.base.css");
194
        $zeptoFile    = $this->getResource("js/zepto.min.js");
195
        $prettifyFile = $this->getResource("js/prettify.min.js");
196
        $clipboard    = $this->getResource("js/clipboard.min.js");
197
        $jsFile       = $this->getResource("js/whoops.base.js");
198
199
        if ($this->customCss) {
200
            $customCssFile = $this->getResource($this->customCss);
201
        }
202
203
        if ($this->customJs) {
204
            $customJsFile = $this->getResource($this->customJs);
205
        }
206
207
        $inspector = $this->getInspector();
208
        $frames = $this->getExceptionFrames();
209
        $code = $this->getExceptionCode();
210
211
        // List of variables that will be passed to the layout template.
212
        $vars = [
213
            "page_title" => $this->getPageTitle(),
214
215
            // @todo: Asset compiler
216
            "stylesheet" => file_get_contents($cssFile),
217
            "zepto"      => file_get_contents($zeptoFile),
218
            "prettify"   => file_get_contents($prettifyFile),
219
            "clipboard"  => file_get_contents($clipboard),
220
            "javascript" => file_get_contents($jsFile),
221
222
            // Template paths:
223
            "header"                     => $this->getResource("views/header.html.php"),
224
            "header_outer"               => $this->getResource("views/header_outer.html.php"),
225
            "frame_list"                 => $this->getResource("views/frame_list.html.php"),
226
            "frames_description"         => $this->getResource("views/frames_description.html.php"),
227
            "frames_container"           => $this->getResource("views/frames_container.html.php"),
228
            "panel_details"              => $this->getResource("views/panel_details.html.php"),
229
            "panel_details_outer"        => $this->getResource("views/panel_details_outer.html.php"),
230
            "panel_left"                 => $this->getResource("views/panel_left.html.php"),
231
            "panel_left_outer"           => $this->getResource("views/panel_left_outer.html.php"),
232
            "frame_code"                 => $this->getResource("views/frame_code.html.php"),
233
            "env_details"                => $this->getResource("views/env_details.html.php"),
234
235
            "title"            => $this->getPageTitle(),
236
            "name"             => explode("\\", $inspector->getExceptionName()),
237
            "message"          => $inspector->getExceptionMessage(),
238
            "previousMessages" => $inspector->getPreviousExceptionMessages(),
239
            "docref_url"       => $inspector->getExceptionDocrefUrl(),
240
            "code"             => $code,
241
            "previousCodes"    => $inspector->getPreviousExceptionCodes(),
242
            "plain_exception"  => Formatter::formatExceptionPlain($inspector),
243
            "frames"           => $frames,
244
            "has_frames"       => !!count($frames),
245
            "handler"          => $this,
246
            "handlers"         => $this->getRun()->getHandlers(),
247
248
            "active_frames_tab" => count($frames) && $frames->offsetGet(0)->isApplication() ?  'application' : 'all',
0 ignored issues
show
Bug introduced by
The method isApplication cannot be called on $frames->offsetGet(0) (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
249
            "has_frames_tabs"   => $this->getApplicationPaths(),
250
251
            "tables"      => [
252
                "GET Data"              => $this->masked($_GET, '_GET'),
253
                "POST Data"             => $this->masked($_POST, '_POST'),
254
                "Files"                 => isset($_FILES) ? $this->masked($_FILES, '_FILES') : [],
255
                "Cookies"               => $this->masked($_COOKIE, '_COOKIE'),
256
                "Session"               => isset($_SESSION) ? $this->masked($_SESSION, '_SESSION') :  [],
257
                "Server/Request Data"   => $this->masked($_SERVER, '_SERVER'),
258
                "Environment Variables" => $this->masked($_ENV, '_ENV'),
259
            ],
260
        ];
261
262
        if (isset($customCssFile)) {
263
            $vars["stylesheet"] .= file_get_contents($customCssFile);
264
        }
265
266
        if (isset($customJsFile)) {
267
            $vars["javascript"] .= file_get_contents($customJsFile);
268
        }
269
270
        // Add extra entries list of data tables:
271
        // @todo: Consolidate addDataTable and addDataTableCallback
272
        $extraTables = array_map(function ($table) use ($inspector) {
273
            return $table instanceof \Closure ? $table($inspector) : $table;
274
        }, $this->getDataTables());
275
        $vars["tables"] = array_merge($extraTables, $vars["tables"]);
276
277
        $plainTextHandler = new PlainTextHandler();
278
        $plainTextHandler->setException($this->getException());
279
        $plainTextHandler->setInspector($this->getInspector());
280
        $vars["preface"] = "<!--\n\n\n" .  $this->templateHelper->escape($plainTextHandler->generateResponse()) . "\n\n\n\n\n\n\n\n\n\n\n-->";
281
282
        $this->templateHelper->setVariables($vars);
283
        $this->templateHelper->render($templateFile);
284
285
        return Handler::QUIT;
286
    }
287
288
    /**
289
     * Get the stack trace frames of the exception that is currently being handled.
290
     *
291
     * @return \Whoops\Exception\FrameCollection;
0 ignored issues
show
Documentation introduced by
The doc-type \Whoops\Exception\FrameCollection; could not be parsed: Expected "|" or "end of type", but got ";" at position 33. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
292
     */
293
    protected function getExceptionFrames()
294
    {
295
        $frames = $this->getInspector()->getFrames();
296
297
        if ($this->getApplicationPaths()) {
298
            foreach ($frames as $frame) {
299
                foreach ($this->getApplicationPaths() as $path) {
300
                    if (strpos($frame->getFile(), $path) === 0) {
301
                        $frame->setApplication(true);
302
                        break;
303
                    }
304
                }
305
            }
306
        }
307
308
        return $frames;
309
    }
310
311
    /**
312
     * Get the code of the exception that is currently being handled.
313
     *
314
     * @return string
315
     */
316
    protected function getExceptionCode()
317
    {
318
        $exception = $this->getException();
319
320
        $code = $exception->getCode();
321
        if ($exception instanceof \ErrorException) {
322
            // ErrorExceptions wrap the php-error types within the 'severity' property
323
            $code = Misc::translateErrorCode($exception->getSeverity());
324
        }
325
326
        return (string) $code;
327
    }
328
329
    /**
330
     * @return string
331
     */
332
    public function contentType()
333
    {
334
        return 'text/html';
335
    }
336
337
    /**
338
     * Adds an entry to the list of tables displayed in the template.
339
     * The expected data is a simple associative array. Any nested arrays
340
     * will be flattened with print_r
341
     * @param string $label
342
     * @param array  $data
343
     */
344 1
    public function addDataTable($label, array $data)
345
    {
346 1
        $this->extraTables[$label] = $data;
347 1
    }
348
349
    /**
350
     * Lazily adds an entry to the list of tables displayed in the table.
351
     * The supplied callback argument will be called when the error is rendered,
352
     * it should produce a simple associative array. Any nested arrays will
353
     * be flattened with print_r.
354
     *
355
     * @throws InvalidArgumentException If $callback is not callable
356
     * @param  string                   $label
357
     * @param  callable                 $callback Callable returning an associative array
358
     */
359 1
    public function addDataTableCallback($label, /* callable */ $callback)
360
    {
361 1
        if (!is_callable($callback)) {
362
            throw new InvalidArgumentException('Expecting callback argument to be callable');
363
        }
364
365 1
        $this->extraTables[$label] = function (\Whoops\Exception\Inspector $inspector = null) use ($callback) {
366
            try {
367 1
                $result = call_user_func($callback, $inspector);
368
369
                // Only return the result if it can be iterated over by foreach().
370 1
                return is_array($result) || $result instanceof \Traversable ? $result : [];
371
            } catch (\Exception $e) {
372
                // Don't allow failure to break the rendering of the original exception.
373
                return [];
374
            }
375
        };
376 1
    }
377
378
    /**
379
     * Returns all the extra data tables registered with this handler.
380
     * Optionally accepts a 'label' parameter, to only return the data
381
     * table under that label.
382
     * @param  string|null      $label
383
     * @return array[]|callable
384
     */
385 2
    public function getDataTables($label = null)
386
    {
387 2
        if ($label !== null) {
388 2
            return isset($this->extraTables[$label]) ?
389 2
                   $this->extraTables[$label] : [];
390
        }
391
392 2
        return $this->extraTables;
393
    }
394
395
    /**
396
     * Allows to disable all attempts to dynamically decide whether to
397
     * handle or return prematurely.
398
     * Set this to ensure that the handler will perform no matter what.
399
     * @param  bool|null $value
400
     * @return bool|null
401
     */
402 1
    public function handleUnconditionally($value = null)
403
    {
404 1
        if (func_num_args() == 0) {
405 1
            return $this->handleUnconditionally;
406
        }
407
408
        $this->handleUnconditionally = (bool) $value;
409
    }
410
411
    /**
412
     * Adds an editor resolver, identified by a string
413
     * name, and that may be a string path, or a callable
414
     * resolver. If the callable returns a string, it will
415
     * be set as the file reference's href attribute.
416
     *
417
     * @example
418
     *  $run->addEditor('macvim', "mvim://open?url=file://%file&line=%line")
419
     * @example
420
     *   $run->addEditor('remove-it', function($file, $line) {
421
     *       unlink($file);
422
     *       return "http://stackoverflow.com";
423
     *   });
424
     * @param string $identifier
425
     * @param string|callable $resolver
426
     */
427 1
    public function addEditor($identifier, $resolver)
428
    {
429 1
        $this->editors[$identifier] = $resolver;
430 1
    }
431
432
    /**
433
     * Set the editor to use to open referenced files, by a string
434
     * identifier, or a callable that will be executed for every
435
     * file reference, with a $file and $line argument, and should
436
     * return a string.
437
     *
438
     * @example
439
     *   $run->setEditor(function($file, $line) { return "file:///{$file}"; });
440
     * @example
441
     *   $run->setEditor('sublime');
442
     *
443
     * @throws InvalidArgumentException If invalid argument identifier provided
444
     * @param  string|callable          $editor
445
     */
446 4
    public function setEditor($editor)
447
    {
448 4
        if (!is_callable($editor) && !isset($this->editors[$editor])) {
449
            throw new InvalidArgumentException(
450
                "Unknown editor identifier: $editor. Known editors:" .
451
                implode(",", array_keys($this->editors))
452
            );
453
        }
454
455 4
        $this->editor = $editor;
456 4
    }
457
458
    /**
459
     * Given a string file path, and an integer file line,
460
     * executes the editor resolver and returns, if available,
461
     * a string that may be used as the href property for that
462
     * file reference.
463
     *
464
     * @throws InvalidArgumentException If editor resolver does not return a string
465
     * @param  string                   $filePath
466
     * @param  int                      $line
467
     * @return string|bool
468
     */
469 4
    public function getEditorHref($filePath, $line)
470
    {
471 4
        $editor = $this->getEditor($filePath, $line);
472
473 4
        if (empty($editor)) {
474 1
            return false;
475
        }
476
477
        // Check that the editor is a string, and replace the
478
        // %line and %file placeholders:
479 4
        if (!isset($editor['url']) || !is_string($editor['url'])) {
480
            throw new UnexpectedValueException(
481
                __METHOD__ . " should always resolve to a string or a valid editor array; got something else instead."
482
            );
483
        }
484
485 4
        $editor['url'] = str_replace("%line", rawurlencode($line), $editor['url']);
486 4
        $editor['url'] = str_replace("%file", rawurlencode($filePath), $editor['url']);
487
488 4
        return $editor['url'];
489
    }
490
491
    /**
492
     * Given a boolean if the editor link should
493
     * act as an Ajax request. The editor must be a
494
     * valid callable function/closure
495
     *
496
     * @throws UnexpectedValueException  If editor resolver does not return a boolean
497
     * @param  string                   $filePath
498
     * @param  int                      $line
499
     * @return bool
500
     */
501 1
    public function getEditorAjax($filePath, $line)
502
    {
503 1
        $editor = $this->getEditor($filePath, $line);
504
505
        // Check that the ajax is a bool
506 1
        if (!isset($editor['ajax']) || !is_bool($editor['ajax'])) {
507
            throw new UnexpectedValueException(
508
                __METHOD__ . " should always resolve to a bool; got something else instead."
509
            );
510
        }
511 1
        return $editor['ajax'];
512
    }
513
514
    /**
515
     * Given a boolean if the editor link should
516
     * act as an Ajax request. The editor must be a
517
     * valid callable function/closure
518
     *
519
     * @param  string $filePath
520
     * @param  int    $line
521
     * @return array
522
     */
523 1
    protected function getEditor($filePath, $line)
524
    {
525 1
        if (!$this->editor || (!is_string($this->editor) && !is_callable($this->editor))) {
526
            return [];
527
        }
528
529 1
        if (is_string($this->editor) && isset($this->editors[$this->editor]) && !is_callable($this->editors[$this->editor])) {
530
            return [
531
                'ajax' => false,
532
                'url' => $this->editors[$this->editor],
533
            ];
534
        }
535
536 1
        if (is_callable($this->editor) || (isset($this->editors[$this->editor]) && is_callable($this->editors[$this->editor]))) {
537 1
            if (is_callable($this->editor)) {
538
                $callback = call_user_func($this->editor, $filePath, $line);
539
            } else {
540 1
                $callback = call_user_func($this->editors[$this->editor], $filePath, $line);
541
            }
542
543 1
            if (empty($callback)) {
544
                return [];
545
            }
546
547 1
            if (is_string($callback)) {
548
                return [
549 1
                    'ajax' => false,
550 1
                    'url' => $callback,
551 1
                ];
552
            }
553
554
            return [
555
                'ajax' => isset($callback['ajax']) ? $callback['ajax'] : false,
556
                'url' => isset($callback['url']) ? $callback['url'] : $callback,
557
            ];
558
        }
559
560
        return [];
561
    }
562
563
    /**
564
     * @param  string $title
565
     * @return void
566
     */
567 1
    public function setPageTitle($title)
568
    {
569 1
        $this->pageTitle = (string) $title;
570 1
    }
571
572
    /**
573
     * @return string
574
     */
575 1
    public function getPageTitle()
576
    {
577 1
        return $this->pageTitle;
578
    }
579
580
    /**
581
     * Adds a path to the list of paths to be searched for
582
     * resources.
583
     *
584
     * @throws InvalidArgumentException If $path is not a valid directory
585
     *
586
     * @param  string $path
587
     * @return void
588
     */
589 2
    public function addResourcePath($path)
590
    {
591 2
        if (!is_dir($path)) {
592 1
            throw new InvalidArgumentException(
593 1
                "'$path' is not a valid directory"
594 1
            );
595
        }
596
597 1
        array_unshift($this->searchPaths, $path);
598 1
    }
599
600
    /**
601
     * Adds a custom css file to be loaded.
602
     *
603
     * @param  string $name
604
     * @return void
605
     */
606
    public function addCustomCss($name)
607
    {
608
        $this->customCss = $name;
609
    }
610
611
    /**
612
     * Adds a custom js file to be loaded.
613
     *
614
     * @param  string $name
615
     * @return void
616
     */
617
    public function addCustomJs($name)
618
    {
619
        $this->customJs = $name;
620
    }
621
622
    /**
623
     * @return array
624
     */
625 1
    public function getResourcePaths()
626
    {
627 1
        return $this->searchPaths;
628
    }
629
630
    /**
631
     * Finds a resource, by its relative path, in all available search paths.
632
     * The search is performed starting at the last search path, and all the
633
     * way back to the first, enabling a cascading-type system of overrides
634
     * for all resources.
635
     *
636
     * @throws RuntimeException If resource cannot be found in any of the available paths
637
     *
638
     * @param  string $resource
639
     * @return string
640
     */
641
    protected function getResource($resource)
642
    {
643
        // If the resource was found before, we can speed things up
644
        // by caching its absolute, resolved path:
645
        if (isset($this->resourceCache[$resource])) {
646
            return $this->resourceCache[$resource];
647
        }
648
649
        // Search through available search paths, until we find the
650
        // resource we're after:
651
        foreach ($this->searchPaths as $path) {
652
            $fullPath = $path . "/$resource";
653
654
            if (is_file($fullPath)) {
655
                // Cache the result:
656
                $this->resourceCache[$resource] = $fullPath;
657
                return $fullPath;
658
            }
659
        }
660
661
        // If we got this far, nothing was found.
662
        throw new RuntimeException(
663
            "Could not find resource '$resource' in any resource paths."
664
            . "(searched: " . join(", ", $this->searchPaths). ")"
665
        );
666
    }
667
668
    /**
669
     * @deprecated
670
     *
671
     * @return string
672
     */
673
    public function getResourcesPath()
674
    {
675
        $allPaths = $this->getResourcePaths();
676
677
        // Compat: return only the first path added
678
        return end($allPaths) ?: null;
679
    }
680
681
    /**
682
     * @deprecated
683
     *
684
     * @param  string $resourcesPath
685
     * @return void
686
     */
687
    public function setResourcesPath($resourcesPath)
688
    {
689
        $this->addResourcePath($resourcesPath);
690
    }
691
692
    /**
693
     * Return the application paths.
694
     *
695
     * @return array
696
     */
697
    public function getApplicationPaths()
698
    {
699
        return $this->applicationPaths;
700
    }
701
702
    /**
703
     * Set the application paths.
704
     *
705
     * @param array $applicationPaths
706
     */
707
    public function setApplicationPaths($applicationPaths)
708
    {
709
        $this->applicationPaths = $applicationPaths;
710
    }
711
712
    /**
713
     * Set the application root path.
714
     *
715
     * @param string $applicationRootPath
716
     */
717
    public function setApplicationRootPath($applicationRootPath)
718
    {
719
        $this->templateHelper->setApplicationRootPath($applicationRootPath);
720
    }
721
722
    /**
723
     * blacklist a sensitive value within one of the superglobal arrays.
724
     *
725
     * @param $superGlobalName string the name of the superglobal array, e.g. '_GET'
726
     * @param $key string the key within the superglobal
727
     */
728 1
    public function blacklist($superGlobalName, $key)
729
    {
730 1
        $this->blacklist[$superGlobalName][] = $key;
731 1
    }
732
733
    /**
734
     * Checks all values within the given superGlobal array.
735
     * Blacklisted values will be replaced by a equal length string cointaining only '*' characters.
736
     *
737
     * We intentionally dont rely on $GLOBALS as it depends on 'auto_globals_jit' php.ini setting.
738
     *
739
     * @param $superGlobal array One of the superglobal arrays
740
     * @param $superGlobalName string the name of the superglobal array, e.g. '_GET'
741
     * @return array $values without sensitive data
742
     */
743
    private function masked(array $superGlobal, $superGlobalName)
744
    {
745
        $blacklisted = $this->blacklist[$superGlobalName];
746
747
        $values = $superGlobal;
748
        foreach ($blacklisted as $key) {
749
            if (isset($superGlobal[$key]) && is_string($superGlobal[$key])) {
750
                $values[$key] = str_repeat('*', strlen($superGlobal[$key]));
751
            }
752
        }
753
        return $values;
754
    }
755
}
756