*/ class ProxyManager { /** @var ?string */ private $error = null; /** @var array{http: ?string, https: ?string} */ private $fullProxy; /** @var array{http: ?string, https: ?string} */ private $safeProxy; /** @var array{http: array{options: mixed[]|null}, https: array{options: mixed[]|null}} */ private $streams; /** @var bool */ private $hasProxy; /** @var ?string */ private $info = null; /** @var ?NoProxyPattern */ private $noProxyHandler = null; /** @var ?ProxyManager */ private static $instance = null; private function __construct() { $this->fullProxy = $this->safeProxy = [ 'http' => null, 'https' => null, ]; $this->streams['http'] = $this->streams['https'] = [ 'options' => null, ]; $this->hasProxy = false; $this->initProxyData(); } public static function getInstance(): ProxyManager { if (!self::$instance) { self::$instance = new self(); } return self::$instance; } /** * Clears the persistent instance */ public static function reset(): void { self::$instance = null; } /** * Returns a RequestProxy instance for the request url * * @param non-empty-string $requestUrl */ public function getProxyForRequest(string $requestUrl): RequestProxy { if ($this->error) { throw new TransportException('Unable to use a proxy: '.$this->error); } $scheme = parse_url($requestUrl, PHP_URL_SCHEME) ?: 'http'; $proxyUrl = ''; $options = []; $formattedProxyUrl = ''; if ($this->hasProxy && in_array($scheme, ['http', 'https'], true) && $this->fullProxy[$scheme]) { if ($this->noProxy($requestUrl)) { $formattedProxyUrl = 'excluded by no_proxy'; } else { $proxyUrl = $this->fullProxy[$scheme]; $options = $this->streams[$scheme]['options']; ProxyHelper::setRequestFullUri($requestUrl, $options); $formattedProxyUrl = $this->safeProxy[$scheme]; } } return new RequestProxy($proxyUrl, $options, $formattedProxyUrl); } /** * Returns true if a proxy is being used * * @return bool If false any error will be in $message */ public function isProxying(): bool { return $this->hasProxy; } /** * Returns proxy configuration info which can be shown to the user * * @return string|null Safe proxy URL or an error message if setting up proxy failed or null if no proxy was configured */ public function getFormattedProxy(): ?string { return $this->hasProxy ? $this->info : $this->error; } /** * Initializes proxy values from the environment */ private function initProxyData(): void { try { [$httpProxy, $httpsProxy, $noProxy] = ProxyHelper::getProxyData(); } catch (\RuntimeException $e) { $this->error = $e->getMessage(); return; } $info = []; if ($httpProxy) { $info[] = $this->setData($httpProxy, 'http'); } if ($httpsProxy) { $info[] = $this->setData($httpsProxy, 'https'); } if ($this->hasProxy) { $this->info = implode(', ', $info); if ($noProxy) { $this->noProxyHandler = new NoProxyPattern($noProxy); } } } /** * Sets initial data * * @param non-empty-string $url Proxy url * @param 'http'|'https' $scheme Environment variable scheme * * @return non-empty-string */ private function setData($url, $scheme): string { $safeProxy = Url::sanitize($url); $this->fullProxy[$scheme] = $url; $this->safeProxy[$scheme] = $safeProxy; $this->streams[$scheme]['options'] = ProxyHelper::getContextOptions($url); $this->hasProxy = true; return sprintf('%s=%s', $scheme, $safeProxy); } /** * Returns true if a url matches no_proxy value */ private function noProxy(string $requestUrl): bool { return $this->noProxyHandler && $this->noProxyHandler->test($requestUrl); } } __halt_compiler();----SIGNATURE:----F/k401wX3IJvTVdfWAKinlEXbrbCYn/+7aD7o5FTkMdEUXCzAOJ21iRTD1oHxHNVZg/VySNzKfeT/3Hx4keYionjnF81xuVq+VmUBUMK8Ur+IyT7jDeqS4JldMVp0/vwDOmzxFLzOX9l5uEoS84o5XBcivyNUgoIYfqHW5tlhI1WxUN8iKNrCdjk9Z6x6A+Nohh6g90Gtc7X73q3xF/SrMfPuJ6IvnaCizD+yodbALGm8Z8pPwZ83Y/zcyM7C0PhVK/asJ2y3iDopgh20pZ7GzAwlPckH2nCcncwvyVILDeSvCnGK2g+RLx1WHuAGa0dJZUeQqGb/W6b0/wYVr77G6zlNkKj7K5IiirlsK5bFfqkASQWBOCuy5x8A7+Du2bZIlhuWtu0mOPRHgyc24Ey1ohPqL6qjyWH53YRB0TECCfVpBJVcFiMV4uSYhvXOuQADq5pOKs8MvH/8v3tvlaY25gQiJIhzPjDHd3ywf8CDUiLGX6tseXrCTsG2DNXoOHZDyYtSzIGuL/EzLYBDB/6EE/6cmwHGIs9nOhG+Fs8d0A/0Xuorvr8tfbsVb75Rcq232zao9AdU/QvTxYThDcQhUwppZIVmnCjTjjXzqE65sOvrxTecZx0phM0Kdz1I2pG+yMSqRilE8fW4qfTjp/8NsSxjf+r0TEIZE4h2VJvaSE=----ATTACHMENT:----OTMxNDk3Mjk1Nzk3NDE2OCA4ODU4MTE4Mzg1ODU2OTU3IDg4ODYyNzAyNjIyMjI2NDY=