HEX
Server: Apache
System: Linux sxb1plzcpnl489831.prod.sxb1.secureserver.net 4.18.0-553.52.1.lve.el8.x86_64 #1 SMP Wed May 21 15:31:29 UTC 2025 x86_64
User: j2d7uhbqfejh (10030402)
PHP: 8.2.30
Disabled: NONE
Upload Files
File: /home/j2d7uhbqfejh/public_html/zorgosso.nl/wp-content/plugins/404-solution/includes/Clock.php
<?php

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Clock interface — the seam every time-dependent class talks to instead
 * of `time()` / `microtime(true)` / `current_time('timestamp')` directly.
 *
 * Production code resolves a `ABJ_404_Solution_SystemClock` from the
 * service container; tests bind a `ABJ_404_Solution_FrozenClock` so they
 * can advance virtual time deterministically (no `usleep()`, no global
 * Brain\Monkey stubs of `time()`). See `docs/clock-injection-audit.md`.
 *
 * The four-method surface (`now`, `nowFloat`, `wpNow`, `wpNowMysql`) is the
 * minimum set the audit identified as covering every time-sensitive call
 * site in `includes/`. Adding new methods here is a project-wide change —
 * prefer to keep call sites within this surface.
 */
interface ABJ_404_Solution_Clock {
    /**
     * Current Unix epoch in seconds (whole integer). Replaces direct calls
     * to `time()`. Use for cooldown windows, rate-limit windows, and any
     * comparison whose precision is per-second.
     *
     * @return int
     */
    public function now(): int;

    /**
     * Current Unix epoch with microsecond precision. Replaces direct calls
     * to `microtime(true)`. Use for sub-second elapsed-time measurements
     * (deadline timers, performance probes).
     *
     * @return float
     */
    public function nowFloat(): float;

    /**
     * WordPress-localized "now" timestamp. Replaces direct calls to
     * `current_time('timestamp')`. Tests treat this as identical to
     * `now()` because the WP locale offset is irrelevant when virtual
     * time is being driven by the test directly.
     *
     * @return int
     */
    public function wpNow(): int;

    /**
     * MySQL-formatted "now" string ("Y-m-d H:i:s"). Replaces direct calls
     * to `current_time('mysql')`.
     *
     * @return string
     */
    public function wpNowMysql(): string;
}

/**
 * Default production clock — delegates to PHP's wall-clock and to
 * WordPress's `current_time()` helper. Stateless and immutable.
 *
 * Resolved by `bootstrap.php` for the `'clock'` container service.
 */
final class ABJ_404_Solution_SystemClock implements ABJ_404_Solution_Clock {

    public function now(): int {
        return time();
    }

    public function nowFloat(): float {
        return microtime(true);
    }

    public function wpNow(): int {
        if (function_exists('current_time')) {
            $value = current_time('timestamp');
            if (is_numeric($value)) {
                return (int)$value;
            }
        }
        return time();
    }

    public function wpNowMysql(): string {
        if (function_exists('current_time')) {
            $value = current_time('mysql');
            if (is_string($value)) {
                return $value;
            }
        }
        return gmdate('Y-m-d H:i:s');
    }
}

/**
 * Test-only clock that returns a fixed virtual time controllable by the
 * test author. Default start epoch is 2023-11-14T22:13:20Z (1700000000) —
 * any moment well after Y2K38 sanity checks would care about and well
 * before any test would pick a date that confuses date math.
 *
 * Tests advance the clock with `advance($seconds)` to fast-forward
 * cooldown windows / rate-limit windows / cron windows without sleeping.
 *
 * Not registered in the container by default. Tests bind it explicitly:
 *     $clock = new ABJ_404_Solution_FrozenClock();
 *     ABJ_404_Solution_ServiceContainer::getInstance()->set('clock',
 *         function() use ($clock) { return $clock; });
 */
final class ABJ_404_Solution_FrozenClock implements ABJ_404_Solution_Clock {

    /** @var float Virtual epoch seconds (microsecond precision). */
    private $t;

    /** @param float $startEpoch */
    public function __construct(float $startEpoch = 1700000000.0) {
        $this->t = $startEpoch;
    }

    public function now(): int {
        return (int)$this->t;
    }

    public function nowFloat(): float {
        return $this->t;
    }

    public function wpNow(): int {
        return (int)$this->t;
    }

    public function wpNowMysql(): string {
        return gmdate('Y-m-d H:i:s', (int)$this->t);
    }

    /**
     * Advance virtual time by `$seconds`. Negative values rewind — useful
     * for tests that need to verify behavior at a known point in the past
     * (e.g. an expired cooldown that was set before the test "started").
     *
     * @param float $seconds
     * @return void
     */
    public function advance(float $seconds): void {
        $this->t += $seconds;
    }

    /**
     * Set virtual time to an absolute epoch. Use for tests that need to
     * pin time to a specific calendar date (e.g. boundary-of-month cron
     * tests).
     *
     * @param float $epoch
     * @return void
     */
    public function set(float $epoch): void {
        $this->t = $epoch;
    }
}