Issues (15)

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.

src/Module.php (6 issues)

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
namespace samsonphp\router;
3
4
use samson\core\SamsonLocale;
5
use samsonframework\core\SystemInterface;
6
use samsonframework\routing\Core;
7
use samsonframework\routing\generator\Structure;
8
use samsonframework\routing\Route;
9
use samsonphp\event\Event;
10
11
/**
12
 * SamsonPHP Routing module implementation.
13
 *
14
 * @package samsonphp\router
15
 */
16
class Module extends \samson\core\CompressableExternalModule
0 ignored issues
show
Deprecated Code introduced by
The class samson\core\CompressableExternalModule has been deprecated with message: Just implement samsonframework\core\CompressInterface

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
17
{
18
    const EVENT_ROUTE_FOUND = 'router.route.found';
19
20
    /** @var string Module identifier */
21
    public $id = 'router';
22
23
    /** @var string Default controller module identifier */
24
    public $defaultModule = 'main';
25
26
    /** @var bool Use automatic locale resolving with browser response headers */
27
    public $browserLocaleRedirect = false;
28
29
    /** @var string Path to routing logic cache file */
30
    protected $cacheFile;
31
32
    /** @var string Current URL path */
33
    protected $requestURI;
34
35
    /**
36
     * Old generic "main_page" route callback searcher to match old logic.
37
     *
38
     * @return Route Default application route "/"
39
     */
40
    protected function findGenericDefaultAction()
41
    {
42
        $callback = null;
43
        // Set pointer to module
44
        $module = $this->system->getContainer()->get($this->defaultModule);
45
        // If callback is passed  - function name
46
        if (is_callable($this->defaultModule)) {
47
            // Use it as main controller callback
48
            $callback = $this->defaultModule;
49
            // Consider as module identifier is passed
50
        } elseif ($module !== null) {
51
            // Try to find module universal controller action
52
            if (method_exists($module, self::CTR_BASE)) {
53
                $callback = $module->id . '#' . self::CTR_BASE;
54
            } else if (method_exists($module, self::CTR_CACHE_BASE)) {
55
                $callback = $module->id . '#' . self::CTR_CACHE_BASE;
56
            } elseif (method_exists($module, self::CTR_UNI)) {
57
                $callback = $module->id . '#' . self::CTR_UNI;
58
            } elseif (method_exists($module, self::CTR_CACHE_UNI)) {
59
                $callback = $module->id . '#' . self::CTR_CACHE_UNI;
60
            }
61
        }
62
63
        return new Route('/', $callback, 'main_page');
0 ignored issues
show
It seems like $callback defined by null on line 42 can also be of type null; however, samsonframework\routing\Route::__construct() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
64
    }
65
66
    /**
67
     * Module initialization.
68
     *
69
     * @param array $params Initialization parameters collection
70
     * @return bool Initialization result
71
     */
72
    public function init(array $params = array())
73
    {
74
        //[PHPCOMPRESSOR(remove,start)]
75
        $modules = $this->system->getContainer()->getServices('module');
76
        // Create SamsonPHP routing table from loaded modules
77
        $rg = new GenericRouteGenerator($modules);
78
79
        // Generate web-application routes
80
        $routes = $rg->generate();
81
        $routes->add($this->findGenericDefaultAction());
82
83
        // Create cache marker
84
        $this->cacheFile = $routes->hash().'.php';
85
        // If we need to refresh cache
86
        if ($this->cache_refresh($this->cacheFile)) {
87
            $generator = new Structure($routes, new \samsonphp\generator\Generator());
0 ignored issues
show
Deprecated Code introduced by
The class samsonphp\generator\Generator has been deprecated with message: Use other separate generators.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
88
            // Generate routing logic function
89
            $routerLogic = $generator->generate();
90
91
            // Store router logic in cache
92
            file_put_contents($this->cacheFile, '<?php '."\n".$routerLogic);
93
        }
94
95
        require($this->cacheFile);
96
        //[PHPCOMPRESSOR(remove,end)]
97
98
        // Set locale resolver mode
99
        SamsonLocale::$leaveDefaultLocale = $this->browserLocaleRedirect;
100
101
        // This should be change to receive path as a parameter on initialization
102
        $pathParts = array_values(array_filter(explode(Route::DELIMITER, $_SERVER['REQUEST_URI']), function($v){
0 ignored issues
show
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
Expected 1 space after closing parenthesis; found 0
Loading history...
103
            return ($v !== '' && null !== $v);
104
        }));
105
106
         // Parse URL and store locale found bug
107
        $localeFound = SamsonLocale::parseURL($pathParts, $this->browserLocaleRedirect);
108
        // Gather URL path parts with removed locale placeholder
109
        $this->requestURI = implode(Route::DELIMITER, $pathParts);
110
111
        // Get localization data
112
        $current = SamsonLocale::current();
113
        $default = SamsonLocale::$defaultLocale;
114
115
        // Browser agent language detection logic
116
        if ($this->browserLocaleRedirect && !$localeFound) {
117
            // Redirect to browser language
118
            $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
119
            // Is browser language supported by application
120
            $langSupport = in_array($lang, SamsonLocale::get(), true);
121
122
            /**
123
             * If browser language header is supported by our web-application and we are already not on that locale
124
             * and current locale is not default.
125
             */
126
            if ($current === $default && $current !== $lang && $langSupport) {
127
                header('Location: http://'.$_SERVER['HTTP_HOST'].'/'.$lang.'/'.$this->requestURI);exit;
0 ignored issues
show
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
128
            } elseif (!$langSupport || $lang === $current) {
129
                SamsonLocale::$leaveDefaultLocale = false;
130
            }
131
        }
132
133
        // Subscribe to samsonphp\core routing event
134
        \samsonphp\event\Event::subscribe('core.routing', array($this, 'router'));
135
136
        // Continue initialization
137
        return parent::init($params);
138
    }
139
140
    /** @see \samson\core\CompressableExternalModule::afterCompress() */
141
    public function afterCompress(&$obj = null, array &$code = null)
142
    {
143
        // Compress generated php code
144
        $obj->compress_php($this->cacheFile, $this, $code, '');
145
    }
146
147
    /**
148
     * Define if HTTP request is asynchronous.
149
     *
150
     * @return bool True if request is asynchronous
151
     */
152
    public function isAsynchronousRequest()
153
    {
154
        return isset($_SERVER['HTTP_SJSASYNC']) || isset($_POST['SJSASYNC']);
155
    }
156
157
    /**
158
     * Parse route parameters received from router logic function.
159
     *
160
     * @param callable $callback Route instance
161
     * @param array $receivedParameters Collection of parsed parameters
162
     * @return array Collection of route callback needed parameters
163
     */
164
    protected function parseParameters($callback, array $receivedParameters)
165
    {
166
        $parameters = array();
167
        // Parse callback signature and get parameters list
168
        if (is_callable($callback)) {
169
            $reflectionMethod = is_array($callback)
170
                ? new \ReflectionMethod($callback[0], $callback[1])
171
                : new \ReflectionFunction($callback);
172
            foreach ($reflectionMethod->getParameters() as $parameter) {
173
                $parameters[] = $parameter->getName();
174
            }
175
        }
176
177
        // Gather parsed route parameters in correct order
178
        $foundParameters = array();
179
        foreach ($parameters as $name) {
180
            // Add to parameters collection
181
            $parameterValue = &$receivedParameters[$name];
182
            if (isset($parameterValue) && isset($parameterValue{0})) {
183
                $foundParameters[] = $parameterValue;
184
            }
185
        }
186
        return $foundParameters;
187
    }
188
189
    /**
190
     * SamsonPHP core.routing event handler
191
     *
192
     * @param SystemInterface $core Pointer to core object
193
     * @param mixed $result Return value as routing result
194
     * @return bool Routing result
195
     */
196
    public function router(SystemInterface &$core, &$result)
197
    {
198
        //elapsed('Start routing');
199
        // Flag for matching SamsonPHP asynchronous requests
200
        $async = $this->isAsynchronousRequest();
201
        // Get HTTP request path
202
        $path = $this->requestURI;//$_SERVER['REQUEST_URI'];
203
        // Get HTTP request method
204
        $method = $_SERVER['REQUEST_METHOD'];
205
        // Prepend HTTP request type, true - asynchronous
206
        $method = ($async ? GenericRouteGenerator::ASYNC_PREFIX : '').$method;
207
208
        $result = false;
209
210
        // Remove first slash if present, add method to path, remove GET params, remove trailing slash
211
        $path = rtrim(ltrim(strtok($path, '?'), '/'), '/');
212
213
        /** @var mixed $routeMetadata Dispatching result route metadata */
214
        if (is_array($routeMetadata = call_user_func(Core::ROUTING_LOGIC_FUNCTION, $path, $method))) {
215
            // Check found route
216
            if (count($routeMetadata) === 3) {
217
                // Get callback info
218
                list($module, $method) = explode("#", $routeMetadata[2]);
219
                // Get module
220
                $module = $core->module($module);
221
                // Create callback
222
                $callback = array($module, $method);
223
    
224
                // Trigger found route event
225
                Event::fire(self::EVENT_ROUTE_FOUND, array(&$module, $callback));
226
    
227
                // Check if we have vaild callback
228
                if (is_callable($callback)) {
229
                    // Get object from callback and set it as current active core module
230
                    $core->active($module);
231
                    // Routing result
232
                    $result = call_user_func_array(
233
                        $callback,
234
                        $this->parseParameters($callback, $routeMetadata[1])
235
                    );
236
    
237
                    // If this is cached method
238
                    if (stripos($method, self::CACHE_PREFIX) !== false) {
239
                        // perform caching
240
                        $core->cached();
241
                    }
242
    
243
                    // If this route is asynchronous
244
                    if ($async) {
245
                        // Set async response
246
                        $core->async(true);
247
    
248
                        // If controller action has failed
249
                        if (!isset($result['status']) || !$result['status']) {
250
                            $result['message'] = "\n" . 'Event failed: ' . $routeMetadata[0];
251
                            $result['status'] = 0;
252
                        }
253
    
254
                        // Encode event result as json object
255
                        echo json_encode($result, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
256
    
257
                        // Mark as successful
258
                        $result = true;
259
                    }
260
                }
261
262
                // If no result is passed - consider success
263
                $result = $result !== false ? true : $result;
264
            }
265
        }
266
267
        //elapsed('Finished routing');
268
        // Return true or false depending on $result
269
        return $result;
270
    }
271
}
272