Issues (166)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

lib/App/Web.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
 * App_Web extends an APP of CommandLine applications with knowledge of HTML
4
 * templates, understanding of pages and routing.
5
*/
6
class App_Web extends App_CLI
7
{
8
    /**
9
     * Cleaned up name of the currently requested page.
10
     */
11
    public $page = null;
12
13
    /**
14
     * Root page where URL will send when ('/') is encountered.
15
     *
16
     * @todo: make this work properly
17
     */
18
    public $index_page = 'index';
19
20
    /**
21
     * Recorded time when execution has started.
22
     */
23
    public $start_time = null;
24
25
    /**
26
     * Skin for web application templates.
27
     */
28
    public $skin;
29
30
    /**
31
     * Set a title of your application, will appear in <title> tag.
32
     */
33
    public $title;
34
35
    /**
36
     * Authentication object
37
     *
38
     * @see Auth_Basic::init()
39
     * @var Auth_Basic
40
     */
41
    public $auth;
42
43
    /**
44
     * jQuery object. Initializes only if you add jQuery in your app.
45
     *
46
     * @see jQuery::init()
47
     * @var jQuery
48
     */
49
    public $jquery;
50
51
    /**
52
     * jQuery UI object. Initializes only if you add jQuery UI in your app.
53
     *
54
     * @see jUI::init()
55
     * @var jUI
56
     */
57
    public $jui;
58
59
    /** @var App_Web */
60
    public $app;
61
    /** @var array For internal use */
62
    protected $included;
63
    /** @var array For internal use */
64
    protected $rendered;
65
66
67
68
    // {{{ Start-up
69
    public function __construct($realm = null, $skin = 'default', $options = array())
70
    {
71
        $m = explode(' ', microtime());
72
        $this->start_time = time() + $m[0];
73
74
        $this->skin = $skin;
75
        try {
76
            parent::__construct($realm, $options);
77
        } catch (Exception $e) {
78
            // This exception is used to abort initialisation of the objects,
79
            // but when normal rendering is still required
80
            if ($e instanceof Exception_Stop) {
81
                return;
82
            }
83
84
            $this->caughtException($e);
85
        }
86
    }
87
88
    /**
89
     * Executed before init, this method will initialize PageManager and
90
     * pathfinder.
91
     */
92
    public function _beforeInit()
93
    {
94
        $this->pm = $this->add($this->pagemanager_class, $this->pagemanager_options);
95
        /** @type Controller_PageManager $this->pm */
96
        $this->pm->parseRequestedURL();
97
        parent::_beforeInit();
98
    }
99
100
    /**
101
     * Redefine this function instead of default constructor.
102
     */
103
    public function init()
104
    {
105
        $this->getLogger();
106
107
        // Verify Licensing
108
        //$this->licenseCheck('atk4');
109
110
        // send headers, no caching
111
        $this->sendHeaders();
112
113
        $this->cleanMagicQuotes();
114
115
        parent::init();
116
117
        // in addition to default initialization, set up logger and template
118
        $this->initializeTemplate();
119
120
        if (get_class($this) == 'App_Web') {
121
            $this->setConfig(array('url_postfix' => '.php', 'url_prefix' => ''));
122
        }
123
    }
124
125
    /**
126
     * Magic Quotes were a design error. Let's strip them if they are enabled.
127
     */
128
    public function cleanMagicQuotes()
129
    {
130
        if (!function_exists('stripslashes_array')) {
131
            function stripslashes_array(&$array, $iterations = 0)
132
            {
133
                if ($iterations < 3) {
134
                    foreach ($array as $key => $value) {
135
                        if (is_array($value)) {
136
                            stripslashes_array($array[$key], $iterations + 1);
137
                        } else {
138
                            $array[$key] = stripslashes($array[$key]);
139
                        }
140
                    }
141
                }
142
            }
143
        }
144
145
        if (get_magic_quotes_gpc()) {
146
            stripslashes_array($_GET);
147
            stripslashes_array($_POST);
148
            stripslashes_array($_COOKIE);
149
        }
150
    }
151
152
    /**
153
     * Sends default headers. Re-define to send your own headers.
154
     */
155
    public function sendHeaders()
156
    {
157
        header('Content-Type: text/html; charset=utf-8');
158
        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');               // Date in the past
159
        header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');  // always modified
160
        header('Cache-Control: no-store, no-cache, must-revalidate');   // HTTP/1.1
161
        header('Cache-Control: post-check=0, pre-check=0', false);
162
        header('Pragma: no-cache');                                     // HTTP/1.0
163
    }
164
165
    /**
166
     * Call this method if you want to see execution time on the bottom of your pages.
167
     */
168
    public function showExecutionTime()
169
    {
170
        $this->addHook('post-render-output', array($this, '_showExecutionTime'));
171
        $this->addHook('post-js-execute', array($this, '_showExecutionTimeJS'));
172
    }
173
174
    /** @ignore */
175
    public function _showExecutionTime()
176
    {
177
        echo 'Took '.(time() + microtime() - $this->start_time).'s';
178
    }
179
180
    /** @ignore */
181
    public function _showExecutionTimeJS()
182
    {
183
        echo "\n\n/* Took ".number_format(time() + microtime() - $this->start_time, 5).'s */';
184
    }
185
    // }}}
186
187
    // {{{ Obsolete
188
    /**
189
     * This method is called when exception was caught in the application.
190
     *
191
     * @param Exception $e
192
     */
193
    public function caughtException($e)
194
    {
195
        $this->hook('caught-exception', array($e));
196
        throw $e;
197
        /* unreachable code
198
        echo '<span style="color:red">Problem with your request.</span>';
199
        echo "<p>Please use 'Logger' class for more sophisticated output<br>\$app-&gt;add('Logger');</p>";
200
        exit;
201
        */
202
    }
203
204
    /**
205
     * @todo Description
206
     *
207
     * @param string $msg
208
     * @param int    $shift
209
     *
210
     * @return bool|void
211
     */
212 View Code Duplication
    public function outputWarning($msg, $shift = 0)
213
    {
214
        if ($this->hook('output-warning', array($msg, $shift))) {
215
            return true;
216
        }
217
        echo '<span style="color:red">', $msg, '</span>';
218
    }
219
220
    /**
221
     * @todo Description
222
     *
223
     * @param string $msg
224
     * @param int    $shift
225
     *
226
     * @return bool|void
227
     */
228 View Code Duplication
    public function outputDebug($msg, $shift = 0)
229
    {
230
        if ($this->hook('output-debug', array($msg, $shift))) {
231
            return true;
232
        }
233
        echo '<span style="color:blue">', $msg, '</font><br />';
234
    }
235
236
    // }}}
237
238
    // {{{ Sessions
239
    /**
240
     * Initializes existing or new session.
241
     *
242
     * Attempts to re-initialize session. If session is not found,
243
     * new one will be created, unless $create is set to false. Avoiding
244
     * session creation and placing cookies is to enhance user privacy.
245
     * Call to memorize() / recall() will automatically create session
246
     *
247
     * @param bool $create
248
     */
249
    public $_is_session_initialized = false;
250
    public function initializeSession($create = true)
251
    {
252
        if ($this->_is_session_initialized || session_id()) {
253
            return;
254
        }
255
256
        // Change settings if defined in settings file
257
        $params = session_get_cookie_params();
258
259
        $params['httponly'] = true;   // true by default
260
261
        foreach ($params as $key => $default) {
262
            $params[$key] = $this->app->getConfig('session/'.$key, $default);
263
        }
264
265
        if ($create === false && !isset($_COOKIE[$this->name])) {
266
            return;
267
        }
268
        $this->_is_session_initialized = true;
269
        session_set_cookie_params(
270
            $params['lifetime'],
271
            $params['path'],
272
            $params['domain'],
273
            $params['secure'],
274
            $params['httponly']
275
        );
276
        session_name($this->name);
277
        session_start();
278
    }
279
280
    /**
281
     * Completely destroy existing session.
282
     */
283
    public function destroySession()
284
    {
285
        if ($this->_is_session_initialized) {
286
            $_SESSION = array();
287
            if (isset($_COOKIE[$this->name])) {
288
                setcookie($this->name/*session_name()*/, '', time() - 42000, '/');
289
            }
290
            session_destroy();
291
            $this->_is_session_initialized = false;
292
        }
293
    }
294
    // }}}
295
296
    // {{{ Sticky GET Argument implementation. Register stickyGET to have it appended to all generated URLs
297
    public $sticky_get_arguments = array();
298
299
    /**
300
     * Make current get argument with specified name automatically appended to all generated URLs.
301
     *
302
     * @param string $name
303
     *
304
     * @return string
305
     */
306
    public function stickyGet($name)
307
    {
308
        $this->sticky_get_arguments[$name] = @$_GET[$name];
309
310
        return $_GET[$name];
311
    }
312
313
    /**
314
     * Remove sticky GET which was set by stickyGET.
315
     *
316
     * @param string $name
317
     */
318
    public function stickyForget($name)
319
    {
320
        unset($this->sticky_get_arguments[$name]);
321
    }
322
323
    /** @ignore - used by URL class */
324
    public function getStickyArguments()
325
    {
326
        return $this->sticky_get_arguments;
327
    }
328
329
    /**
330
     * @todo Description
331
     *
332
     * @param string $name
333
     *
334
     * @return string
335
     */
336
    public function get($name)
337
    {
338
        return $_GET[$name];
339
    }
340
341
    /**
342
     * @todo Description
343
     *
344
     * @param string $file
345
     * @param string $ext
346
     * @param string $locate
347
     *
348
     * @return $this
349
     */
350 View Code Duplication
    public function addStylesheet($file, $ext = '.css', $locate = 'css')
351
    {
352
        //$file = $this->app->locateURL('css', $file . $ext);
353
        if (@$this->included[$locate.'-'.$file.$ext]++) {
354
            return;
355
        }
356
357
        if (strpos($file, 'http') !== 0 && $file[0] != '/') {
358
            $url = $this->locateURL($locate, $file.$ext);
359
        } else {
360
            $url = $file;
361
        }
362
363
        $this->template->appendHTML(
364
            'js_include',
365
            '<link type="text/css" href="'.$url.'" rel="stylesheet" />'."\n"
366
        );
367
368
        return $this;
369
    }
370
    // }}}
371
372
    // {{{ Very Important Methods
373
    /**
374
     * Call this method from your index file. It is the main method of Agile Toolkit.
375
     */
376
    public function main()
377
    {
378
        try {
379
            // Initialize page and all elements from here
380
            $this->initLayout();
381
        } catch (Exception $e) {
382
            if (!($e instanceof Exception_Stop)) {
383
                return $this->caughtException($e);
384
            }
385
            //$this->caughtException($e);
386
        }
387
388
        try {
389
            $this->hook('post-init');
390
            $this->hook('afterInit');
391
392
            $this->hook('pre-exec');
393
            $this->hook('beforeExec');
394
395
            if (isset($_GET['submit']) && $_POST) {
396
                $this->hook('submitted');
397
            }
398
399
            $this->hook('post-submit');
400
            $this->hook('afterSubmit');
401
402
            $this->execute();
403
        } catch (Exception $e) {
404
            $this->caughtException($e);
405
        }
406
        $this->hook('saveDelayedModels');
407
    }
408
409
    /**
410
     * Main execution loop.
411
     */
412
    public function execute()
413
    {
414
        $this->rendered['sub-elements'] = array();
415
        try {
416
            $this->hook('pre-render');
417
            $this->hook('beforeRender');
418
            $this->recursiveRender();
419
            if (isset($_GET['cut_object'])) {
420
                throw new BaseException("Unable to cut object with name='".$_GET['cut_object']."'. ".
421
                    "It wasn't initialized");
422
            }
423
            if (isset($_GET['cut_region'])) {
424
                // @todo Imants: This looks something obsolete. At least property cut_region_result is never defined.
425
                if (!$this->cut_region_result) {
0 ignored issues
show
The property cut_region_result does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
426
                    throw new BaseException("Unable to cut region with name='".$_GET['cut_region']."'");
427
                }
428
                echo $this->cut_region_result;
429
430
                return;
431
            }
432
        } catch (Exception $e) {
433
            if ($e instanceof Exception_Stop) {
434
                $this->hook('cut-output');
435
                if (isset($e->result)) {
436
                    echo $e->result;
437
                }
438
                $this->hook('post-render-output');
439
440
                return;
441
            }
442
            throw $e;
443
        }
444
    }
445
446
    /**
447
     * Renders all objects inside applications and echo all output to the browser.
448
     */
449
    public function render()
450
    {
451
        $this->hook('pre-js-collection');
452
        if (isset($this->app->jquery) && $this->app->jquery) {
453
            $this->app->jquery->getJS($this);
454
        }
455
456
        if (!($this->template)) {
457
            throw new BaseException('You should specify template for APP object');
458
        }
459
460
        $this->hook('pre-render-output');
461
        if (headers_sent($file, $line)) {
462
            echo "<br />Direct output (echo or print) detected on $file:$line. <a target='_blank' "
463
                ."href='http://agiletoolkit.org/error/direct_output'>Use \$this->add('Text') instead</a>.<br />";
464
        }
465
        echo $this->template->render();
466
        $this->hook('post-render-output');
467
    }
468
    // }}}
469
470
    // {{{ Miscelanious Functions
471
    /**
472
     * Render only specified object or object with specified name.
473
     *
474
     * @param mixed $object
475
     *
476
     * @return $this
477
     */
478
    public function cut($object)
479
    {
480
        $_GET['cut_object'] = is_object($object) ? $object->name : $object;
481
482
        return $this;
483
    }
484
485
    /**
486
     * Perform instant redirect to another page.
487
     *
488
     * @param string $page
489
     * @param array  $args
490
     */
491
    public function redirect($page = null, $args = array())
492
    {
493
        /*
494
         * Redirect to specified page. $args are $_GET arguments.
495
         * Use this function instead of issuing header("Location") stuff
496
         */
497
        $url = $this->url($page, $args);
498
        if ($this->app->isAjaxOutput()) {
499
            if ($_GET['cut_page']) {
500
                echo '<script>'.$this->app->js()->redirect($url).'</script>Redirecting page...';
501
                exit;
502
            } else {
503
                $this->app->js()->redirect($url)->execute();
504
            }
505
        }
506
        header('Location: '.$url);
507
        exit;
508
    }
509
510
    /**
511
     * Called on all templates in the system, populates some system-wide tags.
512
     *
513
     * @param Template $t
514
     */
515
    public function setTags($t)
516
    {
517
        // Determine Location to atk_public
518
        if ($this->app->pathfinder && $this->app->pathfinder->atk_public) {
519
            $q = $this->app->pathfinder->atk_public->getURL();
520
        } else {
521
            $q = 'http://www.agiletoolkit.org/';
522
        }
523
524
        $t->trySet('atk_path', $q.'/');
525
        $t->trySet('base_path', $q = $this->app->pm->base_path);
526
527
        // We are using new capability of SMlite to process tags individually
528
        try {
529
            $t->eachTag($tag = 'template', array($this, '_locateTemplate'));
530
            $t->eachTag($tag = 'public', array($this, '_locatePublic'));
531
            $t->eachTag($tag = 'js', array($this, '_locateJS'));
532
            $t->eachTag($tag = 'css', array($this, '_locateCSS'));
533
            $t->eachTag($tag = 'page', array($this, '_locatePage'));
534
        } catch (BaseException $e) {
535
            throw $e
536
                ->addMoreInfo('processing_tag', $tag)
537
                ->addMoreInfo('template', $t->template_file)
538
                ;
539
        }
540
541
        $this->hook('set-tags', array($t));
542
    }
543
544
    /**
545
     * Returns true if browser is going to EVAL output.
546
     *
547
     * @todo rename into isJSOutput();
548
     *
549
     * @return bool
550
     */
551
    public function isAjaxOutput()
552
    {
553
        return isset($_POST['ajax_submit']) || ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest');
554
    }
555
556
    /** @private - NO PRIVATE !!! */
557
    public function _locateTemplate($path)
558
    {
559
        return $this->locateURL('public', $path);
560
    }
561
    public function _locatePublic($path)
562
    {
563
        return $this->locateURL('public', $path);
564
    }
565
    public function _locateJS($path)
566
    {
567
        return $this->locateURL('js', $path);
568
    }
569
    public function _locateCSS($path)
570
    {
571
        return $this->locateURL('css', $path);
572
    }
573
    public function _locatePage($path)
574
    {
575
        return $this->url($path);
576
    }
577
578
    /**
579
     * Only show $object in the final rendering.
580
     *
581
     * @deprecated 4.4
582
     */
583
    public function renderOnly($object)
584
    {
585
        return $this->cut($object);
586
    }
587
    // }}}
588
589
    // {{{ Layout implementation
590
    protected $layout_initialized = false;
591
    /**
592
     * Implements Layouts.
593
     * Layout is region in shared template which may be replaced by object.
594
     */
595
    public function initLayout()
596
    {
597
        if ($this->layout_initialized) {
598
            throw $this->exception('Please do not call initLayout() directly from init()', 'Obsolete');
599
        }
600
        $this->layout_initialized = true;
601
    }
602
603
    // TODO: layouts need to be simplified and obsolete, because we have have other layouts now.
604
    // doc/layouts
605
    //
606
    /**
607
     * Register new layout, which, if has method and tag in the template, will be rendered.
608
     *
609
     * @param string $name
610
     *
611
     * @return $this
612
     */
613
    public function addLayout($name)
614
    {
615
        if (!$this->template) {
616
            return;
617
        }
618
        // TODO: change to functionExists()
619
        if (method_exists($this, $lfunc = 'layout_'.$name)) {
620
            if ($this->template->is_set($name)) {
621
                $this->$lfunc();
622
            }
623
        }
624
625
        return $this;
626
    }
627
628
    /**
629
     * Default handling of Content page. To be replaced by App_Frontend
630
     * This function initializes content. Content is page-dependant.
631
     */
632
    public function layout_Content()
633
    {
634
        $page = str_replace('/', '_', $this->page);
635
636
        if (method_exists($this, $pagefunc = 'page_'.$page)) {
637
            $p = $this->add('Page', $this->page, 'Content');
638
            $this->$pagefunc($p);
639
        } else {
640
            $this->app->locate('page', str_replace('_', '/', $this->page).'.php');
641
            $this->add('page_'.$page, $page, 'Content');
642
            //throw new BaseException("No such page: ".$this->page);
643
        }
644
    }
645
646
    /**
647
     * Default template for the application. Redefine to add your own rules.
648
     *
649
     * @return array|string
650
     */
651
    public function defaultTemplate()
652
    {
653
        return array('html');
654
    }
655
    // }}}
656
}
657