270 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			270 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?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 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 Psr\Log\LoggerInterface;
 | |
| 
 | |
| /**
 | |
|  * Profiler.
 | |
|  *
 | |
|  * @author Fabien Potencier <fabien@symfony.com>
 | |
|  */
 | |
| class Profiler
 | |
| {
 | |
|     /**
 | |
|      * @var ProfilerStorageInterface
 | |
|      */
 | |
|     private $storage;
 | |
| 
 | |
|     /**
 | |
|      * @var DataCollectorInterface[]
 | |
|      */
 | |
|     private $collectors = array();
 | |
| 
 | |
|     /**
 | |
|      * @var LoggerInterface
 | |
|      */
 | |
|     private $logger;
 | |
| 
 | |
|     /**
 | |
|      * @var bool
 | |
|      */
 | |
|     private $enabled = true;
 | |
| 
 | |
|     /**
 | |
|      * Constructor.
 | |
|      *
 | |
|      * @param ProfilerStorageInterface $storage A ProfilerStorageInterface instance
 | |
|      * @param LoggerInterface          $logger  A LoggerInterface instance
 | |
|      */
 | |
|     public function __construct(ProfilerStorageInterface $storage, LoggerInterface $logger = null)
 | |
|     {
 | |
|         $this->storage = $storage;
 | |
|         $this->logger = $logger;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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.
 | |
|      *
 | |
|      * @param Response $response A Response instance
 | |
|      *
 | |
|      * @return Profile A Profile instance
 | |
|      */
 | |
|     public function loadProfileFromResponse(Response $response)
 | |
|     {
 | |
|         if (!$token = $response->headers->get('X-Debug-Token')) {
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         return $this->loadProfile($token);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Loads the Profile for the given token.
 | |
|      *
 | |
|      * @param string $token A token
 | |
|      *
 | |
|      * @return Profile A Profile instance
 | |
|      */
 | |
|     public function loadProfile($token)
 | |
|     {
 | |
|         return $this->storage->read($token);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Saves a Profile.
 | |
|      *
 | |
|      * @param Profile $profile A Profile instance
 | |
|      *
 | |
|      * @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.', array('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 $ip     The IP
 | |
|      * @param string $url    The URL
 | |
|      * @param string $limit  The maximum number of tokens to return
 | |
|      * @param string $method The request method
 | |
|      * @param string $start  The start date to search from
 | |
|      * @param string $end    The end date to search to
 | |
|      *
 | |
|      * @return array An array of tokens
 | |
|      *
 | |
|      * @see http://php.net/manual/en/datetime.formats.php for the supported date/time formats
 | |
|      */
 | |
|     public function find($ip, $url, $limit, $method, $start, $end)
 | |
|     {
 | |
|         return $this->storage->find($ip, $url, $limit, $method, $this->getTimestamp($start), $this->getTimestamp($end));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Collects data for the given Response.
 | |
|      *
 | |
|      * @param Request    $request   A Request instance
 | |
|      * @param Response   $response  A Response instance
 | |
|      * @param \Exception $exception An exception instance if the request threw one
 | |
|      *
 | |
|      * @return Profile|null A Profile instance or null if the profiler is disabled
 | |
|      */
 | |
|     public function collect(Request $request, Response $response, \Exception $exception = null)
 | |
|     {
 | |
|         if (false === $this->enabled) {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         $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');
 | |
|         }
 | |
| 
 | |
|         $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;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Gets the Collectors associated with this profiler.
 | |
|      *
 | |
|      * @return array An array of collectors
 | |
|      */
 | |
|     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 = array())
 | |
|     {
 | |
|         $this->collectors = array();
 | |
|         foreach ($collectors as $collector) {
 | |
|             $this->add($collector);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Adds a Collector.
 | |
|      *
 | |
|      * @param DataCollectorInterface $collector A DataCollectorInterface instance
 | |
|      */
 | |
|     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($name)
 | |
|     {
 | |
|         return isset($this->collectors[$name]);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Gets a Collector by name.
 | |
|      *
 | |
|      * @param string $name A collector name
 | |
|      *
 | |
|      * @return DataCollectorInterface A DataCollectorInterface instance
 | |
|      *
 | |
|      * @throws \InvalidArgumentException if the collector does not exist
 | |
|      */
 | |
|     public function get($name)
 | |
|     {
 | |
|         if (!isset($this->collectors[$name])) {
 | |
|             throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name));
 | |
|         }
 | |
| 
 | |
|         return $this->collectors[$name];
 | |
|     }
 | |
| 
 | |
|     private function getTimestamp($value)
 | |
|     {
 | |
|         if (null === $value || '' == $value) {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         try {
 | |
|             $value = new \DateTime(is_numeric($value) ? '@'.$value : $value);
 | |
|         } catch (\Exception $e) {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         return $value->getTimestamp();
 | |
|     }
 | |
| }
 | 
