2011-07-22 17:33:22 +01:00
< ? php
2011-07-23 22:25:58 +01:00
/*
* 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 .
*/
2011-07-22 17:33:22 +01:00
namespace Symfony\Component\HttpKernel\Profiler ;
/**
2011-08-29 12:51:37 +01:00
* Storage for profiler using files .
2011-07-22 17:33:22 +01:00
*
* @ author Alexandre Salomé < alexandre . salome @ gmail . com >
*/
class FileProfilerStorage implements ProfilerStorageInterface
{
2011-07-24 10:32:23 +01:00
/**
2011-08-29 12:51:37 +01:00
* Folder where profiler data are stored .
2011-07-24 10:32:23 +01:00
*
* @ var string
*/
private $folder ;
2011-07-22 17:33:22 +01:00
2011-07-23 22:17:26 +01:00
/**
2011-08-29 12:51:37 +01:00
* Constructs the file storage using a " dsn-like " path .
2011-07-23 22:17:26 +01:00
*
2011-08-29 12:51:37 +01:00
* Example : " file:/path/to/the/storage/folder "
2011-07-23 22:17:26 +01:00
*
* @ param string $dsn The DSN
2012-12-16 12:02:54 +00:00
*
* @ throws \RuntimeException
2011-07-23 22:17:26 +01:00
*/
2011-07-22 17:33:22 +01:00
public function __construct ( $dsn )
{
if ( 0 !== strpos ( $dsn , 'file:' )) {
2012-10-13 06:49:28 +01:00
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 ));
2011-07-22 17:33:22 +01:00
}
$this -> folder = substr ( $dsn , 5 );
if ( ! is_dir ( $this -> folder )) {
2013-02-07 11:58:33 +00:00
mkdir ( $this -> folder , 0777 , true );
2011-07-22 17:33:22 +01:00
}
}
2011-07-23 22:17:26 +01:00
/**
* { @ inheritdoc }
*/
2012-11-25 17:16:08 +00:00
public function find ( $ip , $url , $limit , $method , $start = null , $end = null )
2011-07-22 17:33:22 +01:00
{
2011-07-23 22:17:26 +01:00
$file = $this -> getIndexFilename ();
if ( ! file_exists ( $file )) {
return array ();
}
2011-08-29 14:34:31 +01:00
$file = fopen ( $file , 'r' );
fseek ( $file , 0 , SEEK_END );
2011-07-23 22:17:26 +01:00
$result = array ();
2013-04-30 12:43:48 +01:00
while ( count ( $result ) < $limit && $line = $this -> readLineFromFile ( $file )) {
2011-09-24 10:20:46 +01:00
list ( $csvToken , $csvIp , $csvMethod , $csvUrl , $csvTime , $csvParent ) = str_getcsv ( $line );
2011-08-29 14:34:31 +01:00
2012-12-20 07:41:17 +00:00
$csvTime = ( int ) $csvTime ;
2012-11-25 17:16:08 +00:00
2012-12-15 21:37:18 +00:00
if ( $ip && false === strpos ( $csvIp , $ip ) || $url && false === strpos ( $csvUrl , $url ) || $method && false === strpos ( $csvMethod , $method )) {
continue ;
}
if ( ! empty ( $start ) && $csvTime < $start ) {
continue ;
}
if ( ! empty ( $end ) && $csvTime > $end ) {
2011-08-29 14:34:31 +01:00
continue ;
}
2012-01-02 11:05:45 +00:00
$result [ $csvToken ] = array (
2011-07-23 22:17:26 +01:00
'token' => $csvToken ,
'ip' => $csvIp ,
2011-09-24 10:20:46 +01:00
'method' => $csvMethod ,
2011-07-23 22:17:26 +01:00
'url' => $csvUrl ,
'time' => $csvTime ,
2011-10-15 00:48:44 +01:00
'parent' => $csvParent ,
2011-07-23 22:17:26 +01:00
);
}
fclose ( $file );
2011-08-29 12:51:37 +01:00
2012-01-02 11:05:45 +00:00
return array_values ( $result );
2011-07-22 17:33:22 +01:00
}
2011-07-23 22:17:26 +01:00
/**
* { @ inheritdoc }
*/
2011-07-22 17:33:22 +01:00
public function purge ()
{
$flags = \FilesystemIterator :: SKIP_DOTS ;
$iterator = new \RecursiveDirectoryIterator ( $this -> folder , $flags );
2011-08-29 12:57:30 +01:00
$iterator = new \RecursiveIteratorIterator ( $iterator , \RecursiveIteratorIterator :: CHILD_FIRST );
2011-07-22 17:33:22 +01:00
2011-07-24 10:58:14 +01:00
foreach ( $iterator as $file ) {
2011-07-24 10:52:27 +01:00
if ( is_file ( $file )) {
unlink ( $file );
2011-08-29 12:57:30 +01:00
} else {
rmdir ( $file );
2011-07-24 10:52:27 +01:00
}
2011-07-22 17:33:22 +01:00
}
}
2011-07-23 22:17:26 +01:00
/**
* { @ inheritdoc }
*/
2011-07-22 17:33:22 +01:00
public function read ( $token )
{
2011-10-15 00:48:44 +01:00
if ( ! $token || ! file_exists ( $file = $this -> getFilename ( $token ))) {
2014-04-16 08:15:58 +01:00
return ;
2011-07-23 22:17:26 +01:00
}
2011-10-15 00:52:05 +01:00
return $this -> createProfileFromData ( $token , unserialize ( file_get_contents ( $file )));
2011-07-22 17:33:22 +01:00
}
2011-07-23 22:17:26 +01:00
/**
* { @ inheritdoc }
*/
2011-07-22 17:33:22 +01:00
public function write ( Profile $profile )
{
2011-07-23 22:35:13 +01:00
$file = $this -> getFilename ( $profile -> getToken ());
2012-07-06 23:32:19 +01:00
$profileIndexed = is_file ( $file );
if ( ! $profileIndexed ) {
// Create directory
$dir = dirname ( $file );
if ( ! is_dir ( $dir )) {
mkdir ( $dir , 0777 , true );
}
2011-07-24 10:52:27 +01:00
}
2011-07-23 22:17:26 +01:00
// Store profile
2011-10-15 00:52:05 +01:00
$data = array (
'token' => $profile -> getToken (),
2011-12-23 08:39:25 +00:00
'parent' => $profile -> getParentToken (),
2011-10-15 00:52:05 +01:00
'children' => array_map ( function ( $p ) { return $p -> getToken (); }, $profile -> getChildren ()),
'data' => $profile -> getCollectors (),
'ip' => $profile -> getIp (),
2011-09-24 10:20:46 +01:00
'method' => $profile -> getMethod (),
2011-10-15 00:52:05 +01:00
'url' => $profile -> getUrl (),
'time' => $profile -> getTime (),
);
2011-11-07 21:31:47 +00:00
if ( false === file_put_contents ( $file , serialize ( $data ))) {
return false ;
}
2011-07-23 22:17:26 +01:00
2012-07-06 23:32:19 +01:00
if ( ! $profileIndexed ) {
// Add to index
if ( false === $file = fopen ( $this -> getIndexFilename (), 'a' )) {
return false ;
}
2011-11-07 21:01:48 +00:00
2012-07-06 23:32:19 +01:00
fputcsv ( $file , array (
$profile -> getToken (),
$profile -> getIp (),
$profile -> getMethod (),
$profile -> getUrl (),
$profile -> getTime (),
$profile -> getParentToken (),
));
fclose ( $file );
}
2011-07-23 22:35:13 +01:00
2011-11-07 21:01:48 +00:00
return true ;
2011-07-22 17:33:22 +01:00
}
2011-07-23 22:17:26 +01:00
/**
2011-08-29 12:51:37 +01:00
* Gets filename to store data , associated to the token .
2011-07-23 22:17:26 +01:00
*
2012-12-16 12:02:54 +00:00
* @ param string $token
*
2011-07-23 22:17:26 +01:00
* @ return string The profile filename
*/
2011-07-22 17:33:22 +01:00
protected function getFilename ( $token )
{
2011-08-29 12:51:37 +01:00
// Uses 4 last characters, because first are mostly the same.
2011-07-24 10:52:27 +01:00
$folderA = substr ( $token , - 2 , 2 );
$folderB = substr ( $token , - 4 , 2 );
2011-07-25 09:51:35 +01:00
return $this -> folder . '/' . $folderA . '/' . $folderB . '/' . $token ;
2011-07-22 17:33:22 +01:00
}
2011-07-23 22:17:26 +01:00
/**
2011-08-29 12:51:37 +01:00
* Gets the index filename .
2011-07-23 22:17:26 +01:00
*
* @ return string The index filename
*/
protected function getIndexFilename ()
{
2011-10-15 00:48:44 +01:00
return $this -> folder . '/index.csv' ;
2011-07-23 22:17:26 +01:00
}
2011-08-29 14:34:31 +01:00
/**
2012-12-18 13:15:42 +00:00
* Reads a line in the file , backward .
2011-08-29 14:34:31 +01:00
*
* 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
*
2012-12-18 13:15:42 +00:00
* @ return mixed A string representing the line or null if beginning of file is reached
2011-08-29 14:34:31 +01:00
*/
protected function readLineFromFile ( $file )
{
2012-12-18 13:15:42 +00:00
$line = '' ;
$position = ftell ( $file );
2011-08-29 14:34:31 +01:00
2012-12-18 13:15:42 +00:00
if ( 0 === $position ) {
2014-04-16 08:15:58 +01:00
return ;
2012-12-18 13:15:42 +00:00
}
2011-08-29 14:34:31 +01:00
2013-03-01 10:42:10 +00:00
while ( true ) {
2012-12-18 13:15:42 +00:00
$chunkSize = min ( $position , 1024 );
$position -= $chunkSize ;
fseek ( $file , $position );
2011-08-29 14:34:31 +01:00
2012-12-18 13:15:42 +00:00
if ( 0 === $chunkSize ) {
// bof reached
2011-08-29 14:34:31 +01:00
break ;
}
2012-12-18 13:15:42 +00:00
$buffer = fread ( $file , $chunkSize );
2011-08-29 14:34:31 +01:00
2012-12-18 13:15:42 +00:00
if ( false === ( $upTo = strrpos ( $buffer , " \n " ))) {
2013-04-02 10:39:57 +01:00
$line = $buffer . $line ;
2012-12-18 13:15:42 +00:00
continue ;
2011-08-29 14:34:31 +01:00
}
2012-12-18 13:15:42 +00:00
$position += $upTo ;
2013-04-02 10:39:57 +01:00
$line = substr ( $buffer , $upTo + 1 ) . $line ;
2012-12-18 13:15:42 +00:00
fseek ( $file , max ( 0 , $position ), SEEK_SET );
if ( '' !== $line ) {
break ;
}
2011-08-29 14:34:31 +01:00
}
2012-12-18 13:15:42 +00:00
return '' === $line ? null : $line ;
2011-08-29 14:34:31 +01:00
}
2011-10-15 00:52:05 +01:00
protected function createProfileFromData ( $token , $data , $parent = null )
{
$profile = new Profile ( $token );
$profile -> setIp ( $data [ 'ip' ]);
2011-09-24 10:20:46 +01:00
$profile -> setMethod ( $data [ 'method' ]);
2011-10-15 00:52:05 +01:00
$profile -> setUrl ( $data [ 'url' ]);
$profile -> setTime ( $data [ 'time' ]);
$profile -> setCollectors ( $data [ 'data' ]);
if ( ! $parent && $data [ 'parent' ]) {
$parent = $this -> read ( $data [ 'parent' ]);
}
if ( $parent ) {
$profile -> setParent ( $parent );
}
foreach ( $data [ 'children' ] as $token ) {
if ( ! $token || ! file_exists ( $file = $this -> getFilename ( $token ))) {
continue ;
}
$profile -> addChild ( $this -> createProfileFromData ( $token , unserialize ( file_get_contents ( $file )), $profile ));
}
return $profile ;
}
2011-07-22 17:33:22 +01:00
}