From b9957435e6997dc95f9a607c21c6ee1d3244106c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9nzes=20Istv=C3=A1n?= Date: Tue, 21 Jun 2022 15:12:40 +0200 Subject: [PATCH 1/6] routing for php8 https://jira.profession.hu/browse/PROTECBAC-3238 --- src/Illuminate/Routing/Route.php | 28 +++- .../Routing/RouteDependencyResolverTrait.php | 112 ++++++++++++++ src/Illuminate/Routing/Router.php | 6 +- src/Illuminate/Support/Reflector.php | 142 ++++++++++++++++++ 4 files changed, 285 insertions(+), 3 deletions(-) create mode 100644 src/Illuminate/Routing/RouteDependencyResolverTrait.php create mode 100644 src/Illuminate/Support/Reflector.php diff --git a/src/Illuminate/Routing/Route.php b/src/Illuminate/Routing/Route.php index 093014f..d078e74 100644 --- a/src/Illuminate/Routing/Route.php +++ b/src/Illuminate/Routing/Route.php @@ -1,5 +1,6 @@ parameters(), function($p) { return isset($p); }); + $callable = $this->action['uses']; - return call_user_func_array($this->action['uses'], $parameters); + return $callable(...array_values($this->resolveMethodDependencies( + $this->parametersWithoutNulls(), new \ReflectionFunction($callable) + ))); } /** @@ -811,4 +823,16 @@ public function getCompiled() return $this->compiled; } + /** + * Set the container instance on the route. + * + * @param \Illuminate\Container\Container $container + * @return $this + */ + public function setContainer(Container $container) + { + $this->container = $container; + + return $this; + } } diff --git a/src/Illuminate/Routing/RouteDependencyResolverTrait.php b/src/Illuminate/Routing/RouteDependencyResolverTrait.php new file mode 100644 index 0000000..a288945 --- /dev/null +++ b/src/Illuminate/Routing/RouteDependencyResolverTrait.php @@ -0,0 +1,112 @@ +resolveMethodDependencies( + $parameters, new ReflectionMethod($instance, $method) + ); + } + + /** + * Resolve the given method's type-hinted dependencies. + * + * @param array $parameters + * @param \ReflectionFunctionAbstract $reflector + * @return array + */ + public function resolveMethodDependencies(array $parameters, ReflectionFunctionAbstract $reflector) + { + $instanceCount = 0; + + $values = array_values($parameters); + + $skippableValue = new stdClass; + + foreach ($reflector->getParameters() as $key => $parameter) { + $instance = $this->transformDependency($parameter, $parameters, $skippableValue); + + if ($instance !== $skippableValue) { + $instanceCount++; + + $this->spliceIntoParameters($parameters, $key, $instance); + } elseif (! isset($values[$key - $instanceCount]) && + $parameter->isDefaultValueAvailable()) { + $this->spliceIntoParameters($parameters, $key, $parameter->getDefaultValue()); + } + } + + return $parameters; + } + + /** + * Attempt to transform the given parameter into a class instance. + * + * @param \ReflectionParameter $parameter + * @param array $parameters + * @param object $skippableValue + * @return mixed + */ + protected function transformDependency(ReflectionParameter $parameter, $parameters, $skippableValue) + { + $className = Reflector::getParameterClassName($parameter); + + // If the parameter has a type-hinted class, we will check to see if it is already in + // the list of parameters. If it is we will just skip it as it is probably a model + // binding and we do not want to mess with those; otherwise, we resolve it here. + if ($className && ! $this->alreadyInParameters($className, $parameters)) { + return $parameter->isDefaultValueAvailable() ? null : $this->container->make($className); + } + + return $skippableValue; + } + + /** + * Determine if an object of the given class is in a list of parameters. + * + * @param string $class + * @param array $parameters + * @return bool + */ + protected function alreadyInParameters($class, array $parameters) + { + return ! is_null(Arr::first($parameters, fn ($value) => $value instanceof $class)); + } + + /** + * Splice the given value into the parameter list. + * + * @param array $parameters + * @param string $offset + * @param mixed $value + * @return void + */ + protected function spliceIntoParameters(array &$parameters, $offset, $value) + { + array_splice( + $parameters, $offset, 0, [$value] + ); + } +} diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 002ebaa..c5ba216 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -857,7 +857,11 @@ protected function createRoute($methods, $uri, $action) */ protected function newRoute($methods, $uri, $action) { - return new Route($methods, $uri, $action); + $route = new Route($methods, $uri, $action); + + $route->setContainer($this->container); + + return $route; } /** diff --git a/src/Illuminate/Support/Reflector.php b/src/Illuminate/Support/Reflector.php new file mode 100644 index 0000000..abf68ea --- /dev/null +++ b/src/Illuminate/Support/Reflector.php @@ -0,0 +1,142 @@ +isPublic(); + } + + if (is_object($var[0]) && method_exists($class, '__call')) { + return (new ReflectionMethod($class, '__call'))->isPublic(); + } + + if (! is_object($var[0]) && method_exists($class, '__callStatic')) { + return (new ReflectionMethod($class, '__callStatic'))->isPublic(); + } + + return false; + } + + /** + * Get the class name of the given parameter's type, if possible. + * + * @param \ReflectionParameter $parameter + * @return string|null + */ + public static function getParameterClassName($parameter) + { + $type = $parameter->getType(); + + if (! $type instanceof ReflectionNamedType || $type->isBuiltin()) { + return; + } + + return static::getTypeName($parameter, $type); + } + + /** + * Get the class names of the given parameter's type, including union types. + * + * @param \ReflectionParameter $parameter + * @return array + */ + public static function getParameterClassNames($parameter) + { + $type = $parameter->getType(); + + if (! $type instanceof ReflectionUnionType) { + return array_filter([static::getParameterClassName($parameter)]); + } + + $unionTypes = []; + + foreach ($type->getTypes() as $listedType) { + if (! $listedType instanceof ReflectionNamedType || $listedType->isBuiltin()) { + continue; + } + + $unionTypes[] = static::getTypeName($parameter, $listedType); + } + + return array_filter($unionTypes); + } + + /** + * Get the given type's class name. + * + * @param \ReflectionParameter $parameter + * @param \ReflectionNamedType $type + * @return string + */ + protected static function getTypeName($parameter, $type) + { + $name = $type->getName(); + + if (! is_null($class = $parameter->getDeclaringClass())) { + if ($name === 'self') { + return $class->getName(); + } + + if ($name === 'parent' && $parent = $class->getParentClass()) { + return $parent->getName(); + } + } + + return $name; + } + + /** + * Determine if the parameter's type is a subclass of the given type. + * + * @param \ReflectionParameter $parameter + * @param string $className + * @return bool + */ + public static function isParameterSubclassOf($parameter, $className) + { + $paramClassName = static::getParameterClassName($parameter); + + return $paramClassName + && (class_exists($paramClassName) || interface_exists($paramClassName)) + && (new ReflectionClass($paramClassName))->isSubclassOf($className); + } +} From 3ec3df72b04482daf13d20247aaa3e803a3aca81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9nzes=20Istv=C3=A1n?= Date: Mon, 14 Nov 2022 17:04:33 +0100 Subject: [PATCH 2/6] reflection parameter deprecated warnings https://jira.profession.hu/browse/PROTECBAC-3464 --- src/Illuminate/Container/Container.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 84b606e..3430455 100644 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -542,7 +542,7 @@ public function build($concrete, $parameters = array()) /** * Resolve all of the dependencies from the ReflectionParameters. * - * @param array $parameters + * @param \ReflectionParameter[] $parameters * @param array $primitives * @return array */ @@ -552,7 +552,7 @@ protected function getDependencies($parameters, array $primitives = array()) foreach ($parameters as $parameter) { - $dependency = $parameter->getClass(); + $dependency = $parameter->getType()?->getName(); // If the class is null, it means the dependency is a string or some other // primitive type which we can not resolve since it is not a class and @@ -606,7 +606,7 @@ protected function resolveClass(ReflectionParameter $parameter) { try { - return $this->make($parameter->getClass()->name); + return $this->make($parameter->getType()->getName()); } // If we can not resolve the class instance, we will check to see if the value From 7ebf327d194738dd030edf7517a55bf518a98114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9nzes=20Istv=C3=A1n?= Date: Mon, 14 Nov 2022 18:09:28 +0100 Subject: [PATCH 3/6] reflection parameter deprecated warnings https://jira.profession.hu/browse/PROTECBAC-3464 --- src/Illuminate/Container/Container.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 3430455..c9aea1f 100644 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -552,7 +552,9 @@ protected function getDependencies($parameters, array $primitives = array()) foreach ($parameters as $parameter) { - $dependency = $parameter->getType()?->getName(); + $dependency = $parameter->getType() && ! $parameter->getType()->isBuiltin() + ? new ReflectionClass($parameter->getType()->getName()) + : null; // If the class is null, it means the dependency is a string or some other // primitive type which we can not resolve since it is not a class and From 40fb8fa14da4b74e8774e11e987ab4bf27a520cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9nzes=20Istv=C3=A1n?= Date: Thu, 24 Nov 2022 10:08:15 +0100 Subject: [PATCH 4/6] phpseclib update --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 00e724b..c45c9e8 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "monolog/monolog": "~1.6", "nesbot/carbon": "~1.0", "patchwork/utf8": "~1.1", - "phpseclib/phpseclib": "0.3.*", + "phpseclib/phpseclib": "~0.3.10||~2.0", "predis/predis": "0.8.*", "stack/builder": "~1.0", "swiftmailer/swiftmailer": "~5.1", From 9f5762bbf47342d979fc9d58ef0180319b697fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9nzes=20Istv=C3=A1n?= Date: Thu, 24 Nov 2022 17:36:24 +0100 Subject: [PATCH 5/6] routing javitasok --- src/Illuminate/Routing/Controller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/Controller.php b/src/Illuminate/Routing/Controller.php index 62fe093..3a49c26 100644 --- a/src/Illuminate/Routing/Controller.php +++ b/src/Illuminate/Routing/Controller.php @@ -228,7 +228,7 @@ public function callAction($method, $parameters) { $this->setupLayout(); - $response = call_user_func_array(array($this, $method), $parameters); + $response = call_user_func_array(array($this, $method), array_values($parameters)); // If no response is returned from the controller action and a layout is being // used we will assume we want to just return the layout view as any nested From 7ed3647a6e6af9751622e2cb429eb1714297ef97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9nzes=20Istv=C3=A1n?= Date: Mon, 28 Nov 2022 12:47:58 +0100 Subject: [PATCH 6/6] security upgrades https://jira.profession.hu/browse/PROTECBAC-3530 --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index c45c9e8..ec1e437 100644 --- a/composer.json +++ b/composer.json @@ -29,11 +29,11 @@ "symfony/debug": "2.7.*", "symfony/dom-crawler": "2.7.*", "symfony/finder": "2.7.*", - "symfony/http-foundation": "2.7.*", - "symfony/http-kernel": "2.7.*", + "symfony/http-foundation": "2.8.52", + "symfony/http-kernel": "2.8.52", "symfony/process": "2.7.*", "symfony/routing": "2.7.*", - "symfony/security-core": "2.7.*", + "symfony/security-core": "2.8.*", "symfony/translation": "2.7.*" }, "replace": {