Skip to content

Commit e166766

Browse files
committed
added FileSession, used by default [Closes #362][Closes #356]
1 parent aa557bd commit e166766

File tree

8 files changed

+124
-17
lines changed

8 files changed

+124
-17
lines changed

examples/ajax-fetch.php

-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66

77
use Tracy\Debugger;
88

9-
// session is required for this functionality
10-
session_start();
11-
129
// For security reasons, Tracy is visible only on localhost.
1310
// You may force Tracy to run in development mode by passing the Debugger::DEVELOPMENT instead of Debugger::DETECT.
1411
Debugger::enable(Debugger::DETECT, __DIR__ . '/log');

examples/ajax-jquery.php

-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66

77
use Tracy\Debugger;
88

9-
// session is required for this functionality
10-
session_start();
11-
129
// For security reasons, Tracy is visible only on localhost.
1310
// You may force Tracy to run in development mode by passing the Debugger::DEVELOPMENT instead of Debugger::DETECT.
1411
Debugger::enable(Debugger::DETECT, __DIR__ . '/log');

examples/preloading.php

-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66

77
use Tracy\Debugger;
88

9-
// session is required for this functionality
10-
session_start();
11-
129
// For security reasons, Tracy is visible only on localhost.
1310
// You may force Tracy to run in development mode by passing the Debugger::DEVELOPMENT instead of Debugger::DETECT.
1411
Debugger::enable(Debugger::DETECT, __DIR__ . '/log');

examples/redirect.php

-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66

77
use Tracy\Debugger;
88

9-
// session is required for this functionality
10-
session_start();
11-
129
// For security reasons, Tracy is visible only on localhost.
1310
// You may force Tracy to run in development mode by passing the Debugger::DEVELOPMENT instead of Debugger::DETECT.
1411
Debugger::enable(Debugger::DETECT, __DIR__ . '/log');

src/Bridges/Nette/TracyExtension.php

+13-4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public function getConfigSchema(): Nette\Schema\Schema
4040
'fromEmail' => Expect::email()->dynamic(),
4141
'emailSnooze' => Expect::string()->dynamic(),
4242
'logSeverity' => Expect::anyOf(Expect::scalar(), Expect::listOf('scalar')),
43+
'storage' => Expect::string(),
4344
'editor' => Expect::string()->dynamic(),
4445
'browser' => Expect::string()->dynamic(),
4546
'errorTemplate' => Expect::string()->dynamic(),
@@ -83,7 +84,7 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class)
8384
$builder = $this->getContainerBuilder();
8485

8586
$options = (array) $this->config;
86-
unset($options['bar'], $options['blueScreen'], $options['netteMailer']);
87+
unset($options['bar'], $options['blueScreen'], $options['netteMailer'], $options['storage']);
8788
if (isset($options['logSeverity'])) {
8889
$res = 0;
8990
foreach ((array) $options['logSeverity'] as $level) {
@@ -131,9 +132,17 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class)
131132
));
132133
}
133134

134-
if (!$this->cliMode && ($name = $builder->getByType(Nette\Http\Session::class))) {
135-
$initialize->addBody('$this->getService(?)->start();', [$name]);
136-
$initialize->addBody('Tracy\Debugger::dispatch();');
135+
if (!$this->cliMode) {
136+
if ($this->config['storage'] === 'session') {
137+
if ($name = $builder->getByType(Nette\Http\Session::class)) {
138+
$initialize->addBody('$this->getService(?)->start();', [$name]);
139+
}
140+
$initialize->addBody('Tracy\Debugger::dispatch();');
141+
142+
} elseif ($this->config['storage'] !== null) {
143+
$initialize->addBody('Tracy\Debugger::setStorage(new Tracy\FileSession(?));', [$this->config['storage']]);
144+
$initialize->addBody('Tracy\Debugger::dispatch();');
145+
}
137146
}
138147
}
139148

