#!/usr/bin/env php bold()->out('Proxy List Cache Updater'); $climate->br(); try { $dotenv = Dotenv::createImmutable(__DIR__ . '/..'); $dotenv->load(); $climate->out('Environment variables loaded'); } catch (\Exception $e) { $climate->yellow()->out('Warning: ' . $e->getMessage()); exit(0); } if (!defined('CACHE_DIR')) { define('CACHE_DIR', __DIR__ . '/../cache'); } if (!isset($_ENV['PROXY_LIST']) || empty($_ENV['PROXY_LIST'])) { $climate->yellow()->out('PROXY_LIST environment variable not set. No proxies to cache.'); exit(0); } $proxyListUrl = $_ENV['PROXY_LIST']; $proxyCachePath = CACHE_DIR . '/proxy_list.json'; // Download proxy list from URL $climate->out('Downloading proxy list from: ' . $proxyListUrl); $proxyList = downloadProxyList($proxyListUrl, $climate); if ($proxyList === false) { $climate->red()->out('Failed to download proxy list from URL: ' . $proxyListUrl); exit(1); } $climate->green()->out('Proxy list downloaded successfully (' . strlen($proxyList) . ' bytes)'); if (!is_dir(CACHE_DIR)) { if (!mkdir(CACHE_DIR, 0755, true)) { $climate->red()->out('Failed to create cache directory: ' . CACHE_DIR); exit(1); } } $climate->out('Parsing proxy list from environment variable...'); $proxies = parseProxyList($proxyList); if (empty($proxies)) { $climate->red()->out('No valid proxies found in PROXY_LIST. Supported formats are:'); $climate->red()->out('1. http://USER:PASSWORD@HOST:PORT'); $climate->red()->out('2. IP:PORT:USER:PASSWORD'); exit(1); } $climate->out('Found ' . count($proxies) . ' valid proxies.'); if (file_put_contents($proxyCachePath, json_encode($proxies))) { $climate->green()->out('Proxy list successfully cached to: ' . $proxyCachePath); } else { $climate->red()->out('Failed to write proxy list to cache file: ' . $proxyCachePath); exit(1); } /** * Parse proxy list from environment variable * * @param string $proxyListString Proxy list in format http://USER:PASSWORD@HOST:PORT or IP:PORT:USER:PASSWORD * @return array Array of valid proxy URLs */ function parseProxyList($proxyListString) { $proxies = []; $lines = preg_split('/[\r\n,]+/', $proxyListString); foreach ($lines as $line) { $line = trim($line); if (empty($line)) continue; // Format 1: http://USER:PASSWORD@HOST:PORT if (preg_match('/^https?:\/\/[^:]+:[^@]+@[^:]+:\d+$/i', $line)) { $proxies[] = $line; continue; } // Format 2: IP:PORT:USER:PASSWORD if (preg_match('/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+):([^:]+):(.+)$/', $line, $matches)) { $ip = $matches[1]; $port = $matches[2]; $user = $matches[3]; $password = $matches[4]; // Convert to standard format $proxies[] = "http://{$user}:{$password}@{$ip}:{$port}"; } } return $proxies; } /** * Download proxy list from URL using php-curl-class * * @param string $url URL to download proxy list from * @param CLImate $climate CLImate instance for output * @return string|false Downloaded content or false on failure */ function downloadProxyList($url, $climate = null) { $curl = new Curl(); // Configure cURL options $curl->setTimeout(30); $curl->setConnectTimeout(10); $curl->setUserAgent('Marreta Proxy Updater/1.0'); $curl->setHeader('Accept', 'text/plain, text/html, */*'); $curl->setHeader('Accept-Encoding', 'gzip, deflate'); $curl->setOpt(CURLOPT_FOLLOWLOCATION, true); $curl->setOpt(CURLOPT_MAXREDIRS, 3); $curl->setOpt(CURLOPT_SSL_VERIFYPEER, false); $curl->setOpt(CURLOPT_SSL_VERIFYHOST, false); try { if ($climate) { $climate->out('Making HTTP request with php-curl-class...'); } $curl->get($url); if ($curl->error) { $errorMsg = 'cURL request failed: ' . $curl->errorMessage . ' (Code: ' . $curl->errorCode . ')'; if ($climate) { $climate->red()->out($errorMsg); } else { error_log($errorMsg); } return false; } $statusCode = $curl->httpStatusCode; if ($climate) { $climate->out('HTTP Status Code: ' . $statusCode); } if ($statusCode === 200) { $content = $curl->response; if ($climate) { $contentType = $curl->responseHeaders['Content-Type'] ?? 'unknown'; $climate->out('Content-Type: ' . $contentType); $climate->out('Content-Length: ' . strlen($content) . ' bytes'); } return $content; } if ($climate) { $climate->yellow()->out('Unexpected HTTP status code: ' . $statusCode); } return false; } catch (\Exception $e) { $errorMsg = 'Unexpected error during download: ' . $e->getMessage(); if ($climate) { $climate->red()->out($errorMsg); } else { error_log($errorMsg); } return false; } finally { $curl->close(); } }