Issues (48)

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/Application.php (5 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
3
namespace Garden;
4
5
use Garden\Exception\NotFoundException;
6
7
class Application {
8
    /// Properties ///
9
    protected static $instances;
10
11
    /**
12
     * @var Request The current request.
13
     */
14
    public $request;
15
16
    /**
17
     *
18
     * @var Response The current response.
19
     */
20
    public $response;
21
22
    /**
23
     * @var array An array of route objects.
24
     */
25
    protected $routes;
26
27
    /// Methods ///
28
29 44
    public function __construct($name = 'default') {
30 44
        $this->routes = array();
31
32 44
        self::$instances[$name] = $this;
33 44
    }
34
35
    public static function instance($name = 'default') {
36
        if (!isset(self::$instances[$name])) {
37
            self::$instances[$name] = new Application($name);
38
        }
39
        return self::$instances[$name];
40
    }
41
42
    /**
43
     * Get all of the matched routes for a request.
44
     *
45
     * @param Request $request The {@link Request} to match against.
46
     * @return array An array of arrays corresponding to matching routes and their args.
47
     */
48 44
    public function matchRoutes(Request $request) {
49 44
        $result = array();
50
51 44
        foreach ($this->routes as $route) {
52 44
            $matches = $route->matches($request, $this);
53 44
            if ($matches) {
54 43
                $result[] = array($route, $matches);
55 43
            }
56 44
        }
57 44
        return $result;
58
    }
59
60
    /**
61
     * Add a new route.
62
     *
63
     * @param string|Route $pathOrRoute The path to the route or the {@link Route} object itself.
64
     * @param callable|string|null $callback Either a callback to map the route to or a string representing
65
     * a format for {@link sprintf()}.
66
     * @return Route Returns the route that was added.
67
     * @throws \InvalidArgumentException Throws an exceptio if {@link $path} isn't a string or {@link Route}.
68
     */
69 44
    public function route($pathOrRoute, $callback = null) {
70 44
        if (is_object($pathOrRoute) && $pathOrRoute instanceof Route) {
71
            $route = $pathOrRoute;
72 44
        } elseif (is_string($pathOrRoute) && $callback !== null) {
73 44
            $route = Route::create($pathOrRoute, $callback);
74 44
        } else {
75
            throw new \InvalidArgumentException("Argument #1 must be either a Garden\\Route or a string.", 500);
76
        }
77 44
        $this->routes[] = $route;
78 44
        return $route;
79
    }
80
81
    /**
82
     * Route to a GET request.
83
     *
84
     * @param string $pattern The url pattern to match.
85
     * @param callable $callback The callback to execute on the route.
86
     * @return CallbackRoute Returns the new route.
87
     */
88 1
    public function get($pattern, callable $callback) {
89 1
        return $this->route($pattern, $callback)->methods('GET');
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->route($pattern, $...lback)->methods('GET'); of type Garden\Route|array adds the type array to the return on line 89 which is incompatible with the return type documented by Garden\Application::get of type Garden\CallbackRoute.
Loading history...
90
    }
91
92
    /**
93
     * Route to a POST request.
94
     *
95
     * @param string $pattern The url pattern to match.
96
     * @param callable $callback The callback to execute on the route.
97
     * @return CallbackRoute Returns the new route.
98
     */
99
    public function post($pattern, callable $callback) {
100
        return $this->route($pattern, $callback)->methods('POST');
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->route($pattern, $...back)->methods('POST'); of type Garden\Route|array adds the type array to the return on line 100 which is incompatible with the return type documented by Garden\Application::post of type Garden\CallbackRoute.
Loading history...
101
    }
102
103
    /**
104
     * Route to a PUT request.
105
     *
106
     * @param string $pattern The url pattern to match.
107
     * @param callable $callback The callback to execute on the route.
108
     * @return CallbackRoute Returns the new route.
109
     */
110
    public function put($pattern, callable $callback) {
111
        return $this->route($pattern, $callback)->methods('PUT');
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->route($pattern, $...lback)->methods('PUT'); of type Garden\Route|array adds the type array to the return on line 111 which is incompatible with the return type documented by Garden\Application::put of type Garden\CallbackRoute.
Loading history...
112
    }
113
114
    /**
115
     * Route to a PATCH request.
116
     *
117
     * @param string $pattern The url pattern to match.
118
     * @param callable $callback The callback to execute on the route.
119
     * @return CallbackRoute Returns the new route.
120
     */
121
    public function patch($pattern, callable $callback) {
122
        return $this->route($pattern, $callback)->methods('PATCH');
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->route($pattern, $...ack)->methods('PATCH'); of type Garden\Route|array adds the type array to the return on line 122 which is incompatible with the return type documented by Garden\Application::patch of type Garden\CallbackRoute.
Loading history...
123
    }
124
125
    /**
126
     * Route to a DELETE request.
127
     *
128
     * @param string $pattern The url pattern to match.
129
     * @param callable $callback The callback to execute on the route.
130
     * @return CallbackRoute Returns the new route.
131
     */
132
    public function delete($pattern, callable $callback) {
133
        return $this->route($pattern, $callback)->methods('DELETE');
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->route($pattern, $...ck)->methods('DELETE'); of type Garden\Route|array adds the type array to the return on line 133 which is incompatible with the return type documented by Garden\Application::delete of type Garden\CallbackRoute.
Loading history...
134
    }
135
136
    /**
137
     * Run the application against a {@link Request}.
138
     *
139
     * @param Request|null $request A {@link Request} to run the application against or null to run against a request
140
     * on the current environment.
141
     * @return mixed Returns a response appropriate to the request's ACCEPT header.
142
     */
143 44
    public function run(Request $request = null) {
144 44
        if ($request === null) {
145
            $request = new Request();
146
        }
147 44
        $this->request = $request;
148 44
        $requestBak = Request::current($request);
149
150
        // Grab all of the matched routes.
151 44
        $routes = $this->matchRoutes($this->request);
152
153
        // Try all of the matched routes in turn.
154 44
        $dispatched = false;
155 44
        $result = null;
156
        try {
157 44
            foreach ($routes as $route_args) {
158 43
                list($route, $args) = $route_args;
159
160
                try {
161
                    // Dispatch the first matched route.
162 43
                    ob_start();
163 43
                    $response = $route->dispatch($request, $args);
164 23
                    $body = ob_get_clean();
165
166
                    $result = [
167 23
                        'routing' => $args,
168 23
                        'response' => $response,
169
                        'body' => $body
170 23
                    ];
171
172
                    // Once a route has been successfully dispatched we break and don't dispatch anymore.
173 23
                    $dispatched = true;
174 23
                    break;
175 21
                } catch (Exception\Pass $pex) {
176 2
                    ob_end_clean();
177
                    // If the route throws a pass then continue on to the next route.
178 2
                    continue;
179 19
                } catch (\Exception $ex) {
180 19
                    ob_end_clean();
181 19
                    throw $ex;
182
                }
183 25
            }
184
185 25
            if (!$dispatched) {
186 4
                throw new NotFoundException();
187
            }
188 44
        } catch (\Exception $ex) {
189 23
            $result = $ex;
190
        }
191
192 44
        $result = $this->finalize($result);
193 23
        Request::current($requestBak);
194
195 23
        return $result;
196
    }
197
198
    /**
199
     * Finalize the result from a dispatch.
200
     *
201
     * @param mixed $result The result of the dispatch.
202
     * @return mixed Returns relevant debug data or processes the response.
203
     * @throws \Exception Throws an exception when finalizing internal content types and the result is an exception.
204
     */
205 44
    protected function finalize($result) {
206 44
        $response = Response::create($result);
207 44
        $response->meta(['request' => $this->request], true);
208 44
        $response->contentTypeFromAccept($this->request->getEnv('HTTP_ACCEPT'));
209 44
        $response->contentAsset($this->request->getEnv('HTTP_X_ASSET'));
210
211 44
        $contentType = $response->contentType();
212
213 44
        if ($this->request->getMethod() === Request::METHOD_HEAD) {
214
            $response->flushHeaders();
215
            return null;
216
        }
217
218
        // Check for known response types.
219
        switch ($contentType) {
220 44
            case 'application/internal':
221 44
                if ($result instanceof \Exception) {
222 23
                    throw $result;
223
                }
224
225 23
                if ($response->contentAsset() === 'response') {
226
                    return $response;
227
                } else {
228 23
                    return $response->jsonSerialize();
229
                }
230
                // No break because everything returns.
231
            case 'application/json':
232
                $response->flushHeaders();
233
                echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
234
                break;
235
            default:
236
                $data = $response->data();
237
                if (is_string($data)) {
238
                    $response->flushHeaders();
239
                    echo $data;
240
                } else {
241
                    $response->status(415);
242
                    $response->flushHeaders();
243
                    echo "Unsupported response type: $contentType";
244
                }
245
                break;
246
        }
247
        return null;
248
    }
249
}
250