Skip to content

Commit c670f8a

Browse files
committed
[HttpKernel] FileProfilerStorage has remove expired profiles mechanism
1 parent e1581a0 commit c670f8a

File tree

2 files changed

+114
-1
lines changed

2 files changed

+114
-1
lines changed

src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
*/
1919
class FileProfilerStorage implements ProfilerStorageInterface
2020
{
21+
protected const MAX_RETENTION_DAYS = 1;
22+
2123
/**
2224
* Folder where profiler data are stored.
2325
*/
@@ -180,7 +182,7 @@ public function write(Profile $profile): bool
180182

181183
if (!$profileIndexed) {
182184
// Add to index
183-
if (false === $file = fopen($this->getIndexFilename(), 'a')) {
185+
if (false === $file = fopen($indexFilename = $this->getIndexFilename(), 'a')) {
184186
return false;
185187
}
186188

@@ -194,11 +196,55 @@ public function write(Profile $profile): bool
194196
$profile->getStatusCode(),
195197
]);
196198
fclose($file);
199+
200+
$this->removeExpiredProfiles($indexFilename);
197201
}
198202

199203
return true;
200204
}
201205

206+
protected function removeExpiredProfiles(string $indexFilename)
207+
{
208+
$minimalProfileTimestamp = (new \DateTime())
209+
->modify(sprintf('-%d days', self::MAX_RETENTION_DAYS))
210+
->getTimestamp();
211+
212+
$handle = fopen($indexFilename, 'r');
213+
214+
$tmpIndexFileName = $indexFilename.'.tmp';
215+
$atLeastOneExpiredProfile = false;
216+
while ($line = fgets($handle)) {
217+
$csv = str_getcsv($line);
218+
$token = $csv[0];
219+
$profileTimestamp = (int) $csv[4];
220+
221+
if (0 !== $profileTimestamp && $profileTimestamp < $minimalProfileTimestamp) {
222+
$atLeastOneExpiredProfile = true;
223+
$this->unlinkTokenFile($token);
224+
} else {
225+
if ($atLeastOneExpiredProfile) {
226+
file_put_contents($tmpIndexFileName, $line);
227+
}
228+
break;
229+
}
230+
}
231+
232+
if ($atLeastOneExpiredProfile) {
233+
file_put_contents($tmpIndexFileName, stream_get_contents($handle), \FILE_APPEND);
234+
unlink($indexFilename);
235+
rename($tmpIndexFileName, $indexFilename);
236+
} else {
237+
fclose($handle);
238+
}
239+
}
240+
241+
public function unlinkTokenFile(string $token)
242+
{
243+
if (file_exists($filename = $this->getFilename($token))) {
244+
unlink($filename);
245+
}
246+
}
247+
202248
/**
203249
* Gets filename to store data, associated to the token.
204250
*/

src/Symfony/Component/HttpKernel/Tests/Profiler/FileProfilerStorageTest.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,73 @@ public function testMultiRowIndexFile()
344344
$this->assertFalse(fgetcsv($handle));
345345
}
346346

347+
/**
348+
* @dataProvider removeExpiredProfilesProvider
349+
*/
350+
public function testRemoveExpiredProfiles(string $originalExpectedIndexContent, string $newExpectedIndexContent)
351+
{
352+
$indexFilename = $this->tmpDir.'/index.csv';
353+
354+
file_put_contents($indexFilename, $originalExpectedIndexContent);
355+
356+
$this->assertSame($originalExpectedIndexContent, file_get_contents($indexFilename));
357+
358+
$r = new \ReflectionMethod($this->storage, 'removeExpiredProfiles');
359+
$r->invoke($this->storage, $indexFilename);
360+
361+
$this->assertSame($newExpectedIndexContent, file_get_contents($indexFilename));
362+
}
363+
364+
public function removeExpiredProfilesProvider()
365+
{
366+
$oneHourAgo = new \DateTime('now');
367+
$oneHourAgo->modify('-1 hour');
368+
369+
yield 'One unexpired profile' => [
370+
<<< CSV
371+
token0,127.0.0.0,,http://foo.bar/0,{$oneHourAgo->getTimestamp()},,
372+
373+
CSV,
374+
<<< CSV
375+
token0,127.0.0.0,,http://foo.bar/0,{$oneHourAgo->getTimestamp()},,
376+
377+
CSV,
378+
];
379+
380+
$twoDaysAgo = new \DateTime('now');
381+
$twoDaysAgo->modify('-2 days');
382+
383+
yield 'One expired profile' => [
384+
<<< CSV
385+
token0,127.0.0.0,,http://foo.bar/0,{$twoDaysAgo->getTimestamp()},,
386+
387+
CSV,
388+
'',
389+
];
390+
391+
$threeDaysAgo = new \DateTime('now');
392+
$threeDaysAgo->modify('-3 days');
393+
394+
$twoDaysAgo = new \DateTime('now');
395+
$twoDaysAgo->modify('-2 days');
396+
397+
$oneHourAgo = new \DateTime('now');
398+
$oneHourAgo->modify('-1 hour');
399+
400+
yield 'Multiple expired profiles' => [
401+
<<< CSV
402+
token0,127.0.0.0,,http://foo.bar/0,{$threeDaysAgo->getTimestamp()},,
403+
token1,127.0.0.1,,http://foo.bar/1,{$twoDaysAgo->getTimestamp()},,
404+
token2,127.0.0.2,,http://foo.bar/2,{$oneHourAgo->getTimestamp()},,
405+
406+
CSV,
407+
<<< CSV
408+
token2,127.0.0.2,,http://foo.bar/2,{$oneHourAgo->getTimestamp()},,
409+
410+
CSV,
411+
];
412+
}
413+
347414
public function testReadLineFromFile()
348415
{
349416
$r = new \ReflectionMethod($this->storage, 'readLineFromFile');

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy