summaryrefslogtreecommitdiffstats
path: root/SessionHelpers.php
diff options
context:
space:
mode:
authorRemi Collet <remi@remirepo.net>2024-09-23 07:58:36 +0200
committerRemi Collet <remi@php.net>2024-09-23 07:58:36 +0200
commit15d4185b94390810af1b5ad52160cd5dd6c03f58 (patch)
treea70b8f6475bf7d94fa9e03117dd8b42422f9161a /SessionHelpers.php
parent5b1e772c6b5e68509728752a7b963a89dc03baf5 (diff)
test build for upcoming 6.1.0RC2
Diffstat (limited to 'SessionHelpers.php')
-rw-r--r--SessionHelpers.php353
1 files changed, 0 insertions, 353 deletions
diff --git a/SessionHelpers.php b/SessionHelpers.php
deleted file mode 100644
index 90ae73b..0000000
--- a/SessionHelpers.php
+++ /dev/null
@@ -1,353 +0,0 @@
-<?php
-
-namespace SessionHelpers;
-
-class PhpSpawner {
- protected static function appendPhpArgs(string $php): string {
- $modules = shell_exec("$php --no-php-ini -m");
-
- /* Determine if we need to specifically add extensions */
- $extensions = array_filter(
- ['igbinary', 'msgpack', 'json', 'redis'],
- function ($module) use ($modules) {
- return strpos($modules, $module) === false;
- }
- );
-
- /* If any are needed add them to the command */
- if ($extensions) {
- $php .= ' --no-php-ini';
- foreach ($extensions as $extension) {
- /* We want to use the locally built redis extension */
- if ($extension == 'redis') {
- $path = dirname(__DIR__) . '/modules/redis';
- if (is_file("{$path}.so"))
- $extension = $path;
- }
-
- $php .= " -dextension=$extension.so";
- }
- }
-
- return $php;
- }
-
- /**
- * Return command to launch PHP with built extension enabled
- * taking care of environment (TEST_PHP_EXECUTABLE and TEST_PHP_ARGS)
- *
- * @param string $script
- *
- * @return string
- */
- public static function cmd(string $script): string {
- static $cmd = NULL;
-
- if ( ! $cmd) {
- $cmd = getenv('TEST_PHP_EXECUTABLE') ?: PHP_BINARY;
-
- if ($test_args = getenv('TEST_PHP_ARGS')) {
- $cmd .= ' ' . $test_args;
- } else {
- $cmd = self::appendPhpArgs($cmd);
- }
- }
-
- return $cmd . ' ' . __DIR__ . '/' . $script . ' ';
- }
-}
-
-class Runner {
- const start_script = 'startSession.php';
- const regenerate_id_script = 'regenerateSessionId.php';
- const get_data_script = 'getSessionData.php';
-
- private $required = ['host', 'handler', 'id'];
-
- private $args = [
- 'handler' => null,
- 'save-path' => null,
- 'id' => null,
- 'sleep' => 0,
- 'max-execution-time' => 300,
- 'locking-enabled' => true,
- 'lock-wait-time' => null,
- 'lock-retries' => -1,
- 'lock-expires' => 0,
- 'data' => '',
- 'lifetime' => 1440,
- 'compression' => 'none',
- ];
-
- private $prefix = NULL;
- private $output_file;
- private $exit_code = -1;
- private $cmd = NULL;
- private $pid;
- private $output;
-
- public function __construct() {
- $this->args['id'] = $this->createId();
- }
-
- public function getExitCode(): int {
- return $this->exit_code;
- }
-
- public function getCmd(): ?string {
- return $this->cmd;
- }
-
- public function getId(): ?string {
- return $this->args['id'];
- }
-
- public function prefix(string $prefix): self {
- $this->prefix = $prefix;
- return $this;
- }
-
- public function getSessionKey(): string {
- return $this->prefix . $this->getId();
- }
-
- public function getSessionLockKey(): string {
- return $this->getSessionKey() . '_LOCK';
- }
-
- protected function set($setting, $v): self {
- $this->args[$setting] = $v;
- return $this;
- }
-
- public function handler(string $handler): self {
- return $this->set('handler', $handler);
- }
-
- public function savePath(string $path): self {
- return $this->set('save-path', $path);
- }
-
- public function id(string $id): self {
- return $this->set('id', $id);
- }
-
- public function sleep(int $sleep): self {
- return $this->set('sleep', $sleep);
- }
-
- public function maxExecutionTime(int $time): self {
- return $this->set('max-execution-time', $time);
- }
-
- public function lockingEnabled(bool $enabled): self {
- return $this->set('locking-enabled', $enabled);
- }
-
- public function lockWaitTime(int $time): self {
- return $this->set('lock-wait-time', $time);
- }
-
- public function lockRetries(int $retries): self {
- return $this->set('lock-retries', $retries);
- }
-
- public function lockExpires(int $expires): self {
- return $this->set('lock-expires', $expires);
- }
-
- public function data(string $data): self {
- return $this->set('data', $data);
- }
-
- public function lifetime(int $lifetime): self {
- return $this->set('lifetime', $lifetime);
- }
-
- public function compression(string $compression): self {
- return $this->set('compression', $compression);
- }
-
- protected function validateArgs(array $required) {
- foreach ($required as $req) {
- if ( ! isset($this->args[$req]) || $this->args[$req] === null)
- throw new \Exception("Command requires '$req' arg");
- }
- }
-
- private function createId(): string {
- if (function_exists('session_create_id'))
- return session_create_id();
-
- return uniqid();
- }
-
- private function getTmpFileName() {
- return '/tmp/sessiontmp.txt';
- return tempnam(sys_get_temp_dir(), 'session');
- }
-
- /*
- * @param $client Redis client
- * @param string $max_wait_sec
- *
- * Sometimes we want to block until a session lock has been detected
- * This is better and faster than arbitrarily sleeping. If we don't
- * detect the session key within the specified maximum number of
- * seconds, the function returns failure.
- *
- * @return bool
- */
- public function waitForLockKey($redis, $max_wait_sec) {
- $now = microtime(true);
-
- do {
- if ($redis->exists($this->getSessionLockKey()))
- return true;
- usleep(10000);
- } while (microtime(true) <= $now + $max_wait_sec);
-
- return false;
- }
-
- private function appendCmdArgs(array $args): string {
- $append = [];
-
- foreach ($args as $arg => $val) {
- if ( ! $val)
- continue;
-
- if (is_string($val))
- $val = escapeshellarg($val);
-
- $append[] = "--$arg";
- $append[] = $val;
- }
-
- return implode(' ', $append);
- }
-
- private function buildPhpCmd(string $script, array $args): string {
- return PhpSpawner::cmd($script) . ' ' . $this->appendCmdArgs($args);
- }
-
- private function startSessionCmd(): string {
- return $this->buildPhpCmd(self::start_script, $this->args);
- }
-
- public function output(?int $timeout = NULL): ?string {
- if ($this->output) {
- var_dump("early return");
- return $this->output;
- }
-
- if ( ! $this->output_file || ! $this->pid) {
- throw new \Exception("Process was not started in the background");
- }
-
- $st = microtime(true);
-
- do {
- if (pcntl_waitpid($this->pid, $exit_code, WNOHANG) == 0)
- break;
- usleep(100000);
- } while ((microtime(true) - $st) < $timeout);
-
- if ( ! file_exists($this->output_file))
- return "";
-
- $this->output = file_get_contents($this->output_file);
- $this->output_file = NULL;
- $this->exit_code = $exit_code;
- $this->pid = NULL;
-
- return $this->output;
- }
-
- public function execBg(): bool {
- if ($this->cmd)
- throw new \Exception("Command already executed!");
-
- $output_file = $this->getTmpFileName();
-
- $this->cmd = $this->startSessionCmd();
- $this->cmd .= " >$output_file 2>&1 & echo $!";
-
- $pid = exec($this->cmd, $output, $exit_code);
- $this->exit_code = $exit_code;
-
- if ($this->exit_code || !is_numeric($pid))
- return false;
-
- $this->pid = (int)$pid;
- $this->output_file = $output_file;
-
- return true;
- }
-
- public function execFg() {
- if ($this->cmd)
- throw new \Exception("Command already executed!");
-
- $this->cmd = $this->startSessionCmd() . ' 2>&1';
-
- exec($this->cmd, $output, $exit_code);
- $this->exit_code = $exit_code;
- $this->output = implode("\n", array_filter($output));
-
- return $this->output;
- }
-
- private function regenerateIdCmd($locking, $destroy, $proxy): string {
- $this->validateArgs(['handler', 'id', 'save-path']);
-
- $args = [
- 'handler' => $this->args['handler'],
- 'save-path' => $this->args['save-path'],
- 'id' => $this->args['id'],
- 'locking-enabled' => !!$locking,
- 'destroy' => !!$destroy,
- 'proxy' => !!$proxy,
- ];
-
- return $this->buildPhpCmd(self::regenerate_id_script, $args);
- }
-
- public function regenerateId($locking = false, $destroy = false, $proxy = false) {
- if ( ! $this->cmd)
- throw new \Exception("Cannot regenerate id before starting session!");
-
- $cmd = $this->regenerateIdCmd($locking, $destroy, $proxy);
-
- exec($cmd, $output, $exit_code);
-
- if ($exit_code != 0)
- return false;
-
- return $output[0];
- }
-
- private function getDataCmd(?int $lifetime): string {
- $this->validateArgs(['handler', 'save-path', 'id']);
-
- $args = [
- 'handler' => $this->args['handler'],
- 'save-path' => $this->args['save-path'],
- 'id' => $this->args['id'],
- 'lifetime' => is_int($lifetime) ? $lifetime : $this->args['lifetime'],
- ];
-
- return $this->buildPhpCmd(self::get_data_script, $args);
- }
-
- public function getData(?int $lifetime = NULL): string {
- $cmd = $this->getDataCmd($lifetime);
-
- exec($cmd, $output, $exit_code);
- if ($exit_code != 0) {
- return implode("\n", $output);
- }
-
- return $output[0];
- }
-}