ÿØÿà JFIF    ÿÛ „  ( %!1"%)+...383-7(-.+  -%%--------+------------/----------------------------ÿÀ  ¶" ÿÄ     ÿÄ @    !1AQaq‘¡"±ÁÑð2’BRráS‚ñ3b¢CT²Ò #cÿÄ    ÿÄ '   1!AQ2a"‘±#ÿÚ   ? ò(/p‘—–¢·,M|¯G»R£üešT. ôŸEoCFñ‡ 4ÔkåóxR|µÁ¨ÓDà!Ç´µ˜‡p ÍQ‹§!þž^õWsŒy  åÁ§$á«%ºq˜™JyyË0y«^Ϗ -3ÃÏËÈ£Æ\P’ä„s&•‹Üs üô'àWt¹pñCp$bÚF`·7.^)¾!)ÒÙ˜–ÅÏš^h¾ø³·ìe±ŒaeÖ—Í,e=B}Jéߦ$$½—šÙÜCC¯¶è8β–Åkèwx LÉngT±æ¹£Ócœ¿Í/©Éÿ ‰ÚCÒ­mq;Tt¶–}0"zÖPcd1š­¤tˆ„ÐÓâqú[™öUCŠ2޿د­É(¸ßúçšmW,Ò ºf‹Ån™ÄLêÁ8üÁkÁ€L¥ÍuJ1œôrÂSŒÓöt!7EUíïb)AËi¬â-ÙHk8òÁiXYwÅ)O^"ÇØriÛô{»wRUKÙÏÚlÓ¬€‚’שT ] ªb—ÊîKC^×M“xùäñz¬zJ× {4[¹M'IÆeH1LCWÕ]œûº WDæà°OÅ‚¹c²ÞuA–rL`HšpCez‡V’— Ž‚Ë„–ñ­'µR0ÕÖ=À:±G»C\nÆÉ5*¢ †3šhQ4ýÒi$Õ1"Ü]¢p-q3zcQ$ªö¨¥æf›‘»´ÝÚHá„e²JÇ–iÊ:·à¬Øc5Åk»Laª*wi [0Ówk ¦a¦0Õ²ÅÅ‚T¸’³q:Æ<¹ú Ò˜Æ}2VE•Ѐp¡Ô3Úº …h³^LJºçì¥Ánó|˜ÖˆÎˆ+« ¦dø‘Mº–d\ªDðÛ„Ì×LÝ——Ð9Ç|•FèçVm™¨€™3õS–9Äå¢<̉Ìm¢±`·º˜&Z²ž Ë®D«¶»6™‰©­HÈ Àá«h­i³04æ’hxœi3ï¨(ÓL·†‹¶ËpŒ ƒÜÒ? :õdsÀ –3æÓ·Üjâ¬9—]8n¼&]I F£¼…ì–—Œ0v°LǐÅfÛ2TÖ’aµ˜N@ÖBSÏ^à´4-±°b×nÈÈœÆD=KdŒø…ÄÈK,›ÖR§fjü$^ÔÎ!„6^ s:Üun\ôkCÞò÷<—Lúl Í›G¹ÀPá¼Nc¡šÒ…ÙWͳœ±vÊáЄ×9‹P‰cEØ‘™›µŸP<×g1 º©Ø¬wiÁ^l5× I/';Ë+´Z‡ÓÄFÕp[Èð’ HÄ ó 9¬Dl4“é±Ï”V=^Hð;žLädÉa‚°Ë,#/Ž~²BÔÛ QãñQtIeórVB,ÏÂf‹4#Μc‹É3ZIÖ Œ¢¥·üxa‡Ãçè„jŠ[5 Ä!U?,3žÎ×…ðdÓ÷háŠA‰ìÄ4÷ÃÜZÃE{‰®+W\ZÍE[‰»µk»MÝ­`¢©†˜ÃV‹-f¢¡†¢a«eŠ%«Y¨©q%jâd,Ôq`) ¤¦…šˆ ¦E>0Ùb²t–Ÿ  ÷jsςҒKÈcø(é›;k(’#ôŒQ ™C> õ³M9óºÆµ¤çâ;uÀ)5>RÔ¸fÓ~Ȧ—’-$fe«"FâUˆÊwµPÏu w+"åÉó¨6s™Û9(À¨ù©hE°½†n`m~“@©›p!Vkhµ Á1šbEqqÊ@ºèl›2 –Yã%‘‚hÛ{a¶‡ÅÞM²¬çL34®Çl]®‹ŽØŒm'RÜe35æöˆ­Á­ cP9šeÁköo´L³Ì=p8]”‡B¶,šº|ɏdzXˆØk*ÇÚ{#ñ‰pã(€¶‡9ý'šÜ³½¯kƒ†Â’ëSOƒ•Å®H6+a¢µˆ‹Y¨b˜b+XˆÖ!°u!¢"µˆˆn2ˆ Å0Ä`Å Ô®c(ÓÜGº•Ä»Œ âWî%q.áÐÄ÷î%umÍ£+ÜQ,Vn¦-GphU¸¢X­&,Gt ·K¢ÅÅ·¥RÄÊÉbKn N­R2g$VµÕó Qr#–ÓZUÏð0ÎtÙÀœz ëöo“Îk¯n„T°"SÞ+³/…€½"ižãO%Í%&Δâ‘ËØ´IˆÓ°Ë‰ÞM3.™yçÁzit›`4C`k¢¼á!álÄï sÂ[×!¤l¾æo"ƒIÔ'@ªu)3›ô®“@Z à¾] üœ'‡4¸PÞkÁ-qÄH‰ÓÍBd´ÿ —¹°ÄA&ÊUC„öz‚‚RæŠtf¬>˜ÑidšEçÑL÷áý¡V±h§­c¿¥¨ƒ@g¼…Ýö^ÞËc.ž„æ“I[ ª+·zÐÒÚ,½Ð»¶€C›7jk$๖€Ž¾ÅÙpp¶ÍþéΤ ½ØÎŒq ñpæžÅ¥#Øâ49ÃÂK^MYV“,¶Éz_òæ:…;Õ«¦I3âJ£¤û5$7Èxün\â]Êe¯(Ÿ&Ž‹¶2<6Ćf× æ¢ƱqWı[(ÙÂŽç‚T7¨@ÈÉÍß‚ïÙ"&3TYlGށ†)†#5ŠA©^T2ÆÁ†)©†©†¤yGXÁ†©"†)©¼ÅV WS†#©]R–r‹q5ÕbâWþBh¯u+ªÅÄ×ü„nÑ^êkªÁj‰jeœWˆÕÕ`µDµ2Ì+Ä µDµµ5Ô{¤Þ0RF’H÷AÛ<ÊÁ§ ƈæ0Ñ£ê4 öÚµ[¬/1²€â<-¬šö²r×0o×w ´xÐÒË„ g01¬„åEM蛇Ã\6µE›‘fÙO k÷CºnÓ1`iîÒ² áÂ!ÑLÄÿ ³¬\õ*:M=Ç»c‹2[‰ØsÕLò\ŒK L^™üÄN\¶#» Ç\……ßïIœÉ$¸ÎñÍ®ÔHÇ Ûí/´>Li”„†g^$ 7NÍÑÑ2M2ªNg=k½Ð}Ÿl6‡ —JWˆ”ÞéT·+µ¦üÂFè¢Vs6ýÆ4»2+2IÝ9ô9®ÇGÙÇ1+Ä8;*Õ§ž½D*îÑWÚçá3Ma¤·ˆ¥t}š²Ü…Q+Æüµ8HíS”üxGéÁˆ¦Ël„éÈ 5 µÄƒ6äÜ(kIš¯S†fÖ&¸®×v|Äyˆ*禌Éù@7-®Ä[]ÎÖ¿ê`º…=:…žJVnݳvðÖKE¼‚ »mà ÷f®:Ë ™–4rð¡4` ܹçž~‹C=œ…¾Ïj|VDtK.ƒ"9 Ï ­–éXá³6WÒïIL-Ї Ç PK'\  README.mdnu[HttpKernel Component ==================== The HttpKernel component provides a structured process for converting a Request into a Response by making use of the EventDispatcher component. It's flexible enough to create full-stack frameworks, micro-frameworks or advanced CMS systems like Drupal. Sponsor ------- The HttpKernel component for Symfony 5.4/6.0 is [backed][1] by [Les-Tilleuls.coop][2]. Les-Tilleuls.coop is a team of 50+ Symfony experts who can help you design, develop and fix your projects. We provide a wide range of professional services including development, consulting, coaching, training and audits. We also are highly skilled in JS, Go and DevOps. We are a worker cooperative! Help Symfony by [sponsoring][3] its development! Resources --------- * [Documentation](https://symfony.com/doc/current/components/http_kernel.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) [1]: https://symfony.com/backers [2]: https://les-tilleuls.coop [3]: https://symfony.com/sponsor PK'\7)=//KernelInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpKernel\Bundle\BundleInterface; /** * The Kernel is the heart of the Symfony system. * * It manages an environment made of application kernel and bundles. * * @method string getBuildDir() Returns the build directory - not implementing it is deprecated since Symfony 5.2. * This directory should be used to store build artifacts, and can be read-only at runtime. * Caches written at runtime should be stored in the "cache directory" ({@see KernelInterface::getCacheDir()}). * * @author Fabien Potencier */ interface KernelInterface extends HttpKernelInterface { /** * Returns an array of bundles to register. * * @return iterable */ public function registerBundles(); /** * Loads the container configuration. */ public function registerContainerConfiguration(LoaderInterface $loader); /** * Boots the current kernel. */ public function boot(); /** * Shutdowns the kernel. * * This method is mainly useful when doing functional testing. */ public function shutdown(); /** * Gets the registered bundle instances. * * @return array */ public function getBundles(); /** * Returns a bundle. * * @return BundleInterface * * @throws \InvalidArgumentException when the bundle is not enabled */ public function getBundle(string $name); /** * Returns the file path for a given bundle resource. * * A Resource can be a file or a directory. * * The resource name must follow the following pattern: * * "@BundleName/path/to/a/file.something" * * where BundleName is the name of the bundle * and the remaining part is the relative path in the bundle. * * @return string * * @throws \InvalidArgumentException if the file cannot be found or the name is not valid * @throws \RuntimeException if the name contains invalid/unsafe characters */ public function locateResource(string $name); /** * Gets the environment. * * @return string */ public function getEnvironment(); /** * Checks if debug mode is enabled. * * @return bool */ public function isDebug(); /** * Gets the project dir (path of the project's composer file). * * @return string */ public function getProjectDir(); /** * Gets the current container. * * @return ContainerInterface */ public function getContainer(); /** * Gets the request start time (not available if debug is disabled). * * @return float */ public function getStartTime(); /** * Gets the cache directory. * * Since Symfony 5.2, the cache directory should be used for caches that are written at runtime. * For caches and artifacts that can be warmed at compile-time and deployed as read-only, * use the new "build directory" returned by the {@see getBuildDir()} method. * * @return string */ public function getCacheDir(); /** * Gets the log directory. * * @return string */ public function getLogDir(); /** * Gets the charset of the application. * * @return string */ public function getCharset(); } PK'\Ģ..KernelEvents.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent; use Symfony\Component\HttpKernel\Event\ControllerEvent; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\Event\TerminateEvent; use Symfony\Component\HttpKernel\Event\ViewEvent; /** * Contains all events thrown in the HttpKernel component. * * @author Bernhard Schussek */ final class KernelEvents { /** * The REQUEST event occurs at the very beginning of request * dispatching. * * This event allows you to create a response for a request before any * other code in the framework is executed. * * @Event("Symfony\Component\HttpKernel\Event\RequestEvent") */ public const REQUEST = 'kernel.request'; /** * The EXCEPTION event occurs when an uncaught exception appears. * * This event allows you to create a response for a thrown exception or * to modify the thrown exception. * * @Event("Symfony\Component\HttpKernel\Event\ExceptionEvent") */ public const EXCEPTION = 'kernel.exception'; /** * The CONTROLLER event occurs once a controller was found for * handling a request. * * This event allows you to change the controller that will handle the * request. * * @Event("Symfony\Component\HttpKernel\Event\ControllerEvent") */ public const CONTROLLER = 'kernel.controller'; /** * The CONTROLLER_ARGUMENTS event occurs once controller arguments have been resolved. * * This event allows you to change the arguments that will be passed to * the controller. * * @Event("Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent") */ public const CONTROLLER_ARGUMENTS = 'kernel.controller_arguments'; /** * The VIEW event occurs when the return value of a controller * is not a Response instance. * * This event allows you to create a response for the return value of the * controller. * * @Event("Symfony\Component\HttpKernel\Event\ViewEvent") */ public const VIEW = 'kernel.view'; /** * The RESPONSE event occurs once a response was created for * replying to a request. * * This event allows you to modify or replace the response that will be * replied. * * @Event("Symfony\Component\HttpKernel\Event\ResponseEvent") */ public const RESPONSE = 'kernel.response'; /** * The FINISH_REQUEST event occurs when a response was generated for a request. * * This event allows you to reset the global and environmental state of * the application, when it was changed during the request. * * @Event("Symfony\Component\HttpKernel\Event\FinishRequestEvent") */ public const FINISH_REQUEST = 'kernel.finish_request'; /** * The TERMINATE event occurs once a response was sent. * * This event allows you to run expensive post-response jobs. * * @Event("Symfony\Component\HttpKernel\Event\TerminateEvent") */ public const TERMINATE = 'kernel.terminate'; /** * Event aliases. * * These aliases can be consumed by RegisterListenersPass. */ public const ALIASES = [ ControllerArgumentsEvent::class => self::CONTROLLER_ARGUMENTS, ControllerEvent::class => self::CONTROLLER, ResponseEvent::class => self::RESPONSE, FinishRequestEvent::class => self::FINISH_REQUEST, RequestEvent::class => self::REQUEST, ViewEvent::class => self::VIEW, ExceptionEvent::class => self::EXCEPTION, TerminateEvent::class => self::TERMINATE, ]; } PK'\>EZ!CacheClearer/Psr6CacheClearer.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\CacheClearer; use Psr\Cache\CacheItemPoolInterface; /** * @author Nicolas Grekas */ class Psr6CacheClearer implements CacheClearerInterface { private $pools = []; /** * @param array $pools */ public function __construct(array $pools = []) { $this->pools = $pools; } /** * @return bool */ public function hasPool(string $name) { return isset($this->pools[$name]); } /** * @return CacheItemPoolInterface * * @throws \InvalidArgumentException If the cache pool with the given name does not exist */ public function getPool(string $name) { if (!$this->hasPool($name)) { throw new \InvalidArgumentException(sprintf('Cache pool not found: "%s".', $name)); } return $this->pools[$name]; } /** * @return bool * * @throws \InvalidArgumentException If the cache pool with the given name does not exist */ public function clearPool(string $name) { if (!isset($this->pools[$name])) { throw new \InvalidArgumentException(sprintf('Cache pool not found: "%s".', $name)); } return $this->pools[$name]->clear(); } /** * {@inheritdoc} */ public function clear(string $cacheDir) { foreach ($this->pools as $pool) { $pool->clear(); } } } PK'\QSS"CacheClearer/ChainCacheClearer.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\CacheClearer; /** * ChainCacheClearer. * * @author Dustin Dobervich * * @final */ class ChainCacheClearer implements CacheClearerInterface { private $clearers; /** * @param iterable $clearers */ public function __construct(iterable $clearers = []) { $this->clearers = $clearers; } /** * {@inheritdoc} */ public function clear(string $cacheDir) { foreach ($this->clearers as $clearer) { $clearer->clear($cacheDir); } } } PK'\#&CacheClearer/CacheClearerInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\CacheClearer; /** * CacheClearerInterface. * * @author Dustin Dobervich */ interface CacheClearerInterface { /** * Clears any caches necessary. */ public function clear(string $cacheDir); } PK'\H !Fragment/FragmentUriGenerator.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\UriSigner; /** * Generates a fragment URI. * * @author Kévin Dunglas * @author Fabien Potencier */ final class FragmentUriGenerator implements FragmentUriGeneratorInterface { private $fragmentPath; private $signer; private $requestStack; public function __construct(string $fragmentPath, UriSigner $signer = null, RequestStack $requestStack = null) { $this->fragmentPath = $fragmentPath; $this->signer = $signer; $this->requestStack = $requestStack; } /** * {@inheritDoc} */ public function generate(ControllerReference $controller, Request $request = null, bool $absolute = false, bool $strict = true, bool $sign = true): string { if (null === $request && (null === $this->requestStack || null === $request = $this->requestStack->getCurrentRequest())) { throw new \LogicException('Generating a fragment URL can only be done when handling a Request.'); } if ($sign && null === $this->signer) { throw new \LogicException('You must use a URI when using the ESI rendering strategy or set a URL signer.'); } if ($strict) { $this->checkNonScalar($controller->attributes); } // We need to forward the current _format and _locale values as we don't have // a proper routing pattern to do the job for us. // This makes things inconsistent if you switch from rendering a controller // to rendering a route if the route pattern does not contain the special // _format and _locale placeholders. if (!isset($controller->attributes['_format'])) { $controller->attributes['_format'] = $request->getRequestFormat(); } if (!isset($controller->attributes['_locale'])) { $controller->attributes['_locale'] = $request->getLocale(); } $controller->attributes['_controller'] = $controller->controller; $controller->query['_path'] = http_build_query($controller->attributes, '', '&'); $path = $this->fragmentPath.'?'.http_build_query($controller->query, '', '&'); // we need to sign the absolute URI, but want to return the path only. $fragmentUri = $sign || $absolute ? $request->getUriForPath($path) : $request->getBaseUrl().$path; if (!$sign) { return $fragmentUri; } $fragmentUri = $this->signer->sign($fragmentUri); return $absolute ? $fragmentUri : substr($fragmentUri, \strlen($request->getSchemeAndHttpHost())); } private function checkNonScalar(array $values): void { foreach ($values as $key => $value) { if (\is_array($value)) { $this->checkNonScalar($value); } elseif (!\is_scalar($value) && null !== $value) { throw new \LogicException(sprintf('Controller attributes cannot contain non-scalar/non-null values (value for key "%s" is not a scalar or null).', $key)); } } } } PK'\r%Fragment/RoutableFragmentRenderer.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\EventListener\FragmentListener; /** * Adds the possibility to generate a fragment URI for a given Controller. * * @author Fabien Potencier */ abstract class RoutableFragmentRenderer implements FragmentRendererInterface { /** * @internal */ protected $fragmentPath = '/_fragment'; /** * Sets the fragment path that triggers the fragment listener. * * @see FragmentListener */ public function setFragmentPath(string $path) { $this->fragmentPath = $path; } /** * Generates a fragment URI for a given controller. * * @param bool $absolute Whether to generate an absolute URL or not * @param bool $strict Whether to allow non-scalar attributes or not * * @return string */ protected function generateFragmentUri(ControllerReference $reference, Request $request, bool $absolute = false, bool $strict = true) { return (new FragmentUriGenerator($this->fragmentPath))->generate($reference, $request, $absolute, $strict, false); } } PK'\4@ .Fragment/AbstractSurrogateFragmentRenderer.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\HttpCache\SurrogateInterface; use Symfony\Component\HttpKernel\UriSigner; /** * Implements Surrogate rendering strategy. * * @author Fabien Potencier */ abstract class AbstractSurrogateFragmentRenderer extends RoutableFragmentRenderer { private $surrogate; private $inlineStrategy; private $signer; /** * The "fallback" strategy when surrogate is not available should always be an * instance of InlineFragmentRenderer. * * @param FragmentRendererInterface $inlineStrategy The inline strategy to use when the surrogate is not supported */ public function __construct(SurrogateInterface $surrogate = null, FragmentRendererInterface $inlineStrategy, UriSigner $signer = null) { $this->surrogate = $surrogate; $this->inlineStrategy = $inlineStrategy; $this->signer = $signer; } /** * {@inheritdoc} * * Note that if the current Request has no surrogate capability, this method * falls back to use the inline rendering strategy. * * Additional available options: * * * alt: an alternative URI to render in case of an error * * comment: a comment to add when returning the surrogate tag * * Note, that not all surrogate strategies support all options. For now * 'alt' and 'comment' are only supported by ESI. * * @see Symfony\Component\HttpKernel\HttpCache\SurrogateInterface */ public function render($uri, Request $request, array $options = []) { if (!$this->surrogate || !$this->surrogate->hasSurrogateCapability($request)) { if ($uri instanceof ControllerReference && $this->containsNonScalars($uri->attributes)) { throw new \InvalidArgumentException('Passing non-scalar values as part of URI attributes to the ESI and SSI rendering strategies is not supported. Use a different rendering strategy or pass scalar values.'); } return $this->inlineStrategy->render($uri, $request, $options); } if ($uri instanceof ControllerReference) { $uri = $this->generateSignedFragmentUri($uri, $request); } $alt = $options['alt'] ?? null; if ($alt instanceof ControllerReference) { $alt = $this->generateSignedFragmentUri($alt, $request); } $tag = $this->surrogate->renderIncludeTag($uri, $alt, $options['ignore_errors'] ?? false, $options['comment'] ?? ''); return new Response($tag); } private function generateSignedFragmentUri(ControllerReference $uri, Request $request): string { return (new FragmentUriGenerator($this->fragmentPath, $this->signer))->generate($uri, $request); } private function containsNonScalars(array $values): bool { foreach ($values as $value) { if (\is_scalar($value) || null === $value) { continue; } if (!\is_array($value) || $this->containsNonScalars($value)) { return true; } } return false; } } PK'\i4Fragment/FragmentHandler.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\Exception\HttpException; /** * Renders a URI that represents a resource fragment. * * This class handles the rendering of resource fragments that are included into * a main resource. The handling of the rendering is managed by specialized renderers. * * @author Fabien Potencier * * @see FragmentRendererInterface */ class FragmentHandler { private $debug; private $renderers = []; private $requestStack; /** * @param FragmentRendererInterface[] $renderers An array of FragmentRendererInterface instances * @param bool $debug Whether the debug mode is enabled or not */ public function __construct(RequestStack $requestStack, array $renderers = [], bool $debug = false) { $this->requestStack = $requestStack; foreach ($renderers as $renderer) { $this->addRenderer($renderer); } $this->debug = $debug; } /** * Adds a renderer. */ public function addRenderer(FragmentRendererInterface $renderer) { $this->renderers[$renderer->getName()] = $renderer; } /** * Renders a URI and returns the Response content. * * Available options: * * * ignore_errors: true to return an empty string in case of an error * * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance * * @return string|null * * @throws \InvalidArgumentException when the renderer does not exist * @throws \LogicException when no main request is being handled */ public function render($uri, string $renderer = 'inline', array $options = []) { if (!isset($options['ignore_errors'])) { $options['ignore_errors'] = !$this->debug; } if (!isset($this->renderers[$renderer])) { throw new \InvalidArgumentException(sprintf('The "%s" renderer does not exist.', $renderer)); } if (!$request = $this->requestStack->getCurrentRequest()) { throw new \LogicException('Rendering a fragment can only be done when handling a Request.'); } return $this->deliver($this->renderers[$renderer]->render($uri, $request, $options)); } /** * Delivers the Response as a string. * * When the Response is a StreamedResponse, the content is streamed immediately * instead of being returned. * * @return string|null The Response content or null when the Response is streamed * * @throws \RuntimeException when the Response is not successful */ protected function deliver(Response $response) { if (!$response->isSuccessful()) { $responseStatusCode = $response->getStatusCode(); throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %d).', $this->requestStack->getCurrentRequest()->getUri(), $responseStatusCode), 0, new HttpException($responseStatusCode)); } if (!$response instanceof StreamedResponse) { return $response->getContent(); } $response->sendContent(); return null; } } PK'\6\&Fragment/FragmentRendererInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Controller\ControllerReference; /** * Interface implemented by all rendering strategies. * * @author Fabien Potencier */ interface FragmentRendererInterface { /** * Renders a URI and returns the Response content. * * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance * * @return Response */ public function render($uri, Request $request, array $options = []); /** * Gets the name of the strategy. * * @return string */ public function getName(); } PK'\h6#Fragment/InlineFragmentRenderer.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\HttpCache\SubRequestHandler; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * Implements the inline rendering strategy where the Request is rendered by the current HTTP kernel. * * @author Fabien Potencier */ class InlineFragmentRenderer extends RoutableFragmentRenderer { private $kernel; private $dispatcher; public function __construct(HttpKernelInterface $kernel, EventDispatcherInterface $dispatcher = null) { $this->kernel = $kernel; $this->dispatcher = $dispatcher; } /** * {@inheritdoc} * * Additional available options: * * * alt: an alternative URI to render in case of an error */ public function render($uri, Request $request, array $options = []) { $reference = null; if ($uri instanceof ControllerReference) { $reference = $uri; // Remove attributes from the generated URI because if not, the Symfony // routing system will use them to populate the Request attributes. We don't // want that as we want to preserve objects (so we manually set Request attributes // below instead) $attributes = $reference->attributes; $reference->attributes = []; // The request format and locale might have been overridden by the user foreach (['_format', '_locale'] as $key) { if (isset($attributes[$key])) { $reference->attributes[$key] = $attributes[$key]; } } $uri = $this->generateFragmentUri($uri, $request, false, false); $reference->attributes = array_merge($attributes, $reference->attributes); } $subRequest = $this->createSubRequest($uri, $request); // override Request attributes as they can be objects (which are not supported by the generated URI) if (null !== $reference) { $subRequest->attributes->add($reference->attributes); } $level = ob_get_level(); try { return SubRequestHandler::handle($this->kernel, $subRequest, HttpKernelInterface::SUB_REQUEST, false); } catch (\Exception $e) { // we dispatch the exception event to trigger the logging // the response that comes back is ignored if (isset($options['ignore_errors']) && $options['ignore_errors'] && $this->dispatcher) { $event = new ExceptionEvent($this->kernel, $request, HttpKernelInterface::SUB_REQUEST, $e); $this->dispatcher->dispatch($event, KernelEvents::EXCEPTION); } // let's clean up the output buffers that were created by the sub-request Response::closeOutputBuffers($level, false); if (isset($options['alt'])) { $alt = $options['alt']; unset($options['alt']); return $this->render($alt, $request, $options); } if (!isset($options['ignore_errors']) || !$options['ignore_errors']) { throw $e; } return new Response(); } } protected function createSubRequest(string $uri, Request $request) { $cookies = $request->cookies->all(); $server = $request->server->all(); unset($server['HTTP_IF_MODIFIED_SINCE']); unset($server['HTTP_IF_NONE_MATCH']); $subRequest = Request::create($uri, 'get', [], $cookies, [], $server); if ($request->headers->has('Surrogate-Capability')) { $subRequest->headers->set('Surrogate-Capability', $request->headers->get('Surrogate-Capability')); } static $setSession; if (null === $setSession) { $setSession = \Closure::bind(static function ($subRequest, $request) { $subRequest->session = $request->session; }, null, Request::class); } $setSession($subRequest, $request); if ($request->get('_format')) { $subRequest->attributes->set('_format', $request->get('_format')); } if ($request->getDefaultLocale() !== $request->getLocale()) { $subRequest->setLocale($request->getLocale()); } return $subRequest; } /** * {@inheritdoc} */ public function getName() { return 'inline'; } } PK'\_Y  *Fragment/FragmentUriGeneratorInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ControllerReference; /** * Interface implemented by rendering strategies able to generate an URL for a fragment. * * @author Kévin Dunglas */ interface FragmentUriGeneratorInterface { /** * Generates a fragment URI for a given controller. * * @param bool $absolute Whether to generate an absolute URL or not * @param bool $strict Whether to allow non-scalar attributes or not * @param bool $sign Whether to sign the URL or not */ public function generate(ControllerReference $controller, Request $request = null, bool $absolute = false, bool $strict = true, bool $sign = true): string; } PK'\@  %Fragment/HIncludeFragmentRenderer.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\UriSigner; use Twig\Environment; /** * Implements the Hinclude rendering strategy. * * @author Fabien Potencier */ class HIncludeFragmentRenderer extends RoutableFragmentRenderer { private $globalDefaultTemplate; private $signer; private $twig; private $charset; /** * @param string $globalDefaultTemplate The global default content (it can be a template name or the content) */ public function __construct(Environment $twig = null, UriSigner $signer = null, string $globalDefaultTemplate = null, string $charset = 'utf-8') { $this->twig = $twig; $this->globalDefaultTemplate = $globalDefaultTemplate; $this->signer = $signer; $this->charset = $charset; } /** * Checks if a templating engine has been set. * * @return bool */ public function hasTemplating() { return null !== $this->twig; } /** * {@inheritdoc} * * Additional available options: * * * default: The default content (it can be a template name or the content) * * id: An optional hx:include tag id attribute * * attributes: An optional array of hx:include tag attributes */ public function render($uri, Request $request, array $options = []) { if ($uri instanceof ControllerReference) { $uri = (new FragmentUriGenerator($this->fragmentPath, $this->signer))->generate($uri, $request); } // We need to replace ampersands in the URI with the encoded form in order to return valid html/xml content. $uri = str_replace('&', '&', $uri); $template = $options['default'] ?? $this->globalDefaultTemplate; if (null !== $this->twig && $template && $this->twig->getLoader()->exists($template)) { $content = $this->twig->render($template); } else { $content = $template; } $attributes = isset($options['attributes']) && \is_array($options['attributes']) ? $options['attributes'] : []; if (isset($options['id']) && $options['id']) { $attributes['id'] = $options['id']; } $renderedAttributes = ''; if (\count($attributes) > 0) { $flags = \ENT_QUOTES | \ENT_SUBSTITUTE; foreach ($attributes as $attribute => $value) { $renderedAttributes .= sprintf( ' %s="%s"', htmlspecialchars($attribute, $flags, $this->charset, false), htmlspecialchars($value, $flags, $this->charset, false) ); } } return new Response(sprintf('%s', $uri, $renderedAttributes, $content)); } /** * {@inheritdoc} */ public function getName() { return 'hinclude'; } } PK'\@933 Fragment/EsiFragmentRenderer.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; /** * Implements the ESI rendering strategy. * * @author Fabien Potencier */ class EsiFragmentRenderer extends AbstractSurrogateFragmentRenderer { /** * {@inheritdoc} */ public function getName() { return 'esi'; } } PK'\33 Fragment/SsiFragmentRenderer.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; /** * Implements the SSI rendering strategy. * * @author Sebastian Krebs */ class SsiFragmentRenderer extends AbstractSurrogateFragmentRenderer { /** * {@inheritdoc} */ public function getName() { return 'ssi'; } } PK'\\>HttpKernelInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * HttpKernelInterface handles a Request to convert it to a Response. * * @author Fabien Potencier */ interface HttpKernelInterface { public const MAIN_REQUEST = 1; public const SUB_REQUEST = 2; /** * @deprecated since symfony/http-kernel 5.3, use MAIN_REQUEST instead. * To ease the migration, this constant won't be removed until Symfony 7.0. */ public const MASTER_REQUEST = self::MAIN_REQUEST; /** * Handles a Request to convert it to a Response. * * When $catch is true, the implementation must catch all exceptions * and do its best to convert them to a Response instance. * * @param int $type The type of the request * (one of HttpKernelInterface::MAIN_REQUEST or HttpKernelInterface::SUB_REQUEST) * @param bool $catch Whether to catch exceptions or not * * @return Response * * @throws \Exception When an Exception occurs during processing */ public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true); } PK'\}(}(HttpKernel.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface; use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent; use Symfony\Component\HttpKernel\Event\ControllerEvent; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\Event\TerminateEvent; use Symfony\Component\HttpKernel\Event\ViewEvent; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\ControllerDoesNotReturnResponseException; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; // Help opcache.preload discover always-needed symbols class_exists(ControllerArgumentsEvent::class); class_exists(ControllerEvent::class); class_exists(ExceptionEvent::class); class_exists(FinishRequestEvent::class); class_exists(RequestEvent::class); class_exists(ResponseEvent::class); class_exists(TerminateEvent::class); class_exists(ViewEvent::class); class_exists(KernelEvents::class); /** * HttpKernel notifies events to convert a Request object to a Response one. * * @author Fabien Potencier */ class HttpKernel implements HttpKernelInterface, TerminableInterface { protected $dispatcher; protected $resolver; protected $requestStack; private $argumentResolver; public function __construct(EventDispatcherInterface $dispatcher, ControllerResolverInterface $resolver, RequestStack $requestStack = null, ArgumentResolverInterface $argumentResolver = null) { $this->dispatcher = $dispatcher; $this->resolver = $resolver; $this->requestStack = $requestStack ?? new RequestStack(); $this->argumentResolver = $argumentResolver ?? new ArgumentResolver(); } /** * {@inheritdoc} */ public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true) { $request->headers->set('X-Php-Ob-Level', (string) ob_get_level()); $this->requestStack->push($request); try { return $this->handleRaw($request, $type); } catch (\Exception $e) { if ($e instanceof RequestExceptionInterface) { $e = new BadRequestHttpException($e->getMessage(), $e); } if (false === $catch) { $this->finishRequest($request, $type); throw $e; } return $this->handleThrowable($e, $request, $type); } finally { $this->requestStack->pop(); } } /** * {@inheritdoc} */ public function terminate(Request $request, Response $response) { $this->dispatcher->dispatch(new TerminateEvent($this, $request, $response), KernelEvents::TERMINATE); } /** * @internal */ public function terminateWithException(\Throwable $exception, Request $request = null) { if (!$request = $request ?: $this->requestStack->getMainRequest()) { throw $exception; } if ($pop = $request !== $this->requestStack->getMainRequest()) { $this->requestStack->push($request); } try { $response = $this->handleThrowable($exception, $request, self::MAIN_REQUEST); } finally { if ($pop) { $this->requestStack->pop(); } } $response->sendHeaders(); $response->sendContent(); $this->terminate($request, $response); } /** * Handles a request to convert it to a response. * * Exceptions are not caught. * * @throws \LogicException If one of the listener does not behave as expected * @throws NotFoundHttpException When controller cannot be found */ private function handleRaw(Request $request, int $type = self::MAIN_REQUEST): Response { // request $event = new RequestEvent($this, $request, $type); $this->dispatcher->dispatch($event, KernelEvents::REQUEST); if ($event->hasResponse()) { return $this->filterResponse($event->getResponse(), $request, $type); } // load controller if (false === $controller = $this->resolver->getController($request)) { throw new NotFoundHttpException(sprintf('Unable to find the controller for path "%s". The route is wrongly configured.', $request->getPathInfo())); } $event = new ControllerEvent($this, $controller, $request, $type); $this->dispatcher->dispatch($event, KernelEvents::CONTROLLER); $controller = $event->getController(); // controller arguments $arguments = $this->argumentResolver->getArguments($request, $controller); $event = new ControllerArgumentsEvent($this, $controller, $arguments, $request, $type); $this->dispatcher->dispatch($event, KernelEvents::CONTROLLER_ARGUMENTS); $controller = $event->getController(); $arguments = $event->getArguments(); // call controller $response = $controller(...$arguments); // view if (!$response instanceof Response) { $event = new ViewEvent($this, $request, $type, $response); $this->dispatcher->dispatch($event, KernelEvents::VIEW); if ($event->hasResponse()) { $response = $event->getResponse(); } else { $msg = sprintf('The controller must return a "Symfony\Component\HttpFoundation\Response" object but it returned %s.', $this->varToString($response)); // the user may have forgotten to return something if (null === $response) { $msg .= ' Did you forget to add a return statement somewhere in your controller?'; } throw new ControllerDoesNotReturnResponseException($msg, $controller, __FILE__, __LINE__ - 17); } } return $this->filterResponse($response, $request, $type); } /** * Filters a response object. * * @throws \RuntimeException if the passed object is not a Response instance */ private function filterResponse(Response $response, Request $request, int $type): Response { $event = new ResponseEvent($this, $request, $type, $response); $this->dispatcher->dispatch($event, KernelEvents::RESPONSE); $this->finishRequest($request, $type); return $event->getResponse(); } /** * Publishes the finish request event, then pop the request from the stack. * * Note that the order of the operations is important here, otherwise * operations such as {@link RequestStack::getParentRequest()} can lead to * weird results. */ private function finishRequest(Request $request, int $type) { $this->dispatcher->dispatch(new FinishRequestEvent($this, $request, $type), KernelEvents::FINISH_REQUEST); } /** * Handles a throwable by trying to convert it to a Response. * * @throws \Exception */ private function handleThrowable(\Throwable $e, Request $request, int $type): Response { $event = new ExceptionEvent($this, $request, $type, $e); $this->dispatcher->dispatch($event, KernelEvents::EXCEPTION); // a listener might have replaced the exception $e = $event->getThrowable(); if (!$event->hasResponse()) { $this->finishRequest($request, $type); throw $e; } $response = $event->getResponse(); // the developer asked for a specific status code if (!$event->isAllowingCustomResponseCode() && !$response->isClientError() && !$response->isServerError() && !$response->isRedirect()) { // ensure that we actually have an error response if ($e instanceof HttpExceptionInterface) { // keep the HTTP status code and headers $response->setStatusCode($e->getStatusCode()); $response->headers->add($e->getHeaders()); } else { $response->setStatusCode(500); } } try { return $this->filterResponse($response, $request, $type); } catch (\Exception $e) { return $response; } } /** * Returns a human-readable string for the specified variable. */ private function varToString($var): string { if (\is_object($var)) { return sprintf('an object of type %s', \get_class($var)); } if (\is_array($var)) { $a = []; foreach ($var as $k => $v) { $a[] = sprintf('%s => ...', $k); } return sprintf('an array ([%s])', mb_substr(implode(', ', $a), 0, 255)); } if (\is_resource($var)) { return sprintf('a resource (%s)', get_resource_type($var)); } if (null === $var) { return 'null'; } if (false === $var) { return 'a boolean value (false)'; } if (true === $var) { return 'a boolean value (true)'; } if (\is_string($var)) { return sprintf('a string ("%s%s")', mb_substr($var, 0, 255), mb_strlen($var) > 255 ? '...' : ''); } if (is_numeric($var)) { return sprintf('a number (%s)', (string) $var); } return (string) $var; } } PK'\6iProfiler/Profiler.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Profiler; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface; use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface; use Symfony\Contracts\Service\ResetInterface; /** * Profiler. * * @author Fabien Potencier */ class Profiler implements ResetInterface { private $storage; /** * @var DataCollectorInterface[] */ private $collectors = []; private $logger; private $initiallyEnabled = true; private $enabled = true; public function __construct(ProfilerStorageInterface $storage, LoggerInterface $logger = null, bool $enable = true) { $this->storage = $storage; $this->logger = $logger; $this->initiallyEnabled = $this->enabled = $enable; } /** * Disables the profiler. */ public function disable() { $this->enabled = false; } /** * Enables the profiler. */ public function enable() { $this->enabled = true; } /** * Loads the Profile for the given Response. * * @return Profile|null */ public function loadProfileFromResponse(Response $response) { if (!$token = $response->headers->get('X-Debug-Token')) { return null; } return $this->loadProfile($token); } /** * Loads the Profile for the given token. * * @return Profile|null */ public function loadProfile(string $token) { return $this->storage->read($token); } /** * Saves a Profile. * * @return bool */ public function saveProfile(Profile $profile) { // late collect foreach ($profile->getCollectors() as $collector) { if ($collector instanceof LateDataCollectorInterface) { $collector->lateCollect(); } } if (!($ret = $this->storage->write($profile)) && null !== $this->logger) { $this->logger->warning('Unable to store the profiler information.', ['configured_storage' => \get_class($this->storage)]); } return $ret; } /** * Purges all data from the storage. */ public function purge() { $this->storage->purge(); } /** * Finds profiler tokens for the given criteria. * * @param string|null $limit The maximum number of tokens to return * @param string|null $start The start date to search from * @param string|null $end The end date to search to * * @return array * * @see https://php.net/datetime.formats for the supported date/time formats */ public function find(?string $ip, ?string $url, ?string $limit, ?string $method, ?string $start, ?string $end, string $statusCode = null) { return $this->storage->find($ip, $url, $limit, $method, $this->getTimestamp($start), $this->getTimestamp($end), $statusCode); } /** * Collects data for the given Response. * * @return Profile|null */ public function collect(Request $request, Response $response, \Throwable $exception = null) { if (false === $this->enabled) { return null; } $profile = new Profile(substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6)); $profile->setTime(time()); $profile->setUrl($request->getUri()); $profile->setMethod($request->getMethod()); $profile->setStatusCode($response->getStatusCode()); try { $profile->setIp($request->getClientIp()); } catch (ConflictingHeadersException $e) { $profile->setIp('Unknown'); } if ($prevToken = $response->headers->get('X-Debug-Token')) { $response->headers->set('X-Previous-Debug-Token', $prevToken); } $response->headers->set('X-Debug-Token', $profile->getToken()); foreach ($this->collectors as $collector) { $collector->collect($request, $response, $exception); // we need to clone for sub-requests $profile->addCollector(clone $collector); } return $profile; } public function reset() { foreach ($this->collectors as $collector) { $collector->reset(); } $this->enabled = $this->initiallyEnabled; } /** * Gets the Collectors associated with this profiler. * * @return array */ public function all() { return $this->collectors; } /** * Sets the Collectors associated with this profiler. * * @param DataCollectorInterface[] $collectors An array of collectors */ public function set(array $collectors = []) { $this->collectors = []; foreach ($collectors as $collector) { $this->add($collector); } } /** * Adds a Collector. */ public function add(DataCollectorInterface $collector) { $this->collectors[$collector->getName()] = $collector; } /** * Returns true if a Collector for the given name exists. * * @param string $name A collector name * * @return bool */ public function has(string $name) { return isset($this->collectors[$name]); } /** * Gets a Collector by name. * * @param string $name A collector name * * @return DataCollectorInterface * * @throws \InvalidArgumentException if the collector does not exist */ public function get(string $name) { if (!isset($this->collectors[$name])) { throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name)); } return $this->collectors[$name]; } private function getTimestamp(?string $value): ?int { if (null === $value || '' === $value) { return null; } try { $value = new \DateTime(is_numeric($value) ? '@'.$value : $value); } catch (\Exception $e) { return null; } return $value->getTimestamp(); } } PK'\gU## Profiler/FileProfilerStorage.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Profiler; /** * Storage for profiler using files. * * @author Alexandre Salomé */ class FileProfilerStorage implements ProfilerStorageInterface { /** * Folder where profiler data are stored. * * @var string */ private $folder; /** * Constructs the file storage using a "dsn-like" path. * * Example : "file:/path/to/the/storage/folder" * * @throws \RuntimeException */ public function __construct(string $dsn) { if (!str_starts_with($dsn, 'file:')) { throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use FileStorage with an invalid dsn "%s". The expected format is "file:/path/to/the/storage/folder".', $dsn)); } $this->folder = substr($dsn, 5); if (!is_dir($this->folder) && false === @mkdir($this->folder, 0777, true) && !is_dir($this->folder)) { throw new \RuntimeException(sprintf('Unable to create the storage directory (%s).', $this->folder)); } } /** * {@inheritdoc} */ public function find(?string $ip, ?string $url, ?int $limit, ?string $method, int $start = null, int $end = null, string $statusCode = null): array { $file = $this->getIndexFilename(); if (!file_exists($file)) { return []; } $file = fopen($file, 'r'); fseek($file, 0, \SEEK_END); $result = []; while (\count($result) < $limit && $line = $this->readLineFromFile($file)) { $values = str_getcsv($line); [$csvToken, $csvIp, $csvMethod, $csvUrl, $csvTime, $csvParent, $csvStatusCode] = $values; $csvTime = (int) $csvTime; if ($ip && !str_contains($csvIp, $ip) || $url && !str_contains($csvUrl, $url) || $method && !str_contains($csvMethod, $method) || $statusCode && !str_contains($csvStatusCode, $statusCode)) { continue; } if (!empty($start) && $csvTime < $start) { continue; } if (!empty($end) && $csvTime > $end) { continue; } $result[$csvToken] = [ 'token' => $csvToken, 'ip' => $csvIp, 'method' => $csvMethod, 'url' => $csvUrl, 'time' => $csvTime, 'parent' => $csvParent, 'status_code' => $csvStatusCode, ]; } fclose($file); return array_values($result); } /** * {@inheritdoc} */ public function purge() { $flags = \FilesystemIterator::SKIP_DOTS; $iterator = new \RecursiveDirectoryIterator($this->folder, $flags); $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST); foreach ($iterator as $file) { if (is_file($file)) { unlink($file); } else { rmdir($file); } } } /** * {@inheritdoc} */ public function read(string $token): ?Profile { return $this->doRead($token); } /** * {@inheritdoc} * * @throws \RuntimeException */ public function write(Profile $profile): bool { $file = $this->getFilename($profile->getToken()); $profileIndexed = is_file($file); if (!$profileIndexed) { // Create directory $dir = \dirname($file); if (!is_dir($dir) && false === @mkdir($dir, 0777, true) && !is_dir($dir)) { throw new \RuntimeException(sprintf('Unable to create the storage directory (%s).', $dir)); } } $profileToken = $profile->getToken(); // when there are errors in sub-requests, the parent and/or children tokens // may equal the profile token, resulting in infinite loops $parentToken = $profile->getParentToken() !== $profileToken ? $profile->getParentToken() : null; $childrenToken = array_filter(array_map(function (Profile $p) use ($profileToken) { return $profileToken !== $p->getToken() ? $p->getToken() : null; }, $profile->getChildren())); // Store profile $data = [ 'token' => $profileToken, 'parent' => $parentToken, 'children' => $childrenToken, 'data' => $profile->getCollectors(), 'ip' => $profile->getIp(), 'method' => $profile->getMethod(), 'url' => $profile->getUrl(), 'time' => $profile->getTime(), 'status_code' => $profile->getStatusCode(), ]; $data = serialize($data); if (\function_exists('gzencode')) { $data = gzencode($data, 3); } if (false === file_put_contents($file, $data, \LOCK_EX)) { return false; } if (!$profileIndexed) { // Add to index if (false === $file = fopen($this->getIndexFilename(), 'a')) { return false; } fputcsv($file, [ $profile->getToken(), $profile->getIp(), $profile->getMethod(), $profile->getUrl(), $profile->getTime(), $profile->getParentToken(), $profile->getStatusCode(), ]); fclose($file); } return true; } /** * Gets filename to store data, associated to the token. * * @return string */ protected function getFilename(string $token) { // Uses 4 last characters, because first are mostly the same. $folderA = substr($token, -2, 2); $folderB = substr($token, -4, 2); return $this->folder.'/'.$folderA.'/'.$folderB.'/'.$token; } /** * Gets the index filename. * * @return string */ protected function getIndexFilename() { return $this->folder.'/index.csv'; } /** * Reads a line in the file, backward. * * This function automatically skips the empty lines and do not include the line return in result value. * * @param resource $file The file resource, with the pointer placed at the end of the line to read * * @return mixed */ protected function readLineFromFile($file) { $line = ''; $position = ftell($file); if (0 === $position) { return null; } while (true) { $chunkSize = min($position, 1024); $position -= $chunkSize; fseek($file, $position); if (0 === $chunkSize) { // bof reached break; } $buffer = fread($file, $chunkSize); if (false === ($upTo = strrpos($buffer, "\n"))) { $line = $buffer.$line; continue; } $position += $upTo; $line = substr($buffer, $upTo + 1).$line; fseek($file, max(0, $position), \SEEK_SET); if ('' !== $line) { break; } } return '' === $line ? null : $line; } protected function createProfileFromData(string $token, array $data, Profile $parent = null) { $profile = new Profile($token); $profile->setIp($data['ip']); $profile->setMethod($data['method']); $profile->setUrl($data['url']); $profile->setTime($data['time']); $profile->setStatusCode($data['status_code']); $profile->setCollectors($data['data']); if (!$parent && $data['parent']) { $parent = $this->read($data['parent']); } if ($parent) { $profile->setParent($parent); } foreach ($data['children'] as $token) { if (null !== $childProfile = $this->doRead($token, $profile)) { $profile->addChild($childProfile); } } return $profile; } private function doRead($token, Profile $profile = null): ?Profile { if (!$token || !file_exists($file = $this->getFilename($token))) { return null; } $h = fopen($file, 'r'); flock($h, \LOCK_SH); $data = stream_get_contents($h); flock($h, \LOCK_UN); fclose($h); if (\function_exists('gzdecode')) { $data = @gzdecode($data) ?: $data; } if (!$data = unserialize($data)) { return null; } return $this->createProfileFromData($token, $data, $profile); } } PK'\/!%Profiler/ProfilerStorageInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Profiler; /** * ProfilerStorageInterface. * * This interface exists for historical reasons. The only supported * implementation is FileProfilerStorage. * * As the profiler must only be used on non-production servers, the file storage * is more than enough and no other implementations will ever be supported. * * @internal * * @author Fabien Potencier */ interface ProfilerStorageInterface { /** * Finds profiler tokens for the given criteria. * * @param int|null $limit The maximum number of tokens to return * @param int|null $start The start date to search from * @param int|null $end The end date to search to */ public function find(?string $ip, ?string $url, ?int $limit, ?string $method, int $start = null, int $end = null): array; /** * Reads data associated with the given token. * * The method returns false if the token does not exist in the storage. */ public function read(string $token): ?Profile; /** * Saves a Profile. */ public function write(Profile $profile): bool; /** * Purges all data from the database. */ public function purge(); } PK'\+Profiler/Profile.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Profiler; use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface; /** * Profile. * * @author Fabien Potencier */ class Profile { private $token; /** * @var DataCollectorInterface[] */ private $collectors = []; private $ip; private $method; private $url; private $time; private $statusCode; /** * @var Profile */ private $parent; /** * @var Profile[] */ private $children = []; public function __construct(string $token) { $this->token = $token; } public function setToken(string $token) { $this->token = $token; } /** * Gets the token. * * @return string */ public function getToken() { return $this->token; } /** * Sets the parent token. */ public function setParent(self $parent) { $this->parent = $parent; } /** * Returns the parent profile. * * @return self|null */ public function getParent() { return $this->parent; } /** * Returns the parent token. * * @return string|null */ public function getParentToken() { return $this->parent ? $this->parent->getToken() : null; } /** * Returns the IP. * * @return string|null */ public function getIp() { return $this->ip; } public function setIp(?string $ip) { $this->ip = $ip; } /** * Returns the request method. * * @return string|null */ public function getMethod() { return $this->method; } public function setMethod(string $method) { $this->method = $method; } /** * Returns the URL. * * @return string|null */ public function getUrl() { return $this->url; } public function setUrl(?string $url) { $this->url = $url; } /** * @return int */ public function getTime() { return $this->time ?? 0; } public function setTime(int $time) { $this->time = $time; } public function setStatusCode(int $statusCode) { $this->statusCode = $statusCode; } /** * @return int|null */ public function getStatusCode() { return $this->statusCode; } /** * Finds children profilers. * * @return self[] */ public function getChildren() { return $this->children; } /** * Sets children profiler. * * @param Profile[] $children */ public function setChildren(array $children) { $this->children = []; foreach ($children as $child) { $this->addChild($child); } } /** * Adds the child token. */ public function addChild(self $child) { $this->children[] = $child; $child->setParent($this); } public function getChildByToken(string $token): ?self { foreach ($this->children as $child) { if ($token === $child->getToken()) { return $child; } } return null; } /** * Gets a Collector by name. * * @return DataCollectorInterface * * @throws \InvalidArgumentException if the collector does not exist */ public function getCollector(string $name) { if (!isset($this->collectors[$name])) { throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name)); } return $this->collectors[$name]; } /** * Gets the Collectors associated with this profile. * * @return DataCollectorInterface[] */ public function getCollectors() { return $this->collectors; } /** * Sets the Collectors associated with this profile. * * @param DataCollectorInterface[] $collectors */ public function setCollectors(array $collectors) { $this->collectors = []; foreach ($collectors as $collector) { $this->addCollector($collector); } } /** * Adds a Collector. */ public function addCollector(DataCollectorInterface $collector) { $this->collectors[$collector->getName()] = $collector; } /** * @return bool */ public function hasCollector(string $name) { return isset($this->collectors[$name]); } /** * @return array */ public function __sleep() { return ['token', 'parent', 'children', 'collectors', 'ip', 'method', 'url', 'time', 'statusCode']; } } PK'\zss Kernel.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Bridge\ProxyManager\LazyProxy\Instantiator\RuntimeInstantiator; use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper; use Symfony\Component\Config\Builder\ConfigBuilderGenerator; use Symfony\Component\Config\ConfigCache; use Symfony\Component\Config\Loader\DelegatingLoader; use Symfony\Component\Config\Loader\LoaderResolver; use Symfony\Component\Debug\DebugClassLoader as LegacyDebugClassLoader; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Dumper\PhpDumper; use Symfony\Component\DependencyInjection\Dumper\Preloader; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\DependencyInjection\Loader\ClosureLoader; use Symfony\Component\DependencyInjection\Loader\DirectoryLoader; use Symfony\Component\DependencyInjection\Loader\GlobFileLoader; use Symfony\Component\DependencyInjection\Loader\IniFileLoader; use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\ErrorHandler\DebugClassLoader; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Bundle\BundleInterface; use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface; use Symfony\Component\HttpKernel\Config\FileLocator; use Symfony\Component\HttpKernel\DependencyInjection\AddAnnotatedClassesToCachePass; use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass; // Help opcache.preload discover always-needed symbols class_exists(ConfigCache::class); /** * The Kernel is the heart of the Symfony system. * * It manages an environment made of bundles. * * Environment names must always start with a letter and * they must only contain letters and numbers. * * @author Fabien Potencier */ abstract class Kernel implements KernelInterface, RebootableInterface, TerminableInterface { /** * @var array */ protected $bundles = []; protected $container; protected $environment; protected $debug; protected $booted = false; protected $startTime; private $projectDir; private $warmupDir; private $requestStackSize = 0; private $resetServices = false; /** * @var array */ private static $freshCache = []; public const VERSION = '5.4.20'; public const VERSION_ID = 50420; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; public const RELEASE_VERSION = 20; public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '11/2025'; public function __construct(string $environment, bool $debug) { if (!$this->environment = $environment) { throw new \InvalidArgumentException(sprintf('Invalid environment provided to "%s": the environment cannot be empty.', get_debug_type($this))); } $this->debug = $debug; } public function __clone() { $this->booted = false; $this->container = null; $this->requestStackSize = 0; $this->resetServices = false; } /** * {@inheritdoc} */ public function boot() { if (true === $this->booted) { if (!$this->requestStackSize && $this->resetServices) { if ($this->container->has('services_resetter')) { $this->container->get('services_resetter')->reset(); } $this->resetServices = false; if ($this->debug) { $this->startTime = microtime(true); } } return; } if (null === $this->container) { $this->preBoot(); } foreach ($this->getBundles() as $bundle) { $bundle->setContainer($this->container); $bundle->boot(); } $this->booted = true; } /** * {@inheritdoc} */ public function reboot(?string $warmupDir) { $this->shutdown(); $this->warmupDir = $warmupDir; $this->boot(); } /** * {@inheritdoc} */ public function terminate(Request $request, Response $response) { if (false === $this->booted) { return; } if ($this->getHttpKernel() instanceof TerminableInterface) { $this->getHttpKernel()->terminate($request, $response); } } /** * {@inheritdoc} */ public function shutdown() { if (false === $this->booted) { return; } $this->booted = false; foreach ($this->getBundles() as $bundle) { $bundle->shutdown(); $bundle->setContainer(null); } $this->container = null; $this->requestStackSize = 0; $this->resetServices = false; } /** * {@inheritdoc} */ public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true) { if (!$this->booted) { $container = $this->container ?? $this->preBoot(); if ($container->has('http_cache')) { return $container->get('http_cache')->handle($request, $type, $catch); } } $this->boot(); ++$this->requestStackSize; $this->resetServices = true; try { return $this->getHttpKernel()->handle($request, $type, $catch); } finally { --$this->requestStackSize; } } /** * Gets an HTTP kernel from the container. * * @return HttpKernelInterface */ protected function getHttpKernel() { return $this->container->get('http_kernel'); } /** * {@inheritdoc} */ public function getBundles() { return $this->bundles; } /** * {@inheritdoc} */ public function getBundle(string $name) { if (!isset($this->bundles[$name])) { throw new \InvalidArgumentException(sprintf('Bundle "%s" does not exist or it is not enabled. Maybe you forgot to add it in the "registerBundles()" method of your "%s.php" file?', $name, get_debug_type($this))); } return $this->bundles[$name]; } /** * {@inheritdoc} */ public function locateResource(string $name) { if ('@' !== $name[0]) { throw new \InvalidArgumentException(sprintf('A resource name must start with @ ("%s" given).', $name)); } if (str_contains($name, '..')) { throw new \RuntimeException(sprintf('File name "%s" contains invalid characters (..).', $name)); } $bundleName = substr($name, 1); $path = ''; if (str_contains($bundleName, '/')) { [$bundleName, $path] = explode('/', $bundleName, 2); } $bundle = $this->getBundle($bundleName); if (file_exists($file = $bundle->getPath().'/'.$path)) { return $file; } throw new \InvalidArgumentException(sprintf('Unable to find file "%s".', $name)); } /** * {@inheritdoc} */ public function getEnvironment() { return $this->environment; } /** * {@inheritdoc} */ public function isDebug() { return $this->debug; } /** * Gets the application root dir (path of the project's composer file). * * @return string */ public function getProjectDir() { if (null === $this->projectDir) { $r = new \ReflectionObject($this); if (!is_file($dir = $r->getFileName())) { throw new \LogicException(sprintf('Cannot auto-detect project dir for kernel of class "%s".', $r->name)); } $dir = $rootDir = \dirname($dir); while (!is_file($dir.'/composer.json')) { if ($dir === \dirname($dir)) { return $this->projectDir = $rootDir; } $dir = \dirname($dir); } $this->projectDir = $dir; } return $this->projectDir; } /** * {@inheritdoc} */ public function getContainer() { if (!$this->container) { throw new \LogicException('Cannot retrieve the container from a non-booted kernel.'); } return $this->container; } /** * @internal */ public function setAnnotatedClassCache(array $annotatedClasses) { file_put_contents(($this->warmupDir ?: $this->getBuildDir()).'/annotations.map', sprintf('debug && null !== $this->startTime ? $this->startTime : -\INF; } /** * {@inheritdoc} */ public function getCacheDir() { return $this->getProjectDir().'/var/cache/'.$this->environment; } /** * {@inheritdoc} */ public function getBuildDir(): string { // Returns $this->getCacheDir() for backward compatibility return $this->getCacheDir(); } /** * {@inheritdoc} */ public function getLogDir() { return $this->getProjectDir().'/var/log'; } /** * {@inheritdoc} */ public function getCharset() { return 'UTF-8'; } /** * Gets the patterns defining the classes to parse and cache for annotations. */ public function getAnnotatedClassesToCompile(): array { return []; } /** * Initializes bundles. * * @throws \LogicException if two bundles share a common name */ protected function initializeBundles() { // init bundles $this->bundles = []; foreach ($this->registerBundles() as $bundle) { $name = $bundle->getName(); if (isset($this->bundles[$name])) { throw new \LogicException(sprintf('Trying to register two bundles with the same name "%s".', $name)); } $this->bundles[$name] = $bundle; } } /** * The extension point similar to the Bundle::build() method. * * Use this method to register compiler passes and manipulate the container during the building process. */ protected function build(ContainerBuilder $container) { } /** * Gets the container class. * * @throws \InvalidArgumentException If the generated classname is invalid * * @return string */ protected function getContainerClass() { $class = static::class; $class = str_contains($class, "@anonymous\0") ? get_parent_class($class).str_replace('.', '_', ContainerBuilder::hash($class)) : $class; $class = str_replace('\\', '_', $class).ucfirst($this->environment).($this->debug ? 'Debug' : '').'Container'; if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $class)) { throw new \InvalidArgumentException(sprintf('The environment "%s" contains invalid characters, it can only contain characters allowed in PHP class names.', $this->environment)); } return $class; } /** * Gets the container's base class. * * All names except Container must be fully qualified. * * @return string */ protected function getContainerBaseClass() { return 'Container'; } /** * Initializes the service container. * * The built version of the service container is used when fresh, otherwise the * container is built. */ protected function initializeContainer() { $class = $this->getContainerClass(); $buildDir = $this->warmupDir ?: $this->getBuildDir(); $cache = new ConfigCache($buildDir.'/'.$class.'.php', $this->debug); $cachePath = $cache->getPath(); // Silence E_WARNING to ignore "include" failures - don't use "@" to prevent silencing fatal errors $errorLevel = error_reporting(\E_ALL ^ \E_WARNING); try { if (is_file($cachePath) && \is_object($this->container = include $cachePath) && (!$this->debug || (self::$freshCache[$cachePath] ?? $cache->isFresh())) ) { self::$freshCache[$cachePath] = true; $this->container->set('kernel', $this); error_reporting($errorLevel); return; } } catch (\Throwable $e) { } $oldContainer = \is_object($this->container) ? new \ReflectionClass($this->container) : $this->container = null; try { is_dir($buildDir) ?: mkdir($buildDir, 0777, true); if ($lock = fopen($cachePath.'.lock', 'w')) { if (!flock($lock, \LOCK_EX | \LOCK_NB, $wouldBlock) && !flock($lock, $wouldBlock ? \LOCK_SH : \LOCK_EX)) { fclose($lock); $lock = null; } elseif (!is_file($cachePath) || !\is_object($this->container = include $cachePath)) { $this->container = null; } elseif (!$oldContainer || \get_class($this->container) !== $oldContainer->name) { flock($lock, \LOCK_UN); fclose($lock); $this->container->set('kernel', $this); return; } } } catch (\Throwable $e) { } finally { error_reporting($errorLevel); } if ($collectDeprecations = $this->debug && !\defined('PHPUNIT_COMPOSER_INSTALL')) { $collectedLogs = []; $previousHandler = set_error_handler(function ($type, $message, $file, $line) use (&$collectedLogs, &$previousHandler) { if (\E_USER_DEPRECATED !== $type && \E_DEPRECATED !== $type) { return $previousHandler ? $previousHandler($type, $message, $file, $line) : false; } if (isset($collectedLogs[$message])) { ++$collectedLogs[$message]['count']; return null; } $backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 5); // Clean the trace by removing first frames added by the error handler itself. for ($i = 0; isset($backtrace[$i]); ++$i) { if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) { $backtrace = \array_slice($backtrace, 1 + $i); break; } } for ($i = 0; isset($backtrace[$i]); ++$i) { if (!isset($backtrace[$i]['file'], $backtrace[$i]['line'], $backtrace[$i]['function'])) { continue; } if (!isset($backtrace[$i]['class']) && 'trigger_deprecation' === $backtrace[$i]['function']) { $file = $backtrace[$i]['file']; $line = $backtrace[$i]['line']; $backtrace = \array_slice($backtrace, 1 + $i); break; } } // Remove frames added by DebugClassLoader. for ($i = \count($backtrace) - 2; 0 < $i; --$i) { if (\in_array($backtrace[$i]['class'] ?? null, [DebugClassLoader::class, LegacyDebugClassLoader::class], true)) { $backtrace = [$backtrace[$i + 1]]; break; } } $collectedLogs[$message] = [ 'type' => $type, 'message' => $message, 'file' => $file, 'line' => $line, 'trace' => [$backtrace[0]], 'count' => 1, ]; return null; }); } try { $container = null; $container = $this->buildContainer(); $container->compile(); } finally { if ($collectDeprecations) { restore_error_handler(); @file_put_contents($buildDir.'/'.$class.'Deprecations.log', serialize(array_values($collectedLogs))); @file_put_contents($buildDir.'/'.$class.'Compiler.log', null !== $container ? implode("\n", $container->getCompiler()->getLog()) : ''); } } $this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass()); if ($lock) { flock($lock, \LOCK_UN); fclose($lock); } $this->container = require $cachePath; $this->container->set('kernel', $this); if ($oldContainer && \get_class($this->container) !== $oldContainer->name) { // Because concurrent requests might still be using them, // old container files are not removed immediately, // but on a next dump of the container. static $legacyContainers = []; $oldContainerDir = \dirname($oldContainer->getFileName()); $legacyContainers[$oldContainerDir.'.legacy'] = true; foreach (glob(\dirname($oldContainerDir).\DIRECTORY_SEPARATOR.'*.legacy', \GLOB_NOSORT) as $legacyContainer) { if (!isset($legacyContainers[$legacyContainer]) && @unlink($legacyContainer)) { (new Filesystem())->remove(substr($legacyContainer, 0, -7)); } } touch($oldContainerDir.'.legacy'); } $preload = $this instanceof WarmableInterface ? (array) $this->warmUp($this->container->getParameter('kernel.cache_dir')) : []; if ($this->container->has('cache_warmer')) { $preload = array_merge($preload, (array) $this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir'))); } if ($preload && method_exists(Preloader::class, 'append') && file_exists($preloadFile = $buildDir.'/'.$class.'.preload.php')) { Preloader::append($preloadFile, $preload); } } /** * Returns the kernel parameters. * * @return array */ protected function getKernelParameters() { $bundles = []; $bundlesMetadata = []; foreach ($this->bundles as $name => $bundle) { $bundles[$name] = \get_class($bundle); $bundlesMetadata[$name] = [ 'path' => $bundle->getPath(), 'namespace' => $bundle->getNamespace(), ]; } return [ 'kernel.project_dir' => realpath($this->getProjectDir()) ?: $this->getProjectDir(), 'kernel.environment' => $this->environment, 'kernel.runtime_environment' => '%env(default:kernel.environment:APP_RUNTIME_ENV)%', 'kernel.debug' => $this->debug, 'kernel.build_dir' => realpath($buildDir = $this->warmupDir ?: $this->getBuildDir()) ?: $buildDir, 'kernel.cache_dir' => realpath($cacheDir = ($this->getCacheDir() === $this->getBuildDir() ? ($this->warmupDir ?: $this->getCacheDir()) : $this->getCacheDir())) ?: $cacheDir, 'kernel.logs_dir' => realpath($this->getLogDir()) ?: $this->getLogDir(), 'kernel.bundles' => $bundles, 'kernel.bundles_metadata' => $bundlesMetadata, 'kernel.charset' => $this->getCharset(), 'kernel.container_class' => $this->getContainerClass(), ]; } /** * Builds the service container. * * @return ContainerBuilder * * @throws \RuntimeException */ protected function buildContainer() { foreach (['cache' => $this->getCacheDir(), 'build' => $this->warmupDir ?: $this->getBuildDir(), 'logs' => $this->getLogDir()] as $name => $dir) { if (!is_dir($dir)) { if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) { throw new \RuntimeException(sprintf('Unable to create the "%s" directory (%s).', $name, $dir)); } } elseif (!is_writable($dir)) { throw new \RuntimeException(sprintf('Unable to write in the "%s" directory (%s).', $name, $dir)); } } $container = $this->getContainerBuilder(); $container->addObjectResource($this); $this->prepareContainer($container); if (null !== $cont = $this->registerContainerConfiguration($this->getContainerLoader($container))) { trigger_deprecation('symfony/http-kernel', '5.3', 'Returning a ContainerBuilder from "%s::registerContainerConfiguration()" is deprecated.', get_debug_type($this)); $container->merge($cont); } $container->addCompilerPass(new AddAnnotatedClassesToCachePass($this)); return $container; } /** * Prepares the ContainerBuilder before it is compiled. */ protected function prepareContainer(ContainerBuilder $container) { $extensions = []; foreach ($this->bundles as $bundle) { if ($extension = $bundle->getContainerExtension()) { $container->registerExtension($extension); } if ($this->debug) { $container->addObjectResource($bundle); } } foreach ($this->bundles as $bundle) { $bundle->build($container); } $this->build($container); foreach ($container->getExtensions() as $extension) { $extensions[] = $extension->getAlias(); } // ensure these extensions are implicitly loaded $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions)); } /** * Gets a new ContainerBuilder instance used to build the service container. * * @return ContainerBuilder */ protected function getContainerBuilder() { $container = new ContainerBuilder(); $container->getParameterBag()->add($this->getKernelParameters()); if ($this instanceof ExtensionInterface) { $container->registerExtension($this); } if ($this instanceof CompilerPassInterface) { $container->addCompilerPass($this, PassConfig::TYPE_BEFORE_OPTIMIZATION, -10000); } if (class_exists(\ProxyManager\Configuration::class) && class_exists(RuntimeInstantiator::class)) { $container->setProxyInstantiator(new RuntimeInstantiator()); } return $container; } /** * Dumps the service container to PHP code in the cache. * * @param string $class The name of the class to generate * @param string $baseClass The name of the container's base class */ protected function dumpContainer(ConfigCache $cache, ContainerBuilder $container, string $class, string $baseClass) { // cache the container $dumper = new PhpDumper($container); if (class_exists(\ProxyManager\Configuration::class) && class_exists(ProxyDumper::class)) { $dumper->setProxyDumper(new ProxyDumper()); } $content = $dumper->dump([ 'class' => $class, 'base_class' => $baseClass, 'file' => $cache->getPath(), 'as_files' => true, 'debug' => $this->debug, 'build_time' => $container->hasParameter('kernel.container_build_time') ? $container->getParameter('kernel.container_build_time') : time(), 'preload_classes' => array_map('get_class', $this->bundles), ]); $rootCode = array_pop($content); $dir = \dirname($cache->getPath()).'/'; $fs = new Filesystem(); foreach ($content as $file => $code) { $fs->dumpFile($dir.$file, $code); @chmod($dir.$file, 0666 & ~umask()); } $legacyFile = \dirname($dir.key($content)).'.legacy'; if (is_file($legacyFile)) { @unlink($legacyFile); } $cache->write($rootCode, $container->getResources()); } /** * Returns a loader for the container. * * @return DelegatingLoader */ protected function getContainerLoader(ContainerInterface $container) { $env = $this->getEnvironment(); $locator = new FileLocator($this); $resolver = new LoaderResolver([ new XmlFileLoader($container, $locator, $env), new YamlFileLoader($container, $locator, $env), new IniFileLoader($container, $locator, $env), new PhpFileLoader($container, $locator, $env, class_exists(ConfigBuilderGenerator::class) ? new ConfigBuilderGenerator($this->getBuildDir()) : null), new GlobFileLoader($container, $locator, $env), new DirectoryLoader($container, $locator, $env), new ClosureLoader($container, $env), ]); return new DelegatingLoader($resolver); } private function preBoot(): ContainerInterface { if ($this->debug) { $this->startTime = microtime(true); } if ($this->debug && !isset($_ENV['SHELL_VERBOSITY']) && !isset($_SERVER['SHELL_VERBOSITY'])) { putenv('SHELL_VERBOSITY=3'); $_ENV['SHELL_VERBOSITY'] = 3; $_SERVER['SHELL_VERBOSITY'] = 3; } $this->initializeBundles(); $this->initializeContainer(); $container = $this->container; if ($container->hasParameter('kernel.trusted_hosts') && $trustedHosts = $container->getParameter('kernel.trusted_hosts')) { Request::setTrustedHosts($trustedHosts); } if ($container->hasParameter('kernel.trusted_proxies') && $container->hasParameter('kernel.trusted_headers') && $trustedProxies = $container->getParameter('kernel.trusted_proxies')) { Request::setTrustedProxies(\is_array($trustedProxies) ? $trustedProxies : array_map('trim', explode(',', $trustedProxies)), $container->getParameter('kernel.trusted_headers')); } return $container; } /** * Removes comments from a PHP source string. * * We don't use the PHP php_strip_whitespace() function * as we want the content to be readable and well-formatted. * * @return string */ public static function stripComments(string $source) { if (!\function_exists('token_get_all')) { return $source; } $rawChunk = ''; $output = ''; $tokens = token_get_all($source); $ignoreSpace = false; for ($i = 0; isset($tokens[$i]); ++$i) { $token = $tokens[$i]; if (!isset($token[1]) || 'b"' === $token) { $rawChunk .= $token; } elseif (\T_START_HEREDOC === $token[0]) { $output .= $rawChunk.$token[1]; do { $token = $tokens[++$i]; $output .= isset($token[1]) && 'b"' !== $token ? $token[1] : $token; } while (\T_END_HEREDOC !== $token[0]); $rawChunk = ''; } elseif (\T_WHITESPACE === $token[0]) { if ($ignoreSpace) { $ignoreSpace = false; continue; } // replace multiple new lines with a single newline $rawChunk .= preg_replace(['/\n{2,}/S'], "\n", $token[1]); } elseif (\in_array($token[0], [\T_COMMENT, \T_DOC_COMMENT])) { if (!\in_array($rawChunk[\strlen($rawChunk) - 1], [' ', "\n", "\r", "\t"], true)) { $rawChunk .= ' '; } $ignoreSpace = true; } else { $rawChunk .= $token[1]; // The PHP-open tag already has a new-line if (\T_OPEN_TAG === $token[0]) { $ignoreSpace = true; } else { $ignoreSpace = false; } } } $output .= $rawChunk; unset($tokens, $rawChunk); gc_mem_caches(); return $output; } /** * @return array */ public function __sleep() { return ['environment', 'debug']; } public function __wakeup() { if (\is_object($this->environment) || \is_object($this->debug)) { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } $this->__construct($this->environment, $this->debug); } } PK'\!ҊHttpKernelBrowser.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\BrowserKit\AbstractBrowser; use Symfony\Component\BrowserKit\CookieJar; use Symfony\Component\BrowserKit\History; use Symfony\Component\BrowserKit\Request as DomRequest; use Symfony\Component\BrowserKit\Response as DomResponse; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * Simulates a browser and makes requests to an HttpKernel instance. * * @author Fabien Potencier * * @method Request getRequest() * @method Response getResponse() */ class HttpKernelBrowser extends AbstractBrowser { protected $kernel; private $catchExceptions = true; /** * @param array $server The server parameters (equivalent of $_SERVER) */ public function __construct(HttpKernelInterface $kernel, array $server = [], History $history = null, CookieJar $cookieJar = null) { // These class properties must be set before calling the parent constructor, as it may depend on it. $this->kernel = $kernel; $this->followRedirects = false; parent::__construct($server, $history, $cookieJar); } /** * Sets whether to catch exceptions when the kernel is handling a request. */ public function catchExceptions(bool $catchExceptions) { $this->catchExceptions = $catchExceptions; } /** * {@inheritdoc} * * @param Request $request * * @return Response */ protected function doRequest(object $request) { $response = $this->kernel->handle($request, HttpKernelInterface::MAIN_REQUEST, $this->catchExceptions); if ($this->kernel instanceof TerminableInterface) { $this->kernel->terminate($request, $response); } return $response; } /** * {@inheritdoc} * * @param Request $request * * @return string */ protected function getScript(object $request) { $kernel = var_export(serialize($this->kernel), true); $request = var_export(serialize($request), true); $errorReporting = error_reporting(); $requires = ''; foreach (get_declared_classes() as $class) { if (0 === strpos($class, 'ComposerAutoloaderInit')) { $r = new \ReflectionClass($class); $file = \dirname($r->getFileName(), 2).'/autoload.php'; if (file_exists($file)) { $requires .= 'require_once '.var_export($file, true).";\n"; } } } if (!$requires) { throw new \RuntimeException('Composer autoloader not found.'); } $code = <<getHandleScript(); } protected function getHandleScript() { return <<<'EOF' $response = $kernel->handle($request); if ($kernel instanceof Symfony\Component\HttpKernel\TerminableInterface) { $kernel->terminate($request, $response); } echo serialize($response); EOF; } /** * {@inheritdoc} * * @return Request */ protected function filterRequest(DomRequest $request) { $httpRequest = Request::create($request->getUri(), $request->getMethod(), $request->getParameters(), $request->getCookies(), $request->getFiles(), $server = $request->getServer(), $request->getContent()); if (!isset($server['HTTP_ACCEPT'])) { $httpRequest->headers->remove('Accept'); } foreach ($this->filterFiles($httpRequest->files->all()) as $key => $value) { $httpRequest->files->set($key, $value); } return $httpRequest; } /** * Filters an array of files. * * This method created test instances of UploadedFile so that the move() * method can be called on those instances. * * If the size of a file is greater than the allowed size (from php.ini) then * an invalid UploadedFile is returned with an error set to UPLOAD_ERR_INI_SIZE. * * @see UploadedFile * * @return array */ protected function filterFiles(array $files) { $filtered = []; foreach ($files as $key => $value) { if (\is_array($value)) { $filtered[$key] = $this->filterFiles($value); } elseif ($value instanceof UploadedFile) { if ($value->isValid() && $value->getSize() > UploadedFile::getMaxFilesize()) { $filtered[$key] = new UploadedFile( '', $value->getClientOriginalName(), $value->getClientMimeType(), \UPLOAD_ERR_INI_SIZE, true ); } else { $filtered[$key] = new UploadedFile( $value->getPathname(), $value->getClientOriginalName(), $value->getClientMimeType(), $value->getError(), true ); } } } return $filtered; } /** * {@inheritdoc} * * @param Response $response * * @return DomResponse */ protected function filterResponse(object $response) { // this is needed to support StreamedResponse ob_start(); $response->sendContent(); $content = ob_get_clean(); return new DomResponse($content, $response->getStatusCode(), $response->headers->all()); } } PK'\|RebootableInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; /** * Allows the Kernel to be rebooted using a temporary cache directory. * * @author Nicolas Grekas */ interface RebootableInterface { /** * Reboots a kernel. * * The getBuildDir() method of a rebootable kernel should not be called * while building the container. Use the %kernel.build_dir% parameter instead. * * @param string|null $warmupDir pass null to reboot in the regular build directory */ public function reboot(?string $warmupDir); } PK'\ZZLog/Logger.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Log; use Psr\Log\AbstractLogger; use Psr\Log\InvalidArgumentException; use Psr\Log\LogLevel; /** * Minimalist PSR-3 logger designed to write in stderr or any other stream. * * @author Kévin Dunglas */ class Logger extends AbstractLogger { private const LEVELS = [ LogLevel::DEBUG => 0, LogLevel::INFO => 1, LogLevel::NOTICE => 2, LogLevel::WARNING => 3, LogLevel::ERROR => 4, LogLevel::CRITICAL => 5, LogLevel::ALERT => 6, LogLevel::EMERGENCY => 7, ]; private $minLevelIndex; private $formatter; /** @var resource|null */ private $handle; /** * @param string|resource|null $output */ public function __construct(string $minLevel = null, $output = null, callable $formatter = null) { if (null === $minLevel) { $minLevel = null === $output || 'php://stdout' === $output || 'php://stderr' === $output ? LogLevel::ERROR : LogLevel::WARNING; if (isset($_ENV['SHELL_VERBOSITY']) || isset($_SERVER['SHELL_VERBOSITY'])) { switch ((int) ($_ENV['SHELL_VERBOSITY'] ?? $_SERVER['SHELL_VERBOSITY'])) { case -1: $minLevel = LogLevel::ERROR; break; case 1: $minLevel = LogLevel::NOTICE; break; case 2: $minLevel = LogLevel::INFO; break; case 3: $minLevel = LogLevel::DEBUG; break; } } } if (!isset(self::LEVELS[$minLevel])) { throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $minLevel)); } $this->minLevelIndex = self::LEVELS[$minLevel]; $this->formatter = $formatter ?: [$this, 'format']; if ($output && false === $this->handle = \is_resource($output) ? $output : @fopen($output, 'a')) { throw new InvalidArgumentException(sprintf('Unable to open "%s".', $output)); } } /** * {@inheritdoc} * * @return void */ public function log($level, $message, array $context = []) { if (!isset(self::LEVELS[$level])) { throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level)); } if (self::LEVELS[$level] < $this->minLevelIndex) { return; } $formatter = $this->formatter; if ($this->handle) { @fwrite($this->handle, $formatter($level, $message, $context).\PHP_EOL); } else { error_log($formatter($level, $message, $context, false)); } } private function format(string $level, string $message, array $context, bool $prefixDate = true): string { if (str_contains($message, '{')) { $replacements = []; foreach ($context as $key => $val) { if (null === $val || \is_scalar($val) || (\is_object($val) && method_exists($val, '__toString'))) { $replacements["{{$key}}"] = $val; } elseif ($val instanceof \DateTimeInterface) { $replacements["{{$key}}"] = $val->format(\DateTime::RFC3339); } elseif (\is_object($val)) { $replacements["{{$key}}"] = '[object '.\get_class($val).']'; } else { $replacements["{{$key}}"] = '['.\gettype($val).']'; } } $message = strtr($message, $replacements); } $log = sprintf('[%s] %s', $level, $message); if ($prefixDate) { $log = date(\DateTime::RFC3339).' '.$log; } return $log; } } PK'\PLog/DebugLoggerInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Log; use Symfony\Component\HttpFoundation\Request; /** * DebugLoggerInterface. * * @author Fabien Potencier */ interface DebugLoggerInterface { /** * Returns an array of logs. * * A log is an array with the following mandatory keys: * timestamp, message, priority, and priorityName. * It can also have an optional context key containing an array. * * @return array */ public function getLogs(Request $request = null); /** * Returns the number of errors. * * @return int */ public function countErrors(Request $request = null); /** * Removes all log records. */ public function clear(); } PK'\tJJHttpClientKernel.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Symfony\Component\Mime\Part\AbstractPart; use Symfony\Component\Mime\Part\DataPart; use Symfony\Component\Mime\Part\Multipart\FormDataPart; use Symfony\Component\Mime\Part\TextPart; use Symfony\Contracts\HttpClient\HttpClientInterface; // Help opcache.preload discover always-needed symbols class_exists(ResponseHeaderBag::class); /** * An implementation of a Symfony HTTP kernel using a "real" HTTP client. * * @author Fabien Potencier */ final class HttpClientKernel implements HttpKernelInterface { private $client; public function __construct(HttpClientInterface $client = null) { if (null === $client && !class_exists(HttpClient::class)) { throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__)); } $this->client = $client ?? HttpClient::create(); } public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response { $headers = $this->getHeaders($request); $body = ''; if (null !== $part = $this->getBody($request)) { $headers = array_merge($headers, $part->getPreparedHeaders()->toArray()); $body = $part->bodyToIterable(); } $response = $this->client->request($request->getMethod(), $request->getUri(), [ 'headers' => $headers, 'body' => $body, ] + $request->attributes->get('http_client_options', [])); $response = new Response($response->getContent(!$catch), $response->getStatusCode(), $response->getHeaders(!$catch)); $response->headers->remove('X-Body-File'); $response->headers->remove('X-Body-Eval'); $response->headers->remove('X-Content-Digest'); $response->headers = new class($response->headers->all()) extends ResponseHeaderBag { protected function computeCacheControlValue(): string { return $this->getCacheControlHeader(); // preserve the original value } }; return $response; } private function getBody(Request $request): ?AbstractPart { if (\in_array($request->getMethod(), ['GET', 'HEAD'])) { return null; } if (!class_exists(AbstractPart::class)) { throw new \LogicException('You cannot pass non-empty bodies as the Mime component is not installed. Try running "composer require symfony/mime".'); } if ($content = $request->getContent()) { return new TextPart($content, 'utf-8', 'plain', '8bit'); } $fields = $request->request->all(); foreach ($request->files->all() as $name => $file) { $fields[$name] = DataPart::fromPath($file->getPathname(), $file->getClientOriginalName(), $file->getClientMimeType()); } return new FormDataPart($fields); } private function getHeaders(Request $request): array { $headers = []; foreach ($request->headers as $key => $value) { $headers[$key] = $value; } $cookies = []; foreach ($request->cookies->all() as $name => $value) { $cookies[] = $name.'='.$value; } if ($cookies) { $headers['cookie'] = implode('; ', $cookies); } return $headers; } } PK'\Bjj-EventListener/AbstractTestSessionListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; trigger_deprecation('symfony/http-kernel', '5.4', '"%s" is deprecated use "%s" instead.', AbstractTestSessionListener::class, AbstractSessionListener::class); /** * TestSessionListener. * * Saves session in test environment. * * @author Bulat Shakirzyanov * @author Fabien Potencier * * @internal * * @deprecated since Symfony 5.4, use AbstractSessionListener instead */ abstract class AbstractTestSessionListener implements EventSubscriberInterface { private $sessionId; private $sessionOptions; public function __construct(array $sessionOptions = []) { $this->sessionOptions = $sessionOptions; } public function onKernelRequest(RequestEvent $event) { if (!$event->isMainRequest()) { return; } // bootstrap the session if ($event->getRequest()->hasSession()) { $session = $event->getRequest()->getSession(); } elseif (!$session = $this->getSession()) { return; } $cookies = $event->getRequest()->cookies; if ($cookies->has($session->getName())) { $this->sessionId = $cookies->get($session->getName()); $session->setId($this->sessionId); } } /** * Checks if session was initialized and saves if current request is the main request * Runs on 'kernel.response' in test environment. */ public function onKernelResponse(ResponseEvent $event) { if (!$event->isMainRequest()) { return; } $request = $event->getRequest(); if (!$request->hasSession()) { return; } $session = $request->getSession(); if ($wasStarted = $session->isStarted()) { $session->save(); } if ($session instanceof Session ? !$session->isEmpty() || (null !== $this->sessionId && $session->getId() !== $this->sessionId) : $wasStarted) { $params = session_get_cookie_params() + ['samesite' => null]; foreach ($this->sessionOptions as $k => $v) { if (str_starts_with($k, 'cookie_')) { $params[substr($k, 7)] = $v; } } foreach ($event->getResponse()->headers->getCookies() as $cookie) { if ($session->getName() === $cookie->getName() && $params['path'] === $cookie->getPath() && $params['domain'] == $cookie->getDomain()) { return; } } $event->getResponse()->headers->setCookie(new Cookie($session->getName(), $session->getId(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly'], false, $params['samesite'] ?: null)); $this->sessionId = $session->getId(); } } public static function getSubscribedEvents(): array { return [ KernelEvents::REQUEST => ['onKernelRequest', 127], // AFTER SessionListener KernelEvents::RESPONSE => ['onKernelResponse', -128], ]; } /** * Gets the session object. * * @return SessionInterface|null */ abstract protected function getSession(); } PK'\BnEventListener/DumpListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\Console\ConsoleEvents; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\VarDumper\Cloner\ClonerInterface; use Symfony\Component\VarDumper\Dumper\DataDumperInterface; use Symfony\Component\VarDumper\Server\Connection; use Symfony\Component\VarDumper\VarDumper; /** * Configures dump() handler. * * @author Nicolas Grekas */ class DumpListener implements EventSubscriberInterface { private $cloner; private $dumper; private $connection; public function __construct(ClonerInterface $cloner, DataDumperInterface $dumper, Connection $connection = null) { $this->cloner = $cloner; $this->dumper = $dumper; $this->connection = $connection; } public function configure() { $cloner = $this->cloner; $dumper = $this->dumper; $connection = $this->connection; VarDumper::setHandler(static function ($var) use ($cloner, $dumper, $connection) { $data = $cloner->cloneVar($var); if (!$connection || !$connection->write($data)) { $dumper->dump($data); } }); } public static function getSubscribedEvents() { if (!class_exists(ConsoleEvents::class)) { return []; } // Register early to have a working dump() as early as possible return [ConsoleEvents::COMMAND => ['configure', 1024]]; } } PK'\56 6 EventListener/LocaleListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\KernelEvent; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Routing\RequestContextAwareInterface; /** * Initializes the locale based on the current request. * * @author Fabien Potencier * * @final */ class LocaleListener implements EventSubscriberInterface { private $router; private $defaultLocale; private $requestStack; private $useAcceptLanguageHeader; private $enabledLocales; public function __construct(RequestStack $requestStack, string $defaultLocale = 'en', RequestContextAwareInterface $router = null, bool $useAcceptLanguageHeader = false, array $enabledLocales = []) { $this->defaultLocale = $defaultLocale; $this->requestStack = $requestStack; $this->router = $router; $this->useAcceptLanguageHeader = $useAcceptLanguageHeader; $this->enabledLocales = $enabledLocales; } public function setDefaultLocale(KernelEvent $event) { $event->getRequest()->setDefaultLocale($this->defaultLocale); } public function onKernelRequest(RequestEvent $event) { $request = $event->getRequest(); $this->setLocale($request); $this->setRouterContext($request); } public function onKernelFinishRequest(FinishRequestEvent $event) { if (null !== $parentRequest = $this->requestStack->getParentRequest()) { $this->setRouterContext($parentRequest); } } private function setLocale(Request $request) { if ($locale = $request->attributes->get('_locale')) { $request->setLocale($locale); } elseif ($this->useAcceptLanguageHeader && $this->enabledLocales && ($preferredLanguage = $request->getPreferredLanguage($this->enabledLocales))) { $request->setLocale($preferredLanguage); $request->attributes->set('_vary_by_language', true); } } private function setRouterContext(Request $request) { if (null !== $this->router) { $this->router->getContext()->setParameter('_locale', $request->getLocale()); } } public static function getSubscribedEvents(): array { return [ KernelEvents::REQUEST => [ ['setDefaultLocale', 100], // must be registered after the Router to have access to the _locale ['onKernelRequest', 16], ], KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]], ]; } } PK'\:WSEventListener/ErrorListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Log\LoggerInterface; use Symfony\Component\Debug\Exception\FlattenException as LegacyFlattenException; use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; /** * @author Fabien Potencier */ class ErrorListener implements EventSubscriberInterface { protected $controller; protected $logger; protected $debug; /** * @var array|null}> */ protected $exceptionsMapping; /** * @param array|null}> $exceptionsMapping */ public function __construct($controller, LoggerInterface $logger = null, bool $debug = false, array $exceptionsMapping = []) { $this->controller = $controller; $this->logger = $logger; $this->debug = $debug; $this->exceptionsMapping = $exceptionsMapping; } public function logKernelException(ExceptionEvent $event) { $throwable = $event->getThrowable(); $logLevel = null; foreach ($this->exceptionsMapping as $class => $config) { if ($throwable instanceof $class && $config['log_level']) { $logLevel = $config['log_level']; break; } } foreach ($this->exceptionsMapping as $class => $config) { if (!$throwable instanceof $class || !$config['status_code']) { continue; } if (!$throwable instanceof HttpExceptionInterface || $throwable->getStatusCode() !== $config['status_code']) { $headers = $throwable instanceof HttpExceptionInterface ? $throwable->getHeaders() : []; $throwable = new HttpException($config['status_code'], $throwable->getMessage(), $throwable, $headers); $event->setThrowable($throwable); } break; } $e = FlattenException::createFromThrowable($throwable); $this->logException($throwable, sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), $e->getFile(), $e->getLine()), $logLevel); } public function onKernelException(ExceptionEvent $event) { if (null === $this->controller) { return; } $throwable = $event->getThrowable(); $request = $this->duplicateRequest($throwable, $event->getRequest()); try { $response = $event->getKernel()->handle($request, HttpKernelInterface::SUB_REQUEST, false); } catch (\Exception $e) { $f = FlattenException::createFromThrowable($e); $this->logException($e, sprintf('Exception thrown when handling an exception (%s: %s at %s line %s)', $f->getClass(), $f->getMessage(), $e->getFile(), $e->getLine())); $prev = $e; do { if ($throwable === $wrapper = $prev) { throw $e; } } while ($prev = $wrapper->getPrevious()); $prev = new \ReflectionProperty($wrapper instanceof \Exception ? \Exception::class : \Error::class, 'previous'); $prev->setAccessible(true); $prev->setValue($wrapper, $throwable); throw $e; } $event->setResponse($response); if ($this->debug) { $event->getRequest()->attributes->set('_remove_csp_headers', true); } } public function removeCspHeader(ResponseEvent $event): void { if ($this->debug && $event->getRequest()->attributes->get('_remove_csp_headers', false)) { $event->getResponse()->headers->remove('Content-Security-Policy'); } } public function onControllerArguments(ControllerArgumentsEvent $event) { $e = $event->getRequest()->attributes->get('exception'); if (!$e instanceof \Throwable || false === $k = array_search($e, $event->getArguments(), true)) { return; } $r = new \ReflectionFunction(\Closure::fromCallable($event->getController())); $r = $r->getParameters()[$k] ?? null; if ($r && (!($r = $r->getType()) instanceof \ReflectionNamedType || \in_array($r->getName(), [FlattenException::class, LegacyFlattenException::class], true))) { $arguments = $event->getArguments(); $arguments[$k] = FlattenException::createFromThrowable($e); $event->setArguments($arguments); } } public static function getSubscribedEvents(): array { return [ KernelEvents::CONTROLLER_ARGUMENTS => 'onControllerArguments', KernelEvents::EXCEPTION => [ ['logKernelException', 0], ['onKernelException', -128], ], KernelEvents::RESPONSE => ['removeCspHeader', -128], ]; } /** * Logs an exception. */ protected function logException(\Throwable $exception, string $message, string $logLevel = null): void { if (null !== $this->logger) { if (null !== $logLevel) { $this->logger->log($logLevel, $message, ['exception' => $exception]); } elseif (!$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500) { $this->logger->critical($message, ['exception' => $exception]); } else { $this->logger->error($message, ['exception' => $exception]); } } } /** * Clones the request for the exception. */ protected function duplicateRequest(\Throwable $exception, Request $request): Request { $attributes = [ '_controller' => $this->controller, 'exception' => $exception, 'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null, ]; $request = $request->duplicate(null, null, $attributes); $request->setMethod('GET'); return $request; } } PK'\ů/~~'EventListener/DebugHandlersListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Log\LoggerInterface; use Symfony\Component\Console\ConsoleEvents; use Symfony\Component\Console\Event\ConsoleEvent; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\ErrorHandler\ErrorHandler; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\KernelEvent; use Symfony\Component\HttpKernel\KernelEvents; /** * Configures errors and exceptions handlers. * * @author Nicolas Grekas * * @final * * @internal since Symfony 5.3 */ class DebugHandlersListener implements EventSubscriberInterface { private $earlyHandler; private $exceptionHandler; private $logger; private $deprecationLogger; private $levels; private $throwAt; private $scream; private $scope; private $firstCall = true; private $hasTerminatedWithException; /** * @param callable|null $exceptionHandler A handler that must support \Throwable instances that will be called on Exception * @param array|int|null $levels An array map of E_* to LogLevel::* or an integer bit field of E_* constants * @param int|null $throwAt Thrown errors in a bit field of E_* constants, or null to keep the current value * @param bool $scream Enables/disables screaming mode, where even silenced errors are logged * @param bool $scope Enables/disables scoping mode */ public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, $levels = \E_ALL, ?int $throwAt = \E_ALL, bool $scream = true, $scope = true, $deprecationLogger = null, $fileLinkFormat = null) { if (!\is_bool($scope)) { trigger_deprecation('symfony/http-kernel', '5.4', 'Passing a $fileLinkFormat is deprecated.'); $scope = $deprecationLogger; $deprecationLogger = $fileLinkFormat; } $handler = set_exception_handler('is_int'); $this->earlyHandler = \is_array($handler) ? $handler[0] : null; restore_exception_handler(); $this->exceptionHandler = $exceptionHandler; $this->logger = $logger; $this->levels = $levels ?? \E_ALL; $this->throwAt = \is_int($throwAt) ? $throwAt : (null === $throwAt ? null : ($throwAt ? \E_ALL : null)); $this->scream = $scream; $this->scope = $scope; $this->deprecationLogger = $deprecationLogger; } /** * Configures the error handler. */ public function configure(object $event = null) { if ($event instanceof ConsoleEvent && !\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { return; } if (!$event instanceof KernelEvent ? !$this->firstCall : !$event->isMainRequest()) { return; } $this->firstCall = $this->hasTerminatedWithException = false; $handler = set_exception_handler('is_int'); $handler = \is_array($handler) ? $handler[0] : null; restore_exception_handler(); if (!$handler instanceof ErrorHandler) { $handler = $this->earlyHandler; } if ($handler instanceof ErrorHandler) { if ($this->logger || $this->deprecationLogger) { $this->setDefaultLoggers($handler); if (\is_array($this->levels)) { $levels = 0; foreach ($this->levels as $type => $log) { $levels |= $type; } } else { $levels = $this->levels; } if ($this->scream) { $handler->screamAt($levels); } if ($this->scope) { $handler->scopeAt($levels & ~\E_USER_DEPRECATED & ~\E_DEPRECATED); } else { $handler->scopeAt(0, true); } $this->logger = $this->deprecationLogger = $this->levels = null; } if (null !== $this->throwAt) { $handler->throwAt($this->throwAt, true); } } if (!$this->exceptionHandler) { if ($event instanceof KernelEvent) { if (method_exists($kernel = $event->getKernel(), 'terminateWithException')) { $request = $event->getRequest(); $hasRun = &$this->hasTerminatedWithException; $this->exceptionHandler = static function (\Throwable $e) use ($kernel, $request, &$hasRun) { if ($hasRun) { throw $e; } $hasRun = true; $kernel->terminateWithException($e, $request); }; } } elseif ($event instanceof ConsoleEvent && $app = $event->getCommand()->getApplication()) { $output = $event->getOutput(); if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } $this->exceptionHandler = static function (\Throwable $e) use ($app, $output) { $app->renderThrowable($e, $output); }; } } if ($this->exceptionHandler) { if ($handler instanceof ErrorHandler) { $handler->setExceptionHandler($this->exceptionHandler); } $this->exceptionHandler = null; } } private function setDefaultLoggers(ErrorHandler $handler): void { if (\is_array($this->levels)) { $levelsDeprecatedOnly = []; $levelsWithoutDeprecated = []; foreach ($this->levels as $type => $log) { if (\E_DEPRECATED == $type || \E_USER_DEPRECATED == $type) { $levelsDeprecatedOnly[$type] = $log; } else { $levelsWithoutDeprecated[$type] = $log; } } } else { $levelsDeprecatedOnly = $this->levels & (\E_DEPRECATED | \E_USER_DEPRECATED); $levelsWithoutDeprecated = $this->levels & ~\E_DEPRECATED & ~\E_USER_DEPRECATED; } $defaultLoggerLevels = $this->levels; if ($this->deprecationLogger && $levelsDeprecatedOnly) { $handler->setDefaultLogger($this->deprecationLogger, $levelsDeprecatedOnly); $defaultLoggerLevels = $levelsWithoutDeprecated; } if ($this->logger && $defaultLoggerLevels) { $handler->setDefaultLogger($this->logger, $defaultLoggerLevels); } } public static function getSubscribedEvents(): array { $events = [KernelEvents::REQUEST => ['configure', 2048]]; if (\defined('Symfony\Component\Console\ConsoleEvents::COMMAND')) { $events[ConsoleEvents::COMMAND] = ['configure', 2048]; } return $events; } } PK'\3׶ EventListener/RouterListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Routing\Exception\MethodNotAllowedException; use Symfony\Component\Routing\Exception\NoConfigurationException; use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Matcher\RequestMatcherInterface; use Symfony\Component\Routing\Matcher\UrlMatcherInterface; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\RequestContextAwareInterface; /** * Initializes the context from the request and sets request attributes based on a matching route. * * @author Fabien Potencier * @author Yonel Ceruto * * @final */ class RouterListener implements EventSubscriberInterface { private $matcher; private $context; private $logger; private $requestStack; private $projectDir; private $debug; /** * @param UrlMatcherInterface|RequestMatcherInterface $matcher The Url or Request matcher * @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface) * * @throws \InvalidArgumentException */ public function __construct($matcher, RequestStack $requestStack, RequestContext $context = null, LoggerInterface $logger = null, string $projectDir = null, bool $debug = true) { if (!$matcher instanceof UrlMatcherInterface && !$matcher instanceof RequestMatcherInterface) { throw new \InvalidArgumentException('Matcher must either implement UrlMatcherInterface or RequestMatcherInterface.'); } if (null === $context && !$matcher instanceof RequestContextAwareInterface) { throw new \InvalidArgumentException('You must either pass a RequestContext or the matcher must implement RequestContextAwareInterface.'); } $this->matcher = $matcher; $this->context = $context ?? $matcher->getContext(); $this->requestStack = $requestStack; $this->logger = $logger; $this->projectDir = $projectDir; $this->debug = $debug; } private function setCurrentRequest(Request $request = null) { if (null !== $request) { try { $this->context->fromRequest($request); } catch (\UnexpectedValueException $e) { throw new BadRequestHttpException($e->getMessage(), $e, $e->getCode()); } } } /** * After a sub-request is done, we need to reset the routing context to the parent request so that the URL generator * operates on the correct context again. */ public function onKernelFinishRequest(FinishRequestEvent $event) { $this->setCurrentRequest($this->requestStack->getParentRequest()); } public function onKernelRequest(RequestEvent $event) { $request = $event->getRequest(); $this->setCurrentRequest($request); if ($request->attributes->has('_controller')) { // routing is already done return; } // add attributes based on the request (routing) try { // matching a request is more powerful than matching a URL path + context, so try that first if ($this->matcher instanceof RequestMatcherInterface) { $parameters = $this->matcher->matchRequest($request); } else { $parameters = $this->matcher->match($request->getPathInfo()); } if (null !== $this->logger) { $this->logger->info('Matched route "{route}".', [ 'route' => $parameters['_route'] ?? 'n/a', 'route_parameters' => $parameters, 'request_uri' => $request->getUri(), 'method' => $request->getMethod(), ]); } $request->attributes->add($parameters); unset($parameters['_route'], $parameters['_controller']); $request->attributes->set('_route_params', $parameters); } catch (ResourceNotFoundException $e) { $message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getUriForPath($request->getPathInfo())); if ($referer = $request->headers->get('referer')) { $message .= sprintf(' (from "%s")', $referer); } throw new NotFoundHttpException($message, $e); } catch (MethodNotAllowedException $e) { $message = sprintf('No route found for "%s %s": Method Not Allowed (Allow: %s)', $request->getMethod(), $request->getUriForPath($request->getPathInfo()), implode(', ', $e->getAllowedMethods())); throw new MethodNotAllowedHttpException($e->getAllowedMethods(), $message, $e); } } public function onKernelException(ExceptionEvent $event) { if (!$this->debug || !($e = $event->getThrowable()) instanceof NotFoundHttpException) { return; } if ($e->getPrevious() instanceof NoConfigurationException) { $event->setResponse($this->createWelcomeResponse()); } } public static function getSubscribedEvents(): array { return [ KernelEvents::REQUEST => [['onKernelRequest', 32]], KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]], KernelEvents::EXCEPTION => ['onKernelException', -64], ]; } private function createWelcomeResponse(): Response { $version = Kernel::VERSION; $projectDir = realpath((string) $this->projectDir).\DIRECTORY_SEPARATOR; $docVersion = substr(Kernel::VERSION, 0, 3); ob_start(); include \dirname(__DIR__).'/Resources/welcome.html.php'; return new Response(ob_get_clean(), Response::HTTP_NOT_FOUND); } } PK'\)jj0EventListener/DisallowRobotsIndexingListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; /** * Ensures that the application is not indexed by search engines. * * @author Gary PEGEOT */ class DisallowRobotsIndexingListener implements EventSubscriberInterface { private const HEADER_NAME = 'X-Robots-Tag'; public function onResponse(ResponseEvent $event): void { if (!$event->getResponse()->headers->has(static::HEADER_NAME)) { $event->getResponse()->headers->set(static::HEADER_NAME, 'noindex'); } } /** * {@inheritdoc} */ public static function getSubscribedEvents() { return [ KernelEvents::RESPONSE => ['onResponse', -255], ]; } } PK'\+-+EventListener/AddRequestFormatsListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; /** * Adds configured formats to each request. * * @author Gildas Quemener * * @final */ class AddRequestFormatsListener implements EventSubscriberInterface { protected $formats; public function __construct(array $formats) { $this->formats = $formats; } /** * Adds request formats. */ public function onKernelRequest(RequestEvent $event) { $request = $event->getRequest(); foreach ($this->formats as $format => $mimeTypes) { $request->setFormat($format, $mimeTypes); } } /** * {@inheritdoc} */ public static function getSubscribedEvents(): array { return [KernelEvents::REQUEST => ['onKernelRequest', 100]]; } } PK'\u000!EventListener/SessionListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; use Symfony\Component\HttpKernel\Event\RequestEvent; /** * Sets the session in the request. * * When the passed container contains a "session_storage" entry which * holds a NativeSessionStorage instance, the "cookie_secure" option * will be set to true whenever the current main request is secure. * * @author Fabien Potencier * * @final */ class SessionListener extends AbstractSessionListener { public function onKernelRequest(RequestEvent $event) { parent::onKernelRequest($event); if (!$event->isMainRequest() || (!$this->container->has('session') && !$this->container->has('session_factory'))) { return; } if ($this->container->has('session_storage') && ($storage = $this->container->get('session_storage')) instanceof NativeSessionStorage && ($mainRequest = $this->container->get('request_stack')->getMainRequest()) && $mainRequest->isSecure() ) { $storage->setOptions(['cookie_secure' => true]); } } protected function getSession(): ?SessionInterface { if ($this->container->has('session')) { return $this->container->get('session'); } if ($this->container->has('session_factory')) { return $this->container->get('session_factory')->createSession(); } return null; } } PK'\<*EventListener/StreamedResponseListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; /** * StreamedResponseListener is responsible for sending the Response * to the client. * * @author Fabien Potencier * * @final */ class StreamedResponseListener implements EventSubscriberInterface { /** * Filters the Response. */ public function onKernelResponse(ResponseEvent $event) { if (!$event->isMainRequest()) { return; } $response = $event->getResponse(); if ($response instanceof StreamedResponse) { $response->send(); } } public static function getSubscribedEvents(): array { return [ KernelEvents::RESPONSE => ['onKernelResponse', -1024], ]; } } PK'\wUw w %EventListener/LocaleAwareListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Contracts\Translation\LocaleAwareInterface; /** * Pass the current locale to the provided services. * * @author Pierre Bobiet */ class LocaleAwareListener implements EventSubscriberInterface { private $localeAwareServices; private $requestStack; /** * @param iterable $localeAwareServices */ public function __construct(iterable $localeAwareServices, RequestStack $requestStack) { $this->localeAwareServices = $localeAwareServices; $this->requestStack = $requestStack; } public function onKernelRequest(RequestEvent $event): void { $this->setLocale($event->getRequest()->getLocale(), $event->getRequest()->getDefaultLocale()); } public function onKernelFinishRequest(FinishRequestEvent $event): void { if (null === $parentRequest = $this->requestStack->getParentRequest()) { foreach ($this->localeAwareServices as $service) { $service->setLocale($event->getRequest()->getDefaultLocale()); } return; } $this->setLocale($parentRequest->getLocale(), $parentRequest->getDefaultLocale()); } public static function getSubscribedEvents() { return [ // must be registered after the Locale listener KernelEvents::REQUEST => [['onKernelRequest', 15]], KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', -15]], ]; } private function setLocale(string $locale, string $defaultLocale): void { foreach ($this->localeAwareServices as $service) { try { $service->setLocale($locale); } catch (\InvalidArgumentException $e) { $service->setLocale($defaultLocale); } } } } PK'\W^ ^ "EventListener/FragmentListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\UriSigner; /** * Handles content fragments represented by special URIs. * * All URL paths starting with /_fragment are handled as * content fragments by this listener. * * Throws an AccessDeniedHttpException exception if the request * is not signed or if it is not an internal sub-request. * * @author Fabien Potencier * * @final */ class FragmentListener implements EventSubscriberInterface { private $signer; private $fragmentPath; /** * @param string $fragmentPath The path that triggers this listener */ public function __construct(UriSigner $signer, string $fragmentPath = '/_fragment') { $this->signer = $signer; $this->fragmentPath = $fragmentPath; } /** * Fixes request attributes when the path is '/_fragment'. * * @throws AccessDeniedHttpException if the request does not come from a trusted IP */ public function onKernelRequest(RequestEvent $event) { $request = $event->getRequest(); if ($this->fragmentPath !== rawurldecode($request->getPathInfo())) { return; } if ($request->attributes->has('_controller')) { // Is a sub-request: no need to parse _path but it should still be removed from query parameters as below. $request->query->remove('_path'); return; } if ($event->isMainRequest()) { $this->validateRequest($request); } parse_str($request->query->get('_path', ''), $attributes); $request->attributes->add($attributes); $request->attributes->set('_route_params', array_replace($request->attributes->get('_route_params', []), $attributes)); $request->query->remove('_path'); } protected function validateRequest(Request $request) { // is the Request safe? if (!$request->isMethodSafe()) { throw new AccessDeniedHttpException(); } // is the Request signed? if ($this->signer->checkRequest($request)) { return; } throw new AccessDeniedHttpException(); } public static function getSubscribedEvents(): array { return [ KernelEvents::REQUEST => [['onKernelRequest', 48]], ]; } } PK'\ E'44)EventListener/AbstractSessionListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Container\ContainerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpFoundation\Session\SessionUtils; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\Exception\UnexpectedSessionUsageException; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Contracts\Service\ResetInterface; /** * Sets the session onto the request on the "kernel.request" event and saves * it on the "kernel.response" event. * * In addition, if the session has been started it overrides the Cache-Control * header in such a way that all caching is disabled in that case. * If you have a scenario where caching responses with session information in * them makes sense, you can disable this behaviour by setting the header * AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER on the response. * * @author Johannes M. Schmitt * @author Tobias Schultze * * @internal */ abstract class AbstractSessionListener implements EventSubscriberInterface, ResetInterface { public const NO_AUTO_CACHE_CONTROL_HEADER = 'Symfony-Session-NoAutoCacheControl'; protected $container; private $sessionUsageStack = []; private $debug; /** * @var array */ private $sessionOptions; public function __construct(ContainerInterface $container = null, bool $debug = false, array $sessionOptions = []) { $this->container = $container; $this->debug = $debug; $this->sessionOptions = $sessionOptions; } public function onKernelRequest(RequestEvent $event) { if (!$event->isMainRequest()) { return; } $request = $event->getRequest(); if (!$request->hasSession()) { // This variable prevents calling `$this->getSession()` twice in case the Request (and the below factory) is cloned $sess = null; $request->setSessionFactory(function () use (&$sess, $request) { if (!$sess) { $sess = $this->getSession(); /* * For supporting sessions in php runtime with runners like roadrunner or swoole, the session * cookie needs to be read from the cookie bag and set on the session storage. * * Do not set it when a native php session is active. */ if ($sess && !$sess->isStarted() && \PHP_SESSION_ACTIVE !== session_status()) { $sessionId = $sess->getId() ?: $request->cookies->get($sess->getName(), ''); $sess->setId($sessionId); } } return $sess; }); } $session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : null; $this->sessionUsageStack[] = $session instanceof Session ? $session->getUsageIndex() : 0; } public function onKernelResponse(ResponseEvent $event) { if (!$event->isMainRequest() || (!$this->container->has('initialized_session') && !$event->getRequest()->hasSession())) { return; } $response = $event->getResponse(); $autoCacheControl = !$response->headers->has(self::NO_AUTO_CACHE_CONTROL_HEADER); // Always remove the internal header if present $response->headers->remove(self::NO_AUTO_CACHE_CONTROL_HEADER); if (!$session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : ($event->getRequest()->hasSession() ? $event->getRequest()->getSession() : null)) { return; } if ($session->isStarted()) { /* * Saves the session, in case it is still open, before sending the response/headers. * * This ensures several things in case the developer did not save the session explicitly: * * * If a session save handler without locking is used, it ensures the data is available * on the next request, e.g. after a redirect. PHPs auto-save at script end via * session_register_shutdown is executed after fastcgi_finish_request. So in this case * the data could be missing the next request because it might not be saved the moment * the new request is processed. * * A locking save handler (e.g. the native 'files') circumvents concurrency problems like * the one above. But by saving the session before long-running things in the terminate event, * we ensure the session is not blocked longer than needed. * * When regenerating the session ID no locking is involved in PHPs session design. See * https://bugs.php.net/61470 for a discussion. So in this case, the session must * be saved anyway before sending the headers with the new session ID. Otherwise session * data could get lost again for concurrent requests with the new ID. One result could be * that you get logged out after just logging in. * * This listener should be executed as one of the last listeners, so that previous listeners * can still operate on the open session. This prevents the overhead of restarting it. * Listeners after closing the session can still work with the session as usual because * Symfonys session implementation starts the session on demand. So writing to it after * it is saved will just restart it. */ $session->save(); /* * For supporting sessions in php runtime with runners like roadrunner or swoole the session * cookie need to be written on the response object and should not be written by PHP itself. */ $sessionName = $session->getName(); $sessionId = $session->getId(); $sessionOptions = $this->getSessionOptions($this->sessionOptions); $sessionCookiePath = $sessionOptions['cookie_path'] ?? '/'; $sessionCookieDomain = $sessionOptions['cookie_domain'] ?? null; $sessionCookieSecure = $sessionOptions['cookie_secure'] ?? false; $sessionCookieHttpOnly = $sessionOptions['cookie_httponly'] ?? true; $sessionCookieSameSite = $sessionOptions['cookie_samesite'] ?? Cookie::SAMESITE_LAX; $sessionUseCookies = $sessionOptions['use_cookies'] ?? true; SessionUtils::popSessionCookie($sessionName, $sessionId); if ($sessionUseCookies) { $request = $event->getRequest(); $requestSessionCookieId = $request->cookies->get($sessionName); $isSessionEmpty = $session->isEmpty() && empty($_SESSION); // checking $_SESSION to keep compatibility with native sessions if ($requestSessionCookieId && $isSessionEmpty) { // PHP internally sets the session cookie value to "deleted" when setcookie() is called with empty string $value argument // which happens in \Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler::destroy // when the session gets invalidated (for example on logout) so we must handle this case here too // otherwise we would send two Set-Cookie headers back with the response SessionUtils::popSessionCookie($sessionName, 'deleted'); $response->headers->clearCookie( $sessionName, $sessionCookiePath, $sessionCookieDomain, $sessionCookieSecure, $sessionCookieHttpOnly, $sessionCookieSameSite ); } elseif ($sessionId !== $requestSessionCookieId && !$isSessionEmpty) { $expire = 0; $lifetime = $sessionOptions['cookie_lifetime'] ?? null; if ($lifetime) { $expire = time() + $lifetime; } $response->headers->setCookie( Cookie::create( $sessionName, $sessionId, $expire, $sessionCookiePath, $sessionCookieDomain, $sessionCookieSecure, $sessionCookieHttpOnly, false, $sessionCookieSameSite ) ); } } } if ($session instanceof Session ? $session->getUsageIndex() === end($this->sessionUsageStack) : !$session->isStarted()) { return; } if ($autoCacheControl) { $maxAge = $response->headers->hasCacheControlDirective('public') ? 0 : (int) $response->getMaxAge(); $response ->setExpires(new \DateTimeImmutable('+'.$maxAge.' seconds')) ->setPrivate() ->setMaxAge($maxAge) ->headers->addCacheControlDirective('must-revalidate'); } if (!$event->getRequest()->attributes->get('_stateless', false)) { return; } if ($this->debug) { throw new UnexpectedSessionUsageException('Session was used while the request was declared stateless.'); } if ($this->container->has('logger')) { $this->container->get('logger')->warning('Session was used while the request was declared stateless.'); } } public function onFinishRequest(FinishRequestEvent $event) { if ($event->isMainRequest()) { array_pop($this->sessionUsageStack); } } public function onSessionUsage(): void { if (!$this->debug) { return; } if ($this->container && $this->container->has('session_collector')) { $this->container->get('session_collector')(); } if (!$requestStack = $this->container && $this->container->has('request_stack') ? $this->container->get('request_stack') : null) { return; } $stateless = false; $clonedRequestStack = clone $requestStack; while (null !== ($request = $clonedRequestStack->pop()) && !$stateless) { $stateless = $request->attributes->get('_stateless'); } if (!$stateless) { return; } if (!$session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : $requestStack->getCurrentRequest()->getSession()) { return; } if ($session->isStarted()) { $session->save(); } throw new UnexpectedSessionUsageException('Session was used while the request was declared stateless.'); } public static function getSubscribedEvents(): array { return [ KernelEvents::REQUEST => ['onKernelRequest', 128], // low priority to come after regular response listeners, but higher than StreamedResponseListener KernelEvents::RESPONSE => ['onKernelResponse', -1000], KernelEvents::FINISH_REQUEST => ['onFinishRequest'], ]; } public function reset(): void { if (\PHP_SESSION_ACTIVE === session_status()) { session_abort(); } session_unset(); $_SESSION = []; if (!headers_sent()) { // session id can only be reset when no headers were so we check for headers_sent first session_id(''); } } /** * Gets the session object. * * @return SessionInterface|null */ abstract protected function getSession(); private function getSessionOptions(array $sessionOptions): array { $mergedSessionOptions = []; foreach (session_get_cookie_params() as $key => $value) { $mergedSessionOptions['cookie_'.$key] = $value; } foreach ($sessionOptions as $key => $value) { // do the same logic as in the NativeSessionStorage if ('cookie_secure' === $key && 'auto' === $value) { continue; } $mergedSessionOptions[$key] = $value; } return $mergedSessionOptions; } } PK'\KxmF,,"EventListener/ProfilerListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcherInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\Event\TerminateEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Profiler\Profile; use Symfony\Component\HttpKernel\Profiler\Profiler; /** * ProfilerListener collects data for the current request by listening to the kernel events. * * @author Fabien Potencier * * @final */ class ProfilerListener implements EventSubscriberInterface { protected $profiler; protected $matcher; protected $onlyException; protected $onlyMainRequests; protected $exception; /** @var \SplObjectStorage */ protected $profiles; protected $requestStack; protected $collectParameter; /** @var \SplObjectStorage */ protected $parents; /** * @param bool $onlyException True if the profiler only collects data when an exception occurs, false otherwise * @param bool $onlyMainRequests True if the profiler only collects data when the request is the main request, false otherwise */ public function __construct(Profiler $profiler, RequestStack $requestStack, RequestMatcherInterface $matcher = null, bool $onlyException = false, bool $onlyMainRequests = false, string $collectParameter = null) { $this->profiler = $profiler; $this->matcher = $matcher; $this->onlyException = $onlyException; $this->onlyMainRequests = $onlyMainRequests; $this->profiles = new \SplObjectStorage(); $this->parents = new \SplObjectStorage(); $this->requestStack = $requestStack; $this->collectParameter = $collectParameter; } /** * Handles the onKernelException event. */ public function onKernelException(ExceptionEvent $event) { if ($this->onlyMainRequests && !$event->isMainRequest()) { return; } $this->exception = $event->getThrowable(); } /** * Handles the onKernelResponse event. */ public function onKernelResponse(ResponseEvent $event) { if ($this->onlyMainRequests && !$event->isMainRequest()) { return; } if ($this->onlyException && null === $this->exception) { return; } $request = $event->getRequest(); if (null !== $this->collectParameter && null !== $collectParameterValue = $request->get($this->collectParameter)) { true === $collectParameterValue || filter_var($collectParameterValue, \FILTER_VALIDATE_BOOLEAN) ? $this->profiler->enable() : $this->profiler->disable(); } $exception = $this->exception; $this->exception = null; if (null !== $this->matcher && !$this->matcher->matches($request)) { return; } $session = $request->hasPreviousSession() && $request->hasSession() ? $request->getSession() : null; if ($session instanceof Session) { $usageIndexValue = $usageIndexReference = &$session->getUsageIndex(); $usageIndexReference = \PHP_INT_MIN; } try { if (!$profile = $this->profiler->collect($request, $event->getResponse(), $exception)) { return; } } finally { if ($session instanceof Session) { $usageIndexReference = $usageIndexValue; } } $this->profiles[$request] = $profile; $this->parents[$request] = $this->requestStack->getParentRequest(); } public function onKernelTerminate(TerminateEvent $event) { // attach children to parents foreach ($this->profiles as $request) { if (null !== $parentRequest = $this->parents[$request]) { if (isset($this->profiles[$parentRequest])) { $this->profiles[$parentRequest]->addChild($this->profiles[$request]); } } } // save profiles foreach ($this->profiles as $request) { $this->profiler->saveProfile($this->profiles[$request]); } $this->profiles = new \SplObjectStorage(); $this->parents = new \SplObjectStorage(); } public static function getSubscribedEvents(): array { return [ KernelEvents::RESPONSE => ['onKernelResponse', -100], KernelEvents::EXCEPTION => ['onKernelException', 0], KernelEvents::TERMINATE => ['onKernelTerminate', -1024], ]; } } PK'\u~n)EventListener/ValidateRequestListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; /** * Validates Requests. * * @author Magnus Nordlander * * @final */ class ValidateRequestListener implements EventSubscriberInterface { /** * Performs the validation. */ public function onKernelRequest(RequestEvent $event) { if (!$event->isMainRequest()) { return; } $request = $event->getRequest(); if ($request::getTrustedProxies()) { $request->getClientIps(); } $request->getHost(); } /** * {@inheritdoc} */ public static function getSubscribedEvents(): array { return [ KernelEvents::REQUEST => [ ['onKernelRequest', 256], ], ]; } } PK'\1;#EventListener/SurrogateListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\HttpCache\HttpCache; use Symfony\Component\HttpKernel\HttpCache\SurrogateInterface; use Symfony\Component\HttpKernel\KernelEvents; /** * SurrogateListener adds a Surrogate-Control HTTP header when the Response needs to be parsed for Surrogates. * * @author Fabien Potencier * * @final */ class SurrogateListener implements EventSubscriberInterface { private $surrogate; public function __construct(SurrogateInterface $surrogate = null) { $this->surrogate = $surrogate; } /** * Filters the Response. */ public function onKernelResponse(ResponseEvent $event) { if (!$event->isMainRequest()) { return; } $kernel = $event->getKernel(); $surrogate = $this->surrogate; if ($kernel instanceof HttpCache) { $surrogate = $kernel->getSurrogate(); if (null !== $this->surrogate && $this->surrogate->getName() !== $surrogate->getName()) { $surrogate = $this->surrogate; } } if (null === $surrogate) { return; } $surrogate->addSurrogateControl($event->getResponse()); } public static function getSubscribedEvents(): array { return [ KernelEvents::RESPONSE => 'onKernelResponse', ]; } } PK'\UU"EventListener/ResponseListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; /** * ResponseListener fixes the Response headers based on the Request. * * @author Fabien Potencier * * @final */ class ResponseListener implements EventSubscriberInterface { private $charset; private $addContentLanguageHeader; public function __construct(string $charset, bool $addContentLanguageHeader = false) { $this->charset = $charset; $this->addContentLanguageHeader = $addContentLanguageHeader; } /** * Filters the Response. */ public function onKernelResponse(ResponseEvent $event) { if (!$event->isMainRequest()) { return; } $response = $event->getResponse(); if (null === $response->getCharset()) { $response->setCharset($this->charset); } if ($this->addContentLanguageHeader && !$response->isInformational() && !$response->isEmpty() && !$response->headers->has('Content-Language')) { $response->headers->set('Content-Language', $event->getRequest()->getLocale()); } if ($event->getRequest()->attributes->get('_vary_by_language')) { $response->setVary('Accept-Language', false); } $response->prepare($event->getRequest()); } public static function getSubscribedEvents(): array { return [ KernelEvents::RESPONSE => 'onKernelResponse', ]; } } PK'\Z%EventListener/TestSessionListener.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Container\ContainerInterface; use Symfony\Component\HttpFoundation\Session\SessionInterface; trigger_deprecation('symfony/http-kernel', '5.4', '"%s" is deprecated, use "%s" instead.', TestSessionListener::class, SessionListener::class); /** * Sets the session in the request. * * @author Fabien Potencier * * @final * * @deprecated since Symfony 5.4, use SessionListener instead */ class TestSessionListener extends AbstractTestSessionListener { private $container; public function __construct(ContainerInterface $container, array $sessionOptions = []) { $this->container = $container; parent::__construct($sessionOptions); } protected function getSession(): ?SessionInterface { if ($this->container->has('session')) { return $this->container->get('session'); } return null; } } PK'\,`Event/FinishRequestEvent.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; /** * Triggered whenever a request is fully processed. * * @author Benjamin Eberlei */ final class FinishRequestEvent extends KernelEvent { } PK'\ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Allows to execute logic after a response was sent. * * Since it's only triggered on main requests, the `getRequestType()` method * will always return the value of `HttpKernelInterface::MAIN_REQUEST`. * * @author Jordi Boggiano */ final class TerminateEvent extends KernelEvent { private $response; public function __construct(HttpKernelInterface $kernel, Request $request, Response $response) { parent::__construct($kernel, $request, HttpKernelInterface::MAIN_REQUEST); $this->response = $response; } public function getResponse(): Response { return $this->response; } } PK'\.Event/ViewEvent.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Allows to create a response for the return value of a controller. * * Call setResponse() to set the response that will be returned for the * current request. The propagation of this event is stopped as soon as a * response is set. * * @author Bernhard Schussek */ final class ViewEvent extends RequestEvent { /** * The return value of the controller. * * @var mixed */ private $controllerResult; public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, $controllerResult) { parent::__construct($kernel, $request, $requestType); $this->controllerResult = $controllerResult; } /** * Returns the return value of the controller. * * @return mixed */ public function getControllerResult() { return $this->controllerResult; } /** * Assigns the return value of the controller. * * @param mixed $controllerResult The controller return value */ public function setControllerResult($controllerResult): void { $this->controllerResult = $controllerResult; } } PK'\vEvent/RequestEvent.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Response; /** * Allows to create a response for a request. * * Call setResponse() to set the response that will be returned for the * current request. The propagation of this event is stopped as soon as a * response is set. * * @author Bernhard Schussek */ class RequestEvent extends KernelEvent { private $response; /** * Returns the response object. * * @return Response|null */ public function getResponse() { return $this->response; } /** * Sets a response and stops event propagation. */ public function setResponse(Response $response) { $this->response = $response; $this->stopPropagation(); } /** * Returns whether a response was set. * * @return bool */ public function hasResponse() { return null !== $this->response; } } PK'\A!  Event/KernelEvent.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Contracts\EventDispatcher\Event; /** * Base class for events thrown in the HttpKernel component. * * @author Bernhard Schussek */ class KernelEvent extends Event { private $kernel; private $request; private $requestType; /** * @param int $requestType The request type the kernel is currently processing; one of * HttpKernelInterface::MAIN_REQUEST or HttpKernelInterface::SUB_REQUEST */ public function __construct(HttpKernelInterface $kernel, Request $request, ?int $requestType) { $this->kernel = $kernel; $this->request = $request; $this->requestType = $requestType; } /** * Returns the kernel in which this event was thrown. * * @return HttpKernelInterface */ public function getKernel() { return $this->kernel; } /** * Returns the request the kernel is currently processing. * * @return Request */ public function getRequest() { return $this->request; } /** * Returns the request type the kernel is currently processing. * * @return int One of HttpKernelInterface::MAIN_REQUEST and * HttpKernelInterface::SUB_REQUEST */ public function getRequestType() { return $this->requestType; } /** * Checks if this is the main request. */ public function isMainRequest(): bool { return HttpKernelInterface::MAIN_REQUEST === $this->requestType; } /** * Checks if this is a master request. * * @return bool * * @deprecated since symfony/http-kernel 5.3, use isMainRequest() instead */ public function isMasterRequest() { trigger_deprecation('symfony/http-kernel', '5.3', '"%s()" is deprecated, use "isMainRequest()" instead.', __METHOD__); return $this->isMainRequest(); } } PK'\j@pEvent/ExceptionEvent.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Allows to create a response for a thrown exception. * * Call setResponse() to set the response that will be returned for the * current request. The propagation of this event is stopped as soon as a * response is set. * * You can also call setThrowable() to replace the thrown exception. This * exception will be thrown if no response is set during processing of this * event. * * @author Bernhard Schussek */ final class ExceptionEvent extends RequestEvent { private $throwable; /** * @var bool */ private $allowCustomResponseCode = false; public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, \Throwable $e) { parent::__construct($kernel, $request, $requestType); $this->setThrowable($e); } public function getThrowable(): \Throwable { return $this->throwable; } /** * Replaces the thrown exception. * * This exception will be thrown if no response is set in the event. */ public function setThrowable(\Throwable $exception): void { $this->throwable = $exception; } /** * Mark the event as allowing a custom response code. */ public function allowCustomResponseCode(): void { $this->allowCustomResponseCode = true; } /** * Returns true if the event allows a custom response code. */ public function isAllowingCustomResponseCode(): bool { return $this->allowCustomResponseCode; } } PK'\0C:Event/ResponseEvent.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Allows to filter a Response object. * * You can call getResponse() to retrieve the current response. With * setResponse() you can set a new response that will be returned to the * browser. * * @author Bernhard Schussek */ final class ResponseEvent extends KernelEvent { private $response; public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, Response $response) { parent::__construct($kernel, $request, $requestType); $this->setResponse($response); } public function getResponse(): Response { return $this->response; } public function setResponse(Response $response): void { $this->response = $response; } } PK'\.ɊEvent/ControllerEvent.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Allows filtering of a controller callable. * * You can call getController() to retrieve the current controller. With * setController() you can set a new controller that is used in the processing * of the request. * * Controllers should be callables. * * @author Bernhard Schussek */ final class ControllerEvent extends KernelEvent { private $controller; public function __construct(HttpKernelInterface $kernel, callable $controller, Request $request, ?int $requestType) { parent::__construct($kernel, $request, $requestType); $this->setController($controller); } public function getController(): callable { return $this->controller; } public function setController(callable $controller): void { $this->controller = $controller; } } PK'\dM//"Event/ControllerArgumentsEvent.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Allows filtering of controller arguments. * * You can call getController() to retrieve the controller and getArguments * to retrieve the current arguments. With setArguments() you can replace * arguments that are used to call the controller. * * Arguments set in the event must be compatible with the signature of the * controller. * * @author Christophe Coevoet */ final class ControllerArgumentsEvent extends KernelEvent { private $controller; private $arguments; public function __construct(HttpKernelInterface $kernel, callable $controller, array $arguments, Request $request, ?int $requestType) { parent::__construct($kernel, $request, $requestType); $this->controller = $controller; $this->arguments = $arguments; } public function getController(): callable { return $this->controller; } public function setController(callable $controller) { $this->controller = $controller; } public function getArguments(): array { return $this->arguments; } public function setArguments(array $arguments) { $this->arguments = $arguments; } } PK'\*4 $DataCollector/EventDataCollector.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use Symfony\Contracts\Service\ResetInterface; /** * @author Fabien Potencier * * @final */ class EventDataCollector extends DataCollector implements LateDataCollectorInterface { protected $dispatcher; private $requestStack; private $currentRequest; public function __construct(EventDispatcherInterface $dispatcher = null, RequestStack $requestStack = null) { $this->dispatcher = $dispatcher; $this->requestStack = $requestStack; } /** * {@inheritdoc} */ public function collect(Request $request, Response $response, \Throwable $exception = null) { $this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null; $this->data = [ 'called_listeners' => [], 'not_called_listeners' => [], 'orphaned_events' => [], ]; } public function reset() { $this->data = []; if ($this->dispatcher instanceof ResetInterface) { $this->dispatcher->reset(); } } public function lateCollect() { if ($this->dispatcher instanceof TraceableEventDispatcher) { $this->setCalledListeners($this->dispatcher->getCalledListeners($this->currentRequest)); $this->setNotCalledListeners($this->dispatcher->getNotCalledListeners($this->currentRequest)); $this->setOrphanedEvents($this->dispatcher->getOrphanedEvents($this->currentRequest)); } $this->data = $this->cloneVar($this->data); } /** * @param array $listeners An array of called listeners * * @see TraceableEventDispatcher */ public function setCalledListeners(array $listeners) { $this->data['called_listeners'] = $listeners; } /** * @see TraceableEventDispatcher * * @return array|Data */ public function getCalledListeners() { return $this->data['called_listeners']; } /** * @see TraceableEventDispatcher */ public function setNotCalledListeners(array $listeners) { $this->data['not_called_listeners'] = $listeners; } /** * @see TraceableEventDispatcher * * @return array|Data */ public function getNotCalledListeners() { return $this->data['not_called_listeners']; } /** * @param array $events An array of orphaned events * * @see TraceableEventDispatcher */ public function setOrphanedEvents(array $events) { $this->data['orphaned_events'] = $events; } /** * @see TraceableEventDispatcher * * @return array|Data */ public function getOrphanedEvents() { return $this->data['orphaned_events']; } /** * {@inheritdoc} */ public function getName(): string { return 'events'; } } PK'\B U U %DataCollector/MemoryDataCollector.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * @author Fabien Potencier * * @final */ class MemoryDataCollector extends DataCollector implements LateDataCollectorInterface { public function __construct() { $this->reset(); } /** * {@inheritdoc} */ public function collect(Request $request, Response $response, \Throwable $exception = null) { $this->updateMemoryUsage(); } /** * {@inheritdoc} */ public function reset() { $this->data = [ 'memory' => 0, 'memory_limit' => $this->convertToBytes(\ini_get('memory_limit')), ]; } /** * {@inheritdoc} */ public function lateCollect() { $this->updateMemoryUsage(); } public function getMemory(): int { return $this->data['memory']; } /** * @return int|float */ public function getMemoryLimit() { return $this->data['memory_limit']; } public function updateMemoryUsage() { $this->data['memory'] = memory_get_peak_usage(true); } /** * {@inheritdoc} */ public function getName(): string { return 'memory'; } /** * @return int|float */ private function convertToBytes(string $memoryLimit) { if ('-1' === $memoryLimit) { return -1; } $memoryLimit = strtolower($memoryLimit); $max = strtolower(ltrim($memoryLimit, '+')); if (str_starts_with($max, '0x')) { $max = \intval($max, 16); } elseif (str_starts_with($max, '0')) { $max = \intval($max, 8); } else { $max = (int) $max; } switch (substr($memoryLimit, -1)) { case 't': $max *= 1024; // no break case 'g': $max *= 1024; // no break case 'm': $max *= 1024; // no break case 'k': $max *= 1024; } return $max; } } PK'\O=R++%DataCollector/LoggerDataCollector.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; /** * @author Fabien Potencier * * @final */ class LoggerDataCollector extends DataCollector implements LateDataCollectorInterface { private $logger; private $containerPathPrefix; private $currentRequest; private $requestStack; private $processedLogs; public function __construct(object $logger = null, string $containerPathPrefix = null, RequestStack $requestStack = null) { if (null !== $logger && $logger instanceof DebugLoggerInterface) { $this->logger = $logger; } $this->containerPathPrefix = $containerPathPrefix; $this->requestStack = $requestStack; } /** * {@inheritdoc} */ public function collect(Request $request, Response $response, \Throwable $exception = null) { $this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null; } /** * {@inheritdoc} */ public function reset() { if ($this->logger instanceof DebugLoggerInterface) { $this->logger->clear(); } $this->data = []; } /** * {@inheritdoc} */ public function lateCollect() { if (null !== $this->logger) { $containerDeprecationLogs = $this->getContainerDeprecationLogs(); $this->data = $this->computeErrorsCount($containerDeprecationLogs); // get compiler logs later (only when they are needed) to improve performance $this->data['compiler_logs'] = []; $this->data['compiler_logs_filepath'] = $this->containerPathPrefix.'Compiler.log'; $this->data['logs'] = $this->sanitizeLogs(array_merge($this->logger->getLogs($this->currentRequest), $containerDeprecationLogs)); $this->data = $this->cloneVar($this->data); } $this->currentRequest = null; } public function getLogs() { return $this->data['logs'] ?? []; } public function getProcessedLogs() { if (null !== $this->processedLogs) { return $this->processedLogs; } $rawLogs = $this->getLogs(); if ([] === $rawLogs) { return $this->processedLogs = $rawLogs; } $logs = []; foreach ($this->getLogs()->getValue() as $rawLog) { $rawLogData = $rawLog->getValue(); if ($rawLogData['priority']->getValue() > 300) { $logType = 'error'; } elseif (isset($rawLogData['scream']) && false === $rawLogData['scream']->getValue()) { $logType = 'deprecation'; } elseif (isset($rawLogData['scream']) && true === $rawLogData['scream']->getValue()) { $logType = 'silenced'; } else { $logType = 'regular'; } $logs[] = [ 'type' => $logType, 'errorCount' => $rawLog['errorCount'] ?? 1, 'timestamp' => $rawLogData['timestamp_rfc3339']->getValue(), 'priority' => $rawLogData['priority']->getValue(), 'priorityName' => $rawLogData['priorityName']->getValue(), 'channel' => $rawLogData['channel']->getValue(), 'message' => $rawLogData['message'], 'context' => $rawLogData['context'], ]; } // sort logs from oldest to newest usort($logs, static function ($logA, $logB) { return $logA['timestamp'] <=> $logB['timestamp']; }); return $this->processedLogs = $logs; } public function getFilters() { $filters = [ 'channel' => [], 'priority' => [ 'Debug' => 100, 'Info' => 200, 'Notice' => 250, 'Warning' => 300, 'Error' => 400, 'Critical' => 500, 'Alert' => 550, 'Emergency' => 600, ], ]; $allChannels = []; foreach ($this->getProcessedLogs() as $log) { if ('' === trim($log['channel'] ?? '')) { continue; } $allChannels[] = $log['channel']; } $channels = array_unique($allChannels); sort($channels); $filters['channel'] = $channels; return $filters; } public function getPriorities() { return $this->data['priorities'] ?? []; } public function countErrors() { return $this->data['error_count'] ?? 0; } public function countDeprecations() { return $this->data['deprecation_count'] ?? 0; } public function countWarnings() { return $this->data['warning_count'] ?? 0; } public function countScreams() { return $this->data['scream_count'] ?? 0; } public function getCompilerLogs() { return $this->cloneVar($this->getContainerCompilerLogs($this->data['compiler_logs_filepath'] ?? null)); } /** * {@inheritdoc} */ public function getName(): string { return 'logger'; } private function getContainerDeprecationLogs(): array { if (null === $this->containerPathPrefix || !is_file($file = $this->containerPathPrefix.'Deprecations.log')) { return []; } if ('' === $logContent = trim(file_get_contents($file))) { return []; } $bootTime = filemtime($file); $logs = []; foreach (unserialize($logContent) as $log) { $log['context'] = ['exception' => new SilencedErrorContext($log['type'], $log['file'], $log['line'], $log['trace'], $log['count'])]; $log['timestamp'] = $bootTime; $log['timestamp_rfc3339'] = (new \DateTimeImmutable())->setTimestamp($bootTime)->format(\DateTimeInterface::RFC3339_EXTENDED); $log['priority'] = 100; $log['priorityName'] = 'DEBUG'; $log['channel'] = null; $log['scream'] = false; unset($log['type'], $log['file'], $log['line'], $log['trace'], $log['trace'], $log['count']); $logs[] = $log; } return $logs; } private function getContainerCompilerLogs(string $compilerLogsFilepath = null): array { if (!is_file($compilerLogsFilepath)) { return []; } $logs = []; foreach (file($compilerLogsFilepath, \FILE_IGNORE_NEW_LINES) as $log) { $log = explode(': ', $log, 2); if (!isset($log[1]) || !preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)++$/', $log[0])) { $log = ['Unknown Compiler Pass', implode(': ', $log)]; } $logs[$log[0]][] = ['message' => $log[1]]; } return $logs; } private function sanitizeLogs(array $logs) { $sanitizedLogs = []; $silencedLogs = []; foreach ($logs as $log) { if (!$this->isSilencedOrDeprecationErrorLog($log)) { $sanitizedLogs[] = $log; continue; } $message = '_'.$log['message']; $exception = $log['context']['exception']; if ($exception instanceof SilencedErrorContext) { if (isset($silencedLogs[$h = spl_object_hash($exception)])) { continue; } $silencedLogs[$h] = true; if (!isset($sanitizedLogs[$message])) { $sanitizedLogs[$message] = $log + [ 'errorCount' => 0, 'scream' => true, ]; } $sanitizedLogs[$message]['errorCount'] += $exception->count; continue; } $errorId = md5("{$exception->getSeverity()}/{$exception->getLine()}/{$exception->getFile()}\0{$message}", true); if (isset($sanitizedLogs[$errorId])) { ++$sanitizedLogs[$errorId]['errorCount']; } else { $log += [ 'errorCount' => 1, 'scream' => false, ]; $sanitizedLogs[$errorId] = $log; } } return array_values($sanitizedLogs); } private function isSilencedOrDeprecationErrorLog(array $log): bool { if (!isset($log['context']['exception'])) { return false; } $exception = $log['context']['exception']; if ($exception instanceof SilencedErrorContext) { return true; } if ($exception instanceof \ErrorException && \in_array($exception->getSeverity(), [\E_DEPRECATED, \E_USER_DEPRECATED], true)) { return true; } return false; } private function computeErrorsCount(array $containerDeprecationLogs): array { $silencedLogs = []; $count = [ 'error_count' => $this->logger->countErrors($this->currentRequest), 'deprecation_count' => 0, 'warning_count' => 0, 'scream_count' => 0, 'priorities' => [], ]; foreach ($this->logger->getLogs($this->currentRequest) as $log) { if (isset($count['priorities'][$log['priority']])) { ++$count['priorities'][$log['priority']]['count']; } else { $count['priorities'][$log['priority']] = [ 'count' => 1, 'name' => $log['priorityName'], ]; } if ('WARNING' === $log['priorityName']) { ++$count['warning_count']; } if ($this->isSilencedOrDeprecationErrorLog($log)) { $exception = $log['context']['exception']; if ($exception instanceof SilencedErrorContext) { if (isset($silencedLogs[$h = spl_object_hash($exception)])) { continue; } $silencedLogs[$h] = true; $count['scream_count'] += $exception->count; } else { ++$count['deprecation_count']; } } } foreach ($containerDeprecationLogs as $deprecationLog) { $count['deprecation_count'] += $deprecationLog['context']['exception']->count; } ksort($count['priorities']); return $count; } } PK'\$h h #DataCollector/TimeDataCollector.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\Stopwatch\StopwatchEvent; /** * @author Fabien Potencier * * @final */ class TimeDataCollector extends DataCollector implements LateDataCollectorInterface { private $kernel; private $stopwatch; public function __construct(KernelInterface $kernel = null, Stopwatch $stopwatch = null) { $this->kernel = $kernel; $this->stopwatch = $stopwatch; } /** * {@inheritdoc} */ public function collect(Request $request, Response $response, \Throwable $exception = null) { if (null !== $this->kernel) { $startTime = $this->kernel->getStartTime(); } else { $startTime = $request->server->get('REQUEST_TIME_FLOAT'); } $this->data = [ 'token' => $request->attributes->get('_stopwatch_token'), 'start_time' => $startTime * 1000, 'events' => [], 'stopwatch_installed' => class_exists(Stopwatch::class, false), ]; } /** * {@inheritdoc} */ public function reset() { $this->data = []; if (null !== $this->stopwatch) { $this->stopwatch->reset(); } } /** * {@inheritdoc} */ public function lateCollect() { if (null !== $this->stopwatch && isset($this->data['token'])) { $this->setEvents($this->stopwatch->getSectionEvents($this->data['token'])); } unset($this->data['token']); } /** * @param StopwatchEvent[] $events The request events */ public function setEvents(array $events) { foreach ($events as $event) { $event->ensureStopped(); } $this->data['events'] = $events; } /** * @return StopwatchEvent[] */ public function getEvents(): array { return $this->data['events']; } /** * Gets the request elapsed time. */ public function getDuration(): float { if (!isset($this->data['events']['__section__'])) { return 0; } $lastEvent = $this->data['events']['__section__']; return $lastEvent->getOrigin() + $lastEvent->getDuration() - $this->getStartTime(); } /** * Gets the initialization time. * * This is the time spent until the beginning of the request handling. */ public function getInitTime(): float { if (!isset($this->data['events']['__section__'])) { return 0; } return $this->data['events']['__section__']->getOrigin() - $this->getStartTime(); } public function getStartTime(): float { return $this->data['start_time']; } public function isStopwatchInstalled(): bool { return $this->data['stopwatch_installed']; } /** * {@inheritdoc} */ public function getName(): string { return 'time'; } } PK'\Sa a %DataCollector/RouterDataCollector.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ControllerEvent; /** * @author Fabien Potencier */ class RouterDataCollector extends DataCollector { /** * @var \SplObjectStorage */ protected $controllers; public function __construct() { $this->reset(); } /** * {@inheritdoc} * * @final */ public function collect(Request $request, Response $response, \Throwable $exception = null) { if ($response instanceof RedirectResponse) { $this->data['redirect'] = true; $this->data['url'] = $response->getTargetUrl(); if ($this->controllers->contains($request)) { $this->data['route'] = $this->guessRoute($request, $this->controllers[$request]); } } unset($this->controllers[$request]); } public function reset() { $this->controllers = new \SplObjectStorage(); $this->data = [ 'redirect' => false, 'url' => null, 'route' => null, ]; } protected function guessRoute(Request $request, $controller) { return 'n/a'; } /** * Remembers the controller associated to each request. */ public function onKernelController(ControllerEvent $event) { $this->controllers[$event->getRequest()] = $event->getController(); } /** * @return bool Whether this request will result in a redirect */ public function getRedirect() { return $this->data['redirect']; } /** * @return string|null */ public function getTargetUrl() { return $this->data['url']; } /** * @return string|null */ public function getTargetRoute() { return $this->data['route']; } /** * {@inheritdoc} */ public function getName() { return 'router'; } } PK'\ <,DataCollector/LateDataCollectorInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; /** * LateDataCollectorInterface. * * @author Fabien Potencier */ interface LateDataCollectorInterface { /** * Collects data as late as possible. */ public function lateCollect(); } PK'\???&DataCollector/RequestDataCollector.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionBagInterface; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\Event\ControllerEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\VarDumper\Cloner\Data; /** * @author Fabien Potencier * * @final */ class RequestDataCollector extends DataCollector implements EventSubscriberInterface, LateDataCollectorInterface { /** * @var \SplObjectStorage */ private $controllers; private $sessionUsages = []; private $requestStack; public function __construct(RequestStack $requestStack = null) { $this->controllers = new \SplObjectStorage(); $this->requestStack = $requestStack; } /** * {@inheritdoc} */ public function collect(Request $request, Response $response, \Throwable $exception = null) { // attributes are serialized and as they can be anything, they need to be converted to strings. $attributes = []; $route = ''; foreach ($request->attributes->all() as $key => $value) { if ('_route' === $key) { $route = \is_object($value) ? $value->getPath() : $value; $attributes[$key] = $route; } else { $attributes[$key] = $value; } } $content = $request->getContent(); $sessionMetadata = []; $sessionAttributes = []; $flashes = []; if ($request->hasSession()) { $session = $request->getSession(); if ($session->isStarted()) { $sessionMetadata['Created'] = date(\DATE_RFC822, $session->getMetadataBag()->getCreated()); $sessionMetadata['Last used'] = date(\DATE_RFC822, $session->getMetadataBag()->getLastUsed()); $sessionMetadata['Lifetime'] = $session->getMetadataBag()->getLifetime(); $sessionAttributes = $session->all(); $flashes = $session->getFlashBag()->peekAll(); } } $statusCode = $response->getStatusCode(); $responseCookies = []; foreach ($response->headers->getCookies() as $cookie) { $responseCookies[$cookie->getName()] = $cookie; } $dotenvVars = []; foreach (explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? $_ENV['SYMFONY_DOTENV_VARS'] ?? '') as $name) { if ('' !== $name && isset($_ENV[$name])) { $dotenvVars[$name] = $_ENV[$name]; } } $this->data = [ 'method' => $request->getMethod(), 'format' => $request->getRequestFormat(), 'content_type' => $response->headers->get('Content-Type', 'text/html'), 'status_text' => Response::$statusTexts[$statusCode] ?? '', 'status_code' => $statusCode, 'request_query' => $request->query->all(), 'request_request' => $request->request->all(), 'request_files' => $request->files->all(), 'request_headers' => $request->headers->all(), 'request_server' => $request->server->all(), 'request_cookies' => $request->cookies->all(), 'request_attributes' => $attributes, 'route' => $route, 'response_headers' => $response->headers->all(), 'response_cookies' => $responseCookies, 'session_metadata' => $sessionMetadata, 'session_attributes' => $sessionAttributes, 'session_usages' => array_values($this->sessionUsages), 'stateless_check' => $this->requestStack && ($mainRequest = $this->requestStack->getMainRequest()) && $mainRequest->attributes->get('_stateless', false), 'flashes' => $flashes, 'path_info' => $request->getPathInfo(), 'controller' => 'n/a', 'locale' => $request->getLocale(), 'dotenv_vars' => $dotenvVars, ]; if (isset($this->data['request_headers']['php-auth-pw'])) { $this->data['request_headers']['php-auth-pw'] = '******'; } if (isset($this->data['request_server']['PHP_AUTH_PW'])) { $this->data['request_server']['PHP_AUTH_PW'] = '******'; } if (isset($this->data['request_request']['_password'])) { $encodedPassword = rawurlencode($this->data['request_request']['_password']); $content = str_replace('_password='.$encodedPassword, '_password=******', $content); $this->data['request_request']['_password'] = '******'; } $this->data['content'] = $content; foreach ($this->data as $key => $value) { if (!\is_array($value)) { continue; } if ('request_headers' === $key || 'response_headers' === $key) { $this->data[$key] = array_map(function ($v) { return isset($v[0]) && !isset($v[1]) ? $v[0] : $v; }, $value); } } if (isset($this->controllers[$request])) { $this->data['controller'] = $this->parseController($this->controllers[$request]); unset($this->controllers[$request]); } if ($request->attributes->has('_redirected') && $redirectCookie = $request->cookies->get('sf_redirect')) { $this->data['redirect'] = json_decode($redirectCookie, true); $response->headers->clearCookie('sf_redirect'); } if ($response->isRedirect()) { $response->headers->setCookie(new Cookie( 'sf_redirect', json_encode([ 'token' => $response->headers->get('x-debug-token'), 'route' => $request->attributes->get('_route', 'n/a'), 'method' => $request->getMethod(), 'controller' => $this->parseController($request->attributes->get('_controller')), 'status_code' => $statusCode, 'status_text' => Response::$statusTexts[$statusCode], ]), 0, '/', null, $request->isSecure(), true, false, 'lax' )); } $this->data['identifier'] = $this->data['route'] ?: (\is_array($this->data['controller']) ? $this->data['controller']['class'].'::'.$this->data['controller']['method'].'()' : $this->data['controller']); if ($response->headers->has('x-previous-debug-token')) { $this->data['forward_token'] = $response->headers->get('x-previous-debug-token'); } } public function lateCollect() { $this->data = $this->cloneVar($this->data); } public function reset() { $this->data = []; $this->controllers = new \SplObjectStorage(); $this->sessionUsages = []; } public function getMethod() { return $this->data['method']; } public function getPathInfo() { return $this->data['path_info']; } public function getRequestRequest() { return new ParameterBag($this->data['request_request']->getValue()); } public function getRequestQuery() { return new ParameterBag($this->data['request_query']->getValue()); } public function getRequestFiles() { return new ParameterBag($this->data['request_files']->getValue()); } public function getRequestHeaders() { return new ParameterBag($this->data['request_headers']->getValue()); } public function getRequestServer(bool $raw = false) { return new ParameterBag($this->data['request_server']->getValue($raw)); } public function getRequestCookies(bool $raw = false) { return new ParameterBag($this->data['request_cookies']->getValue($raw)); } public function getRequestAttributes() { return new ParameterBag($this->data['request_attributes']->getValue()); } public function getResponseHeaders() { return new ParameterBag($this->data['response_headers']->getValue()); } public function getResponseCookies() { return new ParameterBag($this->data['response_cookies']->getValue()); } public function getSessionMetadata() { return $this->data['session_metadata']->getValue(); } public function getSessionAttributes() { return $this->data['session_attributes']->getValue(); } public function getStatelessCheck() { return $this->data['stateless_check']; } public function getSessionUsages() { return $this->data['session_usages']; } public function getFlashes() { return $this->data['flashes']->getValue(); } public function getContent() { return $this->data['content']; } public function isJsonRequest() { return 1 === preg_match('{^application/(?:\w+\++)*json$}i', $this->data['request_headers']['content-type']); } public function getPrettyJson() { $decoded = json_decode($this->getContent()); return \JSON_ERROR_NONE === json_last_error() ? json_encode($decoded, \JSON_PRETTY_PRINT) : null; } public function getContentType() { return $this->data['content_type']; } public function getStatusText() { return $this->data['status_text']; } public function getStatusCode() { return $this->data['status_code']; } public function getFormat() { return $this->data['format']; } public function getLocale() { return $this->data['locale']; } public function getDotenvVars() { return new ParameterBag($this->data['dotenv_vars']->getValue()); } /** * Gets the route name. * * The _route request attributes is automatically set by the Router Matcher. */ public function getRoute(): string { return $this->data['route']; } public function getIdentifier() { return $this->data['identifier']; } /** * Gets the route parameters. * * The _route_params request attributes is automatically set by the RouterListener. */ public function getRouteParams(): array { return isset($this->data['request_attributes']['_route_params']) ? $this->data['request_attributes']['_route_params']->getValue() : []; } /** * Gets the parsed controller. * * @return array|string|Data The controller as a string or array of data * with keys 'class', 'method', 'file' and 'line' */ public function getController() { return $this->data['controller']; } /** * Gets the previous request attributes. * * @return array|Data|false A legacy array of data from the previous redirection response * or false otherwise */ public function getRedirect() { return $this->data['redirect'] ?? false; } public function getForwardToken() { return $this->data['forward_token'] ?? null; } public function onKernelController(ControllerEvent $event) { $this->controllers[$event->getRequest()] = $event->getController(); } public function onKernelResponse(ResponseEvent $event) { if (!$event->isMainRequest()) { return; } if ($event->getRequest()->cookies->has('sf_redirect')) { $event->getRequest()->attributes->set('_redirected', true); } } public static function getSubscribedEvents(): array { return [ KernelEvents::CONTROLLER => 'onKernelController', KernelEvents::RESPONSE => 'onKernelResponse', ]; } /** * {@inheritdoc} */ public function getName(): string { return 'request'; } public function collectSessionUsage(): void { $trace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); $traceEndIndex = \count($trace) - 1; for ($i = $traceEndIndex; $i > 0; --$i) { if (null !== ($class = $trace[$i]['class'] ?? null) && (is_subclass_of($class, SessionInterface::class) || is_subclass_of($class, SessionBagInterface::class))) { $traceEndIndex = $i; break; } } if ((\count($trace) - 1) === $traceEndIndex) { return; } // Remove part of the backtrace that belongs to session only array_splice($trace, 0, $traceEndIndex); // Merge identical backtraces generated by internal call reports $name = sprintf('%s:%s', $trace[1]['class'] ?? $trace[0]['file'], $trace[0]['line']); if (!\array_key_exists($name, $this->sessionUsages)) { $this->sessionUsages[$name] = [ 'name' => $name, 'file' => $trace[0]['file'], 'line' => $trace[0]['line'], 'trace' => $trace, ]; } } /** * @param string|object|array|null $controller The controller to parse * * @return array|string An array of controller data or a simple string */ private function parseController($controller) { if (\is_string($controller) && str_contains($controller, '::')) { $controller = explode('::', $controller); } if (\is_array($controller)) { try { $r = new \ReflectionMethod($controller[0], $controller[1]); return [ 'class' => \is_object($controller[0]) ? get_debug_type($controller[0]) : $controller[0], 'method' => $controller[1], 'file' => $r->getFileName(), 'line' => $r->getStartLine(), ]; } catch (\ReflectionException $e) { if (\is_callable($controller)) { // using __call or __callStatic return [ 'class' => \is_object($controller[0]) ? get_debug_type($controller[0]) : $controller[0], 'method' => $controller[1], 'file' => 'n/a', 'line' => 'n/a', ]; } } } if ($controller instanceof \Closure) { $r = new \ReflectionFunction($controller); $controller = [ 'class' => $r->getName(), 'method' => null, 'file' => $r->getFileName(), 'line' => $r->getStartLine(), ]; if (str_contains($r->name, '{closure}')) { return $controller; } $controller['method'] = $r->name; if ($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) { $controller['class'] = $class->name; } else { return $r->name; } return $controller; } if (\is_object($controller)) { $r = new \ReflectionClass($controller); return [ 'class' => $r->getName(), 'method' => null, 'file' => $r->getFileName(), 'line' => $r->getStartLine(), ]; } return \is_string($controller) ? $controller : 'n/a'; } } PK'\Af f DataCollector/DataCollector.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\VarDumper\Caster\CutStub; use Symfony\Component\VarDumper\Caster\ReflectionCaster; use Symfony\Component\VarDumper\Cloner\ClonerInterface; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\Stub; use Symfony\Component\VarDumper\Cloner\VarCloner; /** * DataCollector. * * Children of this class must store the collected data in the data property. * * @author Fabien Potencier * @author Bernhard Schussek */ abstract class DataCollector implements DataCollectorInterface { /** * @var array|Data */ protected $data = []; /** * @var ClonerInterface */ private $cloner; /** * Converts the variable into a serializable Data instance. * * This array can be displayed in the template using * the VarDumper component. * * @param mixed $var * * @return Data */ protected function cloneVar($var) { if ($var instanceof Data) { return $var; } if (null === $this->cloner) { $this->cloner = new VarCloner(); $this->cloner->setMaxItems(-1); $this->cloner->addCasters($this->getCasters()); } return $this->cloner->cloneVar($var); } /** * @return callable[] The casters to add to the cloner */ protected function getCasters() { $casters = [ '*' => function ($v, array $a, Stub $s, $isNested) { if (!$v instanceof Stub) { foreach ($a as $k => $v) { if (\is_object($v) && !$v instanceof \DateTimeInterface && !$v instanceof Stub) { $a[$k] = new CutStub($v); } } } return $a; }, ] + ReflectionCaster::UNSET_CLOSURE_FILE_INFO; return $casters; } /** * @return array */ public function __sleep() { return ['data']; } public function __wakeup() { } /** * @internal to prevent implementing \Serializable */ final protected function serialize() { } /** * @internal to prevent implementing \Serializable */ final protected function unserialize($data) { } } PK'\ L33#DataCollector/AjaxDataCollector.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * @author Bart van den Burg * * @final */ class AjaxDataCollector extends DataCollector { public function collect(Request $request, Response $response, \Throwable $exception = null) { // all collecting is done client side } public function reset() { // all collecting is done client side } public function getName(): string { return 'ajax'; } } PK'\=%DataCollector/ConfigDataCollector.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\VarDumper\Caster\ClassStub; /** * @author Fabien Potencier * * @final */ class ConfigDataCollector extends DataCollector implements LateDataCollectorInterface { /** * @var KernelInterface */ private $kernel; /** * Sets the Kernel associated with this Request. */ public function setKernel(KernelInterface $kernel = null) { $this->kernel = $kernel; } /** * {@inheritdoc} */ public function collect(Request $request, Response $response, \Throwable $exception = null) { $eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE); $eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE); $this->data = [ 'token' => $response->headers->get('X-Debug-Token'), 'symfony_version' => Kernel::VERSION, 'symfony_minor_version' => sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION), 'symfony_lts' => 4 === Kernel::MINOR_VERSION, 'symfony_state' => $this->determineSymfonyState(), 'symfony_eom' => $eom->format('F Y'), 'symfony_eol' => $eol->format('F Y'), 'env' => isset($this->kernel) ? $this->kernel->getEnvironment() : 'n/a', 'debug' => isset($this->kernel) ? $this->kernel->isDebug() : 'n/a', 'php_version' => \PHP_VERSION, 'php_architecture' => \PHP_INT_SIZE * 8, 'php_intl_locale' => class_exists(\Locale::class, false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a', 'php_timezone' => date_default_timezone_get(), 'xdebug_enabled' => \extension_loaded('xdebug'), 'apcu_enabled' => \extension_loaded('apcu') && filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN), 'zend_opcache_enabled' => \extension_loaded('Zend OPcache') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN), 'bundles' => [], 'sapi_name' => \PHP_SAPI, ]; if (isset($this->kernel)) { foreach ($this->kernel->getBundles() as $name => $bundle) { $this->data['bundles'][$name] = new ClassStub(\get_class($bundle)); } } if (preg_match('~^(\d+(?:\.\d+)*)(.+)?$~', $this->data['php_version'], $matches) && isset($matches[2])) { $this->data['php_version'] = $matches[1]; $this->data['php_version_extra'] = $matches[2]; } } /** * {@inheritdoc} */ public function reset() { $this->data = []; } public function lateCollect() { $this->data = $this->cloneVar($this->data); } /** * Gets the token. */ public function getToken(): ?string { return $this->data['token']; } /** * Gets the Symfony version. */ public function getSymfonyVersion(): string { return $this->data['symfony_version']; } /** * Returns the state of the current Symfony release. * * @return string One of: unknown, dev, stable, eom, eol */ public function getSymfonyState(): string { return $this->data['symfony_state']; } /** * Returns the minor Symfony version used (without patch numbers of extra * suffix like "RC", "beta", etc.). */ public function getSymfonyMinorVersion(): string { return $this->data['symfony_minor_version']; } /** * Returns if the current Symfony version is a Long-Term Support one. */ public function isSymfonyLts(): bool { return $this->data['symfony_lts']; } /** * Returns the human readable date when this Symfony version ends its * maintenance period. */ public function getSymfonyEom(): string { return $this->data['symfony_eom']; } /** * Returns the human readable date when this Symfony version reaches its * "end of life" and won't receive bugs or security fixes. */ public function getSymfonyEol(): string { return $this->data['symfony_eol']; } /** * Gets the PHP version. */ public function getPhpVersion(): string { return $this->data['php_version']; } /** * Gets the PHP version extra part. */ public function getPhpVersionExtra(): ?string { return $this->data['php_version_extra'] ?? null; } /** * @return int The PHP architecture as number of bits (e.g. 32 or 64) */ public function getPhpArchitecture(): int { return $this->data['php_architecture']; } public function getPhpIntlLocale(): string { return $this->data['php_intl_locale']; } public function getPhpTimezone(): string { return $this->data['php_timezone']; } /** * Gets the environment. */ public function getEnv(): string { return $this->data['env']; } /** * Returns true if the debug is enabled. * * @return bool|string true if debug is enabled, false otherwise or a string if no kernel was set */ public function isDebug() { return $this->data['debug']; } /** * Returns true if the XDebug is enabled. */ public function hasXDebug(): bool { return $this->data['xdebug_enabled']; } /** * Returns true if APCu is enabled. */ public function hasApcu(): bool { return $this->data['apcu_enabled']; } /** * Returns true if Zend OPcache is enabled. */ public function hasZendOpcache(): bool { return $this->data['zend_opcache_enabled']; } public function getBundles() { return $this->data['bundles']; } /** * Gets the PHP SAPI name. */ public function getSapiName(): string { return $this->data['sapi_name']; } /** * {@inheritdoc} */ public function getName(): string { return 'config'; } /** * Tries to retrieve information about the current Symfony version. * * @return string One of: dev, stable, eom, eol */ private function determineSymfonyState(): string { $now = new \DateTime(); $eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->modify('last day of this month'); $eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->modify('last day of this month'); if ($now > $eol) { $versionState = 'eol'; } elseif ($now > $eom) { $versionState = 'eom'; } elseif ('' !== Kernel::EXTRA_VERSION) { $versionState = 'dev'; } else { $versionState = 'stable'; } return $versionState; } } PK'\@Nee(DataCollector/DataCollectorInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Contracts\Service\ResetInterface; /** * DataCollectorInterface. * * @author Fabien Potencier */ interface DataCollectorInterface extends ResetInterface { /** * Collects data for the given Request and Response. */ public function collect(Request $request, Response $response, \Throwable $exception = null); /** * Returns the name of the collector. * * @return string */ public function getName(); } PK'\&F(DataCollector/ExceptionDataCollector.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * @author Fabien Potencier * * @final */ class ExceptionDataCollector extends DataCollector { /** * {@inheritdoc} */ public function collect(Request $request, Response $response, \Throwable $exception = null) { if (null !== $exception) { $this->data = [ 'exception' => FlattenException::createFromThrowable($exception), ]; } } /** * {@inheritdoc} */ public function reset() { $this->data = []; } public function hasException(): bool { return isset($this->data['exception']); } /** * @return \Exception|FlattenException */ public function getException() { return $this->data['exception']; } public function getMessage(): string { return $this->data['exception']->getMessage(); } public function getCode(): int { return $this->data['exception']->getCode(); } public function getStatusCode(): int { return $this->data['exception']->getStatusCode(); } public function getTrace(): array { return $this->data['exception']->getTrace(); } /** * {@inheritdoc} */ public function getName(): string { return 'exception'; } } PK'\Ӎ))#DataCollector/DumpDataCollector.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\CliDumper; use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider; use Symfony\Component\VarDumper\Dumper\DataDumperInterface; use Symfony\Component\VarDumper\Dumper\HtmlDumper; use Symfony\Component\VarDumper\Server\Connection; /** * @author Nicolas Grekas * * @final */ class DumpDataCollector extends DataCollector implements DataDumperInterface { private $stopwatch; private $fileLinkFormat; private $dataCount = 0; private $isCollected = true; private $clonesCount = 0; private $clonesIndex = 0; private $rootRefs; private $charset; private $requestStack; private $dumper; private $sourceContextProvider; /** * @param string|FileLinkFormatter|null $fileLinkFormat * @param DataDumperInterface|Connection|null $dumper */ public function __construct(Stopwatch $stopwatch = null, $fileLinkFormat = null, string $charset = null, RequestStack $requestStack = null, $dumper = null) { $fileLinkFormat = $fileLinkFormat ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); $this->stopwatch = $stopwatch; $this->fileLinkFormat = $fileLinkFormat instanceof FileLinkFormatter && false === $fileLinkFormat->format('', 0) ? false : $fileLinkFormat; $this->charset = $charset ?: \ini_get('php.output_encoding') ?: \ini_get('default_charset') ?: 'UTF-8'; $this->requestStack = $requestStack; $this->dumper = $dumper; // All clones share these properties by reference: $this->rootRefs = [ &$this->data, &$this->dataCount, &$this->isCollected, &$this->clonesCount, ]; $this->sourceContextProvider = $dumper instanceof Connection && isset($dumper->getContextProviders()['source']) ? $dumper->getContextProviders()['source'] : new SourceContextProvider($this->charset); } public function __clone() { $this->clonesIndex = ++$this->clonesCount; } public function dump(Data $data) { if ($this->stopwatch) { $this->stopwatch->start('dump'); } ['name' => $name, 'file' => $file, 'line' => $line, 'file_excerpt' => $fileExcerpt] = $this->sourceContextProvider->getContext(); if ($this->dumper instanceof Connection) { if (!$this->dumper->write($data)) { $this->isCollected = false; } } elseif ($this->dumper) { $this->doDump($this->dumper, $data, $name, $file, $line); } else { $this->isCollected = false; } if (!$this->dataCount) { $this->data = []; } $this->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt'); ++$this->dataCount; if ($this->stopwatch) { $this->stopwatch->stop('dump'); } } public function collect(Request $request, Response $response, \Throwable $exception = null) { if (!$this->dataCount) { $this->data = []; } // Sub-requests and programmatic calls stay in the collected profile. if ($this->dumper || ($this->requestStack && $this->requestStack->getMainRequest() !== $request) || $request->isXmlHttpRequest() || $request->headers->has('Origin')) { return; } // In all other conditions that remove the web debug toolbar, dumps are written on the output. if (!$this->requestStack || !$response->headers->has('X-Debug-Token') || $response->isRedirection() || ($response->headers->has('Content-Type') && !str_contains($response->headers->get('Content-Type'), 'html')) || 'html' !== $request->getRequestFormat() || false === strripos($response->getContent(), '') ) { if ($response->headers->has('Content-Type') && str_contains($response->headers->get('Content-Type'), 'html')) { $dumper = new HtmlDumper('php://output', $this->charset); $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } else { $dumper = new CliDumper('php://output', $this->charset); if (method_exists($dumper, 'setDisplayOptions')) { $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } } foreach ($this->data as $dump) { $this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line']); } } } public function reset() { if ($this->stopwatch) { $this->stopwatch->reset(); } $this->data = []; $this->dataCount = 0; $this->isCollected = true; $this->clonesCount = 0; $this->clonesIndex = 0; } /** * @internal */ public function __sleep(): array { if (!$this->dataCount) { $this->data = []; } if ($this->clonesCount !== $this->clonesIndex) { return []; } $this->data[] = $this->fileLinkFormat; $this->data[] = $this->charset; $this->dataCount = 0; $this->isCollected = true; return parent::__sleep(); } /** * @internal */ public function __wakeup() { parent::__wakeup(); $charset = array_pop($this->data); $fileLinkFormat = array_pop($this->data); $this->dataCount = \count($this->data); foreach ($this->data as $dump) { if (!\is_string($dump['name']) || !\is_string($dump['file']) || !\is_int($dump['line'])) { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } } self::__construct($this->stopwatch, \is_string($fileLinkFormat) || $fileLinkFormat instanceof FileLinkFormatter ? $fileLinkFormat : null, \is_string($charset) ? $charset : null); } public function getDumpsCount(): int { return $this->dataCount; } public function getDumps(string $format, int $maxDepthLimit = -1, int $maxItemsPerDepth = -1): array { $data = fopen('php://memory', 'r+'); if ('html' === $format) { $dumper = new HtmlDumper($data, $this->charset); $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } else { throw new \InvalidArgumentException(sprintf('Invalid dump format: "%s".', $format)); } $dumps = []; if (!$this->dataCount) { return $this->data = []; } foreach ($this->data as $dump) { $dumper->dump($dump['data']->withMaxDepth($maxDepthLimit)->withMaxItemsPerDepth($maxItemsPerDepth)); $dump['data'] = stream_get_contents($data, -1, 0); ftruncate($data, 0); rewind($data); $dumps[] = $dump; } return $dumps; } public function getName(): string { return 'dump'; } public function __destruct() { if (0 === $this->clonesCount-- && !$this->isCollected && $this->dataCount) { $this->clonesCount = 0; $this->isCollected = true; $h = headers_list(); $i = \count($h); array_unshift($h, 'Content-Type: '.\ini_get('default_mimetype')); while (0 !== stripos($h[$i], 'Content-Type:')) { --$i; } if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && stripos($h[$i], 'html')) { $dumper = new HtmlDumper('php://output', $this->charset); $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } else { $dumper = new CliDumper('php://output', $this->charset); if (method_exists($dumper, 'setDisplayOptions')) { $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } } foreach ($this->data as $i => $dump) { $this->data[$i] = null; $this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line']); } $this->data = []; $this->dataCount = 0; } } private function doDump(DataDumperInterface $dumper, Data $data, string $name, string $file, int $line) { if ($dumper instanceof CliDumper) { $contextDumper = function ($name, $file, $line, $fmt) { if ($this instanceof HtmlDumper) { if ($file) { $s = $this->style('meta', '%s'); $f = strip_tags($this->style('', $file)); $name = strip_tags($this->style('', $name)); if ($fmt && $link = \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : $fmt->format($file, $line)) { $name = sprintf(''.$s.'', strip_tags($this->style('', $link)), $f, $name); } else { $name = sprintf(''.$s.'', $f, $name); } } else { $name = $this->style('meta', $name); } $this->line = $name.' on line '.$this->style('meta', $line).':'; } else { $this->line = $this->style('meta', $name).' on line '.$this->style('meta', $line).':'; } $this->dumpLine(0); }; $contextDumper = $contextDumper->bindTo($dumper, $dumper); $contextDumper($name, $file, $line, $this->fileLinkFormat); } else { $cloner = new VarCloner(); $dumper->dump($cloner->cloneVar($name.' on line '.$line.':')); } $dumper->dump($data); } } PK'\wKdC C composer.jsonnu[{ "name": "symfony/http-kernel", "type": "library", "description": "Provides a structured process for converting a Request into a Response", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=7.2.5", "symfony/deprecation-contracts": "^2.1|^3", "symfony/error-handler": "^4.4|^5.0|^6.0", "symfony/event-dispatcher": "^5.0|^6.0", "symfony/http-foundation": "^5.3.7|^6.0", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-php73": "^1.9", "symfony/polyfill-php80": "^1.16", "psr/log": "^1|^2" }, "require-dev": { "symfony/browser-kit": "^5.4|^6.0", "symfony/config": "^5.0|^6.0", "symfony/console": "^4.4|^5.0|^6.0", "symfony/css-selector": "^4.4|^5.0|^6.0", "symfony/dependency-injection": "^5.3|^6.0", "symfony/dom-crawler": "^4.4|^5.0|^6.0", "symfony/expression-language": "^4.4|^5.0|^6.0", "symfony/finder": "^4.4|^5.0|^6.0", "symfony/http-client-contracts": "^1.1|^2|^3", "symfony/process": "^4.4|^5.0|^6.0", "symfony/routing": "^4.4|^5.0|^6.0", "symfony/stopwatch": "^4.4|^5.0|^6.0", "symfony/translation": "^4.4|^5.0|^6.0", "symfony/translation-contracts": "^1.1|^2|^3", "psr/cache": "^1.0|^2.0|^3.0", "twig/twig": "^2.13|^3.0.4" }, "provide": { "psr/log-implementation": "1.0|2.0" }, "conflict": { "symfony/browser-kit": "<5.4", "symfony/cache": "<5.0", "symfony/config": "<5.0", "symfony/console": "<4.4", "symfony/form": "<5.0", "symfony/dependency-injection": "<5.3", "symfony/doctrine-bridge": "<5.0", "symfony/http-client": "<5.0", "symfony/mailer": "<5.0", "symfony/messenger": "<5.0", "symfony/translation": "<5.0", "symfony/twig-bridge": "<5.0", "symfony/validator": "<5.0", "twig/twig": "<2.13" }, "suggest": { "symfony/browser-kit": "", "symfony/config": "", "symfony/console": "", "symfony/dependency-injection": "" }, "autoload": { "psr-4": { "Symfony\\Component\\HttpKernel\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "minimum-stability": "dev" } PK'\E^ -DependencyInjection/ResettableServicePass.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Reference; /** * @author Alexander M. Turek */ class ResettableServicePass implements CompilerPassInterface { private $tagName; public function __construct(string $tagName = 'kernel.reset') { if (0 < \func_num_args()) { trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__); } $this->tagName = $tagName; } /** * {@inheritdoc} */ public function process(ContainerBuilder $container) { if (!$container->has('services_resetter')) { return; } $services = $methods = []; foreach ($container->findTaggedServiceIds($this->tagName, true) as $id => $tags) { $services[$id] = new Reference($id, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE); foreach ($tags as $attributes) { if (!isset($attributes['method'])) { throw new RuntimeException(sprintf('Tag "%s" requires the "method" attribute to be set.', $this->tagName)); } if (!isset($methods[$id])) { $methods[$id] = []; } if ('ignore' === ($attributes['on_invalid'] ?? null)) { $attributes['method'] = '?'.$attributes['method']; } $methods[$id][] = $attributes['method']; } } if (!$services) { $container->removeAlias('services_resetter'); $container->removeDefinition('services_resetter'); return; } $container->findDefinition('services_resetter') ->setArgument(0, new IteratorArgument($services)) ->setArgument(1, $methods); } } PK'\ޙ6DependencyInjection/AddAnnotatedClassesToCachePass.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Composer\Autoload\ClassLoader; use Symfony\Component\Debug\DebugClassLoader as LegacyDebugClassLoader; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\ErrorHandler\DebugClassLoader; use Symfony\Component\HttpKernel\Kernel; /** * Sets the classes to compile in the cache for the container. * * @author Fabien Potencier */ class AddAnnotatedClassesToCachePass implements CompilerPassInterface { private $kernel; public function __construct(Kernel $kernel) { $this->kernel = $kernel; } /** * {@inheritdoc} */ public function process(ContainerBuilder $container) { $annotatedClasses = []; foreach ($container->getExtensions() as $extension) { if ($extension instanceof Extension) { $annotatedClasses[] = $extension->getAnnotatedClassesToCompile(); } } $annotatedClasses = array_merge($this->kernel->getAnnotatedClassesToCompile(), ...$annotatedClasses); $existingClasses = $this->getClassesInComposerClassMaps(); $annotatedClasses = $container->getParameterBag()->resolveValue($annotatedClasses); $this->kernel->setAnnotatedClassCache($this->expandClasses($annotatedClasses, $existingClasses)); } /** * Expands the given class patterns using a list of existing classes. * * @param array $patterns The class patterns to expand * @param array $classes The existing classes to match against the patterns */ private function expandClasses(array $patterns, array $classes): array { $expanded = []; // Explicit classes declared in the patterns are returned directly foreach ($patterns as $key => $pattern) { if (!str_ends_with($pattern, '\\') && !str_contains($pattern, '*')) { unset($patterns[$key]); $expanded[] = ltrim($pattern, '\\'); } } // Match patterns with the classes list $regexps = $this->patternsToRegexps($patterns); foreach ($classes as $class) { $class = ltrim($class, '\\'); if ($this->matchAnyRegexps($class, $regexps)) { $expanded[] = $class; } } return array_unique($expanded); } private function getClassesInComposerClassMaps(): array { $classes = []; foreach (spl_autoload_functions() as $function) { if (!\is_array($function)) { continue; } if ($function[0] instanceof DebugClassLoader || $function[0] instanceof LegacyDebugClassLoader) { $function = $function[0]->getClassLoader(); } if (\is_array($function) && $function[0] instanceof ClassLoader) { $classes += array_filter($function[0]->getClassMap()); } } return array_keys($classes); } private function patternsToRegexps(array $patterns): array { $regexps = []; foreach ($patterns as $pattern) { // Escape user input $regex = preg_quote(ltrim($pattern, '\\')); // Wildcards * and ** $regex = strtr($regex, ['\\*\\*' => '.*?', '\\*' => '[^\\\\]*?']); // If this class does not end by a slash, anchor the end if ('\\' !== substr($regex, -1)) { $regex .= '$'; } $regexps[] = '{^\\\\'.$regex.'}'; } return $regexps; } private function matchAnyRegexps(string $class, array $regexps): bool { $isTest = str_contains($class, 'Test'); foreach ($regexps as $regex) { if ($isTest && !str_contains($regex, 'Test')) { continue; } if (preg_match($regex, '\\'.$class)) { return true; } } return false; } } PK'\M󭔞,,>DependencyInjection/RegisterControllerArgumentLocatorsPass.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\DependencyInjection\Attribute\Target; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\LazyProxy\ProxyHelper; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\TypedReference; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; /** * Creates the service-locators required by ServiceValueResolver. * * @author Nicolas Grekas */ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface { private $resolverServiceId; private $controllerTag; private $controllerLocator; private $notTaggedControllerResolverServiceId; public function __construct(string $resolverServiceId = 'argument_resolver.service', string $controllerTag = 'controller.service_arguments', string $controllerLocator = 'argument_resolver.controller_locator', string $notTaggedControllerResolverServiceId = 'argument_resolver.not_tagged_controller') { if (0 < \func_num_args()) { trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__); } $this->resolverServiceId = $resolverServiceId; $this->controllerTag = $controllerTag; $this->controllerLocator = $controllerLocator; $this->notTaggedControllerResolverServiceId = $notTaggedControllerResolverServiceId; } public function process(ContainerBuilder $container) { if (false === $container->hasDefinition($this->resolverServiceId) && false === $container->hasDefinition($this->notTaggedControllerResolverServiceId)) { return; } $parameterBag = $container->getParameterBag(); $controllers = []; $publicAliases = []; foreach ($container->getAliases() as $id => $alias) { if ($alias->isPublic() && !$alias->isPrivate()) { $publicAliases[(string) $alias][] = $id; } } foreach ($container->findTaggedServiceIds($this->controllerTag, true) as $id => $tags) { $def = $container->getDefinition($id); $def->setPublic(true); $class = $def->getClass(); $autowire = $def->isAutowired(); $bindings = $def->getBindings(); // resolve service class, taking parent definitions into account while ($def instanceof ChildDefinition) { $def = $container->findDefinition($def->getParent()); $class = $class ?: $def->getClass(); $bindings += $def->getBindings(); } $class = $parameterBag->resolveValue($class); if (!$r = $container->getReflectionClass($class)) { throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } $isContainerAware = $r->implementsInterface(ContainerAwareInterface::class) || is_subclass_of($class, AbstractController::class); // get regular public methods $methods = []; $arguments = []; foreach ($r->getMethods(\ReflectionMethod::IS_PUBLIC) as $r) { if ('setContainer' === $r->name && $isContainerAware) { continue; } if (!$r->isConstructor() && !$r->isDestructor() && !$r->isAbstract()) { $methods[strtolower($r->name)] = [$r, $r->getParameters()]; } } // validate and collect explicit per-actions and per-arguments service references foreach ($tags as $attributes) { if (!isset($attributes['action']) && !isset($attributes['argument']) && !isset($attributes['id'])) { $autowire = true; continue; } foreach (['action', 'argument', 'id'] as $k) { if (!isset($attributes[$k][0])) { throw new InvalidArgumentException(sprintf('Missing "%s" attribute on tag "%s" %s for service "%s".', $k, $this->controllerTag, json_encode($attributes, \JSON_UNESCAPED_UNICODE), $id)); } } if (!isset($methods[$action = strtolower($attributes['action'])])) { throw new InvalidArgumentException(sprintf('Invalid "action" attribute on tag "%s" for service "%s": no public "%s()" method found on class "%s".', $this->controllerTag, $id, $attributes['action'], $class)); } [$r, $parameters] = $methods[$action]; $found = false; foreach ($parameters as $p) { if ($attributes['argument'] === $p->name) { if (!isset($arguments[$r->name][$p->name])) { $arguments[$r->name][$p->name] = $attributes['id']; } $found = true; break; } } if (!$found) { throw new InvalidArgumentException(sprintf('Invalid "%s" tag for service "%s": method "%s()" has no "%s" argument on class "%s".', $this->controllerTag, $id, $r->name, $attributes['argument'], $class)); } } foreach ($methods as [$r, $parameters]) { /** @var \ReflectionMethod $r */ // create a per-method map of argument-names to service/type-references $args = []; foreach ($parameters as $p) { /** @var \ReflectionParameter $p */ $type = ltrim($target = (string) ProxyHelper::getTypeHint($r, $p), '\\'); $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; if (isset($arguments[$r->name][$p->name])) { $target = $arguments[$r->name][$p->name]; if ('?' !== $target[0]) { $invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE; } elseif ('' === $target = (string) substr($target, 1)) { throw new InvalidArgumentException(sprintf('A "%s" tag must have non-empty "id" attributes for service "%s".', $this->controllerTag, $id)); } elseif ($p->allowsNull() && !$p->isOptional()) { $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE; } } elseif (isset($bindings[$bindingName = $type.' $'.$name = Target::parseName($p)]) || isset($bindings[$bindingName = '$'.$name]) || isset($bindings[$bindingName = $type])) { $binding = $bindings[$bindingName]; [$bindingValue, $bindingId, , $bindingType, $bindingFile] = $binding->getValues(); $binding->setValues([$bindingValue, $bindingId, true, $bindingType, $bindingFile]); if (!$bindingValue instanceof Reference) { $args[$p->name] = new Reference('.value.'.$container->hash($bindingValue)); $container->register((string) $args[$p->name], 'mixed') ->setFactory('current') ->addArgument([$bindingValue]); } else { $args[$p->name] = $bindingValue; } continue; } elseif (!$type || !$autowire || '\\' !== $target[0]) { continue; } elseif (is_subclass_of($type, \UnitEnum::class)) { // do not attempt to register enum typed arguments if not already present in bindings continue; } elseif (!$p->allowsNull()) { $invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE; } if (Request::class === $type || SessionInterface::class === $type || Response::class === $type) { continue; } if ($type && !$p->isOptional() && !$p->allowsNull() && !class_exists($type) && !interface_exists($type, false)) { $message = sprintf('Cannot determine controller argument for "%s::%s()": the $%s argument is type-hinted with the non-existent class or interface: "%s".', $class, $r->name, $p->name, $type); // see if the type-hint lives in the same namespace as the controller if (0 === strncmp($type, $class, strrpos($class, '\\'))) { $message .= ' Did you forget to add a use statement?'; } $container->register($erroredId = '.errored.'.$container->hash($message), $type) ->addError($message); $args[$p->name] = new Reference($erroredId, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE); } else { $target = ltrim($target, '\\'); $args[$p->name] = $type ? new TypedReference($target, $type, $invalidBehavior, Target::parseName($p)) : new Reference($target, $invalidBehavior); } } // register the maps as a per-method service-locators if ($args) { $controllers[$id.'::'.$r->name] = ServiceLocatorTagPass::register($container, $args); foreach ($publicAliases[$id] ?? [] as $alias) { $controllers[$alias.'::'.$r->name] = clone $controllers[$id.'::'.$r->name]; } } } } $controllerLocatorRef = ServiceLocatorTagPass::register($container, $controllers); if ($container->hasDefinition($this->resolverServiceId)) { $container->getDefinition($this->resolverServiceId) ->replaceArgument(0, $controllerLocatorRef); } if ($container->hasDefinition($this->notTaggedControllerResolverServiceId)) { $container->getDefinition($this->notTaggedControllerResolverServiceId) ->replaceArgument(0, $controllerLocatorRef); } $container->setAlias($this->controllerLocator, (string) $controllerLocatorRef); } } PK'\pt -DependencyInjection/ConfigurableExtension.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\ContainerBuilder; /** * This extension sub-class provides first-class integration with the * Config/Definition Component. * * You can use this as base class if * * a) you use the Config/Definition component for configuration, * b) your configuration class is named "Configuration", and * c) the configuration class resides in the DependencyInjection sub-folder. * * @author Johannes M. Schmitt */ abstract class ConfigurableExtension extends Extension { /** * {@inheritdoc} */ final public function load(array $configs, ContainerBuilder $container) { $this->loadInternal($this->processConfiguration($this->getConfiguration($configs, $container), $configs), $container); } /** * Configures the passed container according to the merged configuration. */ abstract protected function loadInternal(array $mergedConfig, ContainerBuilder $container); } PK'\ Hj j ;DependencyInjection/ControllerArgumentValueResolverPass.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver; use Symfony\Component\Stopwatch\Stopwatch; /** * Gathers and configures the argument value resolvers. * * @author Iltar van der Berg */ class ControllerArgumentValueResolverPass implements CompilerPassInterface { use PriorityTaggedServiceTrait; private $argumentResolverService; private $argumentValueResolverTag; private $traceableResolverStopwatch; public function __construct(string $argumentResolverService = 'argument_resolver', string $argumentValueResolverTag = 'controller.argument_value_resolver', string $traceableResolverStopwatch = 'debug.stopwatch') { if (0 < \func_num_args()) { trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__); } $this->argumentResolverService = $argumentResolverService; $this->argumentValueResolverTag = $argumentValueResolverTag; $this->traceableResolverStopwatch = $traceableResolverStopwatch; } public function process(ContainerBuilder $container) { if (!$container->hasDefinition($this->argumentResolverService)) { return; } $resolvers = $this->findAndSortTaggedServices($this->argumentValueResolverTag, $container); if ($container->getParameter('kernel.debug') && class_exists(Stopwatch::class) && $container->has($this->traceableResolverStopwatch)) { foreach ($resolvers as $resolverReference) { $id = (string) $resolverReference; $container->register("debug.$id", TraceableValueResolver::class) ->setDecoratedService($id) ->setArguments([new Reference("debug.$id.inner"), new Reference($this->traceableResolverStopwatch)]); } } $container ->getDefinition($this->argumentResolverService) ->replaceArgument(1, new IteratorArgument($resolvers)) ; } } PK'\ѡ(ʕ7DependencyInjection/MergeExtensionConfigurationPass.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationPass as BaseMergeExtensionConfigurationPass; use Symfony\Component\DependencyInjection\ContainerBuilder; /** * Ensures certain extensions are always loaded. * * @author Kris Wallsmith */ class MergeExtensionConfigurationPass extends BaseMergeExtensionConfigurationPass { private $extensions; /** * @param string[] $extensions */ public function __construct(array $extensions) { $this->extensions = $extensions; } public function process(ContainerBuilder $container) { foreach ($this->extensions as $extension) { if (!\count($container->getExtensionConfig($extension))) { $container->loadFromExtension($extension, []); } } parent::process($container); } } PK'\] ,DependencyInjection/FragmentRendererPass.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface; /** * Adds services tagged kernel.fragment_renderer as HTTP content rendering strategies. * * @author Fabien Potencier */ class FragmentRendererPass implements CompilerPassInterface { private $handlerService; private $rendererTag; public function __construct(string $handlerService = 'fragment.handler', string $rendererTag = 'kernel.fragment_renderer') { if (0 < \func_num_args()) { trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__); } $this->handlerService = $handlerService; $this->rendererTag = $rendererTag; } public function process(ContainerBuilder $container) { if (!$container->hasDefinition($this->handlerService)) { return; } $definition = $container->getDefinition($this->handlerService); $renderers = []; foreach ($container->findTaggedServiceIds($this->rendererTag, true) as $id => $tags) { $def = $container->getDefinition($id); $class = $container->getParameterBag()->resolveValue($def->getClass()); if (!$r = $container->getReflectionClass($class)) { throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } if (!$r->isSubclassOf(FragmentRendererInterface::class)) { throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, FragmentRendererInterface::class)); } foreach ($tags as $tag) { $renderers[$tag['alias']] = new Reference($id); } } $definition->replaceArgument(0, ServiceLocatorTagPass::register($container, $renderers)); } } PK'\thaa2DependencyInjection/LazyLoadingFragmentHandler.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Psr\Container\ContainerInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Fragment\FragmentHandler; /** * Lazily loads fragment renderers from the dependency injection container. * * @author Fabien Potencier */ class LazyLoadingFragmentHandler extends FragmentHandler { private $container; /** * @var array */ private $initialized = []; public function __construct(ContainerInterface $container, RequestStack $requestStack, bool $debug = false) { $this->container = $container; parent::__construct($requestStack, [], $debug); } /** * {@inheritdoc} */ public function render($uri, string $renderer = 'inline', array $options = []) { if (!isset($this->initialized[$renderer]) && $this->container->has($renderer)) { $this->addRenderer($this->container->get($renderer)); $this->initialized[$renderer] = true; } return parent::render($uri, $renderer, $options); } } PK'\F|*AA7DependencyInjection/RegisterLocaleAwareServicesPass.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; /** * Register all services that have the "kernel.locale_aware" tag into the listener. * * @author Pierre Bobiet */ class RegisterLocaleAwareServicesPass implements CompilerPassInterface { private $listenerServiceId; private $localeAwareTag; public function __construct(string $listenerServiceId = 'locale_aware_listener', string $localeAwareTag = 'kernel.locale_aware') { if (0 < \func_num_args()) { trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__); } $this->listenerServiceId = $listenerServiceId; $this->localeAwareTag = $localeAwareTag; } public function process(ContainerBuilder $container) { if (!$container->hasDefinition($this->listenerServiceId)) { return; } $services = []; foreach ($container->findTaggedServiceIds($this->localeAwareTag) as $id => $tags) { $services[] = new Reference($id); } if (!$services) { $container->removeDefinition($this->listenerServiceId); return; } $container ->getDefinition($this->listenerServiceId) ->setArgument(0, new IteratorArgument($services)) ; } } PK'\uZ"DependencyInjection/LoggerPass.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Log\Logger; /** * Registers the default logger if necessary. * * @author Kévin Dunglas */ class LoggerPass implements CompilerPassInterface { /** * {@inheritdoc} */ public function process(ContainerBuilder $container) { $container->setAlias(LoggerInterface::class, 'logger') ->setPublic(false); if ($container->has('logger')) { return; } $container->register('logger', Logger::class) ->setPublic(false); } } PK'\އ ADependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; /** * Removes empty service-locators registered for ServiceValueResolver. * * @author Nicolas Grekas */ class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface { private $controllerLocator; public function __construct(string $controllerLocator = 'argument_resolver.controller_locator') { if (0 < \func_num_args()) { trigger_deprecation('symfony/http-kernel', '5.3', 'Configuring "%s" is deprecated.', __CLASS__); } $this->controllerLocator = $controllerLocator; } public function process(ContainerBuilder $container) { $controllerLocator = $container->findDefinition($this->controllerLocator); $controllers = $controllerLocator->getArgument(0); foreach ($controllers as $controller => $argumentRef) { $argumentLocator = $container->getDefinition((string) $argumentRef->getValues()[0]); if (!$argumentLocator->getArgument(0)) { // remove empty argument locators $reason = sprintf('Removing service-argument resolver for controller "%s": no corresponding services exist for the referenced types.', $controller); } else { // any methods listed for call-at-instantiation cannot be actions $reason = false; [$id, $action] = explode('::', $controller); if ($container->hasAlias($id)) { continue; } $controllerDef = $container->getDefinition($id); foreach ($controllerDef->getMethodCalls() as [$method]) { if (0 === strcasecmp($action, $method)) { $reason = sprintf('Removing method "%s" of service "%s" from controller candidates: the method is called at instantiation, thus cannot be an action.', $action, $id); break; } } if (!$reason) { // see Symfony\Component\HttpKernel\Controller\ContainerControllerResolver $controllers[$id.':'.$action] = $argumentRef; if ('__invoke' === $action) { $controllers[$id] = $argumentRef; } continue; } } unset($controllers[$controller]); $container->log($this, $reason); } $controllerLocator->replaceArgument(0, $controllers); } } PK'\77!DependencyInjection/Extension.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Extension\Extension as BaseExtension; /** * Allow adding classes to the class cache. * * @author Fabien Potencier */ abstract class Extension extends BaseExtension { private $annotatedClasses = []; /** * Gets the annotated classes to cache. * * @return array */ public function getAnnotatedClassesToCompile() { return $this->annotatedClasses; } /** * Adds annotated classes to the class cache. * * @param array $annotatedClasses An array of class patterns */ public function addAnnotatedClassesToCompile(array $annotatedClasses) { $this->annotatedClasses = array_merge($this->annotatedClasses, $annotatedClasses); } } PK'\ txKK(DependencyInjection/ServicesResetter.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Contracts\Service\ResetInterface; /** * Resets provided services. * * @author Alexander M. Turek * @author Nicolas Grekas * * @internal */ class ServicesResetter implements ResetInterface { private $resettableServices; private $resetMethods; /** * @param \Traversable $resettableServices * @param array $resetMethods */ public function __construct(\Traversable $resettableServices, array $resetMethods) { $this->resettableServices = $resettableServices; $this->resetMethods = $resetMethods; } public function reset() { foreach ($this->resettableServices as $id => $service) { foreach ((array) $this->resetMethods[$id] as $resetMethod) { if ('?' === $resetMethod[0] && !method_exists($service, $resetMethod = substr($resetMethod, 1))) { continue; } $service->$resetMethod(); } } } } PK'\nnCacheWarmer/CacheWarmer.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\CacheWarmer; /** * Abstract cache warmer that knows how to write a file to the cache. * * @author Fabien Potencier */ abstract class CacheWarmer implements CacheWarmerInterface { protected function writeCacheFile(string $file, $content) { $tmpFile = @tempnam(\dirname($file), basename($file)); if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $file)) { @chmod($file, 0666 & ~umask()); return; } throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $file)); } } PK'\$CacheWarmer/CacheWarmerInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\CacheWarmer; /** * Interface for classes able to warm up the cache. * * @author Fabien Potencier */ interface CacheWarmerInterface extends WarmableInterface { /** * Checks whether this warmer is optional or not. * * Optional warmers can be ignored on certain conditions. * * A warmer should return true if the cache can be * generated incrementally and on-demand. * * @return bool */ public function isOptional(); } PK'\]dd!CacheWarmer/WarmableInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\CacheWarmer; /** * Interface for classes that support warming their cache. * * @author Fabien Potencier */ interface WarmableInterface { /** * Warms up the cache. * * @return string[] A list of classes or files to preload on PHP 7.4+ */ public function warmUp(string $cacheDir); } PK'\cѧ$CacheWarmer/CacheWarmerAggregate.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\CacheWarmer; /** * Aggregates several cache warmers into a single one. * * @author Fabien Potencier * * @final */ class CacheWarmerAggregate implements CacheWarmerInterface { private $warmers; private $debug; private $deprecationLogsFilepath; private $optionalsEnabled = false; private $onlyOptionalsEnabled = false; /** * @param iterable $warmers */ public function __construct(iterable $warmers = [], bool $debug = false, string $deprecationLogsFilepath = null) { $this->warmers = $warmers; $this->debug = $debug; $this->deprecationLogsFilepath = $deprecationLogsFilepath; } public function enableOptionalWarmers() { $this->optionalsEnabled = true; } public function enableOnlyOptionalWarmers() { $this->onlyOptionalsEnabled = $this->optionalsEnabled = true; } /** * {@inheritdoc} */ public function warmUp(string $cacheDir): array { if ($collectDeprecations = $this->debug && !\defined('PHPUNIT_COMPOSER_INSTALL')) { $collectedLogs = []; $previousHandler = set_error_handler(function ($type, $message, $file, $line) use (&$collectedLogs, &$previousHandler) { if (\E_USER_DEPRECATED !== $type && \E_DEPRECATED !== $type) { return $previousHandler ? $previousHandler($type, $message, $file, $line) : false; } if (isset($collectedLogs[$message])) { ++$collectedLogs[$message]['count']; return null; } $backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 3); // Clean the trace by removing first frames added by the error handler itself. for ($i = 0; isset($backtrace[$i]); ++$i) { if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) { $backtrace = \array_slice($backtrace, 1 + $i); break; } } $collectedLogs[$message] = [ 'type' => $type, 'message' => $message, 'file' => $file, 'line' => $line, 'trace' => $backtrace, 'count' => 1, ]; return null; }); } $preload = []; try { foreach ($this->warmers as $warmer) { if (!$this->optionalsEnabled && $warmer->isOptional()) { continue; } if ($this->onlyOptionalsEnabled && !$warmer->isOptional()) { continue; } $preload[] = array_values((array) $warmer->warmUp($cacheDir)); } } finally { if ($collectDeprecations) { restore_error_handler(); if (is_file($this->deprecationLogsFilepath)) { $previousLogs = unserialize(file_get_contents($this->deprecationLogsFilepath)); if (\is_array($previousLogs)) { $collectedLogs = array_merge($previousLogs, $collectedLogs); } } file_put_contents($this->deprecationLogsFilepath, serialize(array_values($collectedLogs))); } } return array_values(array_unique(array_merge([], ...$preload))); } /** * {@inheritdoc} */ public function isOptional(): bool { return false; } } PK'\s.!!/Exception/UnsupportedMediaTypeHttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class UnsupportedMediaTypeHttpException extends HttpException { /** * @param string|null $message The internal exception message * @param \Throwable|null $previous The previous exception * @param int $code The internal exception code */ public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } parent::__construct(415, $message, $previous, $headers, $code); } } PK'\x׊OO/Exception/PreconditionRequiredHttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey * * @see http://tools.ietf.org/html/rfc6585 */ class PreconditionRequiredHttpException extends HttpException { /** * @param string|null $message The internal exception message * @param \Throwable|null $previous The previous exception * @param int $code The internal exception code */ public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } parent::__construct(428, $message, $previous, $headers, $code); } } PK'\Ӫ@*Exception/TooManyRequestsHttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey * * @see http://tools.ietf.org/html/rfc6585 */ class TooManyRequestsHttpException extends HttpException { /** * @param int|string|null $retryAfter The number of seconds or HTTP-date after which the request may be retried * @param string|null $message The internal exception message * @param \Throwable|null $previous The previous exception * @param int|null $code The internal exception code */ public function __construct($retryAfter = null, ?string $message = '', \Throwable $previous = null, ?int $code = 0, array $headers = []) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } if (null === $code) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $code to "%s()" is deprecated, pass 0 instead.', __METHOD__); $code = 0; } if ($retryAfter) { $headers['Retry-After'] = $retryAfter; } parent::__construct(429, $message, $previous, $headers, $code); } } PK'\حD%Exception/BadRequestHttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class BadRequestHttpException extends HttpException { /** * @param string|null $message The internal exception message * @param \Throwable|null $previous The previous exception * @param int $code The internal exception code */ public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } parent::__construct(400, $message, $previous, $headers, $code); } } PK'\?z+Exception/MethodNotAllowedHttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Kris Wallsmith */ class MethodNotAllowedHttpException extends HttpException { /** * @param string[] $allow An array of allowed methods * @param string|null $message The internal exception message * @param \Throwable|null $previous The previous exception * @param int|null $code The internal exception code */ public function __construct(array $allow, ?string $message = '', \Throwable $previous = null, ?int $code = 0, array $headers = []) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } if (null === $code) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $code to "%s()" is deprecated, pass 0 instead.', __METHOD__); $code = 0; } $headers['Allow'] = strtoupper(implode(', ', $allow)); parent::__construct(405, $message, $previous, $headers, $code); } } PK'\ -Exception/ServiceUnavailableHttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class ServiceUnavailableHttpException extends HttpException { /** * @param int|string|null $retryAfter The number of seconds or HTTP-date after which the request may be retried * @param string|null $message The internal exception message * @param \Throwable|null $previous The previous exception * @param int|null $code The internal exception code */ public function __construct($retryAfter = null, ?string $message = '', \Throwable $previous = null, ?int $code = 0, array $headers = []) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } if (null === $code) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $code to "%s()" is deprecated, pass 0 instead.', __METHOD__); $code = 0; } if ($retryAfter) { $headers['Retry-After'] = $retryAfter; } parent::__construct(503, $message, $previous, $headers, $code); } } PK'\SException/HttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * HttpException. * * @author Kris Wallsmith */ class HttpException extends \RuntimeException implements HttpExceptionInterface { private $statusCode; private $headers; public function __construct(int $statusCode, ?string $message = '', \Throwable $previous = null, array $headers = [], ?int $code = 0) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } if (null === $code) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $code to "%s()" is deprecated, pass 0 instead.', __METHOD__); $code = 0; } $this->statusCode = $statusCode; $this->headers = $headers; parent::__construct($message, $code, $previous); } public function getStatusCode() { return $this->statusCode; } public function getHeaders() { return $this->headers; } /** * Set response headers. * * @param array $headers Response headers */ public function setHeaders(array $headers) { $this->headers = $headers; } } PK'\(Z)).Exception/UnprocessableEntityHttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Steve Hutchins */ class UnprocessableEntityHttpException extends HttpException { /** * @param string|null $message The internal exception message * @param \Throwable|null $previous The previous exception * @param int $code The internal exception code */ public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } parent::__construct(422, $message, $previous, $headers, $code); } } PK'\gj\\&Exception/InvalidMetadataException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; class InvalidMetadataException extends \LogicException { } PK'\@q-Exception/PreconditionFailedHttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class PreconditionFailedHttpException extends HttpException { /** * @param string|null $message The internal exception message * @param \Throwable|null $previous The previous exception * @param int $code The internal exception code */ public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } parent::__construct(412, $message, $previous, $headers, $code); } } PK'\Yq||'Exception/UnauthorizedHttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class UnauthorizedHttpException extends HttpException { /** * @param string $challenge WWW-Authenticate challenge string * @param string|null $message The internal exception message * @param \Throwable|null $previous The previous exception * @param int|null $code The internal exception code */ public function __construct(string $challenge, ?string $message = '', \Throwable $previous = null, ?int $code = 0, array $headers = []) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } if (null === $code) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $code to "%s()" is deprecated, pass 0 instead.', __METHOD__); $code = 0; } $headers['WWW-Authenticate'] = $challenge; parent::__construct(401, $message, $previous, $headers, $code); } } PK'\S )Exception/LengthRequiredHttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class LengthRequiredHttpException extends HttpException { /** * @param string|null $message The internal exception message * @param \Throwable|null $previous The previous exception * @param int $code The internal exception code */ public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } parent::__construct(411, $message, $previous, $headers, $code); } } PK'\<}#Exception/NotFoundHttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Fabien Potencier */ class NotFoundHttpException extends HttpException { /** * @param string|null $message The internal exception message * @param \Throwable|null $previous The previous exception * @param int $code The internal exception code */ public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } parent::__construct(404, $message, $previous, $headers, $code); } } PK'\|&NN'Exception/AccessDeniedHttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Fabien Potencier * @author Christophe Coevoet */ class AccessDeniedHttpException extends HttpException { /** * @param string|null $message The internal exception message * @param \Throwable|null $previous The previous exception * @param int $code The internal exception code */ public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } parent::__construct(403, $message, $previous, $headers, $code); } } PK'\$Exception/HttpExceptionInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * Interface for HTTP error exceptions. * * @author Kris Wallsmith */ interface HttpExceptionInterface extends \Throwable { /** * Returns the status code. * * @return int */ public function getStatusCode(); /** * Returns response headers. * * @return array */ public function getHeaders(); } PK'\F.(Exception/NotAcceptableHttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class NotAcceptableHttpException extends HttpException { /** * @param string|null $message The internal exception message * @param \Throwable|null $previous The previous exception * @param int $code The internal exception code */ public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } parent::__construct(406, $message, $previous, $headers, $code); } } PK'\'  6Exception/ControllerDoesNotReturnResponseException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Grégoire Pineau */ class ControllerDoesNotReturnResponseException extends \LogicException { public function __construct(string $message, callable $controller, string $file, int $line) { parent::__construct($message); if (!$controllerDefinition = $this->parseControllerDefinition($controller)) { return; } $this->file = $controllerDefinition['file']; $this->line = $controllerDefinition['line']; $r = new \ReflectionProperty(\Exception::class, 'trace'); $r->setAccessible(true); $r->setValue($this, array_merge([ [ 'line' => $line, 'file' => $file, ], ], $this->getTrace())); } private function parseControllerDefinition(callable $controller): ?array { if (\is_string($controller) && str_contains($controller, '::')) { $controller = explode('::', $controller); } if (\is_array($controller)) { try { $r = new \ReflectionMethod($controller[0], $controller[1]); return [ 'file' => $r->getFileName(), 'line' => $r->getEndLine(), ]; } catch (\ReflectionException $e) { return null; } } if ($controller instanceof \Closure) { $r = new \ReflectionFunction($controller); return [ 'file' => $r->getFileName(), 'line' => $r->getEndLine(), ]; } if (\is_object($controller)) { $r = new \ReflectionClass($controller); try { $line = $r->getMethod('__invoke')->getEndLine(); } catch (\ReflectionException $e) { $line = $r->getEndLine(); } return [ 'file' => $r->getFileName(), 'line' => $line, ]; } return null; } } PK'\O#Exception/ConflictHttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class ConflictHttpException extends HttpException { /** * @param string|null $message The internal exception message * @param \Throwable|null $previous The previous exception * @param int $code The internal exception code */ public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } parent::__construct(409, $message, $previous, $headers, $code); } } PK'\VException/GoneHttpException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class GoneHttpException extends HttpException { /** * @param string|null $message The internal exception message * @param \Throwable|null $previous The previous exception * @param int $code The internal exception code */ public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { if (null === $message) { trigger_deprecation('symfony/http-kernel', '5.3', 'Passing null as $message to "%s()" is deprecated, pass an empty string instead.', __METHOD__); $message = ''; } parent::__construct(410, $message, $previous, $headers, $code); } } PK'\[_w-Exception/UnexpectedSessionUsageException.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Mathias Arlaud */ class UnexpectedSessionUsageException extends \LogicException { } PK'\UUConfig/FileLocator.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Config; use Symfony\Component\Config\FileLocator as BaseFileLocator; use Symfony\Component\HttpKernel\KernelInterface; /** * FileLocator uses the KernelInterface to locate resources in bundles. * * @author Fabien Potencier */ class FileLocator extends BaseFileLocator { private $kernel; public function __construct(KernelInterface $kernel) { $this->kernel = $kernel; parent::__construct(); } /** * {@inheritdoc} */ public function locate(string $file, string $currentPath = null, bool $first = true) { if (isset($file[0]) && '@' === $file[0]) { $resource = $this->kernel->locateResource($file); return $first ? $resource : [$resource]; } return parent::locate($file, $currentPath, $first); } } PK'\աddHttpCache/Esi.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * Esi implements the ESI capabilities to Request and Response instances. * * For more information, read the following W3C notes: * * * ESI Language Specification 1.0 (http://www.w3.org/TR/esi-lang) * * * Edge Architecture Specification (http://www.w3.org/TR/edge-arch) * * @author Fabien Potencier */ class Esi extends AbstractSurrogate { public function getName() { return 'esi'; } /** * {@inheritdoc} */ public function addSurrogateControl(Response $response) { if (str_contains($response->getContent(), 'headers->set('Surrogate-Control', 'content="ESI/1.0"'); } } /** * {@inheritdoc} */ public function renderIncludeTag(string $uri, string $alt = null, bool $ignoreErrors = true, string $comment = '') { $html = sprintf('', $uri, $ignoreErrors ? ' onerror="continue"' : '', $alt ? sprintf(' alt="%s"', $alt) : '' ); if (!empty($comment)) { return sprintf("\n%s", $comment, $html); } return $html; } /** * {@inheritdoc} */ public function process(Request $request, Response $response) { $type = $response->headers->get('Content-Type'); if (empty($type)) { $type = 'text/html'; } $parts = explode(';', $type); if (!\in_array($parts[0], $this->contentTypes)) { return $response; } // we don't use a proper XML parser here as we can have ESI tags in a plain text response $content = $response->getContent(); $content = preg_replace('#.*?#s', '', $content); $content = preg_replace('#]+>#s', '', $content); $chunks = preg_split('##', $content, -1, \PREG_SPLIT_DELIM_CAPTURE); $chunks[0] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[0]); $i = 1; while (isset($chunks[$i])) { $options = []; preg_match_all('/(src|onerror|alt)="([^"]*?)"/', $chunks[$i], $matches, \PREG_SET_ORDER); foreach ($matches as $set) { $options[$set[1]] = $set[2]; } if (!isset($options['src'])) { throw new \RuntimeException('Unable to process an ESI tag without a "src" attribute.'); } $chunks[$i] = sprintf('surrogate->handle($this, %s, %s, %s) ?>'."\n", var_export($options['src'], true), var_export($options['alt'] ?? '', true), isset($options['onerror']) && 'continue' === $options['onerror'] ? 'true' : 'false' ); ++$i; $chunks[$i] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[$i]); ++$i; } $content = implode('', $chunks); $response->setContent($content); $response->headers->set('X-Body-Eval', 'ESI'); // remove ESI/1.0 from the Surrogate-Control header $this->removeFromControl($response); return $response; } } PK'\L9&c&cHttpCache/HttpCache.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /* * This code is partially based on the Rack-Cache library by Ryan Tomayko, * which is released under the MIT license. * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801) */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\TerminableInterface; /** * Cache provides HTTP caching. * * @author Fabien Potencier */ class HttpCache implements HttpKernelInterface, TerminableInterface { private $kernel; private $store; private $request; private $surrogate; private $surrogateCacheStrategy; private $options = []; private $traces = []; /** * Constructor. * * The available options are: * * * debug If true, exceptions are thrown when things go wrong. Otherwise, the cache * will try to carry on and deliver a meaningful response. * * * trace_level May be one of 'none', 'short' and 'full'. For 'short', a concise trace of the * main request will be added as an HTTP header. 'full' will add traces for all * requests (including ESI subrequests). (default: 'full' if in debug; 'none' otherwise) * * * trace_header Header name to use for traces. (default: X-Symfony-Cache) * * * default_ttl The number of seconds that a cache entry should be considered * fresh when no explicit freshness information is provided in * a response. Explicit Cache-Control or Expires headers * override this value. (default: 0) * * * private_headers Set of request headers that trigger "private" cache-control behavior * on responses that don't explicitly state whether the response is * public or private via a Cache-Control directive. (default: Authorization and Cookie) * * * allow_reload Specifies whether the client can force a cache reload by including a * Cache-Control "no-cache" directive in the request. Set it to ``true`` * for compliance with RFC 2616. (default: false) * * * allow_revalidate Specifies whether the client can force a cache revalidate by including * a Cache-Control "max-age=0" directive in the request. Set it to ``true`` * for compliance with RFC 2616. (default: false) * * * stale_while_revalidate Specifies the default number of seconds (the granularity is the second as the * Response TTL precision is a second) during which the cache can immediately return * a stale response while it revalidates it in the background (default: 2). * This setting is overridden by the stale-while-revalidate HTTP Cache-Control * extension (see RFC 5861). * * * stale_if_error Specifies the default number of seconds (the granularity is the second) during which * the cache can serve a stale response when an error is encountered (default: 60). * This setting is overridden by the stale-if-error HTTP Cache-Control extension * (see RFC 5861). */ public function __construct(HttpKernelInterface $kernel, StoreInterface $store, SurrogateInterface $surrogate = null, array $options = []) { $this->store = $store; $this->kernel = $kernel; $this->surrogate = $surrogate; // needed in case there is a fatal error because the backend is too slow to respond register_shutdown_function([$this->store, 'cleanup']); $this->options = array_merge([ 'debug' => false, 'default_ttl' => 0, 'private_headers' => ['Authorization', 'Cookie'], 'allow_reload' => false, 'allow_revalidate' => false, 'stale_while_revalidate' => 2, 'stale_if_error' => 60, 'trace_level' => 'none', 'trace_header' => 'X-Symfony-Cache', ], $options); if (!isset($options['trace_level'])) { $this->options['trace_level'] = $this->options['debug'] ? 'full' : 'none'; } } /** * Gets the current store. * * @return StoreInterface */ public function getStore() { return $this->store; } /** * Returns an array of events that took place during processing of the last request. * * @return array */ public function getTraces() { return $this->traces; } private function addTraces(Response $response) { $traceString = null; if ('full' === $this->options['trace_level']) { $traceString = $this->getLog(); } if ('short' === $this->options['trace_level'] && $masterId = array_key_first($this->traces)) { $traceString = implode('/', $this->traces[$masterId]); } if (null !== $traceString) { $response->headers->add([$this->options['trace_header'] => $traceString]); } } /** * Returns a log message for the events of the last request processing. * * @return string */ public function getLog() { $log = []; foreach ($this->traces as $request => $traces) { $log[] = sprintf('%s: %s', $request, implode(', ', $traces)); } return implode('; ', $log); } /** * Gets the Request instance associated with the main request. * * @return Request */ public function getRequest() { return $this->request; } /** * Gets the Kernel instance. * * @return HttpKernelInterface */ public function getKernel() { return $this->kernel; } /** * Gets the Surrogate instance. * * @return SurrogateInterface * * @throws \LogicException */ public function getSurrogate() { return $this->surrogate; } /** * {@inheritdoc} */ public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true) { // FIXME: catch exceptions and implement a 500 error page here? -> in Varnish, there is a built-in error page mechanism if (HttpKernelInterface::MAIN_REQUEST === $type) { $this->traces = []; // Keep a clone of the original request for surrogates so they can access it. // We must clone here to get a separate instance because the application will modify the request during // the application flow (we know it always does because we do ourselves by setting REMOTE_ADDR to 127.0.0.1 // and adding the X-Forwarded-For header, see HttpCache::forward()). $this->request = clone $request; if (null !== $this->surrogate) { $this->surrogateCacheStrategy = $this->surrogate->createCacheStrategy(); } } $this->traces[$this->getTraceKey($request)] = []; if (!$request->isMethodSafe()) { $response = $this->invalidate($request, $catch); } elseif ($request->headers->has('expect') || !$request->isMethodCacheable()) { $response = $this->pass($request, $catch); } elseif ($this->options['allow_reload'] && $request->isNoCache()) { /* If allow_reload is configured and the client requests "Cache-Control: no-cache", reload the cache by fetching a fresh response and caching it (if possible). */ $this->record($request, 'reload'); $response = $this->fetch($request, $catch); } else { $response = $this->lookup($request, $catch); } $this->restoreResponseBody($request, $response); if (HttpKernelInterface::MAIN_REQUEST === $type) { $this->addTraces($response); } if (null !== $this->surrogate) { if (HttpKernelInterface::MAIN_REQUEST === $type) { $this->surrogateCacheStrategy->update($response); } else { $this->surrogateCacheStrategy->add($response); } } $response->prepare($request); $response->isNotModified($request); return $response; } /** * {@inheritdoc} */ public function terminate(Request $request, Response $response) { if ($this->getKernel() instanceof TerminableInterface) { $this->getKernel()->terminate($request, $response); } } /** * Forwards the Request to the backend without storing the Response in the cache. * * @param bool $catch Whether to process exceptions * * @return Response */ protected function pass(Request $request, bool $catch = false) { $this->record($request, 'pass'); return $this->forward($request, $catch); } /** * Invalidates non-safe methods (like POST, PUT, and DELETE). * * @param bool $catch Whether to process exceptions * * @return Response * * @throws \Exception * * @see RFC2616 13.10 */ protected function invalidate(Request $request, bool $catch = false) { $response = $this->pass($request, $catch); // invalidate only when the response is successful if ($response->isSuccessful() || $response->isRedirect()) { try { $this->store->invalidate($request); // As per the RFC, invalidate Location and Content-Location URLs if present foreach (['Location', 'Content-Location'] as $header) { if ($uri = $response->headers->get($header)) { $subRequest = Request::create($uri, 'get', [], [], [], $request->server->all()); $this->store->invalidate($subRequest); } } $this->record($request, 'invalidate'); } catch (\Exception $e) { $this->record($request, 'invalidate-failed'); if ($this->options['debug']) { throw $e; } } } return $response; } /** * Lookups a Response from the cache for the given Request. * * When a matching cache entry is found and is fresh, it uses it as the * response without forwarding any request to the backend. When a matching * cache entry is found but is stale, it attempts to "validate" the entry with * the backend using conditional GET. When no matching cache entry is found, * it triggers "miss" processing. * * @param bool $catch Whether to process exceptions * * @return Response * * @throws \Exception */ protected function lookup(Request $request, bool $catch = false) { try { $entry = $this->store->lookup($request); } catch (\Exception $e) { $this->record($request, 'lookup-failed'); if ($this->options['debug']) { throw $e; } return $this->pass($request, $catch); } if (null === $entry) { $this->record($request, 'miss'); return $this->fetch($request, $catch); } if (!$this->isFreshEnough($request, $entry)) { $this->record($request, 'stale'); return $this->validate($request, $entry, $catch); } if ($entry->headers->hasCacheControlDirective('no-cache')) { return $this->validate($request, $entry, $catch); } $this->record($request, 'fresh'); $entry->headers->set('Age', $entry->getAge()); return $entry; } /** * Validates that a cache entry is fresh. * * The original request is used as a template for a conditional * GET request with the backend. * * @param bool $catch Whether to process exceptions * * @return Response */ protected function validate(Request $request, Response $entry, bool $catch = false) { $subRequest = clone $request; // send no head requests because we want content if ('HEAD' === $request->getMethod()) { $subRequest->setMethod('GET'); } // add our cached last-modified validator if ($entry->headers->has('Last-Modified')) { $subRequest->headers->set('If-Modified-Since', $entry->headers->get('Last-Modified')); } // Add our cached etag validator to the environment. // We keep the etags from the client to handle the case when the client // has a different private valid entry which is not cached here. $cachedEtags = $entry->getEtag() ? [$entry->getEtag()] : []; $requestEtags = $request->getETags(); if ($etags = array_unique(array_merge($cachedEtags, $requestEtags))) { $subRequest->headers->set('If-None-Match', implode(', ', $etags)); } $response = $this->forward($subRequest, $catch, $entry); if (304 == $response->getStatusCode()) { $this->record($request, 'valid'); // return the response and not the cache entry if the response is valid but not cached $etag = $response->getEtag(); if ($etag && \in_array($etag, $requestEtags) && !\in_array($etag, $cachedEtags)) { return $response; } $entry = clone $entry; $entry->headers->remove('Date'); foreach (['Date', 'Expires', 'Cache-Control', 'ETag', 'Last-Modified'] as $name) { if ($response->headers->has($name)) { $entry->headers->set($name, $response->headers->get($name)); } } $response = $entry; } else { $this->record($request, 'invalid'); } if ($response->isCacheable()) { $this->store($request, $response); } return $response; } /** * Unconditionally fetches a fresh response from the backend and * stores it in the cache if is cacheable. * * @param bool $catch Whether to process exceptions * * @return Response */ protected function fetch(Request $request, bool $catch = false) { $subRequest = clone $request; // send no head requests because we want content if ('HEAD' === $request->getMethod()) { $subRequest->setMethod('GET'); } // avoid that the backend sends no content $subRequest->headers->remove('If-Modified-Since'); $subRequest->headers->remove('If-None-Match'); $response = $this->forward($subRequest, $catch); if ($response->isCacheable()) { $this->store($request, $response); } return $response; } /** * Forwards the Request to the backend and returns the Response. * * All backend requests (cache passes, fetches, cache validations) * run through this method. * * @param bool $catch Whether to catch exceptions or not * @param Response|null $entry A Response instance (the stale entry if present, null otherwise) * * @return Response */ protected function forward(Request $request, bool $catch = false, Response $entry = null) { if ($this->surrogate) { $this->surrogate->addSurrogateCapability($request); } // always a "master" request (as the real master request can be in cache) $response = SubRequestHandler::handle($this->kernel, $request, HttpKernelInterface::MAIN_REQUEST, $catch); /* * Support stale-if-error given on Responses or as a config option. * RFC 7234 summarizes in Section 4.2.4 (but also mentions with the individual * Cache-Control directives) that * * A cache MUST NOT generate a stale response if it is prohibited by an * explicit in-protocol directive (e.g., by a "no-store" or "no-cache" * cache directive, a "must-revalidate" cache-response-directive, or an * applicable "s-maxage" or "proxy-revalidate" cache-response-directive; * see Section 5.2.2). * * https://tools.ietf.org/html/rfc7234#section-4.2.4 * * We deviate from this in one detail, namely that we *do* serve entries in the * stale-if-error case even if they have a `s-maxage` Cache-Control directive. */ if (null !== $entry && \in_array($response->getStatusCode(), [500, 502, 503, 504]) && !$entry->headers->hasCacheControlDirective('no-cache') && !$entry->mustRevalidate() ) { if (null === $age = $entry->headers->getCacheControlDirective('stale-if-error')) { $age = $this->options['stale_if_error']; } /* * stale-if-error gives the (extra) time that the Response may be used *after* it has become stale. * So we compare the time the $entry has been sitting in the cache already with the * time it was fresh plus the allowed grace period. */ if ($entry->getAge() <= $entry->getMaxAge() + $age) { $this->record($request, 'stale-if-error'); return $entry; } } /* RFC 7231 Sect. 7.1.1.2 says that a server that does not have a reasonably accurate clock MUST NOT send a "Date" header, although it MUST send one in most other cases except for 1xx or 5xx responses where it MAY do so. Anyway, a client that received a message without a "Date" header MUST add it. */ if (!$response->headers->has('Date')) { $response->setDate(\DateTime::createFromFormat('U', time())); } $this->processResponseBody($request, $response); if ($this->isPrivateRequest($request) && !$response->headers->hasCacheControlDirective('public')) { $response->setPrivate(); } elseif ($this->options['default_ttl'] > 0 && null === $response->getTtl() && !$response->headers->getCacheControlDirective('must-revalidate')) { $response->setTtl($this->options['default_ttl']); } return $response; } /** * Checks whether the cache entry is "fresh enough" to satisfy the Request. * * @return bool */ protected function isFreshEnough(Request $request, Response $entry) { if (!$entry->isFresh()) { return $this->lock($request, $entry); } if ($this->options['allow_revalidate'] && null !== $maxAge = $request->headers->getCacheControlDirective('max-age')) { return $maxAge > 0 && $maxAge >= $entry->getAge(); } return true; } /** * Locks a Request during the call to the backend. * * @return bool true if the cache entry can be returned even if it is staled, false otherwise */ protected function lock(Request $request, Response $entry) { // try to acquire a lock to call the backend $lock = $this->store->lock($request); if (true === $lock) { // we have the lock, call the backend return false; } // there is already another process calling the backend // May we serve a stale response? if ($this->mayServeStaleWhileRevalidate($entry)) { $this->record($request, 'stale-while-revalidate'); return true; } // wait for the lock to be released if ($this->waitForLock($request)) { // replace the current entry with the fresh one $new = $this->lookup($request); $entry->headers = $new->headers; $entry->setContent($new->getContent()); $entry->setStatusCode($new->getStatusCode()); $entry->setProtocolVersion($new->getProtocolVersion()); foreach ($new->headers->getCookies() as $cookie) { $entry->headers->setCookie($cookie); } } else { // backend is slow as hell, send a 503 response (to avoid the dog pile effect) $entry->setStatusCode(503); $entry->setContent('503 Service Unavailable'); $entry->headers->set('Retry-After', 10); } return true; } /** * Writes the Response to the cache. * * @throws \Exception */ protected function store(Request $request, Response $response) { try { $this->store->write($request, $response); $this->record($request, 'store'); $response->headers->set('Age', $response->getAge()); } catch (\Exception $e) { $this->record($request, 'store-failed'); if ($this->options['debug']) { throw $e; } } // now that the response is cached, release the lock $this->store->unlock($request); } /** * Restores the Response body. */ private function restoreResponseBody(Request $request, Response $response) { if ($response->headers->has('X-Body-Eval')) { ob_start(); if ($response->headers->has('X-Body-File')) { include $response->headers->get('X-Body-File'); } else { eval('; ?>'.$response->getContent().'setContent(ob_get_clean()); $response->headers->remove('X-Body-Eval'); if (!$response->headers->has('Transfer-Encoding')) { $response->headers->set('Content-Length', \strlen($response->getContent())); } } elseif ($response->headers->has('X-Body-File')) { // Response does not include possibly dynamic content (ESI, SSI), so we need // not handle the content for HEAD requests if (!$request->isMethod('HEAD')) { $response->setContent(file_get_contents($response->headers->get('X-Body-File'))); } } else { return; } $response->headers->remove('X-Body-File'); } protected function processResponseBody(Request $request, Response $response) { if (null !== $this->surrogate && $this->surrogate->needsParsing($response)) { $this->surrogate->process($request, $response); } } /** * Checks if the Request includes authorization or other sensitive information * that should cause the Response to be considered private by default. */ private function isPrivateRequest(Request $request): bool { foreach ($this->options['private_headers'] as $key) { $key = strtolower(str_replace('HTTP_', '', $key)); if ('cookie' === $key) { if (\count($request->cookies->all())) { return true; } } elseif ($request->headers->has($key)) { return true; } } return false; } /** * Records that an event took place. */ private function record(Request $request, string $event) { $this->traces[$this->getTraceKey($request)][] = $event; } /** * Calculates the key we use in the "trace" array for a given request. */ private function getTraceKey(Request $request): string { $path = $request->getPathInfo(); if ($qs = $request->getQueryString()) { $path .= '?'.$qs; } return $request->getMethod().' '.$path; } /** * Checks whether the given (cached) response may be served as "stale" when a revalidation * is currently in progress. */ private function mayServeStaleWhileRevalidate(Response $entry): bool { $timeout = $entry->headers->getCacheControlDirective('stale-while-revalidate'); if (null === $timeout) { $timeout = $this->options['stale_while_revalidate']; } return abs($entry->getTtl() ?? 0) < $timeout; } /** * Waits for the store to release a locked entry. */ private function waitForLock(Request $request): bool { $wait = 0; while ($this->store->isLocked($request) && $wait < 100) { usleep(50000); ++$wait; } return $wait < 100; } } PK'\)eUffHttpCache/AbstractSurrogate.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Abstract class implementing Surrogate capabilities to Request and Response instances. * * @author Fabien Potencier * @author Robin Chalas */ abstract class AbstractSurrogate implements SurrogateInterface { protected $contentTypes; protected $phpEscapeMap = [ ['', '', '', ''], ]; /** * @param array $contentTypes An array of content-type that should be parsed for Surrogate information * (default: text/html, text/xml, application/xhtml+xml, and application/xml) */ public function __construct(array $contentTypes = ['text/html', 'text/xml', 'application/xhtml+xml', 'application/xml']) { $this->contentTypes = $contentTypes; } /** * Returns a new cache strategy instance. * * @return ResponseCacheStrategyInterface */ public function createCacheStrategy() { return new ResponseCacheStrategy(); } /** * {@inheritdoc} */ public function hasSurrogateCapability(Request $request) { if (null === $value = $request->headers->get('Surrogate-Capability')) { return false; } return str_contains($value, sprintf('%s/1.0', strtoupper($this->getName()))); } /** * {@inheritdoc} */ public function addSurrogateCapability(Request $request) { $current = $request->headers->get('Surrogate-Capability'); $new = sprintf('symfony="%s/1.0"', strtoupper($this->getName())); $request->headers->set('Surrogate-Capability', $current ? $current.', '.$new : $new); } /** * {@inheritdoc} */ public function needsParsing(Response $response) { if (!$control = $response->headers->get('Surrogate-Control')) { return false; } $pattern = sprintf('#content="[^"]*%s/1.0[^"]*"#', strtoupper($this->getName())); return (bool) preg_match($pattern, $control); } /** * {@inheritdoc} */ public function handle(HttpCache $cache, string $uri, string $alt, bool $ignoreErrors) { $subRequest = Request::create($uri, Request::METHOD_GET, [], $cache->getRequest()->cookies->all(), [], $cache->getRequest()->server->all()); try { $response = $cache->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true); if (!$response->isSuccessful() && Response::HTTP_NOT_MODIFIED !== $response->getStatusCode()) { throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %d).', $subRequest->getUri(), $response->getStatusCode())); } return $response->getContent(); } catch (\Exception $e) { if ($alt) { return $this->handle($cache, $alt, '', $ignoreErrors); } if (!$ignoreErrors) { throw $e; } } return ''; } /** * Remove the Surrogate from the Surrogate-Control header. */ protected function removeFromControl(Response $response) { if (!$response->headers->has('Surrogate-Control')) { return; } $value = $response->headers->get('Surrogate-Control'); $upperName = strtoupper($this->getName()); if (sprintf('content="%s/1.0"', $upperName) == $value) { $response->headers->remove('Surrogate-Control'); } elseif (preg_match(sprintf('#,\s*content="%s/1.0"#', $upperName), $value)) { $response->headers->set('Surrogate-Control', preg_replace(sprintf('#,\s*content="%s/1.0"#', $upperName), '', $value)); } elseif (preg_match(sprintf('#content="%s/1.0",\s*#', $upperName), $value)) { $response->headers->set('Surrogate-Control', preg_replace(sprintf('#content="%s/1.0",\s*#', $upperName), '', $value)); } } } PK'\^ppHttpCache/StoreInterface.phpnu[ * * This code is partially based on the Rack-Cache library by Ryan Tomayko, * which is released under the MIT license. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * Interface implemented by HTTP cache stores. * * @author Fabien Potencier */ interface StoreInterface { /** * Locates a cached Response for the Request provided. * * @return Response|null */ public function lookup(Request $request); /** * Writes a cache entry to the store for the given Request and Response. * * Existing entries are read and any that match the response are removed. This * method calls write with the new list of cache entries. * * @return string The key under which the response is stored */ public function write(Request $request, Response $response); /** * Invalidates all cache entries that match the request. */ public function invalidate(Request $request); /** * Locks the cache for a given Request. * * @return bool|string true if the lock is acquired, the path to the current lock otherwise */ public function lock(Request $request); /** * Releases the lock for the given Request. * * @return bool False if the lock file does not exist or cannot be unlocked, true otherwise */ public function unlock(Request $request); /** * Returns whether or not a lock exists. * * @return bool true if lock exists, false otherwise */ public function isLocked(Request $request); /** * Purges data for the given URL. * * @return bool true if the URL exists and has been purged, false otherwise */ public function purge(string $url); /** * Cleanups storage. */ public function cleanup(); } PK'\P,HttpCache/ResponseCacheStrategyInterface.phpnu[ * * This code is partially based on the Rack-Cache library by Ryan Tomayko, * which is released under the MIT license. * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801) * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Response; /** * ResponseCacheStrategyInterface implementations know how to compute the * Response cache HTTP header based on the different response cache headers. * * @author Fabien Potencier */ interface ResponseCacheStrategyInterface { /** * Adds a Response. */ public function add(Response $response); /** * Updates the Response HTTP headers based on the embedded Responses. */ public function update(Response $response); } PK'\ó HttpCache/SurrogateInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; interface SurrogateInterface { /** * Returns surrogate name. * * @return string */ public function getName(); /** * Returns a new cache strategy instance. * * @return ResponseCacheStrategyInterface */ public function createCacheStrategy(); /** * Checks that at least one surrogate has Surrogate capability. * * @return bool */ public function hasSurrogateCapability(Request $request); /** * Adds Surrogate-capability to the given Request. */ public function addSurrogateCapability(Request $request); /** * Adds HTTP headers to specify that the Response needs to be parsed for Surrogate. * * This method only adds an Surrogate HTTP header if the Response has some Surrogate tags. */ public function addSurrogateControl(Response $response); /** * Checks that the Response needs to be parsed for Surrogate tags. * * @return bool */ public function needsParsing(Response $response); /** * Renders a Surrogate tag. * * @param string $alt An alternate URI * @param string $comment A comment to add as an esi:include tag * * @return string */ public function renderIncludeTag(string $uri, string $alt = null, bool $ignoreErrors = true, string $comment = ''); /** * Replaces a Response Surrogate tags with the included resource content. * * @return Response */ public function process(Request $request, Response $response); /** * Handles a Surrogate from the cache. * * @param string $alt An alternative URI * * @return string * * @throws \RuntimeException * @throws \Exception */ public function handle(HttpCache $cache, string $uri, string $alt, bool $ignoreErrors); } PK'\;▋###HttpCache/ResponseCacheStrategy.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Response; /** * ResponseCacheStrategy knows how to compute the Response cache HTTP header * based on the different response cache headers. * * This implementation changes the main response TTL to the smallest TTL received * or force validation if one of the surrogates has validation cache strategy. * * @author Fabien Potencier */ class ResponseCacheStrategy implements ResponseCacheStrategyInterface { /** * Cache-Control headers that are sent to the final response if they appear in ANY of the responses. */ private const OVERRIDE_DIRECTIVES = ['private', 'no-cache', 'no-store', 'no-transform', 'must-revalidate', 'proxy-revalidate']; /** * Cache-Control headers that are sent to the final response if they appear in ALL of the responses. */ private const INHERIT_DIRECTIVES = ['public', 'immutable']; private $embeddedResponses = 0; private $isNotCacheableResponseEmbedded = false; private $age = 0; private $flagDirectives = [ 'no-cache' => null, 'no-store' => null, 'no-transform' => null, 'must-revalidate' => null, 'proxy-revalidate' => null, 'public' => null, 'private' => null, 'immutable' => null, ]; private $ageDirectives = [ 'max-age' => null, 's-maxage' => null, 'expires' => null, ]; /** * {@inheritdoc} */ public function add(Response $response) { ++$this->embeddedResponses; foreach (self::OVERRIDE_DIRECTIVES as $directive) { if ($response->headers->hasCacheControlDirective($directive)) { $this->flagDirectives[$directive] = true; } } foreach (self::INHERIT_DIRECTIVES as $directive) { if (false !== $this->flagDirectives[$directive]) { $this->flagDirectives[$directive] = $response->headers->hasCacheControlDirective($directive); } } $age = $response->getAge(); $this->age = max($this->age, $age); if ($this->willMakeFinalResponseUncacheable($response)) { $this->isNotCacheableResponseEmbedded = true; return; } $isHeuristicallyCacheable = $response->headers->hasCacheControlDirective('public'); $maxAge = $response->headers->hasCacheControlDirective('max-age') ? (int) $response->headers->getCacheControlDirective('max-age') : null; $this->storeRelativeAgeDirective('max-age', $maxAge, $age, $isHeuristicallyCacheable); $sharedMaxAge = $response->headers->hasCacheControlDirective('s-maxage') ? (int) $response->headers->getCacheControlDirective('s-maxage') : $maxAge; $this->storeRelativeAgeDirective('s-maxage', $sharedMaxAge, $age, $isHeuristicallyCacheable); $expires = $response->getExpires(); $expires = null !== $expires ? (int) $expires->format('U') - (int) $response->getDate()->format('U') : null; $this->storeRelativeAgeDirective('expires', $expires >= 0 ? $expires : null, 0, $isHeuristicallyCacheable); } /** * {@inheritdoc} */ public function update(Response $response) { // if we have no embedded Response, do nothing if (0 === $this->embeddedResponses) { return; } // Remove validation related headers of the master response, // because some of the response content comes from at least // one embedded response (which likely has a different caching strategy). $response->setEtag(null); $response->setLastModified(null); $this->add($response); $response->headers->set('Age', $this->age); if ($this->isNotCacheableResponseEmbedded) { if ($this->flagDirectives['no-store']) { $response->headers->set('Cache-Control', 'no-cache, no-store, must-revalidate'); } else { $response->headers->set('Cache-Control', 'no-cache, must-revalidate'); } return; } $flags = array_filter($this->flagDirectives); if (isset($flags['must-revalidate'])) { $flags['no-cache'] = true; } $response->headers->set('Cache-Control', implode(', ', array_keys($flags))); $maxAge = null; if (is_numeric($this->ageDirectives['max-age'])) { $maxAge = $this->ageDirectives['max-age'] + $this->age; $response->headers->addCacheControlDirective('max-age', $maxAge); } if (is_numeric($this->ageDirectives['s-maxage'])) { $sMaxage = $this->ageDirectives['s-maxage'] + $this->age; if ($maxAge !== $sMaxage) { $response->headers->addCacheControlDirective('s-maxage', $sMaxage); } } if (is_numeric($this->ageDirectives['expires'])) { $date = clone $response->getDate(); $date->modify('+'.($this->ageDirectives['expires'] + $this->age).' seconds'); $response->setExpires($date); } } /** * RFC2616, Section 13.4. * * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4 */ private function willMakeFinalResponseUncacheable(Response $response): bool { // RFC2616: A response received with a status code of 200, 203, 300, 301 or 410 // MAY be stored by a cache […] unless a cache-control directive prohibits caching. if ($response->headers->hasCacheControlDirective('no-cache') || $response->headers->getCacheControlDirective('no-store') ) { return true; } // Last-Modified and Etag headers cannot be merged, they render the response uncacheable // by default (except if the response also has max-age etc.). if (\in_array($response->getStatusCode(), [200, 203, 300, 301, 410]) && null === $response->getLastModified() && null === $response->getEtag() ) { return false; } // RFC2616: A response received with any other status code (e.g. status codes 302 and 307) // MUST NOT be returned in a reply to a subsequent request unless there are // cache-control directives or another header(s) that explicitly allow it. $cacheControl = ['max-age', 's-maxage', 'must-revalidate', 'proxy-revalidate', 'public', 'private']; foreach ($cacheControl as $key) { if ($response->headers->hasCacheControlDirective($key)) { return false; } } if ($response->headers->has('Expires')) { return false; } return true; } /** * Store lowest max-age/s-maxage/expires for the final response. * * The response might have been stored in cache a while ago. To keep things comparable, * we have to subtract the age so that the value is normalized for an age of 0. * * If the value is lower than the currently stored value, we update the value, to keep a rolling * minimal value of each instruction. * * If the value is NULL and the isHeuristicallyCacheable parameter is false, the directive will * not be set on the final response. In this case, not all responses had the directive set and no * value can be found that satisfies the requirements of all responses. The directive will be dropped * from the final response. * * If the isHeuristicallyCacheable parameter is true, however, the current response has been marked * as cacheable in a public (shared) cache, but did not provide an explicit lifetime that would serve * as an upper bound. In this case, we can proceed and possibly keep the directive on the final response. */ private function storeRelativeAgeDirective(string $directive, ?int $value, int $age, bool $isHeuristicallyCacheable) { if (null === $value) { if ($isHeuristicallyCacheable) { /* * See https://datatracker.ietf.org/doc/html/rfc7234#section-4.2.2 * This particular response does not require maximum lifetime; heuristics might be applied. * Other responses, however, might have more stringent requirements on maximum lifetime. * So, return early here so that the final response can have the more limiting value set. */ return; } $this->ageDirectives[$directive] = false; } if (false !== $this->ageDirectives[$directive]) { $value -= $age; $this->ageDirectives[$directive] = null !== $this->ageDirectives[$directive] ? min($this->ageDirectives[$directive], $value) : $value; } } } PK'\|7|7HttpCache/Store.phpnu[ * * This code is partially based on the Rack-Cache library by Ryan Tomayko, * which is released under the MIT license. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * Store implements all the logic for storing cache metadata (Request and Response headers). * * @author Fabien Potencier */ class Store implements StoreInterface { protected $root; /** @var \SplObjectStorage */ private $keyCache; /** @var array */ private $locks = []; private $options; /** * Constructor. * * The available options are: * * * private_headers Set of response headers that should not be stored * when a response is cached. (default: Set-Cookie) * * @throws \RuntimeException */ public function __construct(string $root, array $options = []) { $this->root = $root; if (!is_dir($this->root) && !@mkdir($this->root, 0777, true) && !is_dir($this->root)) { throw new \RuntimeException(sprintf('Unable to create the store directory (%s).', $this->root)); } $this->keyCache = new \SplObjectStorage(); $this->options = array_merge([ 'private_headers' => ['Set-Cookie'], ], $options); } /** * Cleanups storage. */ public function cleanup() { // unlock everything foreach ($this->locks as $lock) { flock($lock, \LOCK_UN); fclose($lock); } $this->locks = []; } /** * Tries to lock the cache for a given Request, without blocking. * * @return bool|string true if the lock is acquired, the path to the current lock otherwise */ public function lock(Request $request) { $key = $this->getCacheKey($request); if (!isset($this->locks[$key])) { $path = $this->getPath($key); if (!is_dir(\dirname($path)) && false === @mkdir(\dirname($path), 0777, true) && !is_dir(\dirname($path))) { return $path; } $h = fopen($path, 'c'); if (!flock($h, \LOCK_EX | \LOCK_NB)) { fclose($h); return $path; } $this->locks[$key] = $h; } return true; } /** * Releases the lock for the given Request. * * @return bool False if the lock file does not exist or cannot be unlocked, true otherwise */ public function unlock(Request $request) { $key = $this->getCacheKey($request); if (isset($this->locks[$key])) { flock($this->locks[$key], \LOCK_UN); fclose($this->locks[$key]); unset($this->locks[$key]); return true; } return false; } public function isLocked(Request $request) { $key = $this->getCacheKey($request); if (isset($this->locks[$key])) { return true; // shortcut if lock held by this process } if (!is_file($path = $this->getPath($key))) { return false; } $h = fopen($path, 'r'); flock($h, \LOCK_EX | \LOCK_NB, $wouldBlock); flock($h, \LOCK_UN); // release the lock we just acquired fclose($h); return (bool) $wouldBlock; } /** * Locates a cached Response for the Request provided. * * @return Response|null */ public function lookup(Request $request) { $key = $this->getCacheKey($request); if (!$entries = $this->getMetadata($key)) { return null; } // find a cached entry that matches the request. $match = null; foreach ($entries as $entry) { if ($this->requestsMatch(isset($entry[1]['vary'][0]) ? implode(', ', $entry[1]['vary']) : '', $request->headers->all(), $entry[0])) { $match = $entry; break; } } if (null === $match) { return null; } $headers = $match[1]; if (file_exists($path = $this->getPath($headers['x-content-digest'][0]))) { return $this->restoreResponse($headers, $path); } // TODO the metaStore referenced an entity that doesn't exist in // the entityStore. We definitely want to return nil but we should // also purge the entry from the meta-store when this is detected. return null; } /** * Writes a cache entry to the store for the given Request and Response. * * Existing entries are read and any that match the response are removed. This * method calls write with the new list of cache entries. * * @return string * * @throws \RuntimeException */ public function write(Request $request, Response $response) { $key = $this->getCacheKey($request); $storedEnv = $this->persistRequest($request); if ($response->headers->has('X-Body-File')) { // Assume the response came from disk, but at least perform some safeguard checks if (!$response->headers->has('X-Content-Digest')) { throw new \RuntimeException('A restored response must have the X-Content-Digest header.'); } $digest = $response->headers->get('X-Content-Digest'); if ($this->getPath($digest) !== $response->headers->get('X-Body-File')) { throw new \RuntimeException('X-Body-File and X-Content-Digest do not match.'); } // Everything seems ok, omit writing content to disk } else { $digest = $this->generateContentDigest($response); $response->headers->set('X-Content-Digest', $digest); if (!$this->save($digest, $response->getContent(), false)) { throw new \RuntimeException('Unable to store the entity.'); } if (!$response->headers->has('Transfer-Encoding')) { $response->headers->set('Content-Length', \strlen($response->getContent())); } } // read existing cache entries, remove non-varying, and add this one to the list $entries = []; $vary = $response->headers->get('vary'); foreach ($this->getMetadata($key) as $entry) { if (!isset($entry[1]['vary'][0])) { $entry[1]['vary'] = ['']; } if ($entry[1]['vary'][0] != $vary || !$this->requestsMatch($vary ?? '', $entry[0], $storedEnv)) { $entries[] = $entry; } } $headers = $this->persistResponse($response); unset($headers['age']); foreach ($this->options['private_headers'] as $h) { unset($headers[strtolower($h)]); } array_unshift($entries, [$storedEnv, $headers]); if (!$this->save($key, serialize($entries))) { throw new \RuntimeException('Unable to store the metadata.'); } return $key; } /** * Returns content digest for $response. * * @return string */ protected function generateContentDigest(Response $response) { return 'en'.hash('sha256', $response->getContent()); } /** * Invalidates all cache entries that match the request. * * @throws \RuntimeException */ public function invalidate(Request $request) { $modified = false; $key = $this->getCacheKey($request); $entries = []; foreach ($this->getMetadata($key) as $entry) { $response = $this->restoreResponse($entry[1]); if ($response->isFresh()) { $response->expire(); $modified = true; $entries[] = [$entry[0], $this->persistResponse($response)]; } else { $entries[] = $entry; } } if ($modified && !$this->save($key, serialize($entries))) { throw new \RuntimeException('Unable to store the metadata.'); } } /** * Determines whether two Request HTTP header sets are non-varying based on * the vary response header value provided. * * @param string|null $vary A Response vary header * @param array $env1 A Request HTTP header array * @param array $env2 A Request HTTP header array */ private function requestsMatch(?string $vary, array $env1, array $env2): bool { if (empty($vary)) { return true; } foreach (preg_split('/[\s,]+/', $vary) as $header) { $key = str_replace('_', '-', strtolower($header)); $v1 = $env1[$key] ?? null; $v2 = $env2[$key] ?? null; if ($v1 !== $v2) { return false; } } return true; } /** * Gets all data associated with the given key. * * Use this method only if you know what you are doing. */ private function getMetadata(string $key): array { if (!$entries = $this->load($key)) { return []; } return unserialize($entries) ?: []; } /** * Purges data for the given URL. * * This method purges both the HTTP and the HTTPS version of the cache entry. * * @return bool true if the URL exists with either HTTP or HTTPS scheme and has been purged, false otherwise */ public function purge(string $url) { $http = preg_replace('#^https:#', 'http:', $url); $https = preg_replace('#^http:#', 'https:', $url); $purgedHttp = $this->doPurge($http); $purgedHttps = $this->doPurge($https); return $purgedHttp || $purgedHttps; } /** * Purges data for the given URL. */ private function doPurge(string $url): bool { $key = $this->getCacheKey(Request::create($url)); if (isset($this->locks[$key])) { flock($this->locks[$key], \LOCK_UN); fclose($this->locks[$key]); unset($this->locks[$key]); } if (is_file($path = $this->getPath($key))) { unlink($path); return true; } return false; } /** * Loads data for the given key. */ private function load(string $key): ?string { $path = $this->getPath($key); return is_file($path) && false !== ($contents = @file_get_contents($path)) ? $contents : null; } /** * Save data for the given key. */ private function save(string $key, string $data, bool $overwrite = true): bool { $path = $this->getPath($key); if (!$overwrite && file_exists($path)) { return true; } if (isset($this->locks[$key])) { $fp = $this->locks[$key]; @ftruncate($fp, 0); @fseek($fp, 0); $len = @fwrite($fp, $data); if (\strlen($data) !== $len) { @ftruncate($fp, 0); return false; } } else { if (!is_dir(\dirname($path)) && false === @mkdir(\dirname($path), 0777, true) && !is_dir(\dirname($path))) { return false; } $tmpFile = tempnam(\dirname($path), basename($path)); if (false === $fp = @fopen($tmpFile, 'w')) { @unlink($tmpFile); return false; } @fwrite($fp, $data); @fclose($fp); if ($data != file_get_contents($tmpFile)) { @unlink($tmpFile); return false; } if (false === @rename($tmpFile, $path)) { @unlink($tmpFile); return false; } } @chmod($path, 0666 & ~umask()); return true; } public function getPath(string $key) { return $this->root.\DIRECTORY_SEPARATOR.substr($key, 0, 2).\DIRECTORY_SEPARATOR.substr($key, 2, 2).\DIRECTORY_SEPARATOR.substr($key, 4, 2).\DIRECTORY_SEPARATOR.substr($key, 6); } /** * Generates a cache key for the given Request. * * This method should return a key that must only depend on a * normalized version of the request URI. * * If the same URI can have more than one representation, based on some * headers, use a Vary header to indicate them, and each representation will * be stored independently under the same cache key. * * @return string */ protected function generateCacheKey(Request $request) { return 'md'.hash('sha256', $request->getUri()); } /** * Returns a cache key for the given Request. */ private function getCacheKey(Request $request): string { if (isset($this->keyCache[$request])) { return $this->keyCache[$request]; } return $this->keyCache[$request] = $this->generateCacheKey($request); } /** * Persists the Request HTTP headers. */ private function persistRequest(Request $request): array { return $request->headers->all(); } /** * Persists the Response HTTP headers. */ private function persistResponse(Response $response): array { $headers = $response->headers->all(); $headers['X-Status'] = [$response->getStatusCode()]; return $headers; } /** * Restores a Response from the HTTP headers and body. */ private function restoreResponse(array $headers, string $path = null): Response { $status = $headers['X-Status'][0]; unset($headers['X-Status']); if (null !== $path) { $headers['X-Body-File'] = [$path]; } return new Response($path, $status, $headers); } } PK'\㟶QQHttpCache/SubRequestHandler.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\IpUtils; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * @author Nicolas Grekas * * @internal */ class SubRequestHandler { public static function handle(HttpKernelInterface $kernel, Request $request, int $type, bool $catch): Response { // save global state related to trusted headers and proxies $trustedProxies = Request::getTrustedProxies(); $trustedHeaderSet = Request::getTrustedHeaderSet(); // remove untrusted values $remoteAddr = $request->server->get('REMOTE_ADDR'); if (!$remoteAddr || !IpUtils::checkIp($remoteAddr, $trustedProxies)) { $trustedHeaders = [ 'FORWARDED' => $trustedHeaderSet & Request::HEADER_FORWARDED, 'X_FORWARDED_FOR' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_FOR, 'X_FORWARDED_HOST' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_HOST, 'X_FORWARDED_PROTO' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PROTO, 'X_FORWARDED_PORT' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PORT, 'X_FORWARDED_PREFIX' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PREFIX, ]; foreach (array_filter($trustedHeaders) as $name => $key) { $request->headers->remove($name); $request->server->remove('HTTP_'.$name); } } // compute trusted values, taking any trusted proxies into account $trustedIps = []; $trustedValues = []; foreach (array_reverse($request->getClientIps()) as $ip) { $trustedIps[] = $ip; $trustedValues[] = sprintf('for="%s"', $ip); } if ($ip !== $remoteAddr) { $trustedIps[] = $remoteAddr; $trustedValues[] = sprintf('for="%s"', $remoteAddr); } // set trusted values, reusing as much as possible the global trusted settings if (Request::HEADER_FORWARDED & $trustedHeaderSet) { $trustedValues[0] .= sprintf(';host="%s";proto=%s', $request->getHttpHost(), $request->getScheme()); $request->headers->set('Forwarded', $v = implode(', ', $trustedValues)); $request->server->set('HTTP_FORWARDED', $v); } if (Request::HEADER_X_FORWARDED_FOR & $trustedHeaderSet) { $request->headers->set('X-Forwarded-For', $v = implode(', ', $trustedIps)); $request->server->set('HTTP_X_FORWARDED_FOR', $v); } elseif (!(Request::HEADER_FORWARDED & $trustedHeaderSet)) { Request::setTrustedProxies($trustedProxies, $trustedHeaderSet | Request::HEADER_X_FORWARDED_FOR); $request->headers->set('X-Forwarded-For', $v = implode(', ', $trustedIps)); $request->server->set('HTTP_X_FORWARDED_FOR', $v); } // fix the client IP address by setting it to 127.0.0.1, // which is the core responsibility of this method $request->server->set('REMOTE_ADDR', '127.0.0.1'); // ensure 127.0.0.1 is set as trusted proxy if (!IpUtils::checkIp('127.0.0.1', $trustedProxies)) { Request::setTrustedProxies(array_merge($trustedProxies, ['127.0.0.1']), Request::getTrustedHeaderSet()); } try { return $kernel->handle($request, $type, $catch); } finally { // restore global state Request::setTrustedProxies($trustedProxies, $trustedHeaderSet); } } } PK'\rGf f HttpCache/Ssi.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * Ssi implements the SSI capabilities to Request and Response instances. * * @author Sebastian Krebs */ class Ssi extends AbstractSurrogate { /** * {@inheritdoc} */ public function getName() { return 'ssi'; } /** * {@inheritdoc} */ public function addSurrogateControl(Response $response) { if (str_contains($response->getContent(), '', $uri); } /** * {@inheritdoc} */ public function process(Request $request, Response $response) { $type = $response->headers->get('Content-Type'); if (empty($type)) { $type = 'text/html'; } $parts = explode(';', $type); if (!\in_array($parts[0], $this->contentTypes)) { return $response; } // we don't use a proper XML parser here as we can have SSI tags in a plain text response $content = $response->getContent(); $chunks = preg_split('##', $content, -1, \PREG_SPLIT_DELIM_CAPTURE); $chunks[0] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[0]); $i = 1; while (isset($chunks[$i])) { $options = []; preg_match_all('/(virtual)="([^"]*?)"/', $chunks[$i], $matches, \PREG_SET_ORDER); foreach ($matches as $set) { $options[$set[1]] = $set[2]; } if (!isset($options['virtual'])) { throw new \RuntimeException('Unable to process an SSI tag without a "virtual" attribute.'); } $chunks[$i] = sprintf('surrogate->handle($this, %s, \'\', false) ?>'."\n", var_export($options['virtual'], true) ); ++$i; $chunks[$i] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[$i]); ++$i; } $content = implode('', $chunks); $response->setContent($content); $response->headers->set('X-Body-Eval', 'SSI'); // remove SSI/1.0 from the Surrogate-Control header $this->removeFromControl($response); return $response; } } PK'\3NCAttribute/ArgumentInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Attribute; trigger_deprecation('symfony/http-kernel', '5.3', 'The "%s" interface is deprecated.', ArgumentInterface::class); /** * Marker interface for controller argument attributes. * * @deprecated since Symfony 5.3 */ interface ArgumentInterface { } PK'\ Attribute/AsController.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Attribute; /** * Service tag to autoconfigure controllers. */ #[\Attribute(\Attribute::TARGET_CLASS)] class AsController { public function __construct() { } } PK'\dAcێTerminableInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * Terminable extends the Kernel request/response cycle with dispatching a post * response event after sending the response and before shutting down the kernel. * * @author Jordi Boggiano * @author Pierre Minnieur */ interface TerminableInterface { /** * Terminates a request/response cycle. * * Should be called after sending the response and before shutting down the kernel. */ public function terminate(Request $request, Response $response); } PK'\HBundle/BundleInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Bundle; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; /** * BundleInterface. * * @author Fabien Potencier */ interface BundleInterface extends ContainerAwareInterface { /** * Boots the Bundle. */ public function boot(); /** * Shutdowns the Bundle. */ public function shutdown(); /** * Builds the bundle. * * It is only ever called once when the cache is empty. */ public function build(ContainerBuilder $container); /** * Returns the container extension that should be implicitly loaded. * * @return ExtensionInterface|null */ public function getContainerExtension(); /** * Returns the bundle name (the class short name). * * @return string */ public function getName(); /** * Gets the Bundle namespace. * * @return string */ public function getNamespace(); /** * Gets the Bundle directory path. * * The path should always be returned as a Unix path (with /). * * @return string */ public function getPath(); } PK'\+e  Bundle/Bundle.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Bundle; use Symfony\Component\Console\Application; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerAwareTrait; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; /** * An implementation of BundleInterface that adds a few conventions for DependencyInjection extensions. * * @author Fabien Potencier */ abstract class Bundle implements BundleInterface { use ContainerAwareTrait; protected $name; protected $extension; protected $path; private $namespace; /** * {@inheritdoc} */ public function boot() { } /** * {@inheritdoc} */ public function shutdown() { } /** * {@inheritdoc} * * This method can be overridden to register compilation passes, * other extensions, ... */ public function build(ContainerBuilder $container) { } /** * Returns the bundle's container extension. * * @return ExtensionInterface|null * * @throws \LogicException */ public function getContainerExtension() { if (null === $this->extension) { $extension = $this->createContainerExtension(); if (null !== $extension) { if (!$extension instanceof ExtensionInterface) { throw new \LogicException(sprintf('Extension "%s" must implement Symfony\Component\DependencyInjection\Extension\ExtensionInterface.', get_debug_type($extension))); } // check naming convention $basename = preg_replace('/Bundle$/', '', $this->getName()); $expectedAlias = Container::underscore($basename); if ($expectedAlias != $extension->getAlias()) { throw new \LogicException(sprintf('Users will expect the alias of the default extension of a bundle to be the underscored version of the bundle name ("%s"). You can override "Bundle::getContainerExtension()" if you want to use "%s" or another alias.', $expectedAlias, $extension->getAlias())); } $this->extension = $extension; } else { $this->extension = false; } } return $this->extension ?: null; } /** * {@inheritdoc} */ public function getNamespace() { if (null === $this->namespace) { $this->parseClassName(); } return $this->namespace; } /** * {@inheritdoc} */ public function getPath() { if (null === $this->path) { $reflected = new \ReflectionObject($this); $this->path = \dirname($reflected->getFileName()); } return $this->path; } /** * Returns the bundle name (the class short name). */ final public function getName(): string { if (null === $this->name) { $this->parseClassName(); } return $this->name; } public function registerCommands(Application $application) { } /** * Returns the bundle's container extension class. * * @return string */ protected function getContainerExtensionClass() { $basename = preg_replace('/Bundle$/', '', $this->getName()); return $this->getNamespace().'\\DependencyInjection\\'.$basename.'Extension'; } /** * Creates the bundle's container extension. * * @return ExtensionInterface|null */ protected function createContainerExtension() { return class_exists($class = $this->getContainerExtensionClass()) ? new $class() : null; } private function parseClassName() { $pos = strrpos(static::class, '\\'); $this->namespace = false === $pos ? '' : substr(static::class, 0, $pos); if (null === $this->name) { $this->name = false === $pos ? static::class : substr(static::class, $pos + 1); } } } PK'\yeBeB CHANGELOG.mdnu[CHANGELOG ========= 5.4 --- * Add the ability to enable the profiler using a request query parameter, body parameter or attribute * Deprecate `AbstractTestSessionListener` and `TestSessionListener`, use `AbstractSessionListener` and `SessionListener` instead * Deprecate the `fileLinkFormat` parameter of `DebugHandlersListener` * Add support for configuring log level, and status code by exception class * Allow ignoring "kernel.reset" methods that don't exist with "on_invalid" attribute 5.3 --- * Deprecate `ArgumentInterface` * Add `ArgumentMetadata::getAttributes()` * Deprecate `ArgumentMetadata::getAttribute()`, use `getAttributes()` instead * Mark the class `Symfony\Component\HttpKernel\EventListener\DebugHandlersListener` as internal * Deprecate returning a `ContainerBuilder` from `KernelInterface::registerContainerConfiguration()` * Deprecate `HttpKernelInterface::MASTER_REQUEST` and add `HttpKernelInterface::MAIN_REQUEST` as replacement * Deprecate `KernelEvent::isMasterRequest()` and add `isMainRequest()` as replacement * Add `#[AsController]` attribute for declaring standalone controllers on PHP 8 * Add `FragmentUriGeneratorInterface` and `FragmentUriGenerator` to generate the URI of a fragment 5.2.0 ----- * added session usage * made the public `http_cache` service handle requests when available * allowed enabling trusted hosts and proxies using new `kernel.trusted_hosts`, `kernel.trusted_proxies` and `kernel.trusted_headers` parameters * content of request parameter `_password` is now also hidden in the request profiler raw content section * Allowed adding attributes on controller arguments that will be passed to argument resolvers. * kernels implementing the `ExtensionInterface` will now be auto-registered to the container * added parameter `kernel.runtime_environment`, defined as `%env(default:kernel.environment:APP_RUNTIME_ENV)%` * do not set a default `Accept` HTTP header when using `HttpKernelBrowser` 5.1.0 ----- * allowed to use a specific logger channel for deprecations * made `WarmableInterface::warmUp()` return a list of classes or files to preload on PHP 7.4+; not returning an array is deprecated * made kernels implementing `WarmableInterface` be part of the cache warmup stage * deprecated support for `service:action` syntax to reference controllers, use `serviceOrFqcn::method` instead * allowed using public aliases to reference controllers * added session usage reporting when the `_stateless` attribute of the request is set to `true` * added `AbstractSessionListener::onSessionUsage()` to report when the session is used while a request is stateless 5.0.0 ----- * removed support for getting the container from a non-booted kernel * removed the first and second constructor argument of `ConfigDataCollector` * removed `ConfigDataCollector::getApplicationName()` * removed `ConfigDataCollector::getApplicationVersion()` * removed support for `Symfony\Component\Templating\EngineInterface` in `HIncludeFragmentRenderer`, use a `Twig\Environment` only * removed `TranslatorListener` in favor of `LocaleAwareListener` * removed `getRootDir()` and `getName()` from `Kernel` and `KernelInterface` * removed `FilterControllerArgumentsEvent`, use `ControllerArgumentsEvent` instead * removed `FilterControllerEvent`, use `ControllerEvent` instead * removed `FilterResponseEvent`, use `ResponseEvent` instead * removed `GetResponseEvent`, use `RequestEvent` instead * removed `GetResponseForControllerResultEvent`, use `ViewEvent` instead * removed `GetResponseForExceptionEvent`, use `ExceptionEvent` instead * removed `PostResponseEvent`, use `TerminateEvent` instead * removed `SaveSessionListener` in favor of `AbstractSessionListener` * removed `Client`, use `HttpKernelBrowser` instead * added method `getProjectDir()` to `KernelInterface` * removed methods `serialize` and `unserialize` from `DataCollector`, store the serialized state in the data property instead * made `ProfilerStorageInterface` internal * removed the second and third argument of `KernelInterface::locateResource` * removed the second and third argument of `FileLocator::__construct` * removed loading resources from `%kernel.root_dir%/Resources` and `%kernel.root_dir%` as fallback directories. * removed class `ExceptionListener`, use `ErrorListener` instead 4.4.0 ----- * The `DebugHandlersListener` class has been marked as `final` * Added new Bundle directory convention consistent with standard skeletons * Deprecated the second and third argument of `KernelInterface::locateResource` * Deprecated the second and third argument of `FileLocator::__construct` * Deprecated loading resources from `%kernel.root_dir%/Resources` and `%kernel.root_dir%` as fallback directories. Resources like service definitions are usually loaded relative to the current directory or with a glob pattern. The fallback directories have never been advocated so you likely do not use those in any app based on the SF Standard or Flex edition. * Marked all dispatched event classes as `@final` * Added `ErrorController` to enable the preview and error rendering mechanism * Getting the container from a non-booted kernel is deprecated. * Marked the `AjaxDataCollector`, `ConfigDataCollector`, `EventDataCollector`, `ExceptionDataCollector`, `LoggerDataCollector`, `MemoryDataCollector`, `RequestDataCollector` and `TimeDataCollector` classes as `@final`. * Marked the `RouterDataCollector::collect()` method as `@final`. * The `DataCollectorInterface::collect()` and `Profiler::collect()` methods third parameter signature will be `\Throwable $exception = null` instead of `\Exception $exception = null` in Symfony 5.0. * Deprecated methods `ExceptionEvent::get/setException()`, use `get/setThrowable()` instead * Deprecated class `ExceptionListener`, use `ErrorListener` instead 4.3.0 ----- * renamed `Client` to `HttpKernelBrowser` * `KernelInterface` doesn't extend `Serializable` anymore * deprecated the `Kernel::serialize()` and `unserialize()` methods * increased the priority of `Symfony\Component\HttpKernel\EventListener\AddRequestFormatsListener` * made `Symfony\Component\HttpKernel\EventListener\LocaleListener` set the default locale early * deprecated `TranslatorListener` in favor of `LocaleAwareListener` * added the registration of all `LocaleAwareInterface` implementations into the `LocaleAwareListener` * made `FileLinkFormatter` final and not implement `Serializable` anymore * the base `DataCollector` doesn't implement `Serializable` anymore, you should store all the serialized state in the data property instead * `DumpDataCollector` has been marked as `final` * added an event listener to prevent search engines from indexing applications in debug mode. * renamed `FilterControllerArgumentsEvent` to `ControllerArgumentsEvent` * renamed `FilterControllerEvent` to `ControllerEvent` * renamed `FilterResponseEvent` to `ResponseEvent` * renamed `GetResponseEvent` to `RequestEvent` * renamed `GetResponseForControllerResultEvent` to `ViewEvent` * renamed `GetResponseForExceptionEvent` to `ExceptionEvent` * renamed `PostResponseEvent` to `TerminateEvent` * added `HttpClientKernel` for handling requests with an `HttpClientInterface` instance * added `trace_header` and `trace_level` configuration options to `HttpCache` 4.2.0 ----- * deprecated `KernelInterface::getRootDir()` and the `kernel.root_dir` parameter * deprecated `KernelInterface::getName()` and the `kernel.name` parameter * deprecated the first and second constructor argument of `ConfigDataCollector` * deprecated `ConfigDataCollector::getApplicationName()` * deprecated `ConfigDataCollector::getApplicationVersion()` 4.1.0 ----- * added orphaned events support to `EventDataCollector` * `ExceptionListener` now logs exceptions at priority `0` (previously logged at `-128`) * Added support for using `service::method` to reference controllers, making it consistent with other cases. It is recommended over the `service:action` syntax with a single colon, which will be deprecated in the future. * Added the ability to profile individual argument value resolvers via the `Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver` 4.0.0 ----- * removed the `DataCollector::varToString()` method, use `DataCollector::cloneVar()` instead * using the `DataCollector::cloneVar()` method requires the VarDumper component * removed the `ValueExporter` class * removed `ControllerResolverInterface::getArguments()` * removed `TraceableControllerResolver::getArguments()` * removed `ControllerResolver::getArguments()` and the ability to resolve arguments * removed the `argument_resolver` service dependency from the `debug.controller_resolver` * removed `LazyLoadingFragmentHandler::addRendererService()` * removed `Psr6CacheClearer::addPool()` * removed `Extension::addClassesToCompile()` and `Extension::getClassesToCompile()` * removed `Kernel::loadClassCache()`, `Kernel::doLoadClassCache()`, `Kernel::setClassCache()`, and `Kernel::getEnvParameters()` * support for the `X-Status-Code` when handling exceptions in the `HttpKernel` has been dropped, use the `HttpKernel::allowCustomResponseCode()` method instead * removed convention-based commands registration * removed the `ChainCacheClearer::add()` method * removed the `CacheaWarmerAggregate::add()` and `setWarmers()` methods * made `CacheWarmerAggregate` and `ChainCacheClearer` classes final 3.4.0 ----- * added a minimalist PSR-3 `Logger` class that writes in `stderr` * made kernels implementing `CompilerPassInterface` able to process the container * deprecated bundle inheritance * added `RebootableInterface` and implemented it in `Kernel` * deprecated commands auto registration * deprecated `EnvParametersResource` * added `Symfony\Component\HttpKernel\Client::catchExceptions()` * deprecated the `ChainCacheClearer::add()` method * deprecated the `CacheaWarmerAggregate::add()` and `setWarmers()` methods * made `CacheWarmerAggregate` and `ChainCacheClearer` classes final * added the possibility to reset the profiler to its initial state * deprecated data collectors without a `reset()` method * deprecated implementing `DebugLoggerInterface` without a `clear()` method 3.3.0 ----- * added `kernel.project_dir` and `Kernel::getProjectDir()` * deprecated `kernel.root_dir` and `Kernel::getRootDir()` * deprecated `Kernel::getEnvParameters()` * deprecated the special `SYMFONY__` environment variables * added the possibility to change the query string parameter used by `UriSigner` * deprecated `LazyLoadingFragmentHandler::addRendererService()` * deprecated `Extension::addClassesToCompile()` and `Extension::getClassesToCompile()` * deprecated `Psr6CacheClearer::addPool()` 3.2.0 ----- * deprecated `DataCollector::varToString()`, use `cloneVar()` instead * changed surrogate capability name in `AbstractSurrogate::addSurrogateCapability` to 'symfony' * Added `ControllerArgumentValueResolverPass` 3.1.0 ----- * deprecated passing objects as URI attributes to the ESI and SSI renderers * deprecated `ControllerResolver::getArguments()` * added `Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface` * added `Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface` as argument to `HttpKernel` * added `Symfony\Component\HttpKernel\Controller\ArgumentResolver` * added `Symfony\Component\HttpKernel\DataCollector\RequestDataCollector::getMethod()` * added `Symfony\Component\HttpKernel\DataCollector\RequestDataCollector::getRedirect()` * added the `kernel.controller_arguments` event, triggered after controller arguments have been resolved 3.0.0 ----- * removed `Symfony\Component\HttpKernel\Kernel::init()` * removed `Symfony\Component\HttpKernel\Kernel::isClassInActiveBundle()` and `Symfony\Component\HttpKernel\KernelInterface::isClassInActiveBundle()` * removed `Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher::setProfiler()` * removed `Symfony\Component\HttpKernel\EventListener\FragmentListener::getLocalIpAddresses()` * removed `Symfony\Component\HttpKernel\EventListener\LocaleListener::setRequest()` * removed `Symfony\Component\HttpKernel\EventListener\RouterListener::setRequest()` * removed `Symfony\Component\HttpKernel\EventListener\ProfilerListener::onKernelRequest()` * removed `Symfony\Component\HttpKernel\Fragment\FragmentHandler::setRequest()` * removed `Symfony\Component\HttpKernel\HttpCache\Esi::hasSurrogateEsiCapability()` * removed `Symfony\Component\HttpKernel\HttpCache\Esi::addSurrogateEsiCapability()` * removed `Symfony\Component\HttpKernel\HttpCache\Esi::needsEsiParsing()` * removed `Symfony\Component\HttpKernel\HttpCache\HttpCache::getEsi()` * removed `Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel` * removed `Symfony\Component\HttpKernel\DependencyInjection\RegisterListenersPass` * removed `Symfony\Component\HttpKernel\EventListener\ErrorsLoggerListener` * removed `Symfony\Component\HttpKernel\EventListener\EsiListener` * removed `Symfony\Component\HttpKernel\HttpCache\EsiResponseCacheStrategy` * removed `Symfony\Component\HttpKernel\HttpCache\EsiResponseCacheStrategyInterface` * removed `Symfony\Component\HttpKernel\Log\LoggerInterface` * removed `Symfony\Component\HttpKernel\Log\NullLogger` * removed `Symfony\Component\HttpKernel\Profiler::import()` * removed `Symfony\Component\HttpKernel\Profiler::export()` 2.8.0 ----- * deprecated `Profiler::import` and `Profiler::export` 2.7.0 ----- * added the HTTP status code to profiles 2.6.0 ----- * deprecated `Symfony\Component\HttpKernel\EventListener\ErrorsLoggerListener`, use `Symfony\Component\HttpKernel\EventListener\DebugHandlersListener` instead * deprecated unused method `Symfony\Component\HttpKernel\Kernel::isClassInActiveBundle` and `Symfony\Component\HttpKernel\KernelInterface::isClassInActiveBundle` 2.5.0 ----- * deprecated `Symfony\Component\HttpKernel\DependencyInjection\RegisterListenersPass`, use `Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass` instead 2.4.0 ----- * added event listeners for the session * added the KernelEvents::FINISH_REQUEST event 2.3.0 ----- * [BC BREAK] renamed `Symfony\Component\HttpKernel\EventListener\DeprecationLoggerListener` to `Symfony\Component\HttpKernel\EventListener\ErrorsLoggerListener` and changed its constructor * deprecated `Symfony\Component\HttpKernel\Debug\ErrorHandler`, `Symfony\Component\HttpKernel\Debug\ExceptionHandler`, `Symfony\Component\HttpKernel\Exception\FatalErrorException` and `Symfony\Component\HttpKernel\Exception\FlattenException` * deprecated `Symfony\Component\HttpKernel\Kernel::init()` * added the possibility to specify an id an extra attributes to hinclude tags * added the collect of data if a controller is a Closure in the Request collector * pass exceptions from the ExceptionListener to the logger using the logging context to allow for more detailed messages 2.2.0 ----- * [BC BREAK] the path info for sub-request is now always _fragment (or whatever you configured instead of the default) * added Symfony\Component\HttpKernel\EventListener\FragmentListener * added Symfony\Component\HttpKernel\UriSigner * added Symfony\Component\HttpKernel\FragmentRenderer and rendering strategies (in Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface) * added Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel * added ControllerReference to create reference of Controllers (used in the FragmentRenderer class) * [BC BREAK] renamed TimeDataCollector::getTotalTime() to TimeDataCollector::getDuration() * updated the MemoryDataCollector to include the memory used in the kernel.terminate event listeners * moved the Stopwatch classes to a new component * added TraceableControllerResolver * added TraceableEventDispatcher (removed ContainerAwareTraceableEventDispatcher) * added support for WinCache opcode cache in ConfigDataCollector 2.1.0 ----- * [BC BREAK] the charset is now configured via the Kernel::getCharset() method * [BC BREAK] the current locale for the user is not stored anymore in the session * added the HTTP method to the profiler storage * updated all listeners to implement EventSubscriberInterface * added TimeDataCollector * added ContainerAwareTraceableEventDispatcher * moved TraceableEventDispatcherInterface to the EventDispatcher component * added RouterListener, LocaleListener, and StreamedResponseListener * added CacheClearerInterface (and ChainCacheClearer) * added a kernel.terminate event (via TerminableInterface and PostResponseEvent) * added a Stopwatch class * added WarmableInterface * improved extensibility between bundles * added profiler storages for Memcache(d), File-based, MongoDB, Redis * moved Filesystem class to its own component PK'\~~Resources/welcome.html.phpnu[ Welcome to Symfony!

You're seeing this page because you haven't configured any homepage URL and debug mode is enabled.

Welcome to Symfony

Your application is now ready and you can start working on it.

PK'\7 @Controller/ArgumentResolver/NotTaggedControllerValueResolver.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Psr\Container\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Provides an intuitive error message when controller fails because it is not registered as a service. * * @author Simeon Kolev */ final class NotTaggedControllerValueResolver implements ArgumentValueResolverInterface { private $container; public function __construct(ContainerInterface $container) { $this->container = $container; } /** * {@inheritdoc} */ public function supports(Request $request, ArgumentMetadata $argument): bool { $controller = $request->attributes->get('_controller'); if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) { $controller = $controller[0].'::'.$controller[1]; } elseif (!\is_string($controller) || '' === $controller) { return false; } if ('\\' === $controller[0]) { $controller = ltrim($controller, '\\'); } if (!$this->container->has($controller) && false !== $i = strrpos($controller, ':')) { $controller = substr($controller, 0, $i).strtolower(substr($controller, $i)); } return false === $this->container->has($controller); } /** * {@inheritdoc} */ public function resolve(Request $request, ArgumentMetadata $argument): iterable { if (\is_array($controller = $request->attributes->get('_controller'))) { $controller = $controller[0].'::'.$controller[1]; } if ('\\' === $controller[0]) { $controller = ltrim($controller, '\\'); } if (!$this->container->has($controller)) { $controller = (false !== $i = strrpos($controller, ':')) ? substr($controller, 0, $i).strtolower(substr($controller, $i)) : $controller.'::__invoke'; } $what = sprintf('argument $%s of "%s()"', $argument->getName(), $controller); $message = sprintf('Could not resolve %s, maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"?', $what); throw new RuntimeException($message); } } PK'\5)Zrr=Controller/ArgumentResolver/RequestAttributeValueResolver.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Yields a non-variadic argument's value from the request attributes. * * @author Iltar van der Berg */ final class RequestAttributeValueResolver implements ArgumentValueResolverInterface { /** * {@inheritdoc} */ public function supports(Request $request, ArgumentMetadata $argument): bool { return !$argument->isVariadic() && $request->attributes->has($argument->getName()); } /** * {@inheritdoc} */ public function resolve(Request $request, ArgumentMetadata $argument): iterable { yield $request->attributes->get($argument->getName()); } } PK'\@OO4Controller/ArgumentResolver/RequestValueResolver.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Yields the same instance as the request object passed along. * * @author Iltar van der Berg */ final class RequestValueResolver implements ArgumentValueResolverInterface { /** * {@inheritdoc} */ public function supports(Request $request, ArgumentMetadata $argument): bool { return Request::class === $argument->getType() || is_subclass_of($argument->getType(), Request::class); } /** * {@inheritdoc} */ public function resolve(Request $request, ArgumentMetadata $argument): iterable { yield $request; } } PK'\/Ų 4Controller/ArgumentResolver/ServiceValueResolver.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Psr\Container\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Yields a service keyed by _controller and argument name. * * @author Nicolas Grekas */ final class ServiceValueResolver implements ArgumentValueResolverInterface { private $container; public function __construct(ContainerInterface $container) { $this->container = $container; } /** * {@inheritdoc} */ public function supports(Request $request, ArgumentMetadata $argument): bool { $controller = $request->attributes->get('_controller'); if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) { $controller = $controller[0].'::'.$controller[1]; } elseif (!\is_string($controller) || '' === $controller) { return false; } if ('\\' === $controller[0]) { $controller = ltrim($controller, '\\'); } if (!$this->container->has($controller) && false !== $i = strrpos($controller, ':')) { $controller = substr($controller, 0, $i).strtolower(substr($controller, $i)); } return $this->container->has($controller) && $this->container->get($controller)->has($argument->getName()); } /** * {@inheritdoc} */ public function resolve(Request $request, ArgumentMetadata $argument): iterable { if (\is_array($controller = $request->attributes->get('_controller'))) { $controller = $controller[0].'::'.$controller[1]; } if ('\\' === $controller[0]) { $controller = ltrim($controller, '\\'); } if (!$this->container->has($controller)) { $i = strrpos($controller, ':'); $controller = substr($controller, 0, $i).strtolower(substr($controller, $i)); } try { yield $this->container->get($controller)->get($argument->getName()); } catch (RuntimeException $e) { $what = sprintf('argument $%s of "%s()"', $argument->getName(), $controller); $message = preg_replace('/service "\.service_locator\.[^"]++"/', $what, $e->getMessage()); if ($e->getMessage() === $message) { $message = sprintf('Cannot resolve %s: %s', $what, $message); } $r = new \ReflectionProperty($e, 'message'); $r->setAccessible(true); $r->setValue($e, $message); throw $e; } } } PK'\7ay6Controller/ArgumentResolver/TraceableValueResolver.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; use Symfony\Component\Stopwatch\Stopwatch; /** * Provides timing information via the stopwatch. * * @author Iltar van der Berg */ final class TraceableValueResolver implements ArgumentValueResolverInterface { private $inner; private $stopwatch; public function __construct(ArgumentValueResolverInterface $inner, Stopwatch $stopwatch) { $this->inner = $inner; $this->stopwatch = $stopwatch; } /** * {@inheritdoc} */ public function supports(Request $request, ArgumentMetadata $argument): bool { $method = \get_class($this->inner).'::'.__FUNCTION__; $this->stopwatch->start($method, 'controller.argument_value_resolver'); $return = $this->inner->supports($request, $argument); $this->stopwatch->stop($method); return $return; } /** * {@inheritdoc} */ public function resolve(Request $request, ArgumentMetadata $argument): iterable { $method = \get_class($this->inner).'::'.__FUNCTION__; $this->stopwatch->start($method, 'controller.argument_value_resolver'); yield from $this->inner->resolve($request, $argument); $this->stopwatch->stop($method); } } PK'\2 664Controller/ArgumentResolver/SessionValueResolver.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Yields the Session. * * @author Iltar van der Berg */ final class SessionValueResolver implements ArgumentValueResolverInterface { /** * {@inheritdoc} */ public function supports(Request $request, ArgumentMetadata $argument): bool { if (!$request->hasSession()) { return false; } $type = $argument->getType(); if (SessionInterface::class !== $type && !is_subclass_of($type, SessionInterface::class)) { return false; } return $request->getSession() instanceof $type; } /** * {@inheritdoc} */ public function resolve(Request $request, ArgumentMetadata $argument): iterable { yield $request->getSession(); } } PK'\KZ5Controller/ArgumentResolver/VariadicValueResolver.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Yields a variadic argument's values from the request attributes. * * @author Iltar van der Berg */ final class VariadicValueResolver implements ArgumentValueResolverInterface { /** * {@inheritdoc} */ public function supports(Request $request, ArgumentMetadata $argument): bool { return $argument->isVariadic() && $request->attributes->has($argument->getName()); } /** * {@inheritdoc} */ public function resolve(Request $request, ArgumentMetadata $argument): iterable { $values = $request->attributes->get($argument->getName()); if (!\is_array($values)) { throw new \InvalidArgumentException(sprintf('The action argument "...$%1$s" is required to be an array, the request attribute "%1$s" contains a type of "%2$s" instead.', $argument->getName(), get_debug_type($values))); } yield from $values; } } PK'\4Controller/ArgumentResolver/DefaultValueResolver.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Yields the default value defined in the action signature when no value has been given. * * @author Iltar van der Berg */ final class DefaultValueResolver implements ArgumentValueResolverInterface { /** * {@inheritdoc} */ public function supports(Request $request, ArgumentMetadata $argument): bool { return $argument->hasDefaultValue() || (null !== $argument->getType() && $argument->isNullable() && !$argument->isVariadic()); } /** * {@inheritdoc} */ public function resolve(Request $request, ArgumentMetadata $argument): iterable { yield $argument->hasDefaultValue() ? $argument->getDefaultValue() : null; } } PK'\P*Controller/ErrorController.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Renders error or exception pages from a given FlattenException. * * @author Yonel Ceruto * @author Matthias Pigulla */ class ErrorController { private $kernel; private $controller; private $errorRenderer; public function __construct(HttpKernelInterface $kernel, $controller, ErrorRendererInterface $errorRenderer) { $this->kernel = $kernel; $this->controller = $controller; $this->errorRenderer = $errorRenderer; } public function __invoke(\Throwable $exception): Response { $exception = $this->errorRenderer->render($exception); return new Response($exception->getAsString(), $exception->getStatusCode(), $exception->getHeaders()); } public function preview(Request $request, int $code): Response { /* * This Request mimics the parameters set by * \Symfony\Component\HttpKernel\EventListener\ErrorListener::duplicateRequest, with * the additional "showException" flag. */ $subRequest = $request->duplicate(null, null, [ '_controller' => $this->controller, 'exception' => new HttpException($code, 'This is a sample exception.'), 'logger' => null, 'showException' => false, ]); return $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST); } } PK'\2/7`Controller/ArgumentResolver.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributeValueResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\SessionValueResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\VariadicValueResolver; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactoryInterface; /** * Responsible for resolving the arguments passed to an action. * * @author Iltar van der Berg */ final class ArgumentResolver implements ArgumentResolverInterface { private $argumentMetadataFactory; private $argumentValueResolvers; /** * @param iterable $argumentValueResolvers */ public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, iterable $argumentValueResolvers = []) { $this->argumentMetadataFactory = $argumentMetadataFactory ?? new ArgumentMetadataFactory(); $this->argumentValueResolvers = $argumentValueResolvers ?: self::getDefaultArgumentValueResolvers(); } /** * {@inheritdoc} */ public function getArguments(Request $request, callable $controller): array { $arguments = []; foreach ($this->argumentMetadataFactory->createArgumentMetadata($controller) as $metadata) { foreach ($this->argumentValueResolvers as $resolver) { if (!$resolver->supports($request, $metadata)) { continue; } $resolved = $resolver->resolve($request, $metadata); $atLeastOne = false; foreach ($resolved as $append) { $atLeastOne = true; $arguments[] = $append; } if (!$atLeastOne) { throw new \InvalidArgumentException(sprintf('"%s::resolve()" must yield at least one value.', get_debug_type($resolver))); } // continue to the next controller argument continue 2; } $representative = $controller; if (\is_array($representative)) { $representative = sprintf('%s::%s()', \get_class($representative[0]), $representative[1]); } elseif (\is_object($representative)) { $representative = \get_class($representative); } throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or because there is a non optional argument after this one.', $representative, $metadata->getName())); } return $arguments; } /** * @return iterable */ public static function getDefaultArgumentValueResolvers(): iterable { return [ new RequestAttributeValueResolver(), new RequestValueResolver(), new SessionValueResolver(), new DefaultValueResolver(), new VariadicValueResolver(), ]; } } PK'\;:c!Controller/ControllerResolver.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; /** * This implementation uses the '_controller' request attribute to determine * the controller to execute. * * @author Fabien Potencier * @author Tobias Schultze */ class ControllerResolver implements ControllerResolverInterface { private $logger; public function __construct(LoggerInterface $logger = null) { $this->logger = $logger; } /** * {@inheritdoc} */ public function getController(Request $request) { if (!$controller = $request->attributes->get('_controller')) { if (null !== $this->logger) { $this->logger->warning('Unable to look for the controller as the "_controller" parameter is missing.'); } return false; } if (\is_array($controller)) { if (isset($controller[0]) && \is_string($controller[0]) && isset($controller[1])) { try { $controller[0] = $this->instantiateController($controller[0]); } catch (\Error|\LogicException $e) { try { // We cannot just check is_callable but have to use reflection because a non-static method // can still be called statically in PHP but we don't want that. This is deprecated in PHP 7, so we // could simplify this with PHP 8. if ((new \ReflectionMethod($controller[0], $controller[1]))->isStatic()) { return $controller; } } catch (\ReflectionException $reflectionException) { throw $e; } throw $e; } } if (!\is_callable($controller)) { throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$this->getControllerError($controller)); } return $controller; } if (\is_object($controller)) { if (!\is_callable($controller)) { throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$this->getControllerError($controller)); } return $controller; } if (\function_exists($controller)) { return $controller; } try { $callable = $this->createController($controller); } catch (\InvalidArgumentException $e) { throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$e->getMessage(), 0, $e); } if (!\is_callable($callable)) { throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$this->getControllerError($callable)); } return $callable; } /** * Returns a callable for the given controller. * * @return callable * * @throws \InvalidArgumentException When the controller cannot be created */ protected function createController(string $controller) { if (!str_contains($controller, '::')) { $controller = $this->instantiateController($controller); if (!\is_callable($controller)) { throw new \InvalidArgumentException($this->getControllerError($controller)); } return $controller; } [$class, $method] = explode('::', $controller, 2); try { $controller = [$this->instantiateController($class), $method]; } catch (\Error|\LogicException $e) { try { if ((new \ReflectionMethod($class, $method))->isStatic()) { return $class.'::'.$method; } } catch (\ReflectionException $reflectionException) { throw $e; } throw $e; } if (!\is_callable($controller)) { throw new \InvalidArgumentException($this->getControllerError($controller)); } return $controller; } /** * Returns an instantiated controller. * * @return object */ protected function instantiateController(string $class) { return new $class(); } private function getControllerError($callable): string { if (\is_string($callable)) { if (str_contains($callable, '::')) { $callable = explode('::', $callable, 2); } else { return sprintf('Function "%s" does not exist.', $callable); } } if (\is_object($callable)) { $availableMethods = $this->getClassMethodsWithoutMagicMethods($callable); $alternativeMsg = $availableMethods ? sprintf(' or use one of the available methods: "%s"', implode('", "', $availableMethods)) : ''; return sprintf('Controller class "%s" cannot be called without a method name. You need to implement "__invoke"%s.', get_debug_type($callable), $alternativeMsg); } if (!\is_array($callable)) { return sprintf('Invalid type for controller given, expected string, array or object, got "%s".', get_debug_type($callable)); } if (!isset($callable[0]) || !isset($callable[1]) || 2 !== \count($callable)) { return 'Invalid array callable, expected [controller, method].'; } [$controller, $method] = $callable; if (\is_string($controller) && !class_exists($controller)) { return sprintf('Class "%s" does not exist.', $controller); } $className = \is_object($controller) ? get_debug_type($controller) : $controller; if (method_exists($controller, $method)) { return sprintf('Method "%s" on class "%s" should be public and non-abstract.', $method, $className); } $collection = $this->getClassMethodsWithoutMagicMethods($controller); $alternatives = []; foreach ($collection as $item) { $lev = levenshtein($method, $item); if ($lev <= \strlen($method) / 3 || str_contains($item, $method)) { $alternatives[] = $item; } } asort($alternatives); $message = sprintf('Expected method "%s" on class "%s"', $method, $className); if (\count($alternatives) > 0) { $message .= sprintf(', did you mean "%s"?', implode('", "', $alternatives)); } else { $message .= sprintf('. Available methods: "%s".', implode('", "', $collection)); } return $message; } private function getClassMethodsWithoutMagicMethods($classOrObject): array { $methods = get_class_methods($classOrObject); return array_filter($methods, function (string $method) { return 0 !== strncmp($method, '__', 2); }); } } PK'\@9Վ*Controller/TraceableControllerResolver.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Stopwatch\Stopwatch; /** * @author Fabien Potencier */ class TraceableControllerResolver implements ControllerResolverInterface { private $resolver; private $stopwatch; public function __construct(ControllerResolverInterface $resolver, Stopwatch $stopwatch) { $this->resolver = $resolver; $this->stopwatch = $stopwatch; } /** * {@inheritdoc} */ public function getController(Request $request) { $e = $this->stopwatch->start('controller.get_callable'); $ret = $this->resolver->getController($request); $e->stop(); return $ret; } } PK'\]}Y Y *Controller/ContainerControllerResolver.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\Container; /** * A controller resolver searching for a controller in a psr-11 container when using the "service::method" notation. * * @author Fabien Potencier * @author Maxime Steinhausser */ class ContainerControllerResolver extends ControllerResolver { protected $container; public function __construct(ContainerInterface $container, LoggerInterface $logger = null) { $this->container = $container; parent::__construct($logger); } protected function createController(string $controller) { if (1 === substr_count($controller, ':')) { $controller = str_replace(':', '::', $controller); trigger_deprecation('symfony/http-kernel', '5.1', 'Referencing controllers with a single colon is deprecated. Use "%s" instead.', $controller); } return parent::createController($controller); } /** * {@inheritdoc} */ protected function instantiateController(string $class) { $class = ltrim($class, '\\'); if ($this->container->has($class)) { return $this->container->get($class); } try { return parent::instantiateController($class); } catch (\Error $e) { } $this->throwExceptionIfControllerWasRemoved($class, $e); if ($e instanceof \ArgumentCountError) { throw new \InvalidArgumentException(sprintf('Controller "%s" has required constructor arguments and does not exist in the container. Did you forget to define the controller as a service?', $class), 0, $e); } throw new \InvalidArgumentException(sprintf('Controller "%s" does neither exist as service nor as class.', $class), 0, $e); } private function throwExceptionIfControllerWasRemoved(string $controller, \Throwable $previous) { if ($this->container instanceof Container && isset($this->container->getRemovedIds()[$controller])) { throw new \InvalidArgumentException(sprintf('Controller "%s" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?', $controller), 0, $previous); } } } PK'\ "Controller/ControllerReference.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface; /** * Acts as a marker and a data holder for a Controller. * * Some methods in Symfony accept both a URI (as a string) or a controller as * an argument. In the latter case, instead of passing an array representing * the controller, you can use an instance of this class. * * @author Fabien Potencier * * @see FragmentRendererInterface */ class ControllerReference { public $controller; public $attributes = []; public $query = []; /** * @param string $controller The controller name * @param array $attributes An array of parameters to add to the Request attributes * @param array $query An array of parameters to add to the Request query string */ public function __construct(string $controller, array $attributes = [], array $query = []) { $this->controller = $controller; $this->attributes = $attributes; $this->query = $query; } } PK'\ (Controller/TraceableArgumentResolver.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Stopwatch\Stopwatch; /** * @author Fabien Potencier */ class TraceableArgumentResolver implements ArgumentResolverInterface { private $resolver; private $stopwatch; public function __construct(ArgumentResolverInterface $resolver, Stopwatch $stopwatch) { $this->resolver = $resolver; $this->stopwatch = $stopwatch; } /** * {@inheritdoc} */ public function getArguments(Request $request, callable $controller) { $e = $this->stopwatch->start('controller.get_arguments'); $ret = $this->resolver->getArguments($request, $controller); $e->stop(); return $ret; } } PK'\Nl++(Controller/ArgumentResolverInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\HttpFoundation\Request; /** * An ArgumentResolverInterface instance knows how to determine the * arguments for a specific action. * * @author Fabien Potencier */ interface ArgumentResolverInterface { /** * Returns the arguments to pass to the controller. * * @return array * * @throws \RuntimeException When no value could be provided for a required argument */ public function getArguments(Request $request, callable $controller); } PK'\9xLL*Controller/ControllerResolverInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\HttpFoundation\Request; /** * A ControllerResolverInterface implementation knows how to determine the * controller to execute based on a Request object. * * A Controller can be any valid PHP callable. * * @author Fabien Potencier */ interface ControllerResolverInterface { /** * Returns the Controller instance associated with a Request. * * As several resolvers can exist for a single application, a resolver must * return false when it is not able to determine the controller. * * The resolver must only throw an exception when it should be able to load a * controller but cannot because of some errors made by the developer. * * @return callable|false A PHP callable representing the Controller, * or false if this resolver is not able to determine the controller * * @throws \LogicException If a controller was found based on the request but it is not callable */ public function getController(Request $request); } PK'\'U-Controller/ArgumentValueResolverInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Responsible for resolving the value of an argument based on its metadata. * * @author Iltar van der Berg */ interface ArgumentValueResolverInterface { /** * Whether this resolver can resolve the value for the given ArgumentMetadata. * * @return bool */ public function supports(Request $request, ArgumentMetadata $argument); /** * Returns the possible value(s). * * @return iterable */ public function resolve(Request $request, ArgumentMetadata $argument); } PK'\OEf f UriSigner.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\HttpFoundation\Request; /** * Signs URIs. * * @author Fabien Potencier */ class UriSigner { private $secret; private $parameter; /** * @param string $secret A secret * @param string $parameter Query string parameter to use */ public function __construct(string $secret, string $parameter = '_hash') { $this->secret = $secret; $this->parameter = $parameter; } /** * Signs a URI. * * The given URI is signed by adding the query string parameter * which value depends on the URI and the secret. * * @return string */ public function sign(string $uri) { $url = parse_url($uri); if (isset($url['query'])) { parse_str($url['query'], $params); } else { $params = []; } $uri = $this->buildUrl($url, $params); $params[$this->parameter] = $this->computeHash($uri); return $this->buildUrl($url, $params); } /** * Checks that a URI contains the correct hash. * * @return bool */ public function check(string $uri) { $url = parse_url($uri); if (isset($url['query'])) { parse_str($url['query'], $params); } else { $params = []; } if (empty($params[$this->parameter])) { return false; } $hash = $params[$this->parameter]; unset($params[$this->parameter]); return hash_equals($this->computeHash($this->buildUrl($url, $params)), $hash); } public function checkRequest(Request $request): bool { $qs = ($qs = $request->server->get('QUERY_STRING')) ? '?'.$qs : ''; // we cannot use $request->getUri() here as we want to work with the original URI (no query string reordering) return $this->check($request->getSchemeAndHttpHost().$request->getBaseUrl().$request->getPathInfo().$qs); } private function computeHash(string $uri): string { return base64_encode(hash_hmac('sha256', $uri, $this->secret, true)); } private function buildUrl(array $url, array $params = []): string { ksort($params, \SORT_STRING); $url['query'] = http_build_query($params, '', '&'); $scheme = isset($url['scheme']) ? $url['scheme'].'://' : ''; $host = $url['host'] ?? ''; $port = isset($url['port']) ? ':'.$url['port'] : ''; $user = $url['user'] ?? ''; $pass = isset($url['pass']) ? ':'.$url['pass'] : ''; $pass = ($user || $pass) ? "$pass@" : ''; $path = $url['path'] ?? ''; $query = isset($url['query']) && $url['query'] ? '?'.$url['query'] : ''; $fragment = isset($url['fragment']) ? '#'.$url['fragment'] : ''; return $scheme.$user.$pass.$host.$port.$path.$query.$fragment; } } PK'\Q=7ControllerMetadata/ArgumentMetadataFactoryInterface.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\ControllerMetadata; /** * Builds method argument data. * * @author Iltar van der Berg */ interface ArgumentMetadataFactoryInterface { /** * @param string|object|array $controller The controller to resolve the arguments for * * @return ArgumentMetadata[] */ public function createArgumentMetadata($controller); } PK'\a:^ .ControllerMetadata/ArgumentMetadataFactory.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\ControllerMetadata; /** * Builds {@see ArgumentMetadata} objects based on the given Controller. * * @author Iltar van der Berg */ final class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface { /** * {@inheritdoc} */ public function createArgumentMetadata($controller): array { $arguments = []; if (\is_array($controller)) { $reflection = new \ReflectionMethod($controller[0], $controller[1]); $class = $reflection->class; } elseif (\is_object($controller) && !$controller instanceof \Closure) { $reflection = new \ReflectionMethod($controller, '__invoke'); $class = $reflection->class; } else { $reflection = new \ReflectionFunction($controller); if ($class = str_contains($reflection->name, '{closure}') ? null : (\PHP_VERSION_ID >= 80111 ? $reflection->getClosureCalledClass() : $reflection->getClosureScopeClass())) { $class = $class->name; } } foreach ($reflection->getParameters() as $param) { $attributes = []; if (\PHP_VERSION_ID >= 80000) { foreach ($param->getAttributes() as $reflectionAttribute) { if (class_exists($reflectionAttribute->getName())) { $attributes[] = $reflectionAttribute->newInstance(); } } } $arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $class), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull(), $attributes); } return $arguments; } /** * Returns an associated type to the given parameter if available. */ private function getType(\ReflectionParameter $parameter, ?string $class): ?string { if (!$type = $parameter->getType()) { return null; } $name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type; if (null !== $class) { switch (strtolower($name)) { case 'self': return $class; case 'parent': return get_parent_class($class) ?: null; } } return $name; } } PK'\&#'ControllerMetadata/ArgumentMetadata.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\ControllerMetadata; use Symfony\Component\HttpKernel\Attribute\ArgumentInterface; /** * Responsible for storing metadata of an argument. * * @author Iltar van der Berg */ class ArgumentMetadata { public const IS_INSTANCEOF = 2; private $name; private $type; private $isVariadic; private $hasDefaultValue; private $defaultValue; private $isNullable; private $attributes; /** * @param object[] $attributes */ public function __construct(string $name, ?string $type, bool $isVariadic, bool $hasDefaultValue, $defaultValue, bool $isNullable = false, $attributes = []) { $this->name = $name; $this->type = $type; $this->isVariadic = $isVariadic; $this->hasDefaultValue = $hasDefaultValue; $this->defaultValue = $defaultValue; $this->isNullable = $isNullable || null === $type || ($hasDefaultValue && null === $defaultValue); if (null === $attributes || $attributes instanceof ArgumentInterface) { trigger_deprecation('symfony/http-kernel', '5.3', 'The "%s" constructor expects an array of PHP attributes as last argument, %s given.', __CLASS__, get_debug_type($attributes)); $attributes = $attributes ? [$attributes] : []; } $this->attributes = $attributes; } /** * Returns the name as given in PHP, $foo would yield "foo". * * @return string */ public function getName() { return $this->name; } /** * Returns the type of the argument. * * The type is the PHP class in 5.5+ and additionally the basic type in PHP 7.0+. * * @return string|null */ public function getType() { return $this->type; } /** * Returns whether the argument is defined as "...$variadic". * * @return bool */ public function isVariadic() { return $this->isVariadic; } /** * Returns whether the argument has a default value. * * Implies whether an argument is optional. * * @return bool */ public function hasDefaultValue() { return $this->hasDefaultValue; } /** * Returns whether the argument accepts null values. * * @return bool */ public function isNullable() { return $this->isNullable; } /** * Returns the default value of the argument. * * @throws \LogicException if no default value is present; {@see self::hasDefaultValue()} * * @return mixed */ public function getDefaultValue() { if (!$this->hasDefaultValue) { throw new \LogicException(sprintf('Argument $%s does not have a default value. Use "%s::hasDefaultValue()" to avoid this exception.', $this->name, __CLASS__)); } return $this->defaultValue; } /** * Returns the attribute (if any) that was set on the argument. */ public function getAttribute(): ?ArgumentInterface { trigger_deprecation('symfony/http-kernel', '5.3', 'Method "%s()" is deprecated, use "getAttributes()" instead.', __METHOD__); if (!$this->attributes) { return null; } return $this->attributes[0] instanceof ArgumentInterface ? $this->attributes[0] : null; } /** * @return object[] */ public function getAttributes(string $name = null, int $flags = 0): array { if (!$name) { return $this->attributes; } $attributes = []; if ($flags & self::IS_INSTANCEOF) { foreach ($this->attributes as $attribute) { if ($attribute instanceof $name) { $attributes[] = $attribute; } } } else { foreach ($this->attributes as $attribute) { if (\get_class($attribute) === $name) { $attributes[] = $attribute; } } } return $attributes; } } PK'\,))LICENSEnu[Copyright (c) 2004-2023 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK'\xaˆ "Debug/TraceableEventDispatcher.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Debug; use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher as BaseTraceableEventDispatcher; use Symfony\Component\HttpKernel\KernelEvents; /** * Collects some data about event listeners. * * This event dispatcher delegates the dispatching to another one. * * @author Fabien Potencier */ class TraceableEventDispatcher extends BaseTraceableEventDispatcher { /** * {@inheritdoc} */ protected function beforeDispatch(string $eventName, object $event) { switch ($eventName) { case KernelEvents::REQUEST: $event->getRequest()->attributes->set('_stopwatch_token', substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6)); $this->stopwatch->openSection(); break; case KernelEvents::VIEW: case KernelEvents::RESPONSE: // stop only if a controller has been executed if ($this->stopwatch->isStarted('controller')) { $this->stopwatch->stop('controller'); } break; case KernelEvents::TERMINATE: $sectionId = $event->getRequest()->attributes->get('_stopwatch_token'); if (null === $sectionId) { break; } // There is a very special case when using built-in AppCache class as kernel wrapper, in the case // of an ESI request leading to a `stale` response [B] inside a `fresh` cached response [A]. // In this case, `$token` contains the [B] debug token, but the open `stopwatch` section ID // is equal to the [A] debug token. Trying to reopen section with the [B] token throws an exception // which must be caught. try { $this->stopwatch->openSection($sectionId); } catch (\LogicException $e) { } break; } } /** * {@inheritdoc} */ protected function afterDispatch(string $eventName, object $event) { switch ($eventName) { case KernelEvents::CONTROLLER_ARGUMENTS: $this->stopwatch->start('controller', 'section'); break; case KernelEvents::RESPONSE: $sectionId = $event->getRequest()->attributes->get('_stopwatch_token'); if (null === $sectionId) { break; } $this->stopwatch->stopSection($sectionId); break; case KernelEvents::TERMINATE: // In the special case described in the `preDispatch` method above, the `$token` section // does not exist, then closing it throws an exception which must be caught. $sectionId = $event->getRequest()->attributes->get('_stopwatch_token'); if (null === $sectionId) { break; } try { $this->stopwatch->stopSection($sectionId); } catch (\LogicException $e) { } break; } } } PK'\t[++Debug/FileLinkFormatter.phpnu[ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Debug; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; /** * Formats debug file links. * * @author Jérémy Romey * * @final */ class FileLinkFormatter { private const FORMATS = [ 'textmate' => 'txmt://open?url=file://%f&line=%l', 'macvim' => 'mvim://open?url=file://%f&line=%l', 'emacs' => 'emacs://open?url=file://%f&line=%l', 'sublime' => 'subl://open?url=file://%f&line=%l', 'phpstorm' => 'phpstorm://open?file=%f&line=%l', 'atom' => 'atom://core/open/file?filename=%f&line=%l', 'vscode' => 'vscode://file/%f:%l', ]; private $fileLinkFormat; private $requestStack; private $baseDir; private $urlFormat; /** * @param string|array|null $fileLinkFormat * @param string|\Closure $urlFormat the URL format, or a closure that returns it on-demand */ public function __construct($fileLinkFormat = null, RequestStack $requestStack = null, string $baseDir = null, $urlFormat = null) { if (!\is_array($fileLinkFormat) && $fileLinkFormat = (self::FORMATS[$fileLinkFormat] ?? $fileLinkFormat) ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format')) { $i = strpos($f = $fileLinkFormat, '&', max(strrpos($f, '%f'), strrpos($f, '%l'))) ?: \strlen($f); $fileLinkFormat = [substr($f, 0, $i)] + preg_split('/&([^>]++)>/', substr($f, $i), -1, \PREG_SPLIT_DELIM_CAPTURE); } $this->fileLinkFormat = $fileLinkFormat; $this->requestStack = $requestStack; $this->baseDir = $baseDir; $this->urlFormat = $urlFormat; } public function format(string $file, int $line) { if ($fmt = $this->getFileLinkFormat()) { for ($i = 1; isset($fmt[$i]); ++$i) { if (str_starts_with($file, $k = $fmt[$i++])) { $file = substr_replace($file, $fmt[$i], 0, \strlen($k)); break; } } return strtr($fmt[0], ['%f' => $file, '%l' => $line]); } return false; } /** * @internal */ public function __sleep(): array { $this->fileLinkFormat = $this->getFileLinkFormat(); return ['fileLinkFormat']; } /** * @internal */ public static function generateUrlFormat(UrlGeneratorInterface $router, string $routeName, string $queryString): ?string { try { return $router->generate($routeName).$queryString; } catch (\Throwable $e) { return null; } } private function getFileLinkFormat() { if ($this->fileLinkFormat) { return $this->fileLinkFormat; } if ($this->requestStack && $this->baseDir && $this->urlFormat) { $request = $this->requestStack->getMainRequest(); if ($request instanceof Request && (!$this->urlFormat instanceof \Closure || $this->urlFormat = ($this->urlFormat)())) { return [ $request->getSchemeAndHttpHost().$this->urlFormat, $this->baseDir.\DIRECTORY_SEPARATOR, '', ]; } } return null; } } PK'\  README.mdnu[PK'\7)=//KernelInterface.phpnu[PK'\Ģ..yKernelEvents.phpnu[PK'\>EZ!$CacheClearer/Psr6CacheClearer.phpnu[PK'\QSS"+CacheClearer/ChainCacheClearer.phpnu[PK'\#&/CacheClearer/CacheClearerInterface.phpnu[PK'\H !1Fragment/FragmentUriGenerator.phpnu[PK'\r%@Fragment/RoutableFragmentRenderer.phpnu[PK'\4@ .KFFragment/AbstractSurrogateFragmentRenderer.phpnu[PK'\i4TFragment/FragmentHandler.phpnu[PK'\6\&cFragment/FragmentRendererInterface.phpnu[PK'\h6#gFragment/InlineFragmentRenderer.phpnu[PK'\_Y  *{Fragment/FragmentUriGeneratorInterface.phpnu[PK'\@  %Fragment/HIncludeFragmentRenderer.phpnu[PK'\@933 Fragment/EsiFragmentRenderer.phpnu[PK'\33  Fragment/SsiFragmentRenderer.phpnu[PK'\\>HttpKernelInterface.phpnu[PK'\}(}(HttpKernel.phpnu[PK'\6i^Profiler/Profiler.phpnu[PK'\gU## lProfiler/FileProfilerStorage.phpnu[PK'\/!%Profiler/ProfilerStorageInterface.phpnu[PK'\+Profiler/Profile.phpnu[PK'\zss Kernel.phpnu[PK'\!ҊHttpKernelBrowser.phpnu[PK'\|RebootableInterface.phpnu[PK'\ZZELog/Logger.phpnu[PK'\PFLog/DebugLoggerInterface.phpnu[PK'\tJJnHttpClientKernel.phpnu[PK'\Bjj-EventListener/AbstractTestSessionListener.phpnu[PK'\BnEventListener/DumpListener.phpnu[PK'\56 6 EventListener/LocaleListener.phpnu[PK'\:WSuEventListener/ErrorListener.phpnu[PK'\ů/~~' EventListener/DebugHandlersListener.phpnu[PK'\3׶ }&EventListener/RouterListener.phpnu[PK'\)jj0AEventListener/DisallowRobotsIndexingListener.phpnu[PK'\+-+MFEventListener/AddRequestFormatsListener.phpnu[PK'\u000!sKEventListener/SessionListener.phpnu[PK'\<*REventListener/StreamedResponseListener.phpnu[PK'\wUw w %XEventListener/LocaleAwareListener.phpnu[PK'\W^ ^ "aEventListener/FragmentListener.phpnu[PK'\ E'44)mEventListener/AbstractSessionListener.phpnu[PK'\KxmF,,"EventListener/ProfilerListener.phpnu[PK'\u~n)rEventListener/ValidateRequestListener.phpnu[PK'\1;#EventListener/SurrogateListener.phpnu[PK'\UU"EventListener/ResponseListener.phpnu[PK'\Z%vEventListener/TestSessionListener.phpnu[PK'\,`uEvent/FinishRequestEvent.phpnu[PK'\Y&DependencyInjection/RegisterControllerArgumentLocatorsPass.phpnu[PK'\pt -eSDependencyInjection/ConfigurableExtension.phpnu[PK'\ Hj j ;XDependencyInjection/ControllerArgumentValueResolverPass.phpnu[PK'\ѡ(ʕ7cDependencyInjection/MergeExtensionConfigurationPass.phpnu[PK'\] ,hDependencyInjection/FragmentRendererPass.phpnu[PK'\thaa2rDependencyInjection/LazyLoadingFragmentHandler.phpnu[PK'\F|*AA7xDependencyInjection/RegisterLocaleAwareServicesPass.phpnu[PK'\uZ"5DependencyInjection/LoggerPass.phpnu[PK'\އ ADependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.phpnu[PK'\77!DependencyInjection/Extension.phpnu[PK'\ txKK(DependencyInjection/ServicesResetter.phpnu[PK'\nnCacheWarmer/CacheWarmer.phpnu[PK'\$dCacheWarmer/CacheWarmerInterface.phpnu[PK'\]dd!CacheWarmer/WarmableInterface.phpnu[PK'\cѧ$qCacheWarmer/CacheWarmerAggregate.phpnu[PK'\s.!!/lException/UnsupportedMediaTypeHttpException.phpnu[PK'\x׊OO/Exception/PreconditionRequiredHttpException.phpnu[PK'\Ӫ@*Exception/TooManyRequestsHttpException.phpnu[PK'\حD%Exception/BadRequestHttpException.phpnu[PK'\?z+_Exception/MethodNotAllowedHttpException.phpnu[PK'\ -:Exception/ServiceUnavailableHttpException.phpnu[PK'\SkException/HttpException.phpnu[PK'\(Z)).Exception/UnprocessableEntityHttpException.phpnu[PK'\gj\\&\Exception/InvalidMetadataException.phpnu[PK'\@q-Exception/PreconditionFailedHttpException.phpnu[PK'\Yq||'Exception/UnauthorizedHttpException.phpnu[PK'\S )]Exception/LengthRequiredHttpException.phpnu[PK'\<}#Exception/NotFoundHttpException.phpnu[PK'\|&NN'@Exception/AccessDeniedHttpException.phpnu[PK'\$Exception/HttpExceptionInterface.phpnu[PK'\F.(Exception/NotAcceptableHttpException.phpnu[PK'\'  6CException/ControllerDoesNotReturnResponseException.phpnu[PK'\O# Exception/ConflictHttpException.phpnu[PK'\V+Exception/GoneHttpException.phpnu[PK'\[_w-Exception/UnexpectedSessionUsageException.phpnu[PK'\UUConfig/FileLocator.phpnu[PK'\աdd#HttpCache/Esi.phpnu[PK'\L9&c&c'HttpCache/HttpCache.phpnu[PK'\)eUff5HttpCache/AbstractSurrogate.phpnu[PK'\^ppHttpCache/StoreInterface.phpnu[PK'\P,HttpCache/ResponseCacheStrategyInterface.phpnu[PK'\ó HttpCache/SurrogateInterface.phpnu[PK'\;▋###HttpCache/ResponseCacheStrategy.phpnu[PK'\|7|7HttpCache/Store.phpnu[PK'\㟶QQHttpCache/SubRequestHandler.phpnu[PK'\rGf f SHttpCache/Ssi.phpnu[PK'\3NC)Attribute/ArgumentInterface.phpnu[PK'\ a,Attribute/AsController.phpnu[PK'\dAcێn.TerminableInterface.phpnu[PK'\HC2Bundle/BundleInterface.phpnu[PK'\+e  8Bundle/Bundle.phpnu[PK'\yeBeB ICHANGELOG.mdnu[PK'\~~Resources/welcome.html.phpnu[PK'\7 @ Controller/ArgumentResolver/NotTaggedControllerValueResolver.phpnu[PK'\5)Zrr=Controller/ArgumentResolver/RequestAttributeValueResolver.phpnu[PK'\@OO4Controller/ArgumentResolver/RequestValueResolver.phpnu[PK'\/Ų 4c Controller/ArgumentResolver/ServiceValueResolver.phpnu[PK'\7ay6,Controller/ArgumentResolver/TraceableValueResolver.phpnu[PK'\2 6643Controller/ArgumentResolver/SessionValueResolver.phpnu[PK'\KZ5v9Controller/ArgumentResolver/VariadicValueResolver.phpnu[PK'\4w?Controller/ArgumentResolver/DefaultValueResolver.phpnu[PK'\P*DController/ErrorController.phpnu[PK'\2/7`LController/ArgumentResolver.phpnu[PK'\;:c![Controller/ControllerResolver.phpnu[PK'\@9Վ*xController/TraceableControllerResolver.phpnu[PK'\]}Y Y *@}Controller/ContainerControllerResolver.phpnu[PK'\ "Controller/ControllerReference.phpnu[PK'\ (_Controller/TraceableArgumentResolver.phpnu[PK'\Nl++(ƑController/ArgumentResolverInterface.phpnu[PK'\9xLL*IController/ControllerResolverInterface.phpnu[PK'\'U-Controller/ArgumentValueResolverInterface.phpnu[PK'\OEf f UriSigner.phpnu[PK'\Q=7ControllerMetadata/ArgumentMetadataFactoryInterface.phpnu[PK'\a:^ .ControllerMetadata/ArgumentMetadataFactory.phpnu[PK'\&#'nControllerMetadata/ArgumentMetadata.phpnu[PK'\,))LICENSEnu[PK'\xaˆ "Debug/TraceableEventDispatcher.phpnu[PK'\t[++Debug/FileLinkFormatter.phpnu[PK9^