Skip to content

Commit 3fc39c4

Browse files
committed
added FileSession, used by default [Closes #362][Closes #356]
1 parent 7948d53 commit 3fc39c4

File tree

8 files changed

+127
-17
lines changed

8 files changed

+127
-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

+14-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) {
@@ -135,9 +136,18 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class)
135136
));
136137
}
137138

138-
if (!$this->cliMode && ($name = $builder->getByType(Nette\Http\Session::class))) {
139-
$initialize->addBody('$this->getService(?)->start();', [$name]);
140-
$initialize->addBody('Tracy\Debugger::dispatch();');
139+
if (!$this->cliMode) {
140+
if ($this->config->storage === 'session') {
141+
if ($name = $builder->getByType(Nette\Http\Session::class)) {
142+
$initialize->addBody('$this->getService(?)->start();', [$name]);
143+
}
144+
145+
$initialize->addBody('Tracy\Debugger::dispatch();');
146+
147+
} elseif ($this->config->storage !== null) {
148+
$initialize->addBody('Tracy\Debugger::setStorage(new Tracy\FileSession(?));', [$this->config->storage]);
149+
$initialize->addBody('Tracy\Debugger::dispatch();');
150+
}
141151
}
142152
}
143153

src/Tracy/Debugger/Debugger.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ public static function enable($mode = null, ?string $logDirectory = null, $email
235235
'Logger/FireLogger',
236236
'Logger/Logger',
237237
'Session/SessionHandler',
238+
'Session/FileSession',
238239
'Session/NativeSession',
239240
'Helpers',
240241
] as $path) {
@@ -482,7 +483,8 @@ public static function setSessionHandler(SessionHandler $storage): void
482483
public static function getSessionHandler(): SessionHandler
483484
{
484485
if (!self::$sessionHandler) {
485-
self::$sessionHandler = new NativeSession;
486+
$dir = session_save_path() ?: ini_get('upload_tmp_dir') ?: sys_get_temp_dir() ?: self::$logDirectory;
487+
self::$sessionHandler = $dir ? new FileSession($dir) : new NativeSession;
486488
}
487489

488490
return self::$sessionHandler;

src/Tracy/Session/FileSession.php

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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+
46+
return (bool) $this->file;
47+
}
48+
49+
50+
private function open(): void
51+
{
52+
$id = $_COOKIE[$this->cookieName] ?? null;
53+
if (
54+
!is_string($id)
55+
|| !preg_match('#^\w{10}\z#i', $id)
56+
|| !($file = @fopen($path = $this->dir . '/' . self::FILE_PREFIX . $id, 'r+')) // intentionally @
57+
) {
58+
$id = Helpers::createId();
59+
setcookie($this->cookieName, $id, time() + self::COOKIE_LIFETIME, '/', '', false, true);
60+
61+
$file = @fopen($path = $this->dir . '/' . self::FILE_PREFIX . $id, 'c+'); // intentionally @
62+
if ($file === false) {
63+
throw new \RuntimeException("Unable to create file '$path'. " . error_get_last()['message']);
64+
}
65+
}
66+
67+
if (!@flock($file, LOCK_EX)) { // intentionally @
68+
throw new \RuntimeException("Unable to acquire exclusive lock on '$path'. ", error_get_last()['message']);
69+
}
70+
71+
$this->file = $file;
72+
$this->data = @unserialize(stream_get_contents($this->file)) ?: []; // @ - file may be empty
73+
74+
if (mt_rand() / mt_getrandmax() < $this->gcProbability) {
75+
$this->clean();
76+
}
77+
}
78+
79+
80+
public function &getData(): array
81+
{
82+
return $this->data;
83+
}
84+
85+
86+
public function clean(): void
87+
{
88+
$old = strtotime('-1 week');
89+
foreach (glob($this->dir . '/' . self::FILE_PREFIX . '*') as $file) {
90+
if (filemtime($file) < $old) {
91+
unlink($file);
92+
}
93+
}
94+
}
95+
96+
97+
public function __destruct()
98+
{
99+
if (!$this->file) {
100+
return;
101+
}
102+
103+
ftruncate($this->file, 0);
104+
fseek($this->file, 0);
105+
fwrite($this->file, serialize($this->data));
106+
fclose($this->file);
107+
$this->file = null;
108+
}
109+
}

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)