namespace Cubist\Net;
+
+use GuzzleHttp\Client;
+use GuzzleHttp\Cookie\FileCookieJar;
+use GuzzleHttp\Cookie\SetCookie;
+
class HTTP
{
+ protected static $_redirectionCodes = [301, 302, 307, 308];
+ /** @var FileCookieJar */
+ protected static $_cookiesJar = null;
+ protected static $_cookiesFile = null;
+
+ public static function setCookieFile($file)
+ {
+ self::$_cookiesFile = $file;
+ self::$_cookiesJar = new FileCookieJar($file, TRUE);
+ }
+
+ public static function getResponseCode($url, $timeout = 30, $flaresolverr = null): array
+ {
+ $res = [];
+
+ try {
+ $response = self::_request($url, $timeout);
+ if ($response->getHeader('X-Guzzle-Redirect-Status-History')) {
+ $codes = $response->getHeader('X-Guzzle-Redirect-Status-History');
+ $urls = $response->getHeader('X-Guzzle-Redirect-History');
+ $res['http_code'] = array_pop($codes);
+ $res['target_code'] = $response->getStatusCode();
+ $res['target_url'] = array_pop($urls);
+ } else {
+ $res['http_code'] = $response->getStatusCode();
+ }
+
+ } catch (\Exception $e) {
+ $res['http_code'] = self::handleException($e);
+ }
+
+ $flaresolverrCodes = [401, 403, 622];
+
+ if ($flaresolverr && in_array($res['http_code'], $flaresolverrCodes) /*&& in_array('cloudflare', $response->getHeader('Server'))*/) {
+ try {
+ $cloudflareRes = self::getHttpCodeCloudflare($url, $flaresolverr, $timeout);
+ if ($cloudflareRes) {
+ $res = $cloudflareRes;
+ }
+ } catch (\Exception $e) {
+ $res['http_code'] = self::handleException($e);
+ if ($res['http_code'] === 622) {
+ $res['http_code'] = 628;
+ }
+ }
+ }
+
+ if (self::$_cookiesJar) {
+ self::$_cookiesJar->save(self::$_cookiesFile);
+ }
+
+ return $res;
+ }
+
+ public static function handleException(\Throwable $e): int
+ {
+ $map = ['GuzzleHttp\Exception\ConnectException' => 622,
+ 'GuzzleHttp\Psr7\Exception\MalformedUriException' => 629];
+ $messageMap = ['Undefined array key "solution"' => 603];
+ $startMap = ['cURL error 60: SSL: no alternative certificate subject name matches target host name' => 695];
+
+ $exceptionClass = get_class($e);
+ $message = $e->getMessage();
+
+ if (isset($map[$exceptionClass])) {
+ return $map[$exceptionClass];
+ } elseif (isset($messageMap[$message])) {
+ return $messageMap[$message];
+ } else {
+ foreach ($startMap as $str => $code) {
+ if (str_starts_with($message, $str)) {
+ return $code;
+ }
+ }
+ dd($exceptionClass, $message);
+ }
+ }
+
/**
- * @param string $url
- * @param string|null $flaresolverr
- * @return array
+ * @param $url
+ * @return \Psr\Http\Message\ResponseInterface
+ * @throws \GuzzleHttp\Exception\GuzzleException
*/
- public static function getResponseCode(string $url, $timeout = 30, string $flaresolverr = null): array
+ public static function _request($url, $timeout, $method = "GET", $options = [], $browserHeaders = true)
{
- if (null !== $flaresolverr) {
- $headers = get_headers($url, 1);
- if ($headers['Server'] === "cloudflare") {
- return self::getHttpCodeCloudflare($url, $flaresolverr, $timeout);
- }
+ $client = new Client();
+ $headers = ($options['headers'] ?? []);
+ if ($browserHeaders) {
+ $headers = $headers + [
+ 'Connection' => 'keep-alive',
+ 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
+ 'Accept-Encoding' => 'gzip, deflate, br, zstd',
+ 'Accept-Language' => 'fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6',
+ 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36',
+ 'Upgrade-Insecure-Requests' => '1',
+ 'Cache-Control' => 'no-cache',
+ 'Pragma' => 'no-cache',
+ 'Priority' => 'u=0, i',
+ 'Dnt' => '1',
+ ];
+ }
+ $options = ['timeout' => $timeout, 'http_errors' => false, 'headers' => $headers, 'allow_redirects' => ['track_redirects' => true]] + $options;
+ if (self::$_cookiesJar) {
+ $options["cookies"] = self::$_cookiesJar;
}
- return self::getHttpCode($url, $timeout);
+
+ return $client->request($method, $url, $options);
}
public static function getHttpCodeCloudflare($url, $apiUrl, $timeout = 30)
{
- $payload = json_encode([
+ $timeout = max($timeout, 60);
+
+ $payload = [
'cmd' => 'request.get',
'url' => $url,
'maxTimeout' => $timeout * 1000,
- ]);
-
+ ];
- $ch = curl_init($apiUrl);
- self::setCurlOpt($ch, $timeout, [CURLOPT_POST => true,
- CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
- CURLOPT_POSTFIELDS => $payload]);
- $response = curl_exec($ch);
+ $response = self::_request($apiUrl, $timeout, 'POST', ['json' => $payload, 'headers' => ['Content-Type' => 'application/json']], false);
+ $body = json_decode($response->getBody(), true);
+ $httpcode = $body['solution']['status'];
- if (preg_match('/(error|code) \b(301|302|308|404|401|403|405|500|502|503)\b/', $response, $matches)) {
- $httpcode = $matches[2] ?? '';
- $finalUrl = '';
- $finalHttpCode = '';
+ if (self::$_cookiesJar && isset($body['solution']['cookies'])) {
+ foreach ($body['solution']['cookies'] as $cookie) {
+ self::$_cookiesJar->setCookie(new SetCookie($cookie));
+ }
}
- curl_close($ch);
-
- return ['httpcode' => $httpcode, 'finalurl' => $finalUrl, 'finalHttpCode' => $finalHttpCode];
+ return ['http_code' => $httpcode];
}
- protected static function setCurlOpt($ch, $timeout = 30, $moreOptions = [])
- {
- curl_setopt_array($ch, array_merge([
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_HEADER => true,
- CURLOPT_NOBODY => true,
- CURLOPT_TIMEOUT => $timeout], $moreOptions)
- );
- }
-
-
public static function getHttpCodeComment($httpcode)
{
switch ($httpcode) {