src/Tracy/Debugger/Debugger.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ public static function enable($mode = null, string $logDirectory = null, $email
230230
'Logger/FireLogger',
231231
'Logger/Logger',
232232
'Session/SessionHandler',
233+
'Session/FileSession',
233234
'Session/NativeSession',
234235
'Helpers',
235236
] as $path) {
@@ -474,7 +475,8 @@ public static function setSessionHandler(SessionHandler $storage): void
474475
public static function getSessionHandler(): SessionHandler
475476
{
476477
if (!self::$sessionHandler) {
477-
self::$sessionHandler = new NativeSession;
478+
$dir = session_save_path() ?: ini_get('upload_tmp_dir') ?: sys_get_temp_dir() ?: self::$logDirectory;
479+
self::$sessionHandler = $dir ? new FileSession($dir) : new NativeSession;
478480
}
479481
return self::$sessionHandler;
480482
}

src/Tracy/Session/FileSession.php

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the Tracy (https://tracy.nette.org)
5+
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Tracy;
11+
12+
13+
class FileSession implements SessionHandler
14+
{
15+
private const FILE_PREFIX = 'tracy-';
16+
private const COOKIE_LIFETIME = 31557600;
17+
18+
/** @var string */
19+
public $cookieName = 'tracy-session';
20+
21+
/** @var float probability that the clean() routine is started */
22+
public $gcProbability = 0.001;
23+
24+
/** @var string */
25+
private $dir;
26+
27+
/** @var resource */
28+
private $file;
29+
30+
/** @var array */
31+
private $data = [];
32+
33+
34+
public function __construct(string $dir)
35+
{
36+
$this->dir = $dir;
37+
}
38+
39+
40+
public function isAvailable(): bool
41+
{
42+
if (!$this->file) {
43+
$this->open();
44+
}
45+
return (bool) $this->file;
46+
}
47+
48+
49+
private function open(): void
50+
{
51+
$id = $_COOKIE[$this->cookieName] ?? null;
52+
if (
53+
!is_string($id)
54+
|| !preg_match('#^\w{10}\z#i', $id)
55+
|| !($file = @fopen($path = $this->dir . '/' . self::FILE_PREFIX . $id, 'r+')) // intentionally @
56+
) {
57+
$id = Helpers::createId();
58+
setcookie($this->cookieName, $id, time() + self::COOKIE_LIFETIME, '/', '', false, true);
59+
60+
$file = @fopen($path = $this->dir . '/' . self::FILE_PREFIX . $id, 'c+'); // intentionally @
61+
if ($file === false) {
62+
throw new \RuntimeException("Unable to create file '$path'. " . error_get_last()['message']);
63+
}
64+
}
65+
66+
if (!@flock($file, LOCK_EX)) { // intentionally @
67+
throw new \RuntimeException("Unable to acquire exclusive lock on '$path'. ", error_get_last()['message']);
68+
}
69+
70+
$this->file = $file;
71+
$this->data = @unserialize(stream_get_contents($this->file)) ?: []; // @ - file may be empty
72+
73+
if (mt_rand() / mt_getrandmax() < $this->gcProbability) {
74+
$this->clean();
75+
}
76+
}
77+
78+
79+
public function &getData(): array
80+
{
81+
return $this->data;
82+
}
83+
84+
85+
public function clean(): void
86+
{
87+
$old = strtotime('-1 week');
88+
foreach (glob($this->dir . '/' . self::FILE_PREFIX . '*') as $file) {
89+
if (filemtime($file) < $old) {
90+
unlink($file);
91+
}
92+
}
93+
}
94+
95+
96+
public function __destruct()
97+
{
98+
if (!$this->file) {
99+
return;
100+
}
101+
ftruncate($this->file, 0);
102+
fseek($this->file, 0);
103+
fwrite($this->file, serialize($this->data));
104+
fclose($this->file);
105+
$this->file = null;
106+
}
107+
}

src/tracy.php

+1
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@
2727
require __DIR__ . '/Tracy/OutputDebugger/OutputDebugger.php';
2828
require __DIR__ . '/Tracy/Session/SessionHandler.php';
2929
require __DIR__ . '/Tracy/Session/NativeSession.php';
30+
require __DIR__ . '/Tracy/Session/FileSession.php';
3031
require __DIR__ . '/Tracy/Helpers.php';
3132
require __DIR__ . '/Tracy/functions.php';

0 commit comments

Comments
 (0)