currentHost = $_SERVER['SERVER_NAME'] ?? $_SERVER['HTTP_HOST'] ?? ''; // Récupérer les autres en-têtes pour une utilisation ultérieure si nécessaire // getallheaders() n'existe pas en CLI, donc on vérifie $this->headers = function_exists('getallheaders') ? getallheaders() : []; // Déterminer l'adresse IP du client $this->clientIp = $this->getClientIpAddress(); $this->initConfig(); $this->validateApp(); } public static function getInstance(): self { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } private function initConfig(): void { // Configuration de base commune à tous les environnements $baseConfig = [ 'name' => 'geosector', 'encryption_key' => 'Qga2M8Ov6tyx2fIQRWHQ1U6oMK/bAFdTL7A8VRtiDhk=', 'smtp' => [ 'host' => 'barbotte.o2switch.net', 'auth' => true, 'user' => 'noreply@geosector.fr', 'pass' => '@G83^[OMSo^Q', 'secure' => 'ssl', 'port' => 465, ], 'email' => [ 'from' => 'noreply@geosector.fr', 'contact' => 'contact@geosector.fr', 'hourly_limit' => 1500, // Limite de 1500 emails/heure comme mentionné dans le cahier des charges ], 'mapbox' => [ 'api_key' => '', // À remplir avec la clé API Mapbox ], 'stripe' => [ 'public_key_test' => 'pk_test_51QwoVN00pblGEgsXkf8qlXmLGEpxDQcG0KLRpjrGLjJHd7AVZ4Iwd6ChgdjO0w0n3vRqwNCEW8KnHUe5eh3uIlkV00k07kCBmd', // À remplacer par votre clé publique TEST 'secret_key_test' => 'sk_test_51QwoVN00pblGEgsXnvqi8qfYpzHtesWWclvK3lzQjPNoHY0dIyOpJmxIkoLqsbmRMEUZpKS5MQ7iFDRlSqVyTo9c006yWetbsd', // À remplacer par votre clé secrète TEST 'public_key_live' => 'pk_live_XXXXXXXXXXXX', // À remplacer par votre clé publique LIVE 'secret_key_live' => 'sk_live_XXXXXXXXXXXX', // À remplacer par votre clé secrète LIVE 'webhook_secret_test' => 'whsec_test_XXXXXXXXXXXX', // À remplacer après création webhook TEST 'webhook_secret_live' => 'whsec_live_XXXXXXXXXXXX', // À remplacer après création webhook LIVE 'api_version' => '2024-06-20', 'application_fee_percent' => 0, // Pas de commission plateforme 'application_fee_minimum' => 0, // Pas de commission minimum 'mode' => 'test', // 'test' ou 'live' ], 'sms' => [ 'provider' => 'ovh', // Comme mentionné dans le cahier des charges 'api_key' => '', // À remplir avec la clé API SMS OVH 'api_secret' => '', // À remplir avec le secret API SMS OVH ], 'backup' => [ 'encryption_key' => 'K8mN2pQ5rT9wX3zA6bE1fH4jL7oS0vY2', // Clé de 32 caractères pour AES-256 'compression' => true, 'compression_level' => 6, 'cipher' => 'AES-256-CBC' ], ]; // Configuration PRODUCTION $this->config['app.geosector.fr'] = array_merge($baseConfig, [ 'env' => 'production', 'database' => [ 'host' => 'localhost', 'name' => 'geo_app', 'username' => 'geo_app_user_prod', 'password' => 'QO:96-SrHJ6k7-df*?k{4W6m', ], 'addresses_database' => [ 'host' => '13.23.33.26', 'name' => 'adresses', 'username' => 'adr_geo_user', 'password' => 'd66,AdrGeo.User', ], ]); // Configuration RECETTE $this->config['rapp.geosector.fr'] = array_merge($baseConfig, [ 'env' => 'recette', 'database' => [ 'host' => 'localhost', 'name' => 'geo_app', 'username' => 'geo_app_user_rec', 'password' => 'QO:96df*?k-dS3KiO-{4W6m', ], 'addresses_database' => [ 'host' => '13.23.33.36', 'name' => 'adresses', 'username' => 'adr_geo_user', 'password' => 'd66,AdrGeoRec.User', ], // Vous pouvez remplacer d'autres paramètres spécifiques à l'environnement de recette ici ]); // Configuration DÉVELOPPEMENT $this->config['dapp.geosector.fr'] = array_merge($baseConfig, [ 'env' => 'development', 'database' => [ 'host' => 'localhost', 'name' => 'geo_app', 'username' => 'geo_app_user_dev', 'password' => '34GOz-X5gJu-oH@Fa3$#Z', ], 'addresses_database' => [ 'host' => '13.23.33.46', 'name' => 'adresses', 'username' => 'adr_geo_user', 'password' => 'd66,AdrGeoDev.User', ], // Vous pouvez activer des fonctionnalités de débogage en développement 'debug' => true, ]); } private function validateApp(): void { // Si l'hôte est vide, utiliser une solution de secours (développement par défaut) if (empty($this->currentHost)) { // Journaliser cette situation anormale error_log("WARNING: No host detected, falling back to development environment"); $this->currentHost = 'dapp.geosector.fr'; } // Si l'hôte n'existe pas dans la configuration, tenter une correction if (!isset($this->config[$this->currentHost])) { // Essayer de faire correspondre avec l'un des hôtes connus $knownHosts = array_keys($this->config); foreach ($knownHosts as $host) { if (strpos($this->currentHost, str_replace(['app.', 'rapp.', 'dapp.'], '', $host)) !== false) { // Correspondance trouvée, utiliser cette configuration $this->currentHost = $host; break; } } // Si toujours pas de correspondance, utiliser l'environnement de développement par défaut if (!isset($this->config[$this->currentHost])) { error_log("WARNING: Unknown host '{$this->currentHost}', falling back to development environment"); $this->currentHost = 'dapp.geosector.fr'; } } // Journaliser l'environnement détecté $environment = $this->config[$this->currentHost]['env'] ?? 'unknown'; // error_log("INFO: Environment detected: {$environment} (Host: {$this->currentHost}, IP: {$this->clientIp})"); } /** * Retourne le type de client (web, mobile, etc.) * * @return string Le type de client ou 'unknown' si non défini */ public function getClientType(): string { return $this->headers['X-Client-Type'] ?? $_SERVER['HTTP_X_CLIENT_TYPE'] ?? 'unknown'; } /** * Retourne l'identifiant de l'application basé sur l'hôte * * @return string L'identifiant de l'application (app.geosector.fr, rapp.geosector.fr, dapp.geosector.fr) */ public function getAppIdentifier(): string { return $this->currentHost; } /** * Retourne l'environnement actuel (production, recette, development) * * @return string L'environnement actuel */ public function getEnvironment(): string { return $this->getCurrentConfig()['env'] ?? 'production'; } /** * Vérifie si l'application est en mode développement * * @return bool True si l'application est en mode développement */ public function isDevelopment(): bool { return $this->getEnvironment() === 'development'; } /** * Vérifie si l'application est en mode recette * * @return bool True si l'application est en mode recette */ public function isRecette(): bool { return $this->getEnvironment() === 'recette'; } /** * Vérifie si l'application est en mode production * * @return bool True si l'application est en mode production */ public function isProduction(): bool { return $this->getEnvironment() === 'production'; } /** * Retourne la configuration complète de l'environnement actuel * * @return array Configuration de l'environnement */ public function getCurrentConfig(): array { return $this->config[$this->currentHost]; } /** * Retourne le nom de l'application * * @return string Nom de l'application (geosector) */ public function getName(): string { return $this->getCurrentConfig()['name']; } /** * Retourne la configuration de la base de données * * @return array Configuration de la base de données */ public function getDatabaseConfig(): array { return $this->getCurrentConfig()['database']; } /** * Retourne la configuration de la base de données des adresses * * @return array Configuration de la base de données des adresses */ public function getAddressesDatabaseConfig(): array { return $this->getCurrentConfig()['addresses_database']; } /** * Retourne la clé de chiffrement * * @return string Clé de chiffrement */ public function getEncryptionKey(): string { return $this->getCurrentConfig()['encryption_key']; } /** * Retourne la configuration SMTP * * @return array Configuration SMTP */ public function getSmtpConfig(): array { return $this->getCurrentConfig()['smtp']; } /** * Retourne la configuration email * * @return array Configuration email */ public function getEmailConfig(): array { return $this->getCurrentConfig()['email']; } /** * Retourne la configuration Mapbox * * @return array Configuration Mapbox */ public function getMapboxConfig(): array { return $this->getCurrentConfig()['mapbox']; } /** * Retourne la configuration Stripe * * @return array Configuration Stripe */ public function getStripeConfig(): array { return $this->getCurrentConfig()['stripe']; } /** * Retourne la configuration SMS * * @return array Configuration SMS */ public function getSmsConfig(): array { return $this->getCurrentConfig()['sms']; } /** * Retourne si le mode debug est activé * * @return bool True si le mode debug est activé */ public function isDebugEnabled(): bool { return $this->getCurrentConfig()['debug'] ?? false; } /** * Retourne la liste des origines autorisées (domaines) * * @return array Liste des origines autorisées */ public function getAllowedOrigins(): array { return array_keys($this->config); } /** * Vérifie si le client est d'un type spécifique * * @param string $type Type de client à vérifier * @return bool True si le client est du type spécifié */ public function isClientType(string $type): bool { return $this->getClientType() === $type; } /** * Retourne la configuration complète pour l'utilisation externe * * @return array Configuration complète */ public function getFullConfig(): array { return [ 'environment' => $this->getEnvironment(), 'database' => $this->getDatabaseConfig(), 'api' => [ 'allowed_origins' => $this->getAllowedOrigins(), 'current_site' => $this->getName(), ], 'debug' => $this->isDebugEnabled() ]; } /** * Retourne l'adresse IP du client * * @return string L'adresse IP du client */ public function getClientIp(): string { return $this->clientIp; } /** * Retourne la configuration des backups * * @return array Configuration des backups */ public function getBackupConfig(): array { return $this->getCurrentConfig()['backup']; } /** * Retourne la clé de chiffrement des backups * * @return string Clé de chiffrement des backups */ public function getBackupEncryptionKey(): string { return $this->getCurrentConfig()['backup']['encryption_key']; } /** * Détermine l'adresse IP du client en tenant compte des proxys et load balancers * * @return string L'adresse IP du client */ private function getClientIpAddress(): string { // Vérifier les en-têtes courants pour l'IP client $ipSources = [ 'HTTP_X_REAL_IP', // Nginx proxy 'HTTP_CLIENT_IP', // Proxy partagé 'HTTP_X_FORWARDED_FOR', // Proxy ou load balancer courant 'HTTP_X_FORWARDED', // Proxy générique 'HTTP_X_CLUSTER_CLIENT_IP', // Reverse proxy 'HTTP_FORWARDED_FOR', // Proxies précédents 'HTTP_FORWARDED', // Format standardisé (RFC 7239) 'REMOTE_ADDR', // Fallback direct ]; foreach ($ipSources as $source) { if (!empty($_SERVER[$source])) { // Pour des en-têtes comme X-Forwarded-For qui peuvent contenir plusieurs IPs séparées par des virgules // (format: "client, proxy1, proxy2") if ($source === 'HTTP_X_FORWARDED_FOR' || $source === 'HTTP_FORWARDED_FOR') { $ips = explode(',', $_SERVER[$source]); $clientIp = trim($ips[0]); // Prendre la première adresse (client original) } else { $clientIp = $_SERVER[$source]; } // Valider l'IP pour éviter les injections $filteredIp = filter_var($clientIp, FILTER_VALIDATE_IP); if ($filteredIp !== false) { return $filteredIp; } } } // Si aucune adresse IP valide n'est trouvée, retourner une valeur par défaut return '0.0.0.0'; } }