MaartenStaa /
laravel-41-route-caching
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php namespace MaartenStaa\Routing; |
||
| 2 | |||
| 3 | /** |
||
| 4 | * Copyright (c) 2015 by Maarten Staa. |
||
| 5 | * |
||
| 6 | * Some rights reserved. |
||
| 7 | * |
||
| 8 | * Redistribution and use in source and binary forms, with or without |
||
| 9 | * modification, are permitted provided that the following conditions are |
||
| 10 | * met: |
||
| 11 | * |
||
| 12 | * * Redistributions of source code must retain the above copyright |
||
| 13 | * notice, this list of conditions and the following disclaimer. |
||
| 14 | * |
||
| 15 | * * Redistributions in binary form must reproduce the above |
||
| 16 | * copyright notice, this list of conditions and the following |
||
| 17 | * disclaimer in the documentation and/or other materials provided |
||
| 18 | * with the distribution. |
||
| 19 | * |
||
| 20 | * * The names of the contributors may not be used to endorse or |
||
| 21 | * promote products derived from this software without specific |
||
| 22 | * prior written permission. |
||
| 23 | * |
||
| 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||
| 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||
| 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||
| 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||
| 28 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||
| 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||
| 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||
| 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||
| 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
| 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||
| 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
| 35 | */ |
||
| 36 | |||
| 37 | use Closure; |
||
| 38 | use Illuminate\Container\Container; |
||
| 39 | use Illuminate\Events\Dispatcher; |
||
| 40 | use Illuminate\Routing\Router as LaravelRouter; |
||
| 41 | |||
| 42 | class Router extends LaravelRouter |
||
| 43 | { |
||
| 44 | /** |
||
| 45 | * Version of the cache key |
||
| 46 | * |
||
| 47 | * @var string |
||
| 48 | */ |
||
| 49 | protected $cacheVersion = 'v1'; |
||
| 50 | |||
| 51 | /** |
||
| 52 | * Create a new Router instance. |
||
| 53 | * |
||
| 54 | * @param \Illuminate\Events\Dispatcher $events |
||
| 55 | * @param \Illuminate\Container\Container|null $container |
||
| 56 | */ |
||
| 57 | 44 | public function __construct(Dispatcher $events, Container $container = null) |
|
| 58 | { |
||
| 59 | 44 | parent::__construct($events, $container); |
|
| 60 | |||
| 61 | 44 | $this->routes = new RouteCollection; |
|
| 62 | 44 | } |
|
| 63 | |||
| 64 | /** |
||
| 65 | * Indicate that the routes that are defined in the given callback |
||
| 66 | * should be cached. |
||
| 67 | * |
||
| 68 | * @param string $filename |
||
| 69 | * @param Closure $callback |
||
| 70 | * @param int $cacheMinutes |
||
| 71 | * @return string |
||
| 72 | */ |
||
| 73 | 36 | public function cache($filename, Closure $callback, $cacheMinutes = 1440) |
|
| 74 | { |
||
| 75 | // If $cacheMinutes is 0 or lower, there is no need to cache anything. |
||
| 76 | 36 | if ($cacheMinutes <= 0) { |
|
| 77 | // Call closure to define routes that should be cached. |
||
| 78 | 4 | call_user_func($callback, $this); |
|
| 79 | |||
| 80 | // No cache key. |
||
| 81 | 4 | return null; |
|
| 82 | } |
||
| 83 | |||
| 84 | 32 | $cacher = $this->container['cache']; |
|
| 85 | 32 | $cacheKey = $this->getCacheKey($filename); |
|
| 86 | |||
| 87 | // Check if the current route group is cached. |
||
| 88 | 32 | if (($cache = $cacher->get($cacheKey)) !== null) { |
|
| 89 | 28 | $this->routes->restoreRouteCache($cache); |
|
|
0 ignored issues
–
show
|
|||
| 90 | 28 | } else { |
|
| 91 | // Back up current RouteCollection contents. |
||
| 92 | 32 | $this->routes->saveRouteCollection(); |
|
|
0 ignored issues
–
show
It seems like you code against a specific sub-type and not the parent class
Illuminate\Routing\RouteCollection as the method saveRouteCollection() does only exist in the following sub-classes of Illuminate\Routing\RouteCollection: MaartenStaa\Routing\RouteCollection. Maybe you want to instanceof check for one of these explicitly?
Let’s take a look at an example: abstract class User
{
/** @return string */
abstract public function getPassword();
}
class MyUser extends User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
Loading history...
|
|||
| 93 | |||
| 94 | // Call closure to define routes that should be cached. |
||
| 95 | 32 | call_user_func($callback, $this); |
|
| 96 | |||
| 97 | // Put routes in cache. |
||
| 98 | 32 | $cache = $this->routes->getCacheableRoutes(); |
|
|
0 ignored issues
–
show
It seems like you code against a specific sub-type and not the parent class
Illuminate\Routing\RouteCollection as the method getCacheableRoutes() does only exist in the following sub-classes of Illuminate\Routing\RouteCollection: MaartenStaa\Routing\RouteCollection. Maybe you want to instanceof check for one of these explicitly?
Let’s take a look at an example: abstract class User
{
/** @return string */
abstract public function getPassword();
}
class MyUser extends User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
Loading history...
|
|||
| 99 | 32 | $cacher->put($cacheKey, $cache, $cacheMinutes); |
|
| 100 | |||
| 101 | // And restore the routes that shouldn't be cached. |
||
| 102 | 32 | $this->routes->restoreRouteCollection(); |
|
|
0 ignored issues
–
show
It seems like you code against a specific sub-type and not the parent class
Illuminate\Routing\RouteCollection as the method restoreRouteCollection() does only exist in the following sub-classes of Illuminate\Routing\RouteCollection: MaartenStaa\Routing\RouteCollection. Maybe you want to instanceof check for one of these explicitly?
Let’s take a look at an example: abstract class User
{
/** @return string */
abstract public function getPassword();
}
class MyUser extends User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
Loading history...
|
|||
| 103 | } |
||
| 104 | |||
| 105 | 32 | return $cacheKey; |
|
| 106 | } |
||
| 107 | |||
| 108 | /** |
||
| 109 | * Clear the cached data for the given routes file. |
||
| 110 | * |
||
| 111 | * @param string $filename |
||
| 112 | */ |
||
| 113 | 4 | public function clearCache($filename) |
|
| 114 | { |
||
| 115 | 4 | $cacher = $this->container['cache']; |
|
| 116 | |||
| 117 | 4 | $cacher->forget($this->getCacheKey($filename)); |
|
| 118 | 4 | } |
|
| 119 | |||
| 120 | /** |
||
| 121 | * Get the key under which the routes cache for the given file should be stored. |
||
| 122 | * |
||
| 123 | * @param string $filename |
||
| 124 | * @return string |
||
| 125 | */ |
||
| 126 | 32 | protected function getCacheKey($filename) |
|
| 127 | { |
||
| 128 | 32 | return 'routes.cache.'.$this->cacheVersion.'.'.md5($filename).filemtime($filename); |
|
| 129 | } |
||
| 130 | |||
| 131 | /** |
||
| 132 | * Determine if the action is routing to a controller. |
||
| 133 | * |
||
| 134 | * @param array $action |
||
| 135 | * @return bool |
||
| 136 | */ |
||
| 137 | 44 | public function routingToController($action) |
|
| 138 | { |
||
| 139 | 44 | return parent::routingToController($action); |
|
| 140 | } |
||
| 141 | |||
| 142 | /** |
||
| 143 | * Add a controller based route action to the action array. |
||
| 144 | * |
||
| 145 | * @param array|string $action |
||
| 146 | * @return array |
||
| 147 | */ |
||
| 148 | 36 | protected function getControllerAction($action) |
|
| 149 | { |
||
| 150 | 36 | if (is_string($action) === true) { |
|
| 151 | 36 | $action = array('uses' => $action); |
|
| 152 | 36 | } |
|
| 153 | |||
| 154 | // Here we'll get an instance of this controller dispatcher and hand it off to |
||
| 155 | // the Closure so it will be used to resolve the class instances out of our |
||
| 156 | // IoC container instance and call the appropriate methods on the class. |
||
| 157 | 36 | if (count($this->groupStack) > 0) { |
|
| 158 | 4 | $action['uses'] = $this->prependGroupUses($action['uses']); |
|
| 159 | 4 | } |
|
| 160 | |||
| 161 | // Here we'll get an instance of this controller dispatcher and hand it off to |
||
| 162 | // the Closure so it will be used to resolve the class instances out of our |
||
| 163 | // IoC container instance and call the appropriate methods on the class. |
||
| 164 | 36 | $action['controller'] = $action['uses']; |
|
| 165 | |||
| 166 | 36 | $closure = $action['uses']; |
|
| 167 | |||
| 168 | 36 | return array_set($action, 'uses', $closure); |
|
| 169 | } |
||
| 170 | |||
| 171 | /** |
||
| 172 | * Replace the string action in the given array with a Closure to call. |
||
| 173 | * |
||
| 174 | * @param array $action |
||
| 175 | * @return array |
||
| 176 | */ |
||
| 177 | 8 | public function makeControllerActionClosure(array $action) |
|
| 178 | { |
||
| 179 | 8 | $closure = $this->getClassClosure($action['uses']); |
|
| 180 | |||
| 181 | 8 | return array_set($action, 'uses', $closure); |
|
| 182 | } |
||
| 183 | |||
| 184 | /** |
||
| 185 | * Create a new route instance. |
||
| 186 | * |
||
| 187 | * @param array|string $methods |
||
| 188 | * @param string $uri |
||
| 189 | * @param mixed $action |
||
| 190 | * @return \Illuminate\Routing\Route |
||
| 191 | */ |
||
| 192 | 44 | protected function createRoute($methods, $uri, $action) |
|
| 193 | { |
||
| 194 | // If the route is routing to a controller we will parse the route action into |
||
| 195 | // an acceptable array format before registering it and creating this route |
||
| 196 | // instance itself. We need to build the Closure that will call this out. |
||
| 197 | 44 | if ($this->routingToController($action) === true) { |
|
| 198 | 36 | $action = $this->getControllerAction($action); |
|
| 199 | 36 | } |
|
| 200 | |||
| 201 | 44 | $route = $this->newRoute( |
|
| 202 | 44 | $methods, |
|
| 203 | 44 | $uri = $this->prefix($uri), |
|
| 204 | $action |
||
| 205 | 44 | ); |
|
| 206 | |||
| 207 | // If we have groups that need to be merged, we will merge them now after this |
||
| 208 | // route has already been created and is ready to go. After we're done with |
||
| 209 | // the merge we will be ready to return the route back out to the caller. |
||
| 210 | 44 | if (empty($this->groupStack) === false) { |
|
| 211 | 4 | $this->mergeController($route); |
|
| 212 | 4 | } |
|
| 213 | |||
| 214 | 44 | $this->addWhereClausesToRoute($route); |
|
| 215 | |||
| 216 | 44 | return $route; |
|
| 217 | } |
||
| 218 | |||
| 219 | /** |
||
| 220 | * Create a new Route object. |
||
| 221 | * |
||
| 222 | * @param array|string $methods |
||
| 223 | * @param string $uri |
||
| 224 | * @param mixed $action |
||
| 225 | * @return \Illuminate\Routing\Route |
||
| 226 | */ |
||
| 227 | 44 | protected function newRoute($methods, $uri, $action) |
|
| 228 | { |
||
| 229 | 44 | return new Route($methods, $uri, $action); |
|
| 230 | } |
||
| 231 | |||
| 232 | /** |
||
| 233 | * Add the necessary where clauses to the route based on its initial registration. |
||
| 234 | * |
||
| 235 | * @param \Illuminate\Routing\Route $route |
||
| 236 | * @return \Illuminate\Routing\Route |
||
| 237 | */ |
||
| 238 | 44 | protected function addWhereClausesToRoute($route) |
|
| 239 | { |
||
| 240 | 44 | $route->where( |
|
| 241 | 44 | array_merge($this->patterns, array_get($route->getAction(), 'where', array())) |
|
| 242 | 44 | ); |
|
| 243 | 44 | return $route; |
|
| 244 | } |
||
| 245 | } |
||
| 246 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the parent class: