This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
symfony/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php

265 lines
6.8 KiB
PHP
Raw Normal View History

2011-07-22 17:33:22 +01: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.
*/
2011-07-22 17:33:22 +01:00
namespace Symfony\Component\HttpKernel\Profiler;
/**
* Storage for profiler using files.
2011-07-22 17:33:22 +01:00
*
* @author Alexandre Salomé <alexandre.salome@gmail.com>
*/
class FileProfilerStorage implements ProfilerStorageInterface
{
/**
* Folder where profiler data are stored.
*
* @var string
*/
private $folder;
2011-07-22 17:33:22 +01:00
/**
* Constructs the file storage using a "dsn-like" path.
*
* Example : "file:/path/to/the/storage/folder"
*
* @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);
}
}
/**
* {@inheritdoc}
*/
2011-09-24 10:20:46 +01:00
public function find($ip, $url, $limit, $method)
2011-07-22 17:33:22 +01:00
{
$file = $this->getIndexFilename();
if (!file_exists($file)) {
return array();
}
$file = fopen($file, 'r');
fseek($file, 0, SEEK_END);
$result = array();
while ($limit > 0) {
$line = $this->readLineFromFile($file);
if (false === $line) {
break;
}
2011-09-24 10:20:46 +01:00
if ($line === '') {
continue;
}
2011-09-24 10:20:46 +01:00
list($csvToken, $csvIp, $csvMethod, $csvUrl, $csvTime, $csvParent) = str_getcsv($line);
2011-09-24 10:20:46 +01:00
if ($ip && false === strpos($csvIp, $ip) || $url && false === strpos($csvUrl, $url) || $method && false === strpos($csvMethod, $method)) {
continue;
}
$result[$csvToken] = array(
'token' => $csvToken,
'ip' => $csvIp,
2011-09-24 10:20:46 +01:00
'method' => $csvMethod,
'url' => $csvUrl,
'time' => $csvTime,
'parent' => $csvParent,
);
2011-09-24 10:20:46 +01:00
--$limit;
}
fclose($file);
return array_values($result);
2011-07-22 17:33:22 +01:00
}
/**
* {@inheritdoc}
*/
2011-07-22 17:33:22 +01:00
public function purge()
{
$flags = \FilesystemIterator::SKIP_DOTS;
$iterator = new \RecursiveDirectoryIterator($this->folder, $flags);
$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) {
if (is_file($file)) {
unlink($file);
} else {
rmdir($file);
}
2011-07-22 17:33:22 +01:00
}
}
/**
* {@inheritdoc}
*/
2011-07-22 17:33:22 +01:00
public function read($token)
{
if (!$token || !file_exists($file = $this->getFilename($token))) {
return null;
}
return $this->createProfileFromData($token, unserialize(file_get_contents($file)));
2011-07-22 17:33:22 +01:00
}
/**
* {@inheritdoc}
*/
2011-07-22 17:33:22 +01:00
public function write(Profile $profile)
{
$file = $this->getFilename($profile->getToken());
// Create directory
$dir = dirname($file);
if (!is_dir($dir)) {
mkdir($dir, 0777, true);
}
// Store profile
$data = array(
'token' => $profile->getToken(),
'parent' => $profile->getParentToken(),
'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(),
'url' => $profile->getUrl(),
'time' => $profile->getTime(),
);
2011-11-07 21:31:47 +00:00
if (false === file_put_contents($file, serialize($data))) {
return false;
}
// Add to index
2011-11-07 21:31:47 +00:00
if (false === $file = fopen($this->getIndexFilename(), 'a')) {
return false;
}
fputcsv($file, array(
$profile->getToken(),
$profile->getIp(),
2011-09-24 10:20:46 +01:00
$profile->getMethod(),
$profile->getUrl(),
$profile->getTime(),
$profile->getParentToken(),
));
fclose($file);
return true;
2011-07-22 17:33:22 +01:00
}
/**
* Gets filename to store data, associated to the token.
*
* @return string The profile filename
*/
2011-07-22 17:33:22 +01:00
protected function getFilename($token)
{
// Uses 4 last characters, because first are mostly the same.
$folderA = substr($token, -2, 2);
$folderB = substr($token, -4, 2);
return $this->folder.'/'.$folderA.'/'.$folderB.'/'.$token;
2011-07-22 17:33:22 +01:00
}
/**
* Gets the index filename.
*
* @return string The index filename
*/
protected function getIndexFilename()
{
return $this->folder.'/index.csv';
}
/**
* 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;
}
2011-09-24 10:20:46 +01:00
$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;
}
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']);
$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
}