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
|
|
|
|
*/
|
2011-07-22 17:33:22 +01:00
|
|
|
public function __construct($dsn)
|
|
|
|
{
|
|
|
|
if (0 !== strpos($dsn, 'file:')) {
|
|
|
|
throw new \InvalidArgumentException("FileStorage DSN must start with file:");
|
|
|
|
}
|
|
|
|
$this->folder = substr($dsn, 5);
|
|
|
|
|
|
|
|
if (!is_dir($this->folder)) {
|
|
|
|
mkdir($this->folder);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-23 22:17:26 +01:00
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2011-07-22 17:33:22 +01:00
|
|
|
public function find($ip, $url, $limit)
|
|
|
|
{
|
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();
|
|
|
|
|
2011-08-29 14:34:31 +01:00
|
|
|
while ($limit > 0) {
|
|
|
|
$line = $this->readLineFromFile($file);
|
|
|
|
|
|
|
|
if (false === $line) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($line === "") {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
list($csvToken, $csvIp, $csvUrl, $csvTime, $csvParent) = str_getcsv($line);
|
|
|
|
|
|
|
|
if ($ip && false === strpos($csvIp, $ip) || $url && false === strpos($csvUrl, $url)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-07-23 22:17:26 +01:00
|
|
|
$row = array(
|
|
|
|
'token' => $csvToken,
|
|
|
|
'ip' => $csvIp,
|
|
|
|
'url' => $csvUrl,
|
|
|
|
'time' => $csvTime,
|
|
|
|
'parent' => $csvParent
|
|
|
|
);
|
|
|
|
|
|
|
|
$result[] = $row;
|
|
|
|
$limit--;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose($file);
|
2011-08-29 12:51:37 +01:00
|
|
|
|
2011-07-23 22:17:26 +01:00
|
|
|
return $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-07-23 22:17:26 +01:00
|
|
|
$file = $this->getFilename($token);
|
|
|
|
|
|
|
|
if (!file_exists($file)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2011-10-09 21:45:55 +01:00
|
|
|
$profile = unserialize(file_get_contents($file));
|
|
|
|
|
|
|
|
$childrenFile = $this->getChildrenFilename($token);
|
|
|
|
if (file_exists($childrenFile)) {
|
|
|
|
$childrenTokens = explode(',', file_get_contents($childrenFile));
|
|
|
|
foreach ($childrenTokens as $childToken) {
|
|
|
|
$profile->addChild($this->read($childToken));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $profile;
|
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());
|
2011-08-29 14:34:31 +01:00
|
|
|
$exists = file_exists($file);
|
2011-07-23 22:35:13 +01:00
|
|
|
|
2011-07-24 10:52:27 +01:00
|
|
|
// Create directory
|
|
|
|
$dir = dirname($file);
|
|
|
|
if (!is_dir($dir)) {
|
|
|
|
mkdir($dir, 0777, true);
|
|
|
|
}
|
|
|
|
|
2011-07-23 22:17:26 +01:00
|
|
|
// Store profile
|
2011-07-23 22:35:13 +01:00
|
|
|
file_put_contents($file, serialize($profile));
|
2011-07-23 22:17:26 +01:00
|
|
|
|
|
|
|
// Add to index
|
|
|
|
$file = fopen($this->getIndexFilename(), 'a');
|
|
|
|
fputcsv($file, array(
|
|
|
|
$profile->getToken(),
|
|
|
|
$profile->getIp(),
|
|
|
|
$profile->getUrl(),
|
|
|
|
$profile->getTime(),
|
|
|
|
$profile->getParent() ? $profile->getParent()->getToken() : null
|
|
|
|
));
|
|
|
|
fclose($file);
|
2011-07-23 22:35:13 +01:00
|
|
|
|
2011-10-09 21:45:55 +01:00
|
|
|
if ($profile->getParent()) {
|
|
|
|
$childrenFile = $this->getChildrenFilename($profile->getParent()->getToken());
|
|
|
|
$toWrite = file_exists($childrenFile) ? ','.$profile->getToken() : $profile->getToken();
|
|
|
|
$fp = fopen($childrenFile, 'a');
|
|
|
|
fputs($fp, $toWrite);
|
|
|
|
fclose($fp);
|
|
|
|
}
|
|
|
|
|
2011-08-29 14:34:31 +01:00
|
|
|
return ! $exists;
|
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
|
|
|
*
|
|
|
|
* @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-10-09 21:45:55 +01:00
|
|
|
/**
|
|
|
|
* Gets filename to store children tokens.
|
|
|
|
*
|
|
|
|
* @return string The tokens filename
|
|
|
|
*/
|
|
|
|
protected function getChildrenFilename($token)
|
|
|
|
{
|
|
|
|
return $this->getFilename($token).'.children';
|
|
|
|
}
|
|
|
|
|
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-07-25 09:51:35 +01:00
|
|
|
return $this->folder.'/'.'index.csv';
|
2011-07-23 22:17:26 +01:00
|
|
|
}
|
2011-08-29 14:34:31 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Reads a line in the file, ending with the current position.
|
|
|
|
*
|
|
|
|
* 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 A string representating the line or FALSE if beginning of file is reached
|
|
|
|
*/
|
|
|
|
protected function readLineFromFile($file)
|
|
|
|
{
|
|
|
|
if (ftell($file) === 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fseek($file, -1, SEEK_CUR);
|
|
|
|
$str = '';
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
$char = fgetc($file);
|
|
|
|
|
|
|
|
if ($char === "\n") {
|
|
|
|
// Leave the file with cursor before the line return
|
|
|
|
fseek($file, -1, SEEK_CUR);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
$str = $char . $str;
|
|
|
|
|
|
|
|
if (ftell($file) === 1) {
|
|
|
|
// All file is read, so we move cursor to the position 0
|
|
|
|
fseek($file, -1, SEEK_CUR);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
fseek($file, -2, SEEK_CUR);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $str === "" ? $this->readLineFromFile($file) : $str;
|
|
|
|
}
|
2011-07-22 17:33:22 +01:00
|
|
|
}
|