Файловый менеджер - Редактировать - /home/gqdcvggs/go.imators.com/vertchasseur.zip
Назад
PK Q7�[wOPd2% 2% success.phpnu �[��� <?php session_start(); require_once 'db.php'; $session_id = $_GET['session_id'] ?? ''; if (empty($session_id)) { die('Session invalide'); } $stripe_config = require 'config/stripe.php'; $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "https://api.stripe.com/v1/checkout/sessions/" . $session_id, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . $stripe_config['secret_key'] ] ]); $response = curl_exec($curl); curl_close($curl); $session = json_decode($response, true); if (!$session || isset($session['error'])) { die('Erreur lors de la récupération de la session'); } $resident_id = $session['client_reference_id']; $subscription_id = $session['subscription']; $customer_id = $session['customer']; $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "https://api.stripe.com/v1/subscriptions/" . $subscription_id, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . $stripe_config['secret_key'] ] ]); $response = curl_exec($curl); curl_close($curl); $subscription = json_decode($response, true); $check_stmt = $conn->prepare("SELECT id FROM subscriptions WHERE stripe_subscription_id = ?"); $check_stmt->bind_param("s", $subscription_id); $check_stmt->execute(); $existing = $check_stmt->get_result()->fetch_assoc(); if (!$existing) { $stmt = $conn->prepare("INSERT INTO subscriptions (resident_id, stripe_customer_id, stripe_subscription_id, stripe_price_id, status, current_period_start, current_period_end) VALUES (?, ?, ?, ?, ?, FROM_UNIXTIME(?), FROM_UNIXTIME(?))"); $status = $subscription['status']; $stmt->bind_param("issssii", $resident_id, $customer_id, $subscription_id, $stripe_config['price_id'], $status, $subscription['current_period_start'], $subscription['current_period_end'] ); $stmt->execute(); $subscription_db_id = $conn->insert_id; if ($subscription['status'] === 'active') { $update_member = $conn->prepare("UPDATE residents SET member_ = 1 WHERE id = ?"); $update_member->bind_param("i", $resident_id); $update_member->execute(); } $latest_invoice = $subscription['latest_invoice']; if ($latest_invoice) { $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "https://api.stripe.com/v1/invoices/" . $latest_invoice, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . $stripe_config['secret_key'] ] ]); $response = curl_exec($curl); curl_close($curl); $invoice = json_decode($response, true); if ($invoice) { $payment_stmt = $conn->prepare("INSERT INTO payment_history (resident_id, subscription_id, stripe_payment_intent_id, amount, currency, status, payment_date) VALUES (?, ?, ?, ?, ?, ?, NOW())"); $amount = $invoice['amount_paid'] / 100; $currency = $invoice['currency']; $payment_status = $invoice['status']; $payment_intent_id = $invoice['payment_intent']; $payment_stmt->bind_param("iisdss", $resident_id, $subscription_db_id, $payment_intent_id, $amount, $currency, $payment_status ); $payment_stmt->execute(); } } } ?> <!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Paiement réussi</title> <script src="https://cdn.tailwindcss.com"></script> <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap" rel="stylesheet"> <style> body { font-family: 'Poppins', sans-serif; } .checkmark { width: 80px; height: 80px; border-radius: 50%; display: block; stroke-width: 3; stroke: #16a34a; stroke-miterlimit: 10; box-shadow: inset 0px 0px 0px #16a34a; animation: fill 0.4s ease-in-out 0.4s forwards, scale 0.3s ease-in-out 0.9s both; } .checkmark-circle { stroke-dasharray: 166; stroke-dashoffset: 166; stroke-width: 3; stroke-miterlimit: 10; stroke: #16a34a; fill: none; animation: stroke 0.6s cubic-bezier(0.65, 0, 0.45, 1) forwards; } .checkmark-check { transform-origin: 50% 50%; stroke-dasharray: 48; stroke-dashoffset: 48; animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards; } @keyframes stroke { 100% { stroke-dashoffset: 0; } } @keyframes scale { 0%, 100% { transform: none; } 50% { transform: scale3d(1.1, 1.1, 1); } } @keyframes fill { 100% { box-shadow: inset 0px 0px 0px 40px #16a34a; } } </style> </head> <body class="bg-gray-50 dark:bg-gray-900"> <script> if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) { document.documentElement.classList.add('dark'); } const translations = { fr: { title: "Paiement réussi !", subtitle: "Ton abonnement est maintenant actif", instruction: "Pour visualiser tes nouveaux privilèges, ferme cette page en appuyant sur la croix située en haut de l'écran, puis appuie sur le bouton \"Rafraîchir\" une fois de retour sur la page précédente.", invoice: "Une facture de confirmation a été envoyée à ton adresse e-mail.", support: "Si tu rencontres le moindre problème, n'hésite pas à contacter notre support." }, en: { title: "Payment successful!", subtitle: "Your subscription is now active", instruction: "To view your new privileges, close this page by tapping the cross at the top of the screen, then tap the \"Refresh\" button once back on the previous page.", invoice: "A confirmation invoice has been sent to your email address.", support: "If you encounter any issues, feel free to contact our support team." } }; const userLang = navigator.language || navigator.userLanguage; const lang = userLang.startsWith('fr') ? 'fr' : 'en'; const t = translations[lang]; document.addEventListener('DOMContentLoaded', function() { document.getElementById('title').textContent = t.title; document.getElementById('subtitle').textContent = t.subtitle; document.getElementById('instruction').textContent = t.instruction; document.getElementById('invoice').textContent = t.invoice; document.getElementById('support').textContent = t.support; }); </script> <div class="min-h-screen flex items-center justify-center px-4"> <div class="max-w-md w-full bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-8 text-center"> <div class="flex flex-col items-center"> <svg class="checkmark mb-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52"> <circle class="checkmark-circle" cx="26" cy="26" r="25" fill="none"/> <path class="checkmark-check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8"/> </svg> <h2 id="title" class="text-2xl font-semibold text-gray-900 dark:text-white mb-2"> Paiement réussi ! </h2> <p id="subtitle" class="text-lg font-medium text-green-600 dark:text-green-400 mb-4"> Ton abonnement est maintenant actif </p> <div class="w-full bg-gray-100 dark:bg-gray-700 rounded-lg p-4 mb-4"> <p id="instruction" class="text-sm text-gray-700 dark:text-gray-300 mb-3"> Pour visualiser tes nouveaux privilèges, ferme cette page en appuyant sur la croix située en haut de l'écran, puis appuie sur le bouton "Rafraîchir" une fois de retour sur la page précédente. </p> <p id="invoice" class="text-sm text-gray-600 dark:text-gray-400 mb-2"> Une facture de confirmation a été envoyée à ton adresse e-mail. </p> <p id="support" class="text-xs text-gray-500 dark:text-gray-500"> Si tu rencontres le moindre problème, n'hésite pas à contacter notre support. </p> </div> </div> </div> </div> <script> setTimeout(function() { if (window.ReactNativeWebView) { window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'subscription_success', success: true })); } else { window.close(); } }, 2000); </script> </body> </html>PK Q7�[��mo� � subscription.phpnu �[��� <?php session_start(); require_once 'db.php'; require_once 'verify-sso.php'; $sso_token = $_GET['sso_token'] ?? ''; if (empty($sso_token)) { die('Token SSO manquant'); } $sso_verification = verifySSO($sso_token); if (!$sso_verification['valid']) { die('Token SSO invalide ou expiré'); } $resident_id = $sso_verification['user_id']; $_SESSION['resident_id'] = $resident_id; $_SESSION['sso_auth'] = true; $stmt = $conn->prepare("SELECT * FROM residents WHERE id = ?"); $stmt->bind_param("i", $resident_id); $stmt->execute(); $resident = $stmt->get_result()->fetch_assoc(); if (!$resident) { die('Utilisateur introuvable'); } $existing_sub = $conn->prepare("SELECT * FROM subscriptions WHERE resident_id = ? AND status IN ('active', 'trialing')"); $existing_sub->bind_param("i", $resident_id); $existing_sub->execute(); $subscription = $existing_sub->get_result()->fetch_assoc(); if ($subscription) { ?> <!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Abonnement actif</title> </head> <body> <script> if (window.ReactNativeWebView) { window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'subscription_already_active', success: true })); } else { window.close(); } </script> </body> </html> <?php exit; } $stripe_config = require 'config/stripe.php'; $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => "https://api.stripe.com/v1/checkout/sessions", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . $stripe_config['secret_key'], "Content-Type: application/x-www-form-urlencoded" ], CURLOPT_POSTFIELDS => http_build_query([ 'mode' => 'subscription', 'line_items[0][price]' => $stripe_config['price_id'], 'line_items[0][quantity]' => 1, 'success_url' => 'https://imators.systems/vertchasseur/success.php?session_id={CHECKOUT_SESSION_ID}', 'cancel_url' => 'https://imators.systems/vertchasseur/cancel.php', 'customer_email' => $resident['email'], 'client_reference_id' => $resident_id, 'metadata[resident_id]' => $resident_id, 'allow_promotion_codes' => 'true', 'billing_address_collection' => 'auto', 'payment_method_types[0]' => 'card', 'subscription_data[metadata][resident_id]' => $resident_id ]) ]); $response = curl_exec($curl); $error = curl_error($curl); curl_close($curl); if ($error) { die("Erreur Stripe: " . $error); } $session = json_decode($response, true); if (isset($session['error'])) { die("Erreur Stripe: " . $session['error']['message']); } header('Location: ' . $session['url']); exit;PK Q7�[H��e e composer.jsonnu �Iw�� { "require": { "stripe/stripe-php": "^18.0", "firebase/php-jwt": "^6.11" } } PK Q7�[�.���! �! db.phpnu �Iw�� <?php $db_host = "localhost:3306"; $db_name = "gqdcvggs_vertchasseur"; $db_user = "gqdcvggs"; $db_pass = "imators_onlyforcpanelmachineforallwebsite***#@&&*SECURITY"; try { $conn = mysqli_connect($db_host, $db_user, $db_pass, $db_name); if (!$conn) { throw new Exception("La connexion à la base de données a échoué : " . mysqli_connect_error()); } mysqli_set_charset($conn, "utf8mb4"); } catch (Exception $e) { error_log("Erreur de base de données : " . $e->getMessage()); die("Une erreur est survenue lors de la connexion à la base de données. Veuillez réessayer plus tard."); } ini_set('display_errors', 0); error_reporting(E_ALL); function clean_input($data) { global $conn; $data = trim($data); $data = stripslashes($data); $data = htmlspecialchars($data); return mysqli_real_escape_string($conn, $data); } class Database { private static $instance = null; private $connection; private $mysqli_conn; private function __construct() { global $conn, $db_host, $db_name, $db_user, $db_pass; $this->mysqli_conn = $conn; try { $this->connection = new PDO( "mysql:host=" . str_replace(':3306', '', $db_host) . ";dbname=" . $db_name . ";charset=utf8mb4", $db_user, $db_pass, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false ] ); } catch(PDOException $e) { error_log("Erreur de connexion PDO : " . $e->getMessage()); die("Erreur de connexion : " . $e->getMessage()); } } public function getMysqliConnection() { return $this->mysqli_conn; } public static function getInstance() { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } public function getConnection() { return $this->connection; } public function query($sql, $params = []) { try { $stmt = $this->connection->prepare($sql); $stmt->execute($params); return $stmt; } catch(PDOException $e) { error_log("Erreur SQL : " . $e->getMessage()); error_log("SQL : " . $sql); error_log("Params : " . print_r($params, true)); throw $e; } } public function fetchAll($sql, $params = []) { return $this->query($sql, $params)->fetchAll(); } public function fetchOne($sql, $params = []) { return $this->query($sql, $params)->fetch(); } public function insert($table, $data) { $fields = array_keys($data); $placeholders = ':' . implode(', :', $fields); $sql = "INSERT INTO {$table} (" . implode(', ', $fields) . ") VALUES ({$placeholders})"; $params = []; foreach ($data as $key => $value) { $params[':' . $key] = $value; } $stmt = $this->query($sql, $params); return $this->connection->lastInsertId(); } public function update($table, $data, $where, $whereParams = []) { $setClause = []; $params = []; foreach ($data as $field => $value) { $setClause[] = "{$field} = ?"; $params[] = $value; } $sql = "UPDATE {$table} SET " . implode(', ', $setClause) . " WHERE {$where}"; foreach ($whereParams as $param) { $params[] = $param; } return $this->query($sql, $params); } public function delete($table, $where, $whereParams = []) { $sql = "DELETE FROM {$table} WHERE {$where}"; return $this->query($sql, $whereParams); } public function getConfig($key) { try { $result = $this->fetchOne("SELECT valeur FROM vr_config WHERE cle = ?", [$key]); return $result ? $result['valeur'] : null; } catch (Exception $e) { error_log("Erreur getConfig pour clé '$key': " . $e->getMessage()); return null; } } public function setConfig($key, $value) { try { $existing = $this->getConfig($key); if ($existing !== null) { $this->query("UPDATE vr_config SET valeur = ? WHERE cle = ?", [$value, $key]); } else { $this->query("INSERT INTO vr_config (cle, valeur) VALUES (?, ?)", [$key, $value]); } return true; } catch (Exception $e) { error_log("Erreur setConfig pour clé '$key': " . $e->getMessage()); return false; } } public function tableExists($tableName) { try { $result = $this->fetchOne("SHOW TABLES LIKE ?", [$tableName]); return $result !== false; } catch (Exception $e) { return false; } } public function beginTransaction() { return $this->connection->beginTransaction(); } public function commit() { return $this->connection->commit(); } public function rollback() { return $this->connection->rollback(); } } function db() { return Database::getInstance(); } function getStripeKeys() { $mode = db()->getConfig('stripe_mode') ?: 'demo'; if ($mode === 'prod') { return [ 'public' => db()->getConfig('stripe_public_key_prod') ?: '', 'secret' => db()->getConfig('stripe_secret_key_prod') ?: '' ]; } else { return [ 'public' => db()->getConfig('stripe_public_key_demo') ?: '', 'secret' => db()->getConfig('stripe_secret_key_demo') ?: '' ]; } } function calculateDistance($lat1, $lon1, $lat2, $lon2) { $earthRadius = 6371; $lat1Rad = deg2rad($lat1); $lon1Rad = deg2rad($lon1); $lat2Rad = deg2rad($lat2); $lon2Rad = deg2rad($lon2); $deltaLat = $lat2Rad - $lat1Rad; $deltaLon = $lon2Rad - $lon1Rad; $a = sin($deltaLat/2) * sin($deltaLat/2) + cos($lat1Rad) * cos($lat2Rad) * sin($deltaLon/2) * sin($deltaLon/2); $c = 2 * atan2(sqrt($a), sqrt(1-$a)); return $earthRadius * $c; } function calculateDeliveryFees($distance, $nbArticles) { $fraisDistance = $distance * 4.99; $fraisArticles = $nbArticles * 0.010; return round($fraisDistance + $fraisArticles, 2); } function isValidAddress($address) { $address = strtolower(trim($address)); return (strpos($address, 'uccle') !== false || strpos($address, 'fort jaco') !== false); } function sanitizeInput($input) { return htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8'); } function generateCSRFToken() { if (session_status() === PHP_SESSION_NONE) { session_start(); } if (!isset($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } return $_SESSION['csrf_token']; } function verifyCSRFToken($token) { if (session_status() === PHP_SESSION_NONE) { session_start(); } return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token); } function logError($message, $data = null) { $logMessage = "[" . date('Y-m-d H:i:s') . "] " . $message; if ($data) { $logMessage .= " - Data: " . print_r($data, true); } error_log($logMessage); } function createTablesIfNotExist() { try { $db = db(); if (!$db->tableExists('vr_config')) { $sql = " CREATE TABLE vr_config ( id INT AUTO_INCREMENT PRIMARY KEY, cle VARCHAR(100) UNIQUE NOT NULL, valeur TEXT NOT NULL, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); INSERT INTO vr_config (cle, valeur) VALUES ('stripe_mode', 'demo'), ('stripe_public_key_demo', ''), ('stripe_secret_key_demo', ''), ('stripe_public_key_prod', ''), ('stripe_secret_key_prod', ''), ('onesignal_app_id', ''), ('onesignal_api_key', ''); "; $db->getConnection()->exec($sql); logError("Table vr_config créée avec succès"); } } catch (Exception $e) { logError("Erreur création tables : " . $e->getMessage()); } } createTablesIfNotExist(); ?>PK Q7�[�N��� � cancel.phpnu �[��� <!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Paiement annulé</title> <script src="https://cdn.tailwindcss.com"></script> <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap" rel="stylesheet"> <style> body { font-family: 'Poppins', sans-serif; } </style> </head> <body class="bg-gray-50 dark:bg-gray-900"> <script> if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) { document.documentElement.classList.add('dark'); } </script> <div class="min-h-screen flex items-center justify-center px-4"> <div class="max-w-md w-full bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-8 text-center"> <svg class="w-20 h-20 text-orange-500 mx-auto mb-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/> </svg> <h2 class="text-2xl font-semibold text-gray-900 dark:text-white mb-2"> Paiement annulé </h2> <p class="text-gray-600 dark:text-gray-400 mb-6"> Vous pouvez réessayer plus tard. Fermer cette page à l'aide de la croix situer en haut de l'écran. </p> </div> </div> <script> setTimeout(function() { if (window.ReactNativeWebView) { window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'subscription_cancelled', success: false })); } else { window.close(); } }, 2000); </script> </body> </html>PK Q7�[Zqc verify-sso.phpnu �[��� <?php require_once __DIR__ . '/vendor/autoload.php'; use Firebase\JWT\JWT; use Firebase\JWT\Key; $secret_key = "CEE78934B6D2219F29A7977363453"; function verifySSO($token) { global $secret_key; try { $decoded = JWT::decode($token, new Key($secret_key, 'HS256')); return [ 'valid' => true, 'user_id' => $decoded->user_id ]; } catch (Exception $e) { return [ 'valid' => false, 'error' => $e->getMessage() ]; } }PK Q7�[�@Jaџ џ error_lognu �[��� [10-Oct-2025 21:55:05 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [10-Oct-2025 21:55:05 UTC] SQL : SHOW TABLES LIKE ? [10-Oct-2025 21:55:05 UTC] Params : Array ( [0] => vr_config ) [10-Oct-2025 21:55:05 UTC] [2025-10-10 21:55:05] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [10-Oct-2025 21:55:05 UTC] PHP Fatal error: Uncaught mysqli_sql_exception: Table 'gqdcvggs_vertchasseur.sso_tokens' doesn't exist in /home/gqdcvggs/imators.systems/vertchasseur/manage-subscription.php:12 Stack trace: #0 /home/gqdcvggs/imators.systems/vertchasseur/manage-subscription.php(12): mysqli->prepare('SELECT resident...') #1 {main} thrown in /home/gqdcvggs/imators.systems/vertchasseur/manage-subscription.php on line 12 [15-Oct-2025 06:55:21 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [15-Oct-2025 06:55:21 UTC] SQL : SHOW TABLES LIKE ? [15-Oct-2025 06:55:21 UTC] Params : Array ( [0] => vr_config ) [15-Oct-2025 06:55:21 UTC] [2025-10-15 06:55:21] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [16-Oct-2025 09:39:48 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [16-Oct-2025 09:39:48 UTC] SQL : SHOW TABLES LIKE ? [16-Oct-2025 09:39:48 UTC] Params : Array ( [0] => vr_config ) [16-Oct-2025 09:39:48 UTC] [2025-10-16 09:39:48] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [16-Oct-2025 13:42:36 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [16-Oct-2025 13:42:36 UTC] SQL : SHOW TABLES LIKE ? [16-Oct-2025 13:42:36 UTC] Params : Array ( [0] => vr_config ) [16-Oct-2025 13:42:36 UTC] [2025-10-16 13:42:36] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [25-Oct-2025 04:41:23 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [25-Oct-2025 04:41:23 UTC] SQL : SHOW TABLES LIKE ? [25-Oct-2025 04:41:23 UTC] Params : Array ( [0] => vr_config ) [25-Oct-2025 04:41:23 UTC] [2025-10-25 04:41:23] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [25-Oct-2025 04:41:38 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [25-Oct-2025 04:41:38 UTC] SQL : SHOW TABLES LIKE ? [25-Oct-2025 04:41:38 UTC] Params : Array ( [0] => vr_config ) [25-Oct-2025 04:41:38 UTC] [2025-10-25 04:41:38] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [25-Oct-2025 05:42:47 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [25-Oct-2025 05:42:47 UTC] SQL : SHOW TABLES LIKE ? [25-Oct-2025 05:42:47 UTC] Params : Array ( [0] => vr_config ) [25-Oct-2025 05:42:47 UTC] [2025-10-25 05:42:47] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [25-Oct-2025 09:44:03 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [25-Oct-2025 09:44:03 UTC] SQL : SHOW TABLES LIKE ? [25-Oct-2025 09:44:03 UTC] Params : Array ( [0] => vr_config ) [25-Oct-2025 09:44:03 UTC] [2025-10-25 09:44:03] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [25-Oct-2025 23:45:17 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [25-Oct-2025 23:45:17 UTC] SQL : SHOW TABLES LIKE ? [25-Oct-2025 23:45:17 UTC] Params : Array ( [0] => vr_config ) [25-Oct-2025 23:45:17 UTC] [2025-10-25 23:45:17] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [26-Oct-2025 23:23:18 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [26-Oct-2025 23:23:18 UTC] SQL : SHOW TABLES LIKE ? [26-Oct-2025 23:23:18 UTC] Params : Array ( [0] => vr_config ) [26-Oct-2025 23:23:18 UTC] [2025-10-26 23:23:18] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [27-Oct-2025 23:02:30 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [27-Oct-2025 23:02:30 UTC] SQL : SHOW TABLES LIKE ? [27-Oct-2025 23:02:30 UTC] Params : Array ( [0] => vr_config ) [27-Oct-2025 23:02:30 UTC] [2025-10-27 23:02:30] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [02-Nov-2025 19:52:27 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [02-Nov-2025 19:52:27 UTC] SQL : SHOW TABLES LIKE ? [02-Nov-2025 19:52:27 UTC] Params : Array ( [0] => vr_config ) [02-Nov-2025 19:52:27 UTC] [2025-11-02 19:52:27] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [02-Nov-2025 19:55:25 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [02-Nov-2025 19:55:25 UTC] SQL : SHOW TABLES LIKE ? [02-Nov-2025 19:55:25 UTC] Params : Array ( [0] => vr_config ) [02-Nov-2025 19:55:25 UTC] [2025-11-02 19:55:25] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [02-Nov-2025 19:55:26 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [02-Nov-2025 19:55:26 UTC] SQL : SHOW TABLES LIKE ? [02-Nov-2025 19:55:26 UTC] Params : Array ( [0] => vr_config ) [02-Nov-2025 19:55:26 UTC] [2025-11-02 19:55:26] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [02-Nov-2025 19:55:27 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [02-Nov-2025 19:55:27 UTC] SQL : SHOW TABLES LIKE ? [02-Nov-2025 19:55:27 UTC] Params : Array ( [0] => vr_config ) [02-Nov-2025 19:55:27 UTC] [2025-11-02 19:55:27] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [02-Nov-2025 19:55:42 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [02-Nov-2025 19:55:42 UTC] SQL : SHOW TABLES LIKE ? [02-Nov-2025 19:55:42 UTC] Params : Array ( [0] => vr_config ) [02-Nov-2025 19:55:42 UTC] [2025-11-02 19:55:42] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [02-Nov-2025 20:54:50 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [02-Nov-2025 20:54:50 UTC] SQL : SHOW TABLES LIKE ? [02-Nov-2025 20:54:50 UTC] Params : Array ( [0] => vr_config ) [02-Nov-2025 20:54:50 UTC] [2025-11-02 20:54:50] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [02-Nov-2025 20:55:37 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [02-Nov-2025 20:55:37 UTC] SQL : SHOW TABLES LIKE ? [02-Nov-2025 20:55:37 UTC] Params : Array ( [0] => vr_config ) [02-Nov-2025 20:55:37 UTC] [2025-11-02 20:55:37] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [02-Nov-2025 22:57:19 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [02-Nov-2025 22:57:19 UTC] SQL : SHOW TABLES LIKE ? [02-Nov-2025 22:57:19 UTC] Params : Array ( [0] => vr_config ) [02-Nov-2025 22:57:19 UTC] [2025-11-02 22:57:19] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [03-Nov-2025 00:54:02 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [03-Nov-2025 00:54:02 UTC] SQL : SHOW TABLES LIKE ? [03-Nov-2025 00:54:02 UTC] Params : Array ( [0] => vr_config ) [03-Nov-2025 00:54:02 UTC] [2025-11-03 00:54:02] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [03-Nov-2025 00:54:59 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [03-Nov-2025 00:54:59 UTC] SQL : SHOW TABLES LIKE ? [03-Nov-2025 00:54:59 UTC] Params : Array ( [0] => vr_config ) [03-Nov-2025 00:54:59 UTC] [2025-11-03 00:54:59] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [03-Nov-2025 12:15:43 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [03-Nov-2025 12:15:43 UTC] SQL : SHOW TABLES LIKE ? [03-Nov-2025 12:15:43 UTC] Params : Array ( [0] => vr_config ) [03-Nov-2025 12:15:43 UTC] [2025-11-03 12:15:43] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [03-Nov-2025 12:21:41 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [03-Nov-2025 12:21:41 UTC] SQL : SHOW TABLES LIKE ? [03-Nov-2025 12:21:41 UTC] Params : Array ( [0] => vr_config ) [03-Nov-2025 12:21:41 UTC] [2025-11-03 12:21:41] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [03-Nov-2025 12:21:42 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [03-Nov-2025 12:21:42 UTC] SQL : SHOW TABLES LIKE ? [03-Nov-2025 12:21:42 UTC] Params : Array ( [0] => vr_config ) [03-Nov-2025 12:21:42 UTC] [2025-11-03 12:21:42] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [03-Nov-2025 12:21:58 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [03-Nov-2025 12:21:58 UTC] SQL : SHOW TABLES LIKE ? [03-Nov-2025 12:21:58 UTC] Params : Array ( [0] => vr_config ) [03-Nov-2025 12:21:58 UTC] [2025-11-03 12:21:58] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [03-Nov-2025 12:22:05 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [03-Nov-2025 12:22:05 UTC] SQL : SHOW TABLES LIKE ? [03-Nov-2025 12:22:05 UTC] Params : Array ( [0] => vr_config ) [03-Nov-2025 12:22:05 UTC] [2025-11-03 12:22:05] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [03-Nov-2025 13:21:30 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [03-Nov-2025 13:21:30 UTC] SQL : SHOW TABLES LIKE ? [03-Nov-2025 13:21:30 UTC] Params : Array ( [0] => vr_config ) [03-Nov-2025 13:21:30 UTC] [2025-11-03 13:21:30] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [03-Nov-2025 13:21:37 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [03-Nov-2025 13:21:37 UTC] SQL : SHOW TABLES LIKE ? [03-Nov-2025 13:21:37 UTC] Params : Array ( [0] => vr_config ) [03-Nov-2025 13:21:37 UTC] [2025-11-03 13:21:37] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [03-Nov-2025 15:00:48 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [03-Nov-2025 15:00:48 UTC] SQL : SHOW TABLES LIKE ? [03-Nov-2025 15:00:48 UTC] Params : Array ( [0] => vr_config ) [03-Nov-2025 15:00:48 UTC] [2025-11-03 15:00:48] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [03-Nov-2025 15:21:35 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [03-Nov-2025 15:21:35 UTC] SQL : SHOW TABLES LIKE ? [03-Nov-2025 15:21:35 UTC] Params : Array ( [0] => vr_config ) [03-Nov-2025 15:21:35 UTC] [2025-11-03 15:21:35] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [03-Nov-2025 16:50:09 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [03-Nov-2025 16:50:09 UTC] SQL : SHOW TABLES LIKE ? [03-Nov-2025 16:50:09 UTC] Params : Array ( [0] => vr_config ) [03-Nov-2025 16:50:09 UTC] [2025-11-03 16:50:09] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [03-Nov-2025 17:22:33 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [03-Nov-2025 17:22:33 UTC] SQL : SHOW TABLES LIKE ? [03-Nov-2025 17:22:33 UTC] Params : Array ( [0] => vr_config ) [03-Nov-2025 17:22:33 UTC] [2025-11-03 17:22:33] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [03-Nov-2025 17:24:28 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [03-Nov-2025 17:24:28 UTC] SQL : SHOW TABLES LIKE ? [03-Nov-2025 17:24:28 UTC] Params : Array ( [0] => vr_config ) [03-Nov-2025 17:24:28 UTC] [2025-11-03 17:24:28] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [04-Nov-2025 07:32:17 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [04-Nov-2025 07:32:17 UTC] SQL : SHOW TABLES LIKE ? [04-Nov-2025 07:32:17 UTC] Params : Array ( [0] => vr_config ) [04-Nov-2025 07:32:17 UTC] [2025-11-04 07:32:17] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [04-Nov-2025 09:14:39 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [04-Nov-2025 09:14:39 UTC] SQL : SHOW TABLES LIKE ? [04-Nov-2025 09:14:39 UTC] Params : Array ( [0] => vr_config ) [04-Nov-2025 09:14:39 UTC] [2025-11-04 09:14:39] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [04-Nov-2025 11:48:12 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [04-Nov-2025 11:48:12 UTC] SQL : SHOW TABLES LIKE ? [04-Nov-2025 11:48:12 UTC] Params : Array ( [0] => vr_config ) [04-Nov-2025 11:48:12 UTC] [2025-11-04 11:48:12] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [04-Nov-2025 11:48:33 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [04-Nov-2025 11:48:33 UTC] SQL : SHOW TABLES LIKE ? [04-Nov-2025 11:48:33 UTC] Params : Array ( [0] => vr_config ) [04-Nov-2025 11:48:33 UTC] [2025-11-04 11:48:33] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [04-Nov-2025 11:48:34 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [04-Nov-2025 11:48:34 UTC] SQL : SHOW TABLES LIKE ? [04-Nov-2025 11:48:34 UTC] Params : Array ( [0] => vr_config ) [04-Nov-2025 11:48:34 UTC] [2025-11-04 11:48:34] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [04-Nov-2025 11:48:34 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [04-Nov-2025 11:48:34 UTC] SQL : SHOW TABLES LIKE ? [04-Nov-2025 11:48:34 UTC] Params : Array ( [0] => vr_config ) [04-Nov-2025 11:48:34 UTC] [2025-11-04 11:48:34] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [04-Nov-2025 11:48:47 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [04-Nov-2025 11:48:47 UTC] SQL : SHOW TABLES LIKE ? [04-Nov-2025 11:48:47 UTC] Params : Array ( [0] => vr_config ) [04-Nov-2025 11:48:47 UTC] [2025-11-04 11:48:47] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [04-Nov-2025 12:47:42 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [04-Nov-2025 12:47:42 UTC] SQL : SHOW TABLES LIKE ? [04-Nov-2025 12:47:42 UTC] Params : Array ( [0] => vr_config ) [04-Nov-2025 12:47:42 UTC] [2025-11-04 12:47:42] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [04-Nov-2025 12:48:02 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [04-Nov-2025 12:48:02 UTC] SQL : SHOW TABLES LIKE ? [04-Nov-2025 12:48:02 UTC] Params : Array ( [0] => vr_config ) [04-Nov-2025 12:48:02 UTC] [2025-11-04 12:48:02] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [04-Nov-2025 14:50:00 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [04-Nov-2025 14:50:00 UTC] SQL : SHOW TABLES LIKE ? [04-Nov-2025 14:50:00 UTC] Params : Array ( [0] => vr_config ) [04-Nov-2025 14:50:00 UTC] [2025-11-04 14:50:00] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [04-Nov-2025 15:22:48 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [04-Nov-2025 15:22:48 UTC] SQL : SHOW TABLES LIKE ? [04-Nov-2025 15:22:48 UTC] Params : Array ( [0] => vr_config ) [04-Nov-2025 15:22:48 UTC] [2025-11-04 15:22:48] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [04-Nov-2025 16:25:56 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [04-Nov-2025 16:25:56 UTC] SQL : SHOW TABLES LIKE ? [04-Nov-2025 16:25:56 UTC] Params : Array ( [0] => vr_config ) [04-Nov-2025 16:25:56 UTC] [2025-11-04 16:25:56] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [04-Nov-2025 16:47:36 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [04-Nov-2025 16:47:36 UTC] SQL : SHOW TABLES LIKE ? [04-Nov-2025 16:47:36 UTC] Params : Array ( [0] => vr_config ) [04-Nov-2025 16:47:36 UTC] [2025-11-04 16:47:36] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [04-Nov-2025 16:50:07 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [04-Nov-2025 16:50:07 UTC] SQL : SHOW TABLES LIKE ? [04-Nov-2025 16:50:07 UTC] Params : Array ( [0] => vr_config ) [04-Nov-2025 16:50:07 UTC] [2025-11-04 16:50:07] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [05-Nov-2025 06:37:48 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [05-Nov-2025 06:37:48 UTC] SQL : SHOW TABLES LIKE ? [05-Nov-2025 06:37:48 UTC] Params : Array ( [0] => vr_config ) [05-Nov-2025 06:37:48 UTC] [2025-11-05 06:37:48] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [05-Nov-2025 07:28:24 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [05-Nov-2025 07:28:24 UTC] SQL : SHOW TABLES LIKE ? [05-Nov-2025 07:28:24 UTC] Params : Array ( [0] => vr_config ) [05-Nov-2025 07:28:24 UTC] [2025-11-05 07:28:24] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [05-Nov-2025 09:02:06 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [05-Nov-2025 09:02:06 UTC] SQL : SHOW TABLES LIKE ? [05-Nov-2025 09:02:06 UTC] Params : Array ( [0] => vr_config ) [05-Nov-2025 09:02:06 UTC] [2025-11-05 09:02:06] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [05-Nov-2025 09:20:34 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [05-Nov-2025 09:20:34 UTC] SQL : SHOW TABLES LIKE ? [05-Nov-2025 09:20:34 UTC] Params : Array ( [0] => vr_config ) [05-Nov-2025 09:20:34 UTC] [2025-11-05 09:20:34] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [05-Nov-2025 15:46:00 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [05-Nov-2025 15:46:00 UTC] SQL : SHOW TABLES LIKE ? [05-Nov-2025 15:46:00 UTC] Params : Array ( [0] => vr_config ) [05-Nov-2025 15:46:00 UTC] [2025-11-05 15:46:00] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [05-Nov-2025 16:37:23 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [05-Nov-2025 16:37:23 UTC] SQL : SHOW TABLES LIKE ? [05-Nov-2025 16:37:23 UTC] Params : Array ( [0] => vr_config ) [05-Nov-2025 16:37:23 UTC] [2025-11-05 16:37:23] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [06-Nov-2025 06:16:57 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [06-Nov-2025 06:16:57 UTC] SQL : SHOW TABLES LIKE ? [06-Nov-2025 06:16:57 UTC] Params : Array ( [0] => vr_config ) [06-Nov-2025 06:16:57 UTC] [2025-11-06 06:16:57] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [06-Nov-2025 07:46:02 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [06-Nov-2025 07:46:02 UTC] SQL : SHOW TABLES LIKE ? [06-Nov-2025 07:46:02 UTC] Params : Array ( [0] => vr_config ) [06-Nov-2025 07:46:02 UTC] [2025-11-06 07:46:02] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [06-Nov-2025 09:19:03 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [06-Nov-2025 09:19:03 UTC] SQL : SHOW TABLES LIKE ? [06-Nov-2025 09:19:03 UTC] Params : Array ( [0] => vr_config ) [06-Nov-2025 09:19:03 UTC] [2025-11-06 09:19:03] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [06-Nov-2025 09:24:06 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [06-Nov-2025 09:24:06 UTC] SQL : SHOW TABLES LIKE ? [06-Nov-2025 09:24:06 UTC] Params : Array ( [0] => vr_config ) [06-Nov-2025 09:24:06 UTC] [2025-11-06 09:24:06] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [06-Nov-2025 12:05:53 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [06-Nov-2025 12:05:53 UTC] SQL : SHOW TABLES LIKE ? [06-Nov-2025 12:05:53 UTC] Params : Array ( [0] => vr_config ) [06-Nov-2025 12:05:53 UTC] [2025-11-06 12:05:53] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [06-Nov-2025 12:10:39 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [06-Nov-2025 12:10:39 UTC] SQL : SHOW TABLES LIKE ? [06-Nov-2025 12:10:39 UTC] Params : Array ( [0] => vr_config ) [06-Nov-2025 12:10:39 UTC] [2025-11-06 12:10:39] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [06-Nov-2025 12:10:40 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [06-Nov-2025 12:10:40 UTC] SQL : SHOW TABLES LIKE ? [06-Nov-2025 12:10:40 UTC] Params : Array ( [0] => vr_config ) [06-Nov-2025 12:10:40 UTC] [2025-11-06 12:10:40] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [06-Nov-2025 12:10:40 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [06-Nov-2025 12:10:40 UTC] SQL : SHOW TABLES LIKE ? [06-Nov-2025 12:10:40 UTC] Params : Array ( [0] => vr_config ) [06-Nov-2025 12:10:40 UTC] [2025-11-06 12:10:40] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [06-Nov-2025 12:10:53 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [06-Nov-2025 12:10:53 UTC] SQL : SHOW TABLES LIKE ? [06-Nov-2025 12:10:53 UTC] Params : Array ( [0] => vr_config ) [06-Nov-2025 12:10:53 UTC] [2025-11-06 12:10:53] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [06-Nov-2025 13:09:43 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [06-Nov-2025 13:09:43 UTC] SQL : SHOW TABLES LIKE ? [06-Nov-2025 13:09:43 UTC] Params : Array ( [0] => vr_config ) [06-Nov-2025 13:09:43 UTC] [2025-11-06 13:09:43] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [06-Nov-2025 13:11:52 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [06-Nov-2025 13:11:52 UTC] SQL : SHOW TABLES LIKE ? [06-Nov-2025 13:11:52 UTC] Params : Array ( [0] => vr_config ) [06-Nov-2025 13:11:52 UTC] [2025-11-06 13:11:52] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [06-Nov-2025 15:13:42 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [06-Nov-2025 15:13:42 UTC] SQL : SHOW TABLES LIKE ? [06-Nov-2025 15:13:42 UTC] Params : Array ( [0] => vr_config ) [06-Nov-2025 15:13:42 UTC] [2025-11-06 15:13:42] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [06-Nov-2025 17:14:18 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [06-Nov-2025 17:14:18 UTC] SQL : SHOW TABLES LIKE ? [06-Nov-2025 17:14:18 UTC] Params : Array ( [0] => vr_config ) [06-Nov-2025 17:14:18 UTC] [2025-11-06 17:14:18] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [06-Nov-2025 17:14:31 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [06-Nov-2025 17:14:31 UTC] SQL : SHOW TABLES LIKE ? [06-Nov-2025 17:14:31 UTC] Params : Array ( [0] => vr_config ) [06-Nov-2025 17:14:31 UTC] [2025-11-06 17:14:31] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [07-Nov-2025 06:17:29 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [07-Nov-2025 06:17:29 UTC] SQL : SHOW TABLES LIKE ? [07-Nov-2025 06:17:29 UTC] Params : Array ( [0] => vr_config ) [07-Nov-2025 06:17:29 UTC] [2025-11-07 06:17:29] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [07-Nov-2025 06:59:38 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [07-Nov-2025 06:59:38 UTC] SQL : SHOW TABLES LIKE ? [07-Nov-2025 06:59:38 UTC] Params : Array ( [0] => vr_config ) [07-Nov-2025 06:59:38 UTC] [2025-11-07 06:59:38] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [07-Nov-2025 08:53:59 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [07-Nov-2025 08:53:59 UTC] SQL : SHOW TABLES LIKE ? [07-Nov-2025 08:53:59 UTC] Params : Array ( [0] => vr_config ) [07-Nov-2025 08:53:59 UTC] [2025-11-07 08:53:59] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [07-Nov-2025 09:05:36 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [07-Nov-2025 09:05:36 UTC] SQL : SHOW TABLES LIKE ? [07-Nov-2025 09:05:36 UTC] Params : Array ( [0] => vr_config ) [07-Nov-2025 09:05:36 UTC] [2025-11-07 09:05:36] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [08-Nov-2025 06:34:08 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [08-Nov-2025 06:34:08 UTC] SQL : SHOW TABLES LIKE ? [08-Nov-2025 06:34:08 UTC] Params : Array ( [0] => vr_config ) [08-Nov-2025 06:34:08 UTC] [2025-11-08 06:34:08] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [08-Nov-2025 08:48:05 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [08-Nov-2025 08:48:05 UTC] SQL : SHOW TABLES LIKE ? [08-Nov-2025 08:48:05 UTC] Params : Array ( [0] => vr_config ) [08-Nov-2025 08:48:05 UTC] [2025-11-08 08:48:05] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [09-Nov-2025 06:48:52 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [09-Nov-2025 06:48:52 UTC] SQL : SHOW TABLES LIKE ? [09-Nov-2025 06:48:52 UTC] Params : Array ( [0] => vr_config ) [09-Nov-2025 06:48:52 UTC] [2025-11-09 06:48:52] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [09-Nov-2025 08:21:37 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [09-Nov-2025 08:21:37 UTC] SQL : SHOW TABLES LIKE ? [09-Nov-2025 08:21:37 UTC] Params : Array ( [0] => vr_config ) [09-Nov-2025 08:21:37 UTC] [2025-11-09 08:21:37] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists [02-Dec-2025 12:11:07 UTC] Erreur de base de données : Access denied for user 'gqdcvggs'@'localhost' (using password: YES) [02-Dec-2025 12:16:38 UTC] Erreur SQL : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?' at line 1 [02-Dec-2025 12:16:38 UTC] SQL : SHOW TABLES LIKE ? [02-Dec-2025 12:16:38 UTC] Params : Array ( [0] => vr_config ) [02-Dec-2025 12:16:38 UTC] [2025-12-02 12:16:38] Erreur création tables : SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'vr_config' already exists PK Q7�[!{ऒ � config/stripe.phpnu �[��� <?php return [ 'secret_key' => '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', 'publishable_key' => 'pk_live_51LmhGsHQanXHoJn0qgKjMAisGwy6TzfZyUnzSq2Yc9qDmAQv8Syu9wuFDZVjgpg8kWUxm9bQ8MMi8E3WwNayGXus00Oe5tyNIP', 'webhook_secret' => 'whsec_CjhJaRbs3dl4mVBw2I8sgSEJAUMX2iE7', 'price_id' => 'price_1S313NHQanXHoJn0kaCs0yKF' ];PK Q7�[���6 �6 manage-subscription.phpnu �[��� <?php session_start(); require_once __DIR__ . '/vendor/autoload.php'; require_once 'db.php'; $stripe_config = require 'config/stripe.php'; \Stripe\Stripe::setApiKey($stripe_config['secret_key']); if (isset($_GET['sso_token'])) { $sso_token = $_GET['sso_token']; $stmt = $conn->prepare("SELECT resident_id, expires_at FROM sso_tokens WHERE token = ? AND used = 0"); $stmt->bind_param("s", $sso_token); $stmt->execute(); $result = $stmt->get_result(); if ($token_data = $result->fetch_assoc()) { if (strtotime($token_data['expires_at']) > time()) { $_SESSION['resident_id'] = $token_data['resident_id']; $update_stmt = $conn->prepare("UPDATE sso_tokens SET used = 1 WHERE token = ?"); $update_stmt->bind_param("s", $sso_token); $update_stmt->execute(); header('Location: manage-subscription.php'); exit; } else { die('Token expiré. Veuillez réessayer.'); } } else { die('Token invalide.'); } } if (!isset($_SESSION['resident_id'])) { header('Location: login.php'); exit; } $resident_id = $_SESSION['resident_id']; $stmt = $conn->prepare("SELECT * FROM residents WHERE id = ?"); $stmt->bind_param("i", $resident_id); $stmt->execute(); $resident = $stmt->get_result()->fetch_assoc(); $sub_stmt = $conn->prepare("SELECT * FROM subscriptions WHERE resident_id = ? ORDER BY created_at DESC LIMIT 1"); $sub_stmt->bind_param("i", $resident_id); $sub_stmt->execute(); $subscription = $sub_stmt->get_result()->fetch_assoc(); if (!$subscription) { header('Location: subscription.php'); exit; } $payments_stmt = $conn->prepare("SELECT * FROM payment_history WHERE resident_id = ? ORDER BY payment_date DESC LIMIT 10"); $payments_stmt->bind_param("i", $resident_id); $payments_stmt->execute(); $payments = $payments_stmt->get_result(); $success_message = ''; $error_message = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { try { if (isset($_POST['action'])) { if ($_POST['action'] === 'cancel_subscription') { $stripe_subscription = \Stripe\Subscription::retrieve($subscription['stripe_subscription_id']); $stripe_subscription->cancel(); $update = $conn->prepare("UPDATE subscriptions SET status = 'canceled', cancel_at_period_end = 1 WHERE id = ?"); $update->bind_param("i", $subscription['id']); $update->execute(); $update_member = $conn->prepare("UPDATE residents SET member_ = 0 WHERE id = ?"); $update_member->bind_param("i", $resident_id); $update_member->execute(); $success_message = 'Abonnement annulé avec succès.'; header('Location: manage-subscription.php?canceled=1'); exit; } if ($_POST['action'] === 'reactivate_subscription') { $stripe_subscription = \Stripe\Subscription::retrieve($subscription['stripe_subscription_id']); \Stripe\Subscription::update($subscription['stripe_subscription_id'], [ 'cancel_at_period_end' => false ]); $update = $conn->prepare("UPDATE subscriptions SET cancel_at_period_end = 0 WHERE id = ?"); $update->bind_param("i", $subscription['id']); $update->execute(); $success_message = 'Abonnement réactivé avec succès.'; header('Location: manage-subscription.php?reactivated=1'); exit; } } } catch (Exception $e) { $error_message = 'Erreur : ' . $e->getMessage(); } } $status_labels = [ 'active' => ['text' => 'Actif', 'class' => 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300'], 'canceled' => ['text' => 'Annulé', 'class' => 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300'], 'past_due' => ['text' => 'Paiement en retard', 'class' => 'bg-orange-100 text-orange-800 dark:bg-orange-900/30 dark:text-orange-300'], 'unpaid' => ['text' => 'Non payé', 'class' => 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300'], 'trialing' => ['text' => 'Période d\'essai', 'class' => 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300'] ]; $current_status = $status_labels[$subscription['status']] ?? ['text' => $subscription['status'], 'class' => 'bg-gray-100 text-gray-800']; ?> <!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Gérer mon abonnement - Vert Chasseur</title> <link rel="icon" type="image/png" href="logo_new.png"> <script src="https://cdn.tailwindcss.com"></script> <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap" rel="stylesheet"> <style> body { font-family: 'Poppins', sans-serif; } </style> </head> <body class="bg-gray-50 dark:bg-gray-900"> <script> if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) { document.documentElement.classList.add('dark'); } </script> <div class="min-h-screen py-12 px-4"> <div class="max-w-4xl mx-auto"> <div class="mb-8"> <a href="https://vertchasseur.be/dashboard.php" class="text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white text-sm inline-flex items-center gap-2 mb-4"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/> </svg> Retour </a> <h1 class="text-3xl font-light text-gray-900 dark:text-white">Gérer mon abonnement</h1> </div> <?php if (isset($_GET['canceled'])): ?> <div class="bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg p-4 mb-6"> <p class="text-green-800 dark:text-green-200">Ton abonnement a été annulé avec succès.</p> </div> <?php endif; ?> <?php if (isset($_GET['reactivated'])): ?> <div class="bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg p-4 mb-6"> <p class="text-green-800 dark:text-green-200">Ton abonnement a été réactivé avec succès.</p> </div> <?php endif; ?> <?php if ($error_message): ?> <div class="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4 mb-6"> <p class="text-red-800 dark:text-red-200"><?= htmlspecialchars($error_message) ?></p> </div> <?php endif; ?> <div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6 md:p-8 mb-6"> <h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-6">Détails de l'abonnement</h2> <div class="space-y-4"> <div class="flex justify-between items-center py-3 border-b border-gray-200 dark:border-gray-700"> <span class="text-gray-600 dark:text-gray-400">Statut</span> <span class="px-3 py-1 rounded-full text-sm font-medium <?= $current_status['class'] ?>"> <?= $current_status['text'] ?> </span> </div> <div class="flex justify-between items-center py-3 border-b border-gray-200 dark:border-gray-700"> <span class="text-gray-600 dark:text-gray-400">Prix</span> <span class="text-gray-900 dark:text-white font-semibold">1,99€ / mois</span> </div> <div class="flex justify-between items-center py-3 border-b border-gray-200 dark:border-gray-700"> <span class="text-gray-600 dark:text-gray-400">Début de période</span> <span class="text-gray-900 dark:text-white"><?= date('d/m/Y', strtotime($subscription['current_period_start'])) ?></span> </div> <div class="flex justify-between items-center py-3 border-b border-gray-200 dark:border-gray-700"> <span class="text-gray-600 dark:text-gray-400">Fin de période</span> <span class="text-gray-900 dark:text-white"><?= date('d/m/Y', strtotime($subscription['current_period_end'])) ?></span> </div> <div class="flex justify-between items-center py-3"> <span class="text-gray-600 dark:text-gray-400">Renouvellement automatique</span> <span class="text-gray-900 dark:text-white"> <?= $subscription['cancel_at_period_end'] ? 'Non' : 'Oui' ?> </span> </div> </div> <?php if ($subscription['status'] === 'active' && !$subscription['cancel_at_period_end']): ?> <form method="POST" onsubmit="return confirm('Es-tu sûr de vouloir annuler ton abonnement ?')" class="mt-8"> <input type="hidden" name="action" value="cancel_subscription"> <button type="submit" class="w-full bg-red-600 hover:bg-red-700 text-white font-semibold py-3 rounded-xl transition-colors duration-200"> Annuler l'abonnement </button> <p class="text-xs text-center text-gray-500 dark:text-gray-400 mt-2"> Tu conserveras l'accès jusqu'au <?= date('d/m/Y', strtotime($subscription['current_period_end'])) ?> </p> </form> <?php elseif ($subscription['cancel_at_period_end']): ?> <form method="POST" class="mt-8"> <input type="hidden" name="action" value="reactivate_subscription"> <button type="submit" class="w-full bg-green-600 hover:bg-green-700 text-white font-semibold py-3 rounded-xl transition-colors duration-200"> Réactiver l'abonnement </button> <p class="text-xs text-center text-gray-500 dark:text-gray-400 mt-2"> Ton abonnement sera automatiquement renouvelé </p> </form> <?php endif; ?> </div> <div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6 md:p-8"> <h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-6">Historique des paiements</h2> <?php if ($payments->num_rows > 0): ?> <div class="overflow-x-auto"> <table class="w-full"> <thead> <tr class="border-b border-gray-200 dark:border-gray-700"> <th class="text-left py-3 px-4 text-gray-600 dark:text-gray-400 font-medium text-sm">Date</th> <th class="text-left py-3 px-4 text-gray-600 dark:text-gray-400 font-medium text-sm">Montant</th> <th class="text-left py-3 px-4 text-gray-600 dark:text-gray-400 font-medium text-sm">Statut</th> </tr> </thead> <tbody> <?php while($payment = $payments->fetch_assoc()): ?> <tr class="border-b border-gray-100 dark:border-gray-700/50"> <td class="py-4 px-4 text-gray-900 dark:text-white"> <?= date('d/m/Y H:i', strtotime($payment['payment_date'])) ?> </td> <td class="py-4 px-4 text-gray-900 dark:text-white font-semibold"> <?= number_format($payment['amount'], 2, ',', ' ') ?>€ </td> <td class="py-4 px-4"> <?php if ($payment['status'] === 'succeeded' || $payment['status'] === 'paid'): ?> <span class="px-3 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300"> Payé </span> <?php else: ?> <span class="px-3 py-1 rounded-full text-xs font-medium bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300"> <?= htmlspecialchars($payment['status']) ?> </span> <?php endif; ?> </td> </tr> <?php endwhile; ?> </tbody> </table> </div> <?php else: ?> <p class="text-center text-gray-500 dark:text-gray-400 py-8"> Aucun paiement enregistré </p> <?php endif; ?> </div> </div> </div> </body> </html>PK Q7�[߾�`� � composer.locknu �Iw�� { "_readme": [ "This file locks the dependencies of your project to a known state", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], "content-hash": "aa2f9115ae5fd5a894c96105cdf9c332", "packages": [ { "name": "firebase/php-jwt", "version": "v6.11.1", "source": { "type": "git", "url": "https://github.com/firebase/php-jwt.git", "reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/firebase/php-jwt/zipball/d1e91ecf8c598d073d0995afa8cd5c75c6e19e66", "reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66", "shasum": "" }, "require": { "php": "^8.0" }, "require-dev": { "guzzlehttp/guzzle": "^7.4", "phpspec/prophecy-phpunit": "^2.0", "phpunit/phpunit": "^9.5", "psr/cache": "^2.0||^3.0", "psr/http-client": "^1.0", "psr/http-factory": "^1.0" }, "suggest": { "ext-sodium": "Support EdDSA (Ed25519) signatures", "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" }, "type": "library", "autoload": { "psr-4": { "Firebase\\JWT\\": "src" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Neuman Vong", "email": "neuman+pear@twilio.com", "role": "Developer" }, { "name": "Anant Narayanan", "email": "anant@php.net", "role": "Developer" } ], "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", "homepage": "https://github.com/firebase/php-jwt", "keywords": [ "jwt", "php" ], "support": { "issues": "https://github.com/firebase/php-jwt/issues", "source": "https://github.com/firebase/php-jwt/tree/v6.11.1" }, "time": "2025-04-09T20:32:01+00:00" }, { "name": "stripe/stripe-php", "version": "v18.0.0", "source": { "type": "git", "url": "https://github.com/stripe/stripe-php.git", "reference": "70d6c286f0eca002b60ccd62afa7140c43c14bbb" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/stripe/stripe-php/zipball/70d6c286f0eca002b60ccd62afa7140c43c14bbb", "reference": "70d6c286f0eca002b60ccd62afa7140c43c14bbb", "shasum": "" }, "require": { "ext-curl": "*", "ext-json": "*", "ext-mbstring": "*", "php": ">=5.6.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "3.72.0", "phpstan/phpstan": "^1.2", "phpunit/phpunit": "^5.7 || ^9.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "2.0-dev" } }, "autoload": { "psr-4": { "Stripe\\": "lib/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Stripe and contributors", "homepage": "https://github.com/stripe/stripe-php/contributors" } ], "description": "Stripe PHP Library", "homepage": "https://stripe.com/", "keywords": [ "api", "payment processing", "stripe" ], "support": { "issues": "https://github.com/stripe/stripe-php/issues", "source": "https://github.com/stripe/stripe-php/tree/v18.0.0" }, "time": "2025-09-30T22:56:22+00:00" } ], "packages-dev": [], "aliases": [], "minimum-stability": "stable", "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": {}, "platform-dev": {}, "plugin-api-version": "2.6.0" } PK Q7�[T,�� � % vendor/firebase/php-jwt/composer.jsonnu �Iw�� { "name": "firebase/php-jwt", "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", "homepage": "https://github.com/firebase/php-jwt", "keywords": [ "php", "jwt" ], "authors": [ { "name": "Neuman Vong", "email": "neuman+pear@twilio.com", "role": "Developer" }, { "name": "Anant Narayanan", "email": "anant@php.net", "role": "Developer" } ], "license": "BSD-3-Clause", "require": { "php": "^8.0" }, "suggest": { "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present", "ext-sodium": "Support EdDSA (Ed25519) signatures" }, "autoload": { "psr-4": { "Firebase\\JWT\\": "src" } }, "require-dev": { "guzzlehttp/guzzle": "^7.4", "phpspec/prophecy-phpunit": "^2.0", "phpunit/phpunit": "^9.5", "psr/cache": "^2.0||^3.0", "psr/http-client": "^1.0", "psr/http-factory": "^1.0" } } PK Q7�[��#� � vendor/firebase/php-jwt/LICENSEnu �Iw�� Copyright (c) 2011, Neuman Vong All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. PK Q7�[�S�<f f 9 vendor/firebase/php-jwt/src/SignatureInvalidException.phpnu �Iw�� <?php namespace Firebase\JWT; class SignatureInvalidException extends \UnexpectedValueException { } PK Q7�[��eP- - # vendor/firebase/php-jwt/src/Key.phpnu �Iw�� <?php namespace Firebase\JWT; use InvalidArgumentException; use OpenSSLAsymmetricKey; use OpenSSLCertificate; use TypeError; class Key { /** * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial * @param string $algorithm */ public function __construct( private $keyMaterial, private string $algorithm ) { if ( !\is_string($keyMaterial) && !$keyMaterial instanceof OpenSSLAsymmetricKey && !$keyMaterial instanceof OpenSSLCertificate && !\is_resource($keyMaterial) ) { throw new TypeError('Key material must be a string, resource, or OpenSSLAsymmetricKey'); } if (empty($keyMaterial)) { throw new InvalidArgumentException('Key material must not be empty'); } if (empty($algorithm)) { throw new InvalidArgumentException('Algorithm must not be empty'); } } /** * Return the algorithm valid for this key * * @return string */ public function getAlgorithm(): string { return $this->algorithm; } /** * @return string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate */ public function getKeyMaterial() { return $this->keyMaterial; } } PK Q7�[��r�/ / # vendor/firebase/php-jwt/src/JWK.phpnu �Iw�� <?php namespace Firebase\JWT; use DomainException; use InvalidArgumentException; use UnexpectedValueException; /** * JSON Web Key implementation, based on this spec: * https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41 * * PHP version 5 * * @category Authentication * @package Authentication_JWT * @author Bui Sy Nguyen <nguyenbs@gmail.com> * @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD * @link https://github.com/firebase/php-jwt */ class JWK { private const OID = '1.2.840.10045.2.1'; private const ASN1_OBJECT_IDENTIFIER = 0x06; private const ASN1_SEQUENCE = 0x10; // also defined in JWT private const ASN1_BIT_STRING = 0x03; private const EC_CURVES = [ 'P-256' => '1.2.840.10045.3.1.7', // Len: 64 'secp256k1' => '1.3.132.0.10', // Len: 64 'P-384' => '1.3.132.0.34', // Len: 96 // 'P-521' => '1.3.132.0.35', // Len: 132 (not supported) ]; // For keys with "kty" equal to "OKP" (Octet Key Pair), the "crv" parameter must contain the key subtype. // This library supports the following subtypes: private const OKP_SUBTYPES = [ 'Ed25519' => true, // RFC 8037 ]; /** * Parse a set of JWK keys * * @param array<mixed> $jwks The JSON Web Key Set as an associative array * @param string $defaultAlg The algorithm for the Key object if "alg" is not set in the * JSON Web Key Set * * @return array<string, Key> An associative array of key IDs (kid) to Key objects * * @throws InvalidArgumentException Provided JWK Set is empty * @throws UnexpectedValueException Provided JWK Set was invalid * @throws DomainException OpenSSL failure * * @uses parseKey */ public static function parseKeySet(array $jwks, ?string $defaultAlg = null): array { $keys = []; if (!isset($jwks['keys'])) { throw new UnexpectedValueException('"keys" member must exist in the JWK Set'); } if (empty($jwks['keys'])) { throw new InvalidArgumentException('JWK Set did not contain any keys'); } foreach ($jwks['keys'] as $k => $v) { $kid = isset($v['kid']) ? $v['kid'] : $k; if ($key = self::parseKey($v, $defaultAlg)) { $keys[(string) $kid] = $key; } } if (0 === \count($keys)) { throw new UnexpectedValueException('No supported algorithms found in JWK Set'); } return $keys; } /** * Parse a JWK key * * @param array<mixed> $jwk An individual JWK * @param string $defaultAlg The algorithm for the Key object if "alg" is not set in the * JSON Web Key Set * * @return Key The key object for the JWK * * @throws InvalidArgumentException Provided JWK is empty * @throws UnexpectedValueException Provided JWK was invalid * @throws DomainException OpenSSL failure * * @uses createPemFromModulusAndExponent */ public static function parseKey(array $jwk, ?string $defaultAlg = null): ?Key { if (empty($jwk)) { throw new InvalidArgumentException('JWK must not be empty'); } if (!isset($jwk['kty'])) { throw new UnexpectedValueException('JWK must contain a "kty" parameter'); } if (!isset($jwk['alg'])) { if (\is_null($defaultAlg)) { // The "alg" parameter is optional in a KTY, but an algorithm is required // for parsing in this library. Use the $defaultAlg parameter when parsing the // key set in order to prevent this error. // @see https://datatracker.ietf.org/doc/html/rfc7517#section-4.4 throw new UnexpectedValueException('JWK must contain an "alg" parameter'); } $jwk['alg'] = $defaultAlg; } switch ($jwk['kty']) { case 'RSA': if (!empty($jwk['d'])) { throw new UnexpectedValueException('RSA private keys are not supported'); } if (!isset($jwk['n']) || !isset($jwk['e'])) { throw new UnexpectedValueException('RSA keys must contain values for both "n" and "e"'); } $pem = self::createPemFromModulusAndExponent($jwk['n'], $jwk['e']); $publicKey = \openssl_pkey_get_public($pem); if (false === $publicKey) { throw new DomainException( 'OpenSSL error: ' . \openssl_error_string() ); } return new Key($publicKey, $jwk['alg']); case 'EC': if (isset($jwk['d'])) { // The key is actually a private key throw new UnexpectedValueException('Key data must be for a public key'); } if (empty($jwk['crv'])) { throw new UnexpectedValueException('crv not set'); } if (!isset(self::EC_CURVES[$jwk['crv']])) { throw new DomainException('Unrecognised or unsupported EC curve'); } if (empty($jwk['x']) || empty($jwk['y'])) { throw new UnexpectedValueException('x and y not set'); } $publicKey = self::createPemFromCrvAndXYCoordinates($jwk['crv'], $jwk['x'], $jwk['y']); return new Key($publicKey, $jwk['alg']); case 'OKP': if (isset($jwk['d'])) { // The key is actually a private key throw new UnexpectedValueException('Key data must be for a public key'); } if (!isset($jwk['crv'])) { throw new UnexpectedValueException('crv not set'); } if (empty(self::OKP_SUBTYPES[$jwk['crv']])) { throw new DomainException('Unrecognised or unsupported OKP key subtype'); } if (empty($jwk['x'])) { throw new UnexpectedValueException('x not set'); } // This library works internally with EdDSA keys (Ed25519) encoded in standard base64. $publicKey = JWT::convertBase64urlToBase64($jwk['x']); return new Key($publicKey, $jwk['alg']); case 'oct': if (!isset($jwk['k'])) { throw new UnexpectedValueException('k not set'); } return new Key(JWT::urlsafeB64Decode($jwk['k']), $jwk['alg']); default: break; } return null; } /** * Converts the EC JWK values to pem format. * * @param string $crv The EC curve (only P-256 & P-384 is supported) * @param string $x The EC x-coordinate * @param string $y The EC y-coordinate * * @return string */ private static function createPemFromCrvAndXYCoordinates(string $crv, string $x, string $y): string { $pem = self::encodeDER( self::ASN1_SEQUENCE, self::encodeDER( self::ASN1_SEQUENCE, self::encodeDER( self::ASN1_OBJECT_IDENTIFIER, self::encodeOID(self::OID) ) . self::encodeDER( self::ASN1_OBJECT_IDENTIFIER, self::encodeOID(self::EC_CURVES[$crv]) ) ) . self::encodeDER( self::ASN1_BIT_STRING, \chr(0x00) . \chr(0x04) . JWT::urlsafeB64Decode($x) . JWT::urlsafeB64Decode($y) ) ); return \sprintf( "-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n", wordwrap(base64_encode($pem), 64, "\n", true) ); } /** * Create a public key represented in PEM format from RSA modulus and exponent information * * @param string $n The RSA modulus encoded in Base64 * @param string $e The RSA exponent encoded in Base64 * * @return string The RSA public key represented in PEM format * * @uses encodeLength */ private static function createPemFromModulusAndExponent( string $n, string $e ): string { $mod = JWT::urlsafeB64Decode($n); $exp = JWT::urlsafeB64Decode($e); $modulus = \pack('Ca*a*', 2, self::encodeLength(\strlen($mod)), $mod); $publicExponent = \pack('Ca*a*', 2, self::encodeLength(\strlen($exp)), $exp); $rsaPublicKey = \pack( 'Ca*a*a*', 48, self::encodeLength(\strlen($modulus) + \strlen($publicExponent)), $modulus, $publicExponent ); // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption. $rsaOID = \pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA $rsaPublicKey = \chr(0) . $rsaPublicKey; $rsaPublicKey = \chr(3) . self::encodeLength(\strlen($rsaPublicKey)) . $rsaPublicKey; $rsaPublicKey = \pack( 'Ca*a*', 48, self::encodeLength(\strlen($rsaOID . $rsaPublicKey)), $rsaOID . $rsaPublicKey ); return "-----BEGIN PUBLIC KEY-----\r\n" . \chunk_split(\base64_encode($rsaPublicKey), 64) . '-----END PUBLIC KEY-----'; } /** * DER-encode the length * * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information. * * @param int $length * @return string */ private static function encodeLength(int $length): string { if ($length <= 0x7F) { return \chr($length); } $temp = \ltrim(\pack('N', $length), \chr(0)); return \pack('Ca*', 0x80 | \strlen($temp), $temp); } /** * Encodes a value into a DER object. * Also defined in Firebase\JWT\JWT * * @param int $type DER tag * @param string $value the value to encode * @return string the encoded object */ private static function encodeDER(int $type, string $value): string { $tag_header = 0; if ($type === self::ASN1_SEQUENCE) { $tag_header |= 0x20; } // Type $der = \chr($tag_header | $type); // Length $der .= \chr(\strlen($value)); return $der . $value; } /** * Encodes a string into a DER-encoded OID. * * @param string $oid the OID string * @return string the binary DER-encoded OID */ private static function encodeOID(string $oid): string { $octets = explode('.', $oid); // Get the first octet $first = (int) array_shift($octets); $second = (int) array_shift($octets); $oid = \chr($first * 40 + $second); // Iterate over subsequent octets foreach ($octets as $octet) { if ($octet == 0) { $oid .= \chr(0x00); continue; } $bin = ''; while ($octet) { $bin .= \chr(0x80 | ($octet & 0x7f)); $octet >>= 7; } $bin[0] = $bin[0] & \chr(0x7f); // Convert to big endian if necessary if (pack('V', 65534) == pack('L', 65534)) { $oid .= strrev($bin); } else { $oid .= $bin; } } return $oid; } } PK Q7�[ى��� � @ vendor/firebase/php-jwt/src/JWTExceptionWithPayloadInterface.phpnu �Iw�� <?php namespace Firebase\JWT; interface JWTExceptionWithPayloadInterface { /** * Get the payload that caused this exception. * * @return object */ public function getPayload(): object; /** * Get the payload that caused this exception. * * @param object $payload * @return void */ public function setPayload(object $payload): void; } PK Q7�[����e e 4 vendor/firebase/php-jwt/src/BeforeValidException.phpnu �Iw�� <?php namespace Firebase\JWT; class BeforeValidException extends \UnexpectedValueException implements JWTExceptionWithPayloadInterface { private object $payload; public function setPayload(object $payload): void { $this->payload = $payload; } public function getPayload(): object { return $this->payload; } } PK Q7�[�ht , vendor/firebase/php-jwt/src/CachedKeySet.phpnu �Iw�� <?php namespace Firebase\JWT; use ArrayAccess; use InvalidArgumentException; use LogicException; use OutOfBoundsException; use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemPoolInterface; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; use RuntimeException; use UnexpectedValueException; /** * @implements ArrayAccess<string, Key> */ class CachedKeySet implements ArrayAccess { /** * @var string */ private $jwksUri; /** * @var ClientInterface */ private $httpClient; /** * @var RequestFactoryInterface */ private $httpFactory; /** * @var CacheItemPoolInterface */ private $cache; /** * @var ?int */ private $expiresAfter; /** * @var ?CacheItemInterface */ private $cacheItem; /** * @var array<string, array<mixed>> */ private $keySet; /** * @var string */ private $cacheKey; /** * @var string */ private $cacheKeyPrefix = 'jwks'; /** * @var int */ private $maxKeyLength = 64; /** * @var bool */ private $rateLimit; /** * @var string */ private $rateLimitCacheKey; /** * @var int */ private $maxCallsPerMinute = 10; /** * @var string|null */ private $defaultAlg; public function __construct( string $jwksUri, ClientInterface $httpClient, RequestFactoryInterface $httpFactory, CacheItemPoolInterface $cache, ?int $expiresAfter = null, bool $rateLimit = false, ?string $defaultAlg = null ) { $this->jwksUri = $jwksUri; $this->httpClient = $httpClient; $this->httpFactory = $httpFactory; $this->cache = $cache; $this->expiresAfter = $expiresAfter; $this->rateLimit = $rateLimit; $this->defaultAlg = $defaultAlg; $this->setCacheKeys(); } /** * @param string $keyId * @return Key */ public function offsetGet($keyId): Key { if (!$this->keyIdExists($keyId)) { throw new OutOfBoundsException('Key ID not found'); } return JWK::parseKey($this->keySet[$keyId], $this->defaultAlg); } /** * @param string $keyId * @return bool */ public function offsetExists($keyId): bool { return $this->keyIdExists($keyId); } /** * @param string $offset * @param Key $value */ public function offsetSet($offset, $value): void { throw new LogicException('Method not implemented'); } /** * @param string $offset */ public function offsetUnset($offset): void { throw new LogicException('Method not implemented'); } /** * @return array<mixed> */ private function formatJwksForCache(string $jwks): array { $jwks = json_decode($jwks, true); if (!isset($jwks['keys'])) { throw new UnexpectedValueException('"keys" member must exist in the JWK Set'); } if (empty($jwks['keys'])) { throw new InvalidArgumentException('JWK Set did not contain any keys'); } $keys = []; foreach ($jwks['keys'] as $k => $v) { $kid = isset($v['kid']) ? $v['kid'] : $k; $keys[(string) $kid] = $v; } return $keys; } private function keyIdExists(string $keyId): bool { if (null === $this->keySet) { $item = $this->getCacheItem(); // Try to load keys from cache if ($item->isHit()) { // item found! retrieve it $this->keySet = $item->get(); // If the cached item is a string, the JWKS response was cached (previous behavior). // Parse this into expected format array<kid, jwk> instead. if (\is_string($this->keySet)) { $this->keySet = $this->formatJwksForCache($this->keySet); } } } if (!isset($this->keySet[$keyId])) { if ($this->rateLimitExceeded()) { return false; } $request = $this->httpFactory->createRequest('GET', $this->jwksUri); $jwksResponse = $this->httpClient->sendRequest($request); if ($jwksResponse->getStatusCode() !== 200) { throw new UnexpectedValueException( \sprintf('HTTP Error: %d %s for URI "%s"', $jwksResponse->getStatusCode(), $jwksResponse->getReasonPhrase(), $this->jwksUri, ), $jwksResponse->getStatusCode() ); } $this->keySet = $this->formatJwksForCache((string) $jwksResponse->getBody()); if (!isset($this->keySet[$keyId])) { return false; } $item = $this->getCacheItem(); $item->set($this->keySet); if ($this->expiresAfter) { $item->expiresAfter($this->expiresAfter); } $this->cache->save($item); } return true; } private function rateLimitExceeded(): bool { if (!$this->rateLimit) { return false; } $cacheItem = $this->cache->getItem($this->rateLimitCacheKey); $cacheItemData = []; if ($cacheItem->isHit() && \is_array($data = $cacheItem->get())) { $cacheItemData = $data; } $callsPerMinute = $cacheItemData['callsPerMinute'] ?? 0; $expiry = $cacheItemData['expiry'] ?? new \DateTime('+60 seconds', new \DateTimeZone('UTC')); if (++$callsPerMinute > $this->maxCallsPerMinute) { return true; } $cacheItem->set(['expiry' => $expiry, 'callsPerMinute' => $callsPerMinute]); $cacheItem->expiresAt($expiry); $this->cache->save($cacheItem); return false; } private function getCacheItem(): CacheItemInterface { if (\is_null($this->cacheItem)) { $this->cacheItem = $this->cache->getItem($this->cacheKey); } return $this->cacheItem; } private function setCacheKeys(): void { if (empty($this->jwksUri)) { throw new RuntimeException('JWKS URI is empty'); } // ensure we do not have illegal characters $key = preg_replace('|[^a-zA-Z0-9_\.!]|', '', $this->jwksUri); // add prefix $key = $this->cacheKeyPrefix . $key; // Hash keys if they exceed $maxKeyLength of 64 if (\strlen($key) > $this->maxKeyLength) { $key = substr(hash('sha256', $key), 0, $this->maxKeyLength); } $this->cacheKey = $key; if ($this->rateLimit) { // add prefix $rateLimitKey = $this->cacheKeyPrefix . 'ratelimit' . $key; // Hash keys if they exceed $maxKeyLength of 64 if (\strlen($rateLimitKey) > $this->maxKeyLength) { $rateLimitKey = substr(hash('sha256', $rateLimitKey), 0, $this->maxKeyLength); } $this->rateLimitCacheKey = $rateLimitKey; } } } PK Q7�[Ҧ�a�^ �^ # vendor/firebase/php-jwt/src/JWT.phpnu �Iw�� <?php namespace Firebase\JWT; use ArrayAccess; use DateTime; use DomainException; use Exception; use InvalidArgumentException; use OpenSSLAsymmetricKey; use OpenSSLCertificate; use stdClass; use UnexpectedValueException; /** * JSON Web Token implementation, based on this spec: * https://tools.ietf.org/html/rfc7519 * * PHP version 5 * * @category Authentication * @package Authentication_JWT * @author Neuman Vong <neuman@twilio.com> * @author Anant Narayanan <anant@php.net> * @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD * @link https://github.com/firebase/php-jwt */ class JWT { private const ASN1_INTEGER = 0x02; private const ASN1_SEQUENCE = 0x10; private const ASN1_BIT_STRING = 0x03; /** * When checking nbf, iat or expiration times, * we want to provide some extra leeway time to * account for clock skew. * * @var int */ public static $leeway = 0; /** * Allow the current timestamp to be specified. * Useful for fixing a value within unit testing. * Will default to PHP time() value if null. * * @var ?int */ public static $timestamp = null; /** * @var array<string, string[]> */ public static $supported_algs = [ 'ES384' => ['openssl', 'SHA384'], 'ES256' => ['openssl', 'SHA256'], 'ES256K' => ['openssl', 'SHA256'], 'HS256' => ['hash_hmac', 'SHA256'], 'HS384' => ['hash_hmac', 'SHA384'], 'HS512' => ['hash_hmac', 'SHA512'], 'RS256' => ['openssl', 'SHA256'], 'RS384' => ['openssl', 'SHA384'], 'RS512' => ['openssl', 'SHA512'], 'EdDSA' => ['sodium_crypto', 'EdDSA'], ]; /** * Decodes a JWT string into a PHP object. * * @param string $jwt The JWT * @param Key|ArrayAccess<string,Key>|array<string,Key> $keyOrKeyArray The Key or associative array of key IDs * (kid) to Key objects. * If the algorithm used is asymmetric, this is * the public key. * Each Key object contains an algorithm and * matching key. * Supported algorithms are 'ES384','ES256', * 'HS256', 'HS384', 'HS512', 'RS256', 'RS384' * and 'RS512'. * @param stdClass $headers Optional. Populates stdClass with headers. * * @return stdClass The JWT's payload as a PHP object * * @throws InvalidArgumentException Provided key/key-array was empty or malformed * @throws DomainException Provided JWT is malformed * @throws UnexpectedValueException Provided JWT was invalid * @throws SignatureInvalidException Provided JWT was invalid because the signature verification failed * @throws BeforeValidException Provided JWT is trying to be used before it's eligible as defined by 'nbf' * @throws BeforeValidException Provided JWT is trying to be used before it's been created as defined by 'iat' * @throws ExpiredException Provided JWT has since expired, as defined by the 'exp' claim * * @uses jsonDecode * @uses urlsafeB64Decode */ public static function decode( string $jwt, $keyOrKeyArray, ?stdClass &$headers = null ): stdClass { // Validate JWT $timestamp = \is_null(static::$timestamp) ? \time() : static::$timestamp; if (empty($keyOrKeyArray)) { throw new InvalidArgumentException('Key may not be empty'); } $tks = \explode('.', $jwt); if (\count($tks) !== 3) { throw new UnexpectedValueException('Wrong number of segments'); } list($headb64, $bodyb64, $cryptob64) = $tks; $headerRaw = static::urlsafeB64Decode($headb64); if (null === ($header = static::jsonDecode($headerRaw))) { throw new UnexpectedValueException('Invalid header encoding'); } if ($headers !== null) { $headers = $header; } $payloadRaw = static::urlsafeB64Decode($bodyb64); if (null === ($payload = static::jsonDecode($payloadRaw))) { throw new UnexpectedValueException('Invalid claims encoding'); } if (\is_array($payload)) { // prevent PHP Fatal Error in edge-cases when payload is empty array $payload = (object) $payload; } if (!$payload instanceof stdClass) { throw new UnexpectedValueException('Payload must be a JSON object'); } $sig = static::urlsafeB64Decode($cryptob64); if (empty($header->alg)) { throw new UnexpectedValueException('Empty algorithm'); } if (empty(static::$supported_algs[$header->alg])) { throw new UnexpectedValueException('Algorithm not supported'); } $key = self::getKey($keyOrKeyArray, property_exists($header, 'kid') ? $header->kid : null); // Check the algorithm if (!self::constantTimeEquals($key->getAlgorithm(), $header->alg)) { // See issue #351 throw new UnexpectedValueException('Incorrect key for this algorithm'); } if (\in_array($header->alg, ['ES256', 'ES256K', 'ES384'], true)) { // OpenSSL expects an ASN.1 DER sequence for ES256/ES256K/ES384 signatures $sig = self::signatureToDER($sig); } if (!self::verify("{$headb64}.{$bodyb64}", $sig, $key->getKeyMaterial(), $header->alg)) { throw new SignatureInvalidException('Signature verification failed'); } // Check the nbf if it is defined. This is the time that the // token can actually be used. If it's not yet that time, abort. if (isset($payload->nbf) && floor($payload->nbf) > ($timestamp + static::$leeway)) { $ex = new BeforeValidException( 'Cannot handle token with nbf prior to ' . \date(DateTime::ISO8601, (int) floor($payload->nbf)) ); $ex->setPayload($payload); throw $ex; } // Check that this token has been created before 'now'. This prevents // using tokens that have been created for later use (and haven't // correctly used the nbf claim). if (!isset($payload->nbf) && isset($payload->iat) && floor($payload->iat) > ($timestamp + static::$leeway)) { $ex = new BeforeValidException( 'Cannot handle token with iat prior to ' . \date(DateTime::ISO8601, (int) floor($payload->iat)) ); $ex->setPayload($payload); throw $ex; } // Check if this token has expired. if (isset($payload->exp) && ($timestamp - static::$leeway) >= $payload->exp) { $ex = new ExpiredException('Expired token'); $ex->setPayload($payload); throw $ex; } return $payload; } /** * Converts and signs a PHP array into a JWT string. * * @param array<mixed> $payload PHP array * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key. * @param string $alg Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256', * 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512' * @param string $keyId * @param array<string, string> $head An array with header elements to attach * * @return string A signed JWT * * @uses jsonEncode * @uses urlsafeB64Encode */ public static function encode( array $payload, $key, string $alg, ?string $keyId = null, ?array $head = null ): string { $header = ['typ' => 'JWT']; if (isset($head)) { $header = \array_merge($header, $head); } $header['alg'] = $alg; if ($keyId !== null) { $header['kid'] = $keyId; } $segments = []; $segments[] = static::urlsafeB64Encode((string) static::jsonEncode($header)); $segments[] = static::urlsafeB64Encode((string) static::jsonEncode($payload)); $signing_input = \implode('.', $segments); $signature = static::sign($signing_input, $key, $alg); $segments[] = static::urlsafeB64Encode($signature); return \implode('.', $segments); } /** * Sign a string with a given key and algorithm. * * @param string $msg The message to sign * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key. * @param string $alg Supported algorithms are 'EdDSA', 'ES384', 'ES256', 'ES256K', 'HS256', * 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512' * * @return string An encrypted message * * @throws DomainException Unsupported algorithm or bad key was specified */ public static function sign( string $msg, $key, string $alg ): string { if (empty(static::$supported_algs[$alg])) { throw new DomainException('Algorithm not supported'); } list($function, $algorithm) = static::$supported_algs[$alg]; switch ($function) { case 'hash_hmac': if (!\is_string($key)) { throw new InvalidArgumentException('key must be a string when using hmac'); } return \hash_hmac($algorithm, $msg, $key, true); case 'openssl': $signature = ''; if (!\is_resource($key) && !openssl_pkey_get_private($key)) { throw new DomainException('OpenSSL unable to validate key'); } $success = \openssl_sign($msg, $signature, $key, $algorithm); // @phpstan-ignore-line if (!$success) { throw new DomainException('OpenSSL unable to sign data'); } if ($alg === 'ES256' || $alg === 'ES256K') { $signature = self::signatureFromDER($signature, 256); } elseif ($alg === 'ES384') { $signature = self::signatureFromDER($signature, 384); } return $signature; case 'sodium_crypto': if (!\function_exists('sodium_crypto_sign_detached')) { throw new DomainException('libsodium is not available'); } if (!\is_string($key)) { throw new InvalidArgumentException('key must be a string when using EdDSA'); } try { // The last non-empty line is used as the key. $lines = array_filter(explode("\n", $key)); $key = base64_decode((string) end($lines)); if (\strlen($key) === 0) { throw new DomainException('Key cannot be empty string'); } return sodium_crypto_sign_detached($msg, $key); } catch (Exception $e) { throw new DomainException($e->getMessage(), 0, $e); } } throw new DomainException('Algorithm not supported'); } /** * Verify a signature with the message, key and method. Not all methods * are symmetric, so we must have a separate verify and sign method. * * @param string $msg The original message (header and body) * @param string $signature The original signature * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial For Ed*, ES*, HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey * @param string $alg The algorithm * * @return bool * * @throws DomainException Invalid Algorithm, bad key, or OpenSSL failure */ private static function verify( string $msg, string $signature, $keyMaterial, string $alg ): bool { if (empty(static::$supported_algs[$alg])) { throw new DomainException('Algorithm not supported'); } list($function, $algorithm) = static::$supported_algs[$alg]; switch ($function) { case 'openssl': $success = \openssl_verify($msg, $signature, $keyMaterial, $algorithm); // @phpstan-ignore-line if ($success === 1) { return true; } if ($success === 0) { return false; } // returns 1 on success, 0 on failure, -1 on error. throw new DomainException( 'OpenSSL error: ' . \openssl_error_string() ); case 'sodium_crypto': if (!\function_exists('sodium_crypto_sign_verify_detached')) { throw new DomainException('libsodium is not available'); } if (!\is_string($keyMaterial)) { throw new InvalidArgumentException('key must be a string when using EdDSA'); } try { // The last non-empty line is used as the key. $lines = array_filter(explode("\n", $keyMaterial)); $key = base64_decode((string) end($lines)); if (\strlen($key) === 0) { throw new DomainException('Key cannot be empty string'); } if (\strlen($signature) === 0) { throw new DomainException('Signature cannot be empty string'); } return sodium_crypto_sign_verify_detached($signature, $msg, $key); } catch (Exception $e) { throw new DomainException($e->getMessage(), 0, $e); } case 'hash_hmac': default: if (!\is_string($keyMaterial)) { throw new InvalidArgumentException('key must be a string when using hmac'); } $hash = \hash_hmac($algorithm, $msg, $keyMaterial, true); return self::constantTimeEquals($hash, $signature); } } /** * Decode a JSON string into a PHP object. * * @param string $input JSON string * * @return mixed The decoded JSON string * * @throws DomainException Provided string was invalid JSON */ public static function jsonDecode(string $input) { $obj = \json_decode($input, false, 512, JSON_BIGINT_AS_STRING); if ($errno = \json_last_error()) { self::handleJsonError($errno); } elseif ($obj === null && $input !== 'null') { throw new DomainException('Null result with non-null input'); } return $obj; } /** * Encode a PHP array into a JSON string. * * @param array<mixed> $input A PHP array * * @return string JSON representation of the PHP array * * @throws DomainException Provided object could not be encoded to valid JSON */ public static function jsonEncode(array $input): string { $json = \json_encode($input, \JSON_UNESCAPED_SLASHES); if ($errno = \json_last_error()) { self::handleJsonError($errno); } elseif ($json === 'null') { throw new DomainException('Null result with non-null input'); } if ($json === false) { throw new DomainException('Provided object could not be encoded to valid JSON'); } return $json; } /** * Decode a string with URL-safe Base64. * * @param string $input A Base64 encoded string * * @return string A decoded string * * @throws InvalidArgumentException invalid base64 characters */ public static function urlsafeB64Decode(string $input): string { return \base64_decode(self::convertBase64UrlToBase64($input)); } /** * Convert a string in the base64url (URL-safe Base64) encoding to standard base64. * * @param string $input A Base64 encoded string with URL-safe characters (-_ and no padding) * * @return string A Base64 encoded string with standard characters (+/) and padding (=), when * needed. * * @see https://www.rfc-editor.org/rfc/rfc4648 */ public static function convertBase64UrlToBase64(string $input): string { $remainder = \strlen($input) % 4; if ($remainder) { $padlen = 4 - $remainder; $input .= \str_repeat('=', $padlen); } return \strtr($input, '-_', '+/'); } /** * Encode a string with URL-safe Base64. * * @param string $input The string you want encoded * * @return string The base64 encode of what you passed in */ public static function urlsafeB64Encode(string $input): string { return \str_replace('=', '', \strtr(\base64_encode($input), '+/', '-_')); } /** * Determine if an algorithm has been provided for each Key * * @param Key|ArrayAccess<string,Key>|array<string,Key> $keyOrKeyArray * @param string|null $kid * * @throws UnexpectedValueException * * @return Key */ private static function getKey( $keyOrKeyArray, ?string $kid ): Key { if ($keyOrKeyArray instanceof Key) { return $keyOrKeyArray; } if (empty($kid) && $kid !== '0') { throw new UnexpectedValueException('"kid" empty, unable to lookup correct key'); } if ($keyOrKeyArray instanceof CachedKeySet) { // Skip "isset" check, as this will automatically refresh if not set return $keyOrKeyArray[$kid]; } if (!isset($keyOrKeyArray[$kid])) { throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key'); } return $keyOrKeyArray[$kid]; } /** * @param string $left The string of known length to compare against * @param string $right The user-supplied string * @return bool */ public static function constantTimeEquals(string $left, string $right): bool { if (\function_exists('hash_equals')) { return \hash_equals($left, $right); } $len = \min(self::safeStrlen($left), self::safeStrlen($right)); $status = 0; for ($i = 0; $i < $len; $i++) { $status |= (\ord($left[$i]) ^ \ord($right[$i])); } $status |= (self::safeStrlen($left) ^ self::safeStrlen($right)); return ($status === 0); } /** * Helper method to create a JSON error. * * @param int $errno An error number from json_last_error() * * @throws DomainException * * @return void */ private static function handleJsonError(int $errno): void { $messages = [ JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON', JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON', JSON_ERROR_UTF8 => 'Malformed UTF-8 characters' //PHP >= 5.3.3 ]; throw new DomainException( isset($messages[$errno]) ? $messages[$errno] : 'Unknown JSON error: ' . $errno ); } /** * Get the number of bytes in cryptographic strings. * * @param string $str * * @return int */ private static function safeStrlen(string $str): int { if (\function_exists('mb_strlen')) { return \mb_strlen($str, '8bit'); } return \strlen($str); } /** * Convert an ECDSA signature to an ASN.1 DER sequence * * @param string $sig The ECDSA signature to convert * @return string The encoded DER object */ private static function signatureToDER(string $sig): string { // Separate the signature into r-value and s-value $length = max(1, (int) (\strlen($sig) / 2)); list($r, $s) = \str_split($sig, $length); // Trim leading zeros $r = \ltrim($r, "\x00"); $s = \ltrim($s, "\x00"); // Convert r-value and s-value from unsigned big-endian integers to // signed two's complement if (\ord($r[0]) > 0x7f) { $r = "\x00" . $r; } if (\ord($s[0]) > 0x7f) { $s = "\x00" . $s; } return self::encodeDER( self::ASN1_SEQUENCE, self::encodeDER(self::ASN1_INTEGER, $r) . self::encodeDER(self::ASN1_INTEGER, $s) ); } /** * Encodes a value into a DER object. * * @param int $type DER tag * @param string $value the value to encode * * @return string the encoded object */ private static function encodeDER(int $type, string $value): string { $tag_header = 0; if ($type === self::ASN1_SEQUENCE) { $tag_header |= 0x20; } // Type $der = \chr($tag_header | $type); // Length $der .= \chr(\strlen($value)); return $der . $value; } /** * Encodes signature from a DER object. * * @param string $der binary signature in DER format * @param int $keySize the number of bits in the key * * @return string the signature */ private static function signatureFromDER(string $der, int $keySize): string { // OpenSSL returns the ECDSA signatures as a binary ASN.1 DER SEQUENCE list($offset, $_) = self::readDER($der); list($offset, $r) = self::readDER($der, $offset); list($offset, $s) = self::readDER($der, $offset); // Convert r-value and s-value from signed two's compliment to unsigned // big-endian integers $r = \ltrim($r, "\x00"); $s = \ltrim($s, "\x00"); // Pad out r and s so that they are $keySize bits long $r = \str_pad($r, $keySize / 8, "\x00", STR_PAD_LEFT); $s = \str_pad($s, $keySize / 8, "\x00", STR_PAD_LEFT); return $r . $s; } /** * Reads binary DER-encoded data and decodes into a single object * * @param string $der the binary data in DER format * @param int $offset the offset of the data stream containing the object * to decode * * @return array{int, string|null} the new offset and the decoded object */ private static function readDER(string $der, int $offset = 0): array { $pos = $offset; $size = \strlen($der); $constructed = (\ord($der[$pos]) >> 5) & 0x01; $type = \ord($der[$pos++]) & 0x1f; // Length $len = \ord($der[$pos++]); if ($len & 0x80) { $n = $len & 0x1f; $len = 0; while ($n-- && $pos < $size) { $len = ($len << 8) | \ord($der[$pos++]); } } // Value if ($type === self::ASN1_BIT_STRING) { $pos++; // Skip the first contents octet (padding indicator) $data = \substr($der, $pos, $len - 1); $pos += $len - 1; } elseif (!$constructed) { $data = \substr($der, $pos, $len); $pos += $len; } else { $data = null; } return [$pos, $data]; } } PK Q7�[7'�ha a 0 vendor/firebase/php-jwt/src/ExpiredException.phpnu �Iw�� <?php namespace Firebase\JWT; class ExpiredException extends \UnexpectedValueException implements JWTExceptionWithPayloadInterface { private object $payload; public function setPayload(object $payload): void { $this->payload = $payload; } public function getPayload(): object { return $this->payload; } } PK Q7�[�D�( �( $ vendor/firebase/php-jwt/CHANGELOG.mdnu �Iw�� # Changelog ## [6.11.1](https://github.com/firebase/php-jwt/compare/v6.11.0...v6.11.1) (2025-04-09) ### Bug Fixes * update error text for consistency ([#528](https://github.com/firebase/php-jwt/issues/528)) ([c11113a](https://github.com/firebase/php-jwt/commit/c11113afa13265e016a669e75494b9203b8a7775)) ## [6.11.0](https://github.com/firebase/php-jwt/compare/v6.10.2...v6.11.0) (2025-01-23) ### Features * support octet typed JWK ([#587](https://github.com/firebase/php-jwt/issues/587)) ([7cb8a26](https://github.com/firebase/php-jwt/commit/7cb8a265fa81edf2fa6ef8098f5bc5ae573c33ad)) ### Bug Fixes * refactor constructor Key to use PHP 8.0 syntax ([#577](https://github.com/firebase/php-jwt/issues/577)) ([29fa2ce](https://github.com/firebase/php-jwt/commit/29fa2ce9e0582cd397711eec1e80c05ce20fabca)) ## [6.10.2](https://github.com/firebase/php-jwt/compare/v6.10.1...v6.10.2) (2024-11-24) ### Bug Fixes * Mitigate PHP8.4 deprecation warnings ([#570](https://github.com/firebase/php-jwt/issues/570)) ([76808fa](https://github.com/firebase/php-jwt/commit/76808fa227f3811aa5cdb3bf81233714b799a5b5)) * support php 8.4 ([#583](https://github.com/firebase/php-jwt/issues/583)) ([e3d68b0](https://github.com/firebase/php-jwt/commit/e3d68b044421339443c74199edd020e03fb1887e)) ## [6.10.1](https://github.com/firebase/php-jwt/compare/v6.10.0...v6.10.1) (2024-05-18) ### Bug Fixes * ensure ratelimit expiry is set every time ([#556](https://github.com/firebase/php-jwt/issues/556)) ([09cb208](https://github.com/firebase/php-jwt/commit/09cb2081c2c3bc0f61e2f2a5fbea5741f7498648)) * ratelimit cache expiration ([#550](https://github.com/firebase/php-jwt/issues/550)) ([dda7250](https://github.com/firebase/php-jwt/commit/dda725033585ece30ff8cae8937320d7e9f18bae)) ## [6.10.0](https://github.com/firebase/php-jwt/compare/v6.9.0...v6.10.0) (2023-11-28) ### Features * allow typ header override ([#546](https://github.com/firebase/php-jwt/issues/546)) ([79cb30b](https://github.com/firebase/php-jwt/commit/79cb30b729a22931b2fbd6b53f20629a83031ba9)) ## [6.9.0](https://github.com/firebase/php-jwt/compare/v6.8.1...v6.9.0) (2023-10-04) ### Features * add payload to jwt exception ([#521](https://github.com/firebase/php-jwt/issues/521)) ([175edf9](https://github.com/firebase/php-jwt/commit/175edf958bb61922ec135b2333acf5622f2238a2)) ## [6.8.1](https://github.com/firebase/php-jwt/compare/v6.8.0...v6.8.1) (2023-07-14) ### Bug Fixes * accept float claims but round down to ignore them ([#492](https://github.com/firebase/php-jwt/issues/492)) ([3936842](https://github.com/firebase/php-jwt/commit/39368423beeaacb3002afa7dcb75baebf204fe7e)) * different BeforeValidException messages for nbf and iat ([#526](https://github.com/firebase/php-jwt/issues/526)) ([0a53cf2](https://github.com/firebase/php-jwt/commit/0a53cf2986e45c2bcbf1a269f313ebf56a154ee4)) ## [6.8.0](https://github.com/firebase/php-jwt/compare/v6.7.0...v6.8.0) (2023-06-14) ### Features * add support for P-384 curve ([#515](https://github.com/firebase/php-jwt/issues/515)) ([5de4323](https://github.com/firebase/php-jwt/commit/5de4323f4baf4d70bca8663bd87682a69c656c3d)) ### Bug Fixes * handle invalid http responses ([#508](https://github.com/firebase/php-jwt/issues/508)) ([91c39c7](https://github.com/firebase/php-jwt/commit/91c39c72b22fc3e1191e574089552c1f2041c718)) ## [6.7.0](https://github.com/firebase/php-jwt/compare/v6.6.0...v6.7.0) (2023-06-14) ### Features * add ed25519 support to JWK (public keys) ([#452](https://github.com/firebase/php-jwt/issues/452)) ([e53979a](https://github.com/firebase/php-jwt/commit/e53979abae927de916a75b9d239cfda8ce32be2a)) ## [6.6.0](https://github.com/firebase/php-jwt/compare/v6.5.0...v6.6.0) (2023-06-13) ### Features * allow get headers when decoding token ([#442](https://github.com/firebase/php-jwt/issues/442)) ([fb85f47](https://github.com/firebase/php-jwt/commit/fb85f47cfaeffdd94faf8defdf07164abcdad6c3)) ### Bug Fixes * only check iat if nbf is not used ([#493](https://github.com/firebase/php-jwt/issues/493)) ([398ccd2](https://github.com/firebase/php-jwt/commit/398ccd25ea12fa84b9e4f1085d5ff448c21ec797)) ## [6.5.0](https://github.com/firebase/php-jwt/compare/v6.4.0...v6.5.0) (2023-05-12) ### Bug Fixes * allow KID of '0' ([#505](https://github.com/firebase/php-jwt/issues/505)) ([9dc46a9](https://github.com/firebase/php-jwt/commit/9dc46a9c3e5801294249cfd2554c5363c9f9326a)) ### Miscellaneous Chores * drop support for PHP 7.3 ([#495](https://github.com/firebase/php-jwt/issues/495)) ## [6.4.0](https://github.com/firebase/php-jwt/compare/v6.3.2...v6.4.0) (2023-02-08) ### Features * add support for W3C ES256K ([#462](https://github.com/firebase/php-jwt/issues/462)) ([213924f](https://github.com/firebase/php-jwt/commit/213924f51936291fbbca99158b11bd4ae56c2c95)) * improve caching by only decoding jwks when necessary ([#486](https://github.com/firebase/php-jwt/issues/486)) ([78d3ed1](https://github.com/firebase/php-jwt/commit/78d3ed1073553f7d0bbffa6c2010009a0d483d5c)) ## [6.3.2](https://github.com/firebase/php-jwt/compare/v6.3.1...v6.3.2) (2022-11-01) ### Bug Fixes * check kid before using as array index ([bad1b04](https://github.com/firebase/php-jwt/commit/bad1b040d0c736bbf86814c6b5ae614f517cf7bd)) ## [6.3.1](https://github.com/firebase/php-jwt/compare/v6.3.0...v6.3.1) (2022-11-01) ### Bug Fixes * casing of GET for PSR compat ([#451](https://github.com/firebase/php-jwt/issues/451)) ([60b52b7](https://github.com/firebase/php-jwt/commit/60b52b71978790eafcf3b95cfbd83db0439e8d22)) * string interpolation format for php 8.2 ([#446](https://github.com/firebase/php-jwt/issues/446)) ([2e07d8a](https://github.com/firebase/php-jwt/commit/2e07d8a1524d12b69b110ad649f17461d068b8f2)) ## 6.3.0 / 2022-07-15 - Added ES256 support to JWK parsing ([#399](https://github.com/firebase/php-jwt/pull/399)) - Fixed potential caching error in `CachedKeySet` by caching jwks as strings ([#435](https://github.com/firebase/php-jwt/pull/435)) ## 6.2.0 / 2022-05-14 - Added `CachedKeySet` ([#397](https://github.com/firebase/php-jwt/pull/397)) - Added `$defaultAlg` parameter to `JWT::parseKey` and `JWT::parseKeySet` ([#426](https://github.com/firebase/php-jwt/pull/426)). ## 6.1.0 / 2022-03-23 - Drop support for PHP 5.3, 5.4, 5.5, 5.6, and 7.0 - Add parameter typing and return types where possible ## 6.0.0 / 2022-01-24 - **Backwards-Compatibility Breaking Changes**: See the [Release Notes](https://github.com/firebase/php-jwt/releases/tag/v6.0.0) for more information. - New Key object to prevent key/algorithm type confusion (#365) - Add JWK support (#273) - Add ES256 support (#256) - Add ES384 support (#324) - Add Ed25519 support (#343) ## 5.0.0 / 2017-06-26 - Support RS384 and RS512. See [#117](https://github.com/firebase/php-jwt/pull/117). Thanks [@joostfaassen](https://github.com/joostfaassen)! - Add an example for RS256 openssl. See [#125](https://github.com/firebase/php-jwt/pull/125). Thanks [@akeeman](https://github.com/akeeman)! - Detect invalid Base64 encoding in signature. See [#162](https://github.com/firebase/php-jwt/pull/162). Thanks [@psignoret](https://github.com/psignoret)! - Update `JWT::verify` to handle OpenSSL errors. See [#159](https://github.com/firebase/php-jwt/pull/159). Thanks [@bshaffer](https://github.com/bshaffer)! - Add `array` type hinting to `decode` method See [#101](https://github.com/firebase/php-jwt/pull/101). Thanks [@hywak](https://github.com/hywak)! - Add all JSON error types. See [#110](https://github.com/firebase/php-jwt/pull/110). Thanks [@gbalduzzi](https://github.com/gbalduzzi)! - Bugfix 'kid' not in given key list. See [#129](https://github.com/firebase/php-jwt/pull/129). Thanks [@stampycode](https://github.com/stampycode)! - Miscellaneous cleanup, documentation and test fixes. See [#107](https://github.com/firebase/php-jwt/pull/107), [#115](https://github.com/firebase/php-jwt/pull/115), [#160](https://github.com/firebase/php-jwt/pull/160), [#161](https://github.com/firebase/php-jwt/pull/161), and [#165](https://github.com/firebase/php-jwt/pull/165). Thanks [@akeeman](https://github.com/akeeman), [@chinedufn](https://github.com/chinedufn), and [@bshaffer](https://github.com/bshaffer)! ## 4.0.0 / 2016-07-17 - Add support for late static binding. See [#88](https://github.com/firebase/php-jwt/pull/88) for details. Thanks to [@chappy84](https://github.com/chappy84)! - Use static `$timestamp` instead of `time()` to improve unit testing. See [#93](https://github.com/firebase/php-jwt/pull/93) for details. Thanks to [@josephmcdermott](https://github.com/josephmcdermott)! - Fixes to exceptions classes. See [#81](https://github.com/firebase/php-jwt/pull/81) for details. Thanks to [@Maks3w](https://github.com/Maks3w)! - Fixes to PHPDoc. See [#76](https://github.com/firebase/php-jwt/pull/76) for details. Thanks to [@akeeman](https://github.com/akeeman)! ## 3.0.0 / 2015-07-22 - Minimum PHP version updated from `5.2.0` to `5.3.0`. - Add `\Firebase\JWT` namespace. See [#59](https://github.com/firebase/php-jwt/pull/59) for details. Thanks to [@Dashron](https://github.com/Dashron)! - Require a non-empty key to decode and verify a JWT. See [#60](https://github.com/firebase/php-jwt/pull/60) for details. Thanks to [@sjones608](https://github.com/sjones608)! - Cleaner documentation blocks in the code. See [#62](https://github.com/firebase/php-jwt/pull/62) for details. Thanks to [@johanderuijter](https://github.com/johanderuijter)! ## 2.2.0 / 2015-06-22 - Add support for adding custom, optional JWT headers to `JWT::encode()`. See [#53](https://github.com/firebase/php-jwt/pull/53/files) for details. Thanks to [@mcocaro](https://github.com/mcocaro)! ## 2.1.0 / 2015-05-20 - Add support for adding a leeway to `JWT:decode()` that accounts for clock skew between signing and verifying entities. Thanks to [@lcabral](https://github.com/lcabral)! - Add support for passing an object implementing the `ArrayAccess` interface for `$keys` argument in `JWT::decode()`. Thanks to [@aztech-dev](https://github.com/aztech-dev)! ## 2.0.0 / 2015-04-01 - **Note**: It is strongly recommended that you update to > v2.0.0 to address known security vulnerabilities in prior versions when both symmetric and asymmetric keys are used together. - Update signature for `JWT::decode(...)` to require an array of supported algorithms to use when verifying token signatures. PK Q7�[!Uk��4 �4 ! vendor/firebase/php-jwt/README.mdnu �Iw��  [](https://packagist.org/packages/firebase/php-jwt) [](https://packagist.org/packages/firebase/php-jwt) [](https://packagist.org/packages/firebase/php-jwt) PHP-JWT ======= A simple library to encode and decode JSON Web Tokens (JWT) in PHP, conforming to [RFC 7519](https://tools.ietf.org/html/rfc7519). Installation ------------ Use composer to manage your dependencies and download PHP-JWT: ```bash composer require firebase/php-jwt ``` Optionally, install the `paragonie/sodium_compat` package from composer if your php env does not have libsodium installed: ```bash composer require paragonie/sodium_compat ``` Example ------- ```php use Firebase\JWT\JWT; use Firebase\JWT\Key; $key = 'example_key'; $payload = [ 'iss' => 'http://example.org', 'aud' => 'http://example.com', 'iat' => 1356999524, 'nbf' => 1357000000 ]; /** * IMPORTANT: * You must specify supported algorithms for your application. See * https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40 * for a list of spec-compliant algorithms. */ $jwt = JWT::encode($payload, $key, 'HS256'); $decoded = JWT::decode($jwt, new Key($key, 'HS256')); print_r($decoded); // Pass a stdClass in as the third parameter to get the decoded header values $headers = new stdClass(); $decoded = JWT::decode($jwt, new Key($key, 'HS256'), $headers); print_r($headers); /* NOTE: This will now be an object instead of an associative array. To get an associative array, you will need to cast it as such: */ $decoded_array = (array) $decoded; /** * You can add a leeway to account for when there is a clock skew times between * the signing and verifying servers. It is recommended that this leeway should * not be bigger than a few minutes. * * Source: http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#nbfDef */ JWT::$leeway = 60; // $leeway in seconds $decoded = JWT::decode($jwt, new Key($key, 'HS256')); ``` Example encode/decode headers ------- Decoding the JWT headers without verifying the JWT first is NOT recommended, and is not supported by this library. This is because without verifying the JWT, the header values could have been tampered with. Any value pulled from an unverified header should be treated as if it could be any string sent in from an attacker. If this is something you still want to do in your application for whatever reason, it's possible to decode the header values manually simply by calling `json_decode` and `base64_decode` on the JWT header part: ```php use Firebase\JWT\JWT; $key = 'example_key'; $payload = [ 'iss' => 'http://example.org', 'aud' => 'http://example.com', 'iat' => 1356999524, 'nbf' => 1357000000 ]; $headers = [ 'x-forwarded-for' => 'www.google.com' ]; // Encode headers in the JWT string $jwt = JWT::encode($payload, $key, 'HS256', null, $headers); // Decode headers from the JWT string WITHOUT validation // **IMPORTANT**: This operation is vulnerable to attacks, as the JWT has not yet been verified. // These headers could be any value sent by an attacker. list($headersB64, $payloadB64, $sig) = explode('.', $jwt); $decoded = json_decode(base64_decode($headersB64), true); print_r($decoded); ``` Example with RS256 (openssl) ---------------------------- ```php use Firebase\JWT\JWT; use Firebase\JWT\Key; $privateKey = <<<EOD -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAuzWHNM5f+amCjQztc5QTfJfzCC5J4nuW+L/aOxZ4f8J3Frew M2c/dufrnmedsApb0By7WhaHlcqCh/ScAPyJhzkPYLae7bTVro3hok0zDITR8F6S JGL42JAEUk+ILkPI+DONM0+3vzk6Kvfe548tu4czCuqU8BGVOlnp6IqBHhAswNMM 78pos/2z0CjPM4tbeXqSTTbNkXRboxjU29vSopcT51koWOgiTf3C7nJUoMWZHZI5 HqnIhPAG9yv8HAgNk6CMk2CadVHDo4IxjxTzTTqo1SCSH2pooJl9O8at6kkRYsrZ WwsKlOFE2LUce7ObnXsYihStBUDoeBQlGG/BwQIDAQABAoIBAFtGaOqNKGwggn9k 6yzr6GhZ6Wt2rh1Xpq8XUz514UBhPxD7dFRLpbzCrLVpzY80LbmVGJ9+1pJozyWc VKeCeUdNwbqkr240Oe7GTFmGjDoxU+5/HX/SJYPpC8JZ9oqgEA87iz+WQX9hVoP2 oF6EB4ckDvXmk8FMwVZW2l2/kd5mrEVbDaXKxhvUDf52iVD+sGIlTif7mBgR99/b c3qiCnxCMmfYUnT2eh7Vv2LhCR/G9S6C3R4lA71rEyiU3KgsGfg0d82/XWXbegJW h3QbWNtQLxTuIvLq5aAryV3PfaHlPgdgK0ft6ocU2de2FagFka3nfVEyC7IUsNTK bq6nhAECgYEA7d/0DPOIaItl/8BWKyCuAHMss47j0wlGbBSHdJIiS55akMvnAG0M 39y22Qqfzh1at9kBFeYeFIIU82ZLF3xOcE3z6pJZ4Dyvx4BYdXH77odo9uVK9s1l 3T3BlMcqd1hvZLMS7dviyH79jZo4CXSHiKzc7pQ2YfK5eKxKqONeXuECgYEAyXlG vonaus/YTb1IBei9HwaccnQ/1HRn6MvfDjb7JJDIBhNClGPt6xRlzBbSZ73c2QEC 6Fu9h36K/HZ2qcLd2bXiNyhIV7b6tVKk+0Psoj0dL9EbhsD1OsmE1nTPyAc9XZbb OPYxy+dpBCUA8/1U9+uiFoCa7mIbWcSQ+39gHuECgYAz82pQfct30aH4JiBrkNqP nJfRq05UY70uk5k1u0ikLTRoVS/hJu/d4E1Kv4hBMqYCavFSwAwnvHUo51lVCr/y xQOVYlsgnwBg2MX4+GjmIkqpSVCC8D7j/73MaWb746OIYZervQ8dbKahi2HbpsiG 8AHcVSA/agxZr38qvWV54QKBgCD5TlDE8x18AuTGQ9FjxAAd7uD0kbXNz2vUYg9L hFL5tyL3aAAtUrUUw4xhd9IuysRhW/53dU+FsG2dXdJu6CxHjlyEpUJl2iZu/j15 YnMzGWHIEX8+eWRDsw/+Ujtko/B7TinGcWPz3cYl4EAOiCeDUyXnqnO1btCEUU44 DJ1BAoGBAJuPD27ErTSVtId90+M4zFPNibFP50KprVdc8CR37BE7r8vuGgNYXmnI RLnGP9p3pVgFCktORuYS2J/6t84I3+A17nEoB4xvhTLeAinAW/uTQOUmNicOP4Ek 2MsLL2kHgL8bLTmvXV4FX+PXphrDKg1XxzOYn0otuoqdAQrkK4og -----END RSA PRIVATE KEY----- EOD; $publicKey = <<<EOD -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzWHNM5f+amCjQztc5QT fJfzCC5J4nuW+L/aOxZ4f8J3FrewM2c/dufrnmedsApb0By7WhaHlcqCh/ScAPyJ hzkPYLae7bTVro3hok0zDITR8F6SJGL42JAEUk+ILkPI+DONM0+3vzk6Kvfe548t u4czCuqU8BGVOlnp6IqBHhAswNMM78pos/2z0CjPM4tbeXqSTTbNkXRboxjU29vS opcT51koWOgiTf3C7nJUoMWZHZI5HqnIhPAG9yv8HAgNk6CMk2CadVHDo4IxjxTz TTqo1SCSH2pooJl9O8at6kkRYsrZWwsKlOFE2LUce7ObnXsYihStBUDoeBQlGG/B wQIDAQAB -----END PUBLIC KEY----- EOD; $payload = [ 'iss' => 'example.org', 'aud' => 'example.com', 'iat' => 1356999524, 'nbf' => 1357000000 ]; $jwt = JWT::encode($payload, $privateKey, 'RS256'); echo "Encode:\n" . print_r($jwt, true) . "\n"; $decoded = JWT::decode($jwt, new Key($publicKey, 'RS256')); /* NOTE: This will now be an object instead of an associative array. To get an associative array, you will need to cast it as such: */ $decoded_array = (array) $decoded; echo "Decode:\n" . print_r($decoded_array, true) . "\n"; ``` Example with a passphrase ------------------------- ```php use Firebase\JWT\JWT; use Firebase\JWT\Key; // Your passphrase $passphrase = '[YOUR_PASSPHRASE]'; // Your private key file with passphrase // Can be generated with "ssh-keygen -t rsa -m pem" $privateKeyFile = '/path/to/key-with-passphrase.pem'; // Create a private key of type "resource" $privateKey = openssl_pkey_get_private( file_get_contents($privateKeyFile), $passphrase ); $payload = [ 'iss' => 'example.org', 'aud' => 'example.com', 'iat' => 1356999524, 'nbf' => 1357000000 ]; $jwt = JWT::encode($payload, $privateKey, 'RS256'); echo "Encode:\n" . print_r($jwt, true) . "\n"; // Get public key from the private key, or pull from from a file. $publicKey = openssl_pkey_get_details($privateKey)['key']; $decoded = JWT::decode($jwt, new Key($publicKey, 'RS256')); echo "Decode:\n" . print_r((array) $decoded, true) . "\n"; ``` Example with EdDSA (libsodium and Ed25519 signature) ---------------------------- ```php use Firebase\JWT\JWT; use Firebase\JWT\Key; // Public and private keys are expected to be Base64 encoded. The last // non-empty line is used so that keys can be generated with // sodium_crypto_sign_keypair(). The secret keys generated by other tools may // need to be adjusted to match the input expected by libsodium. $keyPair = sodium_crypto_sign_keypair(); $privateKey = base64_encode(sodium_crypto_sign_secretkey($keyPair)); $publicKey = base64_encode(sodium_crypto_sign_publickey($keyPair)); $payload = [ 'iss' => 'example.org', 'aud' => 'example.com', 'iat' => 1356999524, 'nbf' => 1357000000 ]; $jwt = JWT::encode($payload, $privateKey, 'EdDSA'); echo "Encode:\n" . print_r($jwt, true) . "\n"; $decoded = JWT::decode($jwt, new Key($publicKey, 'EdDSA')); echo "Decode:\n" . print_r((array) $decoded, true) . "\n"; ```` Example with multiple keys -------------------------- ```php use Firebase\JWT\JWT; use Firebase\JWT\Key; // Example RSA keys from previous example // $privateKey1 = '...'; // $publicKey1 = '...'; // Example EdDSA keys from previous example // $privateKey2 = '...'; // $publicKey2 = '...'; $payload = [ 'iss' => 'example.org', 'aud' => 'example.com', 'iat' => 1356999524, 'nbf' => 1357000000 ]; $jwt1 = JWT::encode($payload, $privateKey1, 'RS256', 'kid1'); $jwt2 = JWT::encode($payload, $privateKey2, 'EdDSA', 'kid2'); echo "Encode 1:\n" . print_r($jwt1, true) . "\n"; echo "Encode 2:\n" . print_r($jwt2, true) . "\n"; $keys = [ 'kid1' => new Key($publicKey1, 'RS256'), 'kid2' => new Key($publicKey2, 'EdDSA'), ]; $decoded1 = JWT::decode($jwt1, $keys); $decoded2 = JWT::decode($jwt2, $keys); echo "Decode 1:\n" . print_r((array) $decoded1, true) . "\n"; echo "Decode 2:\n" . print_r((array) $decoded2, true) . "\n"; ``` Using JWKs ---------- ```php use Firebase\JWT\JWK; use Firebase\JWT\JWT; // Set of keys. The "keys" key is required. For example, the JSON response to // this endpoint: https://www.gstatic.com/iap/verify/public_key-jwk $jwks = ['keys' => []]; // JWK::parseKeySet($jwks) returns an associative array of **kid** to Firebase\JWT\Key // objects. Pass this as the second parameter to JWT::decode. JWT::decode($jwt, JWK::parseKeySet($jwks)); ``` Using Cached Key Sets --------------------- The `CachedKeySet` class can be used to fetch and cache JWKS (JSON Web Key Sets) from a public URI. This has the following advantages: 1. The results are cached for performance. 2. If an unrecognized key is requested, the cache is refreshed, to accomodate for key rotation. 3. If rate limiting is enabled, the JWKS URI will not make more than 10 requests a second. ```php use Firebase\JWT\CachedKeySet; use Firebase\JWT\JWT; // The URI for the JWKS you wish to cache the results from $jwksUri = 'https://www.gstatic.com/iap/verify/public_key-jwk'; // Create an HTTP client (can be any PSR-7 compatible HTTP client) $httpClient = new GuzzleHttp\Client(); // Create an HTTP request factory (can be any PSR-17 compatible HTTP request factory) $httpFactory = new GuzzleHttp\Psr\HttpFactory(); // Create a cache item pool (can be any PSR-6 compatible cache item pool) $cacheItemPool = Phpfastcache\CacheManager::getInstance('files'); $keySet = new CachedKeySet( $jwksUri, $httpClient, $httpFactory, $cacheItemPool, null, // $expiresAfter int seconds to set the JWKS to expire true // $rateLimit true to enable rate limit of 10 RPS on lookup of invalid keys ); $jwt = 'eyJhbGci...'; // Some JWT signed by a key from the $jwkUri above $decoded = JWT::decode($jwt, $keySet); ``` Miscellaneous ------------- #### Exception Handling When a call to `JWT::decode` is invalid, it will throw one of the following exceptions: ```php use Firebase\JWT\JWT; use Firebase\JWT\SignatureInvalidException; use Firebase\JWT\BeforeValidException; use Firebase\JWT\ExpiredException; use DomainException; use InvalidArgumentException; use UnexpectedValueException; try { $decoded = JWT::decode($jwt, $keys); } catch (InvalidArgumentException $e) { // provided key/key-array is empty or malformed. } catch (DomainException $e) { // provided algorithm is unsupported OR // provided key is invalid OR // unknown error thrown in openSSL or libsodium OR // libsodium is required but not available. } catch (SignatureInvalidException $e) { // provided JWT signature verification failed. } catch (BeforeValidException $e) { // provided JWT is trying to be used before "nbf" claim OR // provided JWT is trying to be used before "iat" claim. } catch (ExpiredException $e) { // provided JWT is trying to be used after "exp" claim. } catch (UnexpectedValueException $e) { // provided JWT is malformed OR // provided JWT is missing an algorithm / using an unsupported algorithm OR // provided JWT algorithm does not match provided key OR // provided key ID in key/key-array is empty or invalid. } ``` All exceptions in the `Firebase\JWT` namespace extend `UnexpectedValueException`, and can be simplified like this: ```php use Firebase\JWT\JWT; use UnexpectedValueException; try { $decoded = JWT::decode($jwt, $keys); } catch (LogicException $e) { // errors having to do with environmental setup or malformed JWT Keys } catch (UnexpectedValueException $e) { // errors having to do with JWT signature and claims } ``` #### Casting to array The return value of `JWT::decode` is the generic PHP object `stdClass`. If you'd like to handle with arrays instead, you can do the following: ```php // return type is stdClass $decoded = JWT::decode($jwt, $keys); // cast to array $decoded = json_decode(json_encode($decoded), true); ``` Tests ----- Run the tests using phpunit: ```bash $ pear install PHPUnit $ phpunit --configuration phpunit.xml.dist PHPUnit 3.7.10 by Sebastian Bergmann. ..... Time: 0 seconds, Memory: 2.50Mb OK (5 tests, 5 assertions) ``` New Lines in private keys ----- If your private key contains `\n` characters, be sure to wrap it in double quotes `""` and not single quotes `''` in order to properly interpret the escaped characters. License ------- [3-Clause BSD](http://opensource.org/licenses/BSD-3-Clause). PK Q7�[�\O�� � vendor/autoload.phpnu �Iw�� <?php // autoload.php @generated by Composer if (PHP_VERSION_ID < 50600) { if (!headers_sent()) { header('HTTP/1.1 500 Internal Server Error'); } $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; if (!ini_get('display_errors')) { if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { fwrite(STDERR, $err); } elseif (!headers_sent()) { echo $err; } } throw new RuntimeException($err); } require_once __DIR__ . '/composer/autoload_real.php'; return ComposerAutoloaderInit40aa654f2e66c20881ae0572fe987a10::getLoader(); PK Q7�['ۋ ( vendor/stripe/stripe-php/OPENAPI_VERSIONnu �Iw�� v2028PK Q7�[ پO O &