Mercurial > hg > isophonics-drupal-site
comparison vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 1fec387a4317 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 /* | |
4 * This file is part of the Symfony package. | |
5 * | |
6 * (c) Fabien Potencier <fabien@symfony.com> | |
7 * | |
8 * For the full copyright and license information, please view the LICENSE | |
9 * file that was distributed with this source code. | |
10 */ | |
11 | |
12 namespace Symfony\Component\HttpKernel\Profiler; | |
13 | |
14 /** | |
15 * Storage for profiler using files. | |
16 * | |
17 * @author Alexandre Salomé <alexandre.salome@gmail.com> | |
18 */ | |
19 class FileProfilerStorage implements ProfilerStorageInterface | |
20 { | |
21 /** | |
22 * Folder where profiler data are stored. | |
23 * | |
24 * @var string | |
25 */ | |
26 private $folder; | |
27 | |
28 /** | |
29 * Constructs the file storage using a "dsn-like" path. | |
30 * | |
31 * Example : "file:/path/to/the/storage/folder" | |
32 * | |
33 * @param string $dsn The DSN | |
34 * | |
35 * @throws \RuntimeException | |
36 */ | |
37 public function __construct($dsn) | |
38 { | |
39 if (0 !== strpos($dsn, 'file:')) { | |
40 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)); | |
41 } | |
42 $this->folder = substr($dsn, 5); | |
43 | |
44 if (!is_dir($this->folder) && false === @mkdir($this->folder, 0777, true) && !is_dir($this->folder)) { | |
45 throw new \RuntimeException(sprintf('Unable to create the storage directory (%s).', $this->folder)); | |
46 } | |
47 } | |
48 | |
49 /** | |
50 * {@inheritdoc} | |
51 */ | |
52 public function find($ip, $url, $limit, $method, $start = null, $end = null, $statusCode = null) | |
53 { | |
54 $file = $this->getIndexFilename(); | |
55 | |
56 if (!file_exists($file)) { | |
57 return array(); | |
58 } | |
59 | |
60 $file = fopen($file, 'r'); | |
61 fseek($file, 0, SEEK_END); | |
62 | |
63 $result = array(); | |
64 while (count($result) < $limit && $line = $this->readLineFromFile($file)) { | |
65 $values = str_getcsv($line); | |
66 list($csvToken, $csvIp, $csvMethod, $csvUrl, $csvTime, $csvParent, $csvStatusCode) = $values; | |
67 $csvTime = (int) $csvTime; | |
68 | |
69 if ($ip && false === strpos($csvIp, $ip) || $url && false === strpos($csvUrl, $url) || $method && false === strpos($csvMethod, $method) || $statusCode && false === strpos($csvStatusCode, $statusCode)) { | |
70 continue; | |
71 } | |
72 | |
73 if (!empty($start) && $csvTime < $start) { | |
74 continue; | |
75 } | |
76 | |
77 if (!empty($end) && $csvTime > $end) { | |
78 continue; | |
79 } | |
80 | |
81 $result[$csvToken] = array( | |
82 'token' => $csvToken, | |
83 'ip' => $csvIp, | |
84 'method' => $csvMethod, | |
85 'url' => $csvUrl, | |
86 'time' => $csvTime, | |
87 'parent' => $csvParent, | |
88 'status_code' => $csvStatusCode, | |
89 ); | |
90 } | |
91 | |
92 fclose($file); | |
93 | |
94 return array_values($result); | |
95 } | |
96 | |
97 /** | |
98 * {@inheritdoc} | |
99 */ | |
100 public function purge() | |
101 { | |
102 $flags = \FilesystemIterator::SKIP_DOTS; | |
103 $iterator = new \RecursiveDirectoryIterator($this->folder, $flags); | |
104 $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST); | |
105 | |
106 foreach ($iterator as $file) { | |
107 if (is_file($file)) { | |
108 unlink($file); | |
109 } else { | |
110 rmdir($file); | |
111 } | |
112 } | |
113 } | |
114 | |
115 /** | |
116 * {@inheritdoc} | |
117 */ | |
118 public function read($token) | |
119 { | |
120 if (!$token || !file_exists($file = $this->getFilename($token))) { | |
121 return; | |
122 } | |
123 | |
124 return $this->createProfileFromData($token, unserialize(file_get_contents($file))); | |
125 } | |
126 | |
127 /** | |
128 * {@inheritdoc} | |
129 * | |
130 * @throws \RuntimeException | |
131 */ | |
132 public function write(Profile $profile) | |
133 { | |
134 $file = $this->getFilename($profile->getToken()); | |
135 | |
136 $profileIndexed = is_file($file); | |
137 if (!$profileIndexed) { | |
138 // Create directory | |
139 $dir = dirname($file); | |
140 if (!is_dir($dir) && false === @mkdir($dir, 0777, true) && !is_dir($dir)) { | |
141 throw new \RuntimeException(sprintf('Unable to create the storage directory (%s).', $dir)); | |
142 } | |
143 } | |
144 | |
145 // Store profile | |
146 $data = array( | |
147 'token' => $profile->getToken(), | |
148 'parent' => $profile->getParentToken(), | |
149 'children' => array_map(function ($p) { return $p->getToken(); }, $profile->getChildren()), | |
150 'data' => $profile->getCollectors(), | |
151 'ip' => $profile->getIp(), | |
152 'method' => $profile->getMethod(), | |
153 'url' => $profile->getUrl(), | |
154 'time' => $profile->getTime(), | |
155 'status_code' => $profile->getStatusCode(), | |
156 ); | |
157 | |
158 if (false === file_put_contents($file, serialize($data))) { | |
159 return false; | |
160 } | |
161 | |
162 if (!$profileIndexed) { | |
163 // Add to index | |
164 if (false === $file = fopen($this->getIndexFilename(), 'a')) { | |
165 return false; | |
166 } | |
167 | |
168 fputcsv($file, array( | |
169 $profile->getToken(), | |
170 $profile->getIp(), | |
171 $profile->getMethod(), | |
172 $profile->getUrl(), | |
173 $profile->getTime(), | |
174 $profile->getParentToken(), | |
175 $profile->getStatusCode(), | |
176 )); | |
177 fclose($file); | |
178 } | |
179 | |
180 return true; | |
181 } | |
182 | |
183 /** | |
184 * Gets filename to store data, associated to the token. | |
185 * | |
186 * @param string $token | |
187 * | |
188 * @return string The profile filename | |
189 */ | |
190 protected function getFilename($token) | |
191 { | |
192 // Uses 4 last characters, because first are mostly the same. | |
193 $folderA = substr($token, -2, 2); | |
194 $folderB = substr($token, -4, 2); | |
195 | |
196 return $this->folder.'/'.$folderA.'/'.$folderB.'/'.$token; | |
197 } | |
198 | |
199 /** | |
200 * Gets the index filename. | |
201 * | |
202 * @return string The index filename | |
203 */ | |
204 protected function getIndexFilename() | |
205 { | |
206 return $this->folder.'/index.csv'; | |
207 } | |
208 | |
209 /** | |
210 * Reads a line in the file, backward. | |
211 * | |
212 * This function automatically skips the empty lines and do not include the line return in result value. | |
213 * | |
214 * @param resource $file The file resource, with the pointer placed at the end of the line to read | |
215 * | |
216 * @return mixed A string representing the line or null if beginning of file is reached | |
217 */ | |
218 protected function readLineFromFile($file) | |
219 { | |
220 $line = ''; | |
221 $position = ftell($file); | |
222 | |
223 if (0 === $position) { | |
224 return; | |
225 } | |
226 | |
227 while (true) { | |
228 $chunkSize = min($position, 1024); | |
229 $position -= $chunkSize; | |
230 fseek($file, $position); | |
231 | |
232 if (0 === $chunkSize) { | |
233 // bof reached | |
234 break; | |
235 } | |
236 | |
237 $buffer = fread($file, $chunkSize); | |
238 | |
239 if (false === ($upTo = strrpos($buffer, "\n"))) { | |
240 $line = $buffer.$line; | |
241 continue; | |
242 } | |
243 | |
244 $position += $upTo; | |
245 $line = substr($buffer, $upTo + 1).$line; | |
246 fseek($file, max(0, $position), SEEK_SET); | |
247 | |
248 if ('' !== $line) { | |
249 break; | |
250 } | |
251 } | |
252 | |
253 return '' === $line ? null : $line; | |
254 } | |
255 | |
256 protected function createProfileFromData($token, $data, $parent = null) | |
257 { | |
258 $profile = new Profile($token); | |
259 $profile->setIp($data['ip']); | |
260 $profile->setMethod($data['method']); | |
261 $profile->setUrl($data['url']); | |
262 $profile->setTime($data['time']); | |
263 $profile->setStatusCode($data['status_code']); | |
264 $profile->setCollectors($data['data']); | |
265 | |
266 if (!$parent && $data['parent']) { | |
267 $parent = $this->read($data['parent']); | |
268 } | |
269 | |
270 if ($parent) { | |
271 $profile->setParent($parent); | |
272 } | |
273 | |
274 foreach ($data['children'] as $token) { | |
275 if (!$token || !file_exists($file = $this->getFilename($token))) { | |
276 continue; | |
277 } | |
278 | |
279 $profile->addChild($this->createProfileFromData($token, unserialize(file_get_contents($file)), $profile)); | |
280 } | |
281 | |
282 return $profile; | |
283 } | |
284 } |