2015-08-18 00:00:26 +00:00
< ? 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 ;
2018-11-23 12:29:20 +00:00
use Psr\Log\LoggerInterface ;
2017-02-03 00:28:38 +00:00
use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException ;
2015-08-18 00:00:26 +00:00
use Symfony\Component\HttpFoundation\Request ;
use Symfony\Component\HttpFoundation\Response ;
use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface ;
use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface ;
/**
* Profiler .
*
* @ author Fabien Potencier < fabien @ symfony . com >
*/
class Profiler
{
private $storage ;
/**
* @ var DataCollectorInterface []
*/
private $collectors = array ();
private $logger ;
2018-11-23 12:29:20 +00:00
private $initiallyEnabled = true ;
2015-08-18 00:00:26 +00:00
private $enabled = true ;
/**
2018-11-23 12:29:20 +00:00
* @ param bool $enable The initial enabled state
2015-08-18 00:00:26 +00:00
*/
2018-11-23 12:29:20 +00:00
public function __construct ( ProfilerStorageInterface $storage , LoggerInterface $logger = null , $enable = true )
2015-08-18 00:00:26 +00:00
{
$this -> storage = $storage ;
$this -> logger = $logger ;
2018-11-23 12:29:20 +00:00
$this -> initiallyEnabled = $this -> enabled = ( bool ) $enable ;
2015-08-18 00:00:26 +00:00
}
/**
* 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 .
*
2017-02-03 00:28:38 +00:00
* @ return Profile | false A Profile instance
2015-08-18 00:00:26 +00:00
*/
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 .
*
* @ 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 ) {
2018-11-23 12:29:20 +00:00
$this -> logger -> warning ( 'Unable to store the profiler information.' , array ( 'configured_storage' => \get_class ( $this -> storage )));
2015-08-18 00:00:26 +00:00
}
return $ret ;
}
/**
* Purges all data from the storage .
*/
public function purge ()
{
$this -> storage -> purge ();
}
/**
* Finds profiler tokens for the given criteria .
*
2018-11-23 12:29:20 +00:00
* @ 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
* @ param string $statusCode The request status code
2015-08-18 00:00:26 +00:00
*
* @ return array An array of tokens
*
* @ see http :// php . net / manual / en / datetime . formats . php for the supported date / time formats
*/
2018-11-23 12:29:20 +00:00
public function find ( $ip , $url , $limit , $method , $start , $end , $statusCode = null )
2015-08-18 00:00:26 +00:00
{
2018-11-23 12:29:20 +00:00
return $this -> storage -> find ( $ip , $url , $limit , $method , $this -> getTimestamp ( $start ), $this -> getTimestamp ( $end ), $statusCode );
2015-08-18 00:00:26 +00:00
}
/**
* Collects data for the given Response .
*
* @ 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 ());
2017-02-03 00:28:38 +00:00
try {
$profile -> setIp ( $request -> getClientIp ());
} catch ( ConflictingHeadersException $e ) {
$profile -> setIp ( 'Unknown' );
}
2015-08-18 00:00:26 +00:00
$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 ;
}
2018-11-23 12:29:20 +00:00
public function reset ()
{
foreach ( $this -> collectors as $collector ) {
if ( ! method_exists ( $collector , 'reset' )) {
continue ;
}
$collector -> reset ();
}
$this -> enabled = $this -> initiallyEnabled ;
}
2015-08-18 00:00:26 +00:00
/**
* 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 .
*/
public function add ( DataCollectorInterface $collector )
{
2018-11-23 12:29:20 +00:00
if ( ! method_exists ( $collector , 'reset' )) {
@ trigger_error ( sprintf ( 'Implementing "%s" without the "reset()" method is deprecated since Symfony 3.4 and will be unsupported in 4.0 for class "%s".' , DataCollectorInterface :: class , \get_class ( $collector )), E_USER_DEPRECATED );
}
2015-08-18 00:00:26 +00:00
$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 ();
}
}