| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 | <?php/* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * 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 <fabien@symfony.com> */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 int|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, ?int $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();    }}
 |