From 5d5be6c58d75c954e511f7284b183fcd344e4572 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 2 Apr 2019 19:27:00 +0200 Subject: [PATCH] added FileSession, used by default [Closes #362][Closes #356] --- examples/ajax-fetch.php | 3 - examples/ajax-jquery.php | 3 - examples/preloading.php | 3 - examples/redirect.php | 3 - readme.md | 5 +- src/Bridges/Nette/TracyExtension.php | 6 +- src/Tracy/Debugger/Debugger.php | 8 +- src/Tracy/Session/FileSession.php | 109 +++++++++++++++++++++++++++ src/tracy.php | 1 + 9 files changed, 125 insertions(+), 16 deletions(-) create mode 100644 src/Tracy/Session/FileSession.php diff --git a/examples/ajax-fetch.php b/examples/ajax-fetch.php index f6ed451f0..d53884113 100644 --- a/examples/ajax-fetch.php +++ b/examples/ajax-fetch.php @@ -6,9 +6,6 @@ use Tracy\Debugger; -// session is required for this functionality -session_start(); - // For security reasons, Tracy is visible only on localhost. // You may force Tracy to run in development mode by passing the Debugger::DEVELOPMENT instead of Debugger::DETECT. Debugger::enable(Debugger::DETECT, __DIR__ . '/log'); diff --git a/examples/ajax-jquery.php b/examples/ajax-jquery.php index fc1d41ad3..8d941f6bb 100644 --- a/examples/ajax-jquery.php +++ b/examples/ajax-jquery.php @@ -6,9 +6,6 @@ use Tracy\Debugger; -// session is required for this functionality -session_start(); - // For security reasons, Tracy is visible only on localhost. // You may force Tracy to run in development mode by passing the Debugger::DEVELOPMENT instead of Debugger::DETECT. Debugger::enable(Debugger::DETECT, __DIR__ . '/log'); diff --git a/examples/preloading.php b/examples/preloading.php index 154918ca3..6ac06a9a4 100644 --- a/examples/preloading.php +++ b/examples/preloading.php @@ -6,9 +6,6 @@ use Tracy\Debugger; -// session is required for this functionality -session_start(); - // For security reasons, Tracy is visible only on localhost. // You may force Tracy to run in development mode by passing the Debugger::DEVELOPMENT instead of Debugger::DETECT. Debugger::enable(Debugger::DETECT, __DIR__ . '/log'); diff --git a/examples/redirect.php b/examples/redirect.php index eab6e884a..4b6979e9e 100644 --- a/examples/redirect.php +++ b/examples/redirect.php @@ -6,9 +6,6 @@ use Tracy\Debugger; -// session is required for this functionality -session_start(); - // For security reasons, Tracy is visible only on localhost. // You may force Tracy to run in development mode by passing the Debugger::DEVELOPMENT instead of Debugger::DETECT. Debugger::enable(Debugger::DETECT, __DIR__ . '/log'); diff --git a/readme.md b/readme.md index f2555896b..9ccd59118 100644 --- a/readme.md +++ b/readme.md @@ -177,10 +177,10 @@ any scripts: AJAX and redirected requests ---------------------------- -Tracy is able to show Debug bar and Bluescreens for AJAX and redirected requests. You just have to start session before Tracy: +Tracy is able to show Debug bar and Bluescreens for AJAX and redirected requests. Tracy keeps the data in a temporary files and uses the `tracy-session` cookie. Tracy can be configured to use a standard PHP session: ```php -session_start(); +Debugger::setSessionStorage(new Tracy\NativeSession); Debugger::enable(); ``` @@ -188,6 +188,7 @@ In case you use non-standard session handler, you can start Tracy immediately (i and then inform Tracy that session is ready to use via `dispatch()`: ```php +Debugger::setSessionStorage(new Tracy\NativeSession); Debugger::enable(); // initialize session handler diff --git a/src/Bridges/Nette/TracyExtension.php b/src/Bridges/Nette/TracyExtension.php index c3bce8809..17d397668 100644 --- a/src/Bridges/Nette/TracyExtension.php +++ b/src/Bridges/Nette/TracyExtension.php @@ -135,7 +135,11 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class) )); } - if (!$this->cliMode && ($name = $builder->getByType(Nette\Http\Session::class))) { + if ( + !$this->cliMode + && Tracy\Debugger::getSessionStorage() instanceof Tracy\NativeSession + && ($name = $builder->getByType(Nette\Http\Session::class)) + ) { $initialize->addBody('$this->getService(?)->start();', [$name]); $initialize->addBody('Tracy\Debugger::dispatch();'); } diff --git a/src/Tracy/Debugger/Debugger.php b/src/Tracy/Debugger/Debugger.php index 9b10cc7f3..00ac65382 100644 --- a/src/Tracy/Debugger/Debugger.php +++ b/src/Tracy/Debugger/Debugger.php @@ -235,6 +235,7 @@ public static function enable($mode = null, ?string $logDirectory = null, $email 'Logger/FireLogger', 'Logger/Logger', 'Session/SessionStorage', + 'Session/FileSession', 'Session/NativeSession', 'Helpers', ] as $path) { @@ -482,7 +483,12 @@ public static function setSessionStorage(SessionStorage $storage): void public static function getSessionStorage(): SessionStorage { if (!self::$sessionStorage) { - self::$sessionStorage = new NativeSession; + self::$sessionStorage = is_dir($dir = session_save_path()) + || is_dir($dir = ini_get('upload_tmp_dir')) + || is_dir($dir = sys_get_temp_dir()) + || ($dir = self::$logDirectory) + ? new FileSession($dir) + : new NativeSession; } return self::$sessionStorage; diff --git a/src/Tracy/Session/FileSession.php b/src/Tracy/Session/FileSession.php new file mode 100644 index 000000000..24c278e02 --- /dev/null +++ b/src/Tracy/Session/FileSession.php @@ -0,0 +1,109 @@ +dir = $dir; + } + + + public function isAvailable(): bool + { + if (!$this->file) { + $this->open(); + } + + return true; + } + + + private function open(): void + { + $id = $_COOKIE[$this->cookieName] ?? null; + if ( + !is_string($id) + || !preg_match('#^\w{10}\z#i', $id) + || !($file = @fopen($path = $this->dir . '/' . self::FILE_PREFIX . $id, 'r+')) // intentionally @ + ) { + $id = Helpers::createId(); + setcookie($this->cookieName, $id, time() + self::COOKIE_LIFETIME, '/', '', false, true); + + $file = @fopen($path = $this->dir . '/' . self::FILE_PREFIX . $id, 'c+'); // intentionally @ + if ($file === false) { + throw new \RuntimeException("Unable to create file '$path'. " . error_get_last()['message']); + } + } + + if (!@flock($file, LOCK_EX)) { // intentionally @ + throw new \RuntimeException("Unable to acquire exclusive lock on '$path'. ", error_get_last()['message']); + } + + $this->file = $file; + $this->data = @unserialize(stream_get_contents($this->file)) ?: []; // @ - file may be empty + + if (mt_rand() / mt_getrandmax() < $this->gcProbability) { + $this->clean(); + } + } + + + public function &getData(): array + { + return $this->data; + } + + + public function clean(): void + { + $old = strtotime('-1 week'); + foreach (glob($this->dir . '/' . self::FILE_PREFIX . '*') as $file) { + if (filemtime($file) < $old) { + unlink($file); + } + } + } + + + public function __destruct() + { + if (!$this->file) { + return; + } + + ftruncate($this->file, 0); + fseek($this->file, 0); + fwrite($this->file, serialize($this->data)); + fclose($this->file); + $this->file = null; + } +} diff --git a/src/tracy.php b/src/tracy.php index 22e9f391e..73259adff 100644 --- a/src/tracy.php +++ b/src/tracy.php @@ -27,5 +27,6 @@ require __DIR__ . '/Tracy/OutputDebugger/OutputDebugger.php'; require __DIR__ . '/Tracy/Session/SessionStorage.php'; require __DIR__ . '/Tracy/Session/NativeSession.php'; +require __DIR__ . '/Tracy/Session/FileSession.php'; require __DIR__ . '/Tracy/Helpers.php'; require __DIR__ . '/Tracy/functions.php';