1<?php declare(strict_types=1); 2 3/* 4 * This file is part of the Monolog package. 5 * 6 * (c) Jordi Boggiano <j.boggiano@seld.be> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Monolog\Handler\Curl; 13 14use CurlHandle; 15 16/** 17 * This class is marked as internal and it is not under the BC promise of the package. 18 * 19 * @internal 20 */ 21final class Util 22{ 23 /** @var array<int> */ 24 private static $retriableErrorCodes = [ 25 CURLE_COULDNT_RESOLVE_HOST, 26 CURLE_COULDNT_CONNECT, 27 CURLE_HTTP_NOT_FOUND, 28 CURLE_READ_ERROR, 29 CURLE_OPERATION_TIMEOUTED, 30 CURLE_HTTP_POST_ERROR, 31 CURLE_SSL_CONNECT_ERROR, 32 ]; 33 34 /** 35 * Executes a CURL request with optional retries and exception on failure 36 * 37 * @param resource|CurlHandle $ch curl handler 38 * @param int $retries 39 * @param bool $closeAfterDone 40 * @return bool|string @see curl_exec 41 */ 42 public static function execute($ch, int $retries = 5, bool $closeAfterDone = true) 43 { 44 while ($retries--) { 45 $curlResponse = curl_exec($ch); 46 if ($curlResponse === false) { 47 $curlErrno = curl_errno($ch); 48 49 if (false === in_array($curlErrno, self::$retriableErrorCodes, true) || !$retries) { 50 $curlError = curl_error($ch); 51 52 if ($closeAfterDone) { 53 curl_close($ch); 54 } 55 56 throw new \RuntimeException(sprintf('Curl error (code %d): %s', $curlErrno, $curlError)); 57 } 58 59 continue; 60 } 61 62 if ($closeAfterDone) { 63 curl_close($ch); 64 } 65 66 return $curlResponse; 67 } 68 69 return false; 70 } 71} 72