diff --git a/composer.json b/composer.json index a2ddce03..5fdb4226 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,6 @@ "inc/functions/num.php", "inc/functions/format.php", "inc/functions/theme.php", - "inc/driver/http-driver.php", "inc/driver/log-driver.php", "inc/service/captcha-queries.php", "inc/context.php" diff --git a/inc/Data/Driver/HttpDriver.php b/inc/Data/Driver/HttpDriver.php new file mode 100644 index 00000000..022fcbab --- /dev/null +++ b/inc/Data/Driver/HttpDriver.php @@ -0,0 +1,131 @@ +inner); + \curl_setopt_array($this->inner, [ + \CURLOPT_URL => $url, + \CURLOPT_TIMEOUT => $timeout, + \CURLOPT_USERAGENT => 'Tinyboard', + \CURLOPT_PROTOCOLS => \CURLPROTO_HTTP | \CURLPROTO_HTTPS, + ]); + } + + public function __construct(int $timeout, int $max_file_size) { + $this->inner = \curl_init(); + $this->timeout = $timeout; + $this->max_file_size = $max_file_size; + } + + public function __destruct() { + \curl_close($this->inner); + } + + /** + * Execute a GET request. + * + * @param string $endpoint Uri endpoint. + * @param ?array $data Optional GET parameters. + * @param int $timeout Optional request timeout in seconds. Use the default timeout if 0. + * @return string Returns the body of the response. + * @throws RuntimeException Throws on IO error. + */ + public function requestGet(string $endpoint, ?array $data, int $timeout = 0): string { + if (!empty($data)) { + $endpoint .= '?' . \http_build_query($data); + } + if ($timeout == 0) { + $timeout = $this->timeout; + } + + $this->resetTowards($endpoint, $timeout); + \curl_setopt($this->inner, \CURLOPT_RETURNTRANSFER, true); + $ret = \curl_exec($this->inner); + + if ($ret === false) { + throw new \RuntimeException(\curl_error($this->inner)); + } + return $ret; + } + + /** + * Execute a POST request. + * + * @param string $endpoint Uri endpoint. + * @param ?array $data Optional POST parameters. + * @param int $timeout Optional request timeout in seconds. Use the default timeout if 0. + * @return string Returns the body of the response. + * @throws RuntimeException Throws on IO error. + */ + public function requestPost(string $endpoint, ?array $data, int $timeout = 0): string { + if ($timeout == 0) { + $timeout = $this->timeout; + } + + $this->resetTowards($endpoint, $timeout); + \curl_setopt($this->inner, \CURLOPT_POST, true); + if (!empty($data)) { + \curl_setopt($this->inner, \CURLOPT_POSTFIELDS, \http_build_query($data)); + } + \curl_setopt($this->inner, \CURLOPT_RETURNTRANSFER, true); + $ret = \curl_exec($this->inner); + + if ($ret === false) { + throw new \RuntimeException(\curl_error($this->inner)); + } + return $ret; + } + + /** + * Download the url's target with curl. + * + * @param string $url Url to the file to download. + * @param ?array $data Optional GET parameters. + * @param resource $fd File descriptor to save the content to. + * @param int $timeout Optional request timeout in seconds. Use the default timeout if 0. + * @return bool Returns true on success, false if the file was too large. + * @throws RuntimeException Throws on IO error. + */ + public function requestGetInto(string $endpoint, ?array $data, mixed $fd, int $timeout = 0): bool { + if (!empty($data)) { + $endpoint .= '?' . \http_build_query($data); + } + if ($timeout == 0) { + $timeout = $this->timeout; + } + + $this->resetTowards($endpoint, $timeout); + // Adapted from: https://stackoverflow.com/a/17642638 + $opt = (\PHP_MAJOR_VERSION >= 8 && \PHP_MINOR_VERSION >= 2) ? \CURLOPT_XFERINFOFUNCTION : \CURLOPT_PROGRESSFUNCTION; + \curl_setopt_array($this->inner, [ + \CURLOPT_NOPROGRESS => false, + $opt => fn($res, $next_dl, $dl, $next_up, $up) => (int)($dl <= $this->max_file_size), + \CURLOPT_FAILONERROR => true, + \CURLOPT_FOLLOWLOCATION => false, + \CURLOPT_FILE => $fd, + \CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4, + ]); + $ret = \curl_exec($this->inner); + + if ($ret === false) { + if (\curl_errno($this->inner) === CURLE_ABORTED_BY_CALLBACK) { + return false; + } + + throw new \RuntimeException(\curl_error($this->inner)); + } + return true; + } +} diff --git a/inc/context.php b/inc/context.php index 3f8a75d6..c64f6a9c 100644 --- a/inc/context.php +++ b/inc/context.php @@ -2,7 +2,8 @@ namespace Vichan; use RuntimeException; -use Vichan\Driver\{HttpDriver, HttpDrivers, Log, LogDrivers}; +use Vichan\Driver\{Log, LogDrivers}; +use Vichan\Data\Driver\HttpDriver; use Vichan\Service\HCaptchaQuery; use Vichan\Service\NativeCaptchaQuery; use Vichan\Service\ReCaptchaQuery; @@ -56,7 +57,7 @@ function build_context(array $config): Context { }, HttpDriver::class => function($c) { $config = $c->get('config'); - return HttpDrivers::getHttpDriver($config['upload_by_url_timeout'], $config['max_filesize']); + return new HttpDriver($config['upload_by_url_timeout'], $config['max_filesize']); }, RemoteCaptchaQuery::class => function($c) { $config = $c->get('config'); diff --git a/inc/driver/http-driver.php b/inc/driver/http-driver.php deleted file mode 100644 index cfbedfad..00000000 --- a/inc/driver/http-driver.php +++ /dev/null @@ -1,151 +0,0 @@ -inner); - curl_setopt_array($this->inner, array( - CURLOPT_URL => $url, - CURLOPT_TIMEOUT => $this->timeout, - CURLOPT_USERAGENT => $this->user_agent, - CURLOPT_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS, - )); - } - - private function setSizeLimit(): void { - // Adapted from: https://stackoverflow.com/a/17642638 - curl_setopt($this->inner, CURLOPT_NOPROGRESS, false); - - if (PHP_MAJOR_VERSION >= 8 && PHP_MINOR_VERSION >= 2) { - curl_setopt($this->inner, CURLOPT_XFERINFOFUNCTION, function($res, $next_dl, $dl, $next_up, $up) { - return (int)($dl <= $this->max_file_size); - }); - } else { - curl_setopt($this->inner, CURLOPT_PROGRESSFUNCTION, function($res, $next_dl, $dl, $next_up, $up) { - return (int)($dl <= $this->max_file_size); - }); - } - } - - function __construct($timeout, $user_agent, $max_file_size) { - $this->inner = curl_init(); - $this->timeout = $timeout; - $this->user_agent = $user_agent; - $this->max_file_size = $max_file_size; - } - - function __destruct() { - curl_close($this->inner); - } - - /** - * Execute a GET request. - * - * @param string $endpoint Uri endpoint. - * @param ?array $data Optional GET parameters. - * @param int $timeout Optional request timeout in seconds. Use the default timeout if 0. - * @return string Returns the body of the response. - * @throws RuntimeException Throws on IO error. - */ - public function requestGet(string $endpoint, ?array $data, int $timeout = 0): string { - if (!empty($data)) { - $endpoint .= '?' . http_build_query($data); - } - if ($timeout == 0) { - $timeout = $this->timeout; - } - - $this->resetTowards($endpoint, $timeout); - curl_setopt($this->inner, CURLOPT_RETURNTRANSFER, true); - $ret = curl_exec($this->inner); - - if ($ret === false) { - throw new \RuntimeException(curl_error($this->inner)); - } - return $ret; - } - - /** - * Execute a POST request. - * - * @param string $endpoint Uri endpoint. - * @param ?array $data Optional POST parameters. - * @param int $timeout Optional request timeout in seconds. Use the default timeout if 0. - * @return string Returns the body of the response. - * @throws RuntimeException Throws on IO error. - */ - public function requestPost(string $endpoint, ?array $data, int $timeout = 0): string { - if ($timeout == 0) { - $timeout = $this->timeout; - } - - $this->resetTowards($endpoint, $timeout); - curl_setopt($this->inner, CURLOPT_POST, true); - if (!empty($data)) { - curl_setopt($this->inner, CURLOPT_POSTFIELDS, http_build_query($data)); - } - curl_setopt($this->inner, CURLOPT_RETURNTRANSFER, true); - $ret = curl_exec($this->inner); - - if ($ret === false) { - throw new \RuntimeException(curl_error($this->inner)); - } - return $ret; - } - - /** - * Download the url's target with curl. - * - * @param string $url Url to the file to download. - * @param ?array $data Optional GET parameters. - * @param resource $fd File descriptor to save the content to. - * @param int $timeout Optional request timeout in seconds. Use the default timeout if 0. - * @return bool Returns true on success, false if the file was too large. - * @throws RuntimeException Throws on IO error. - */ - public function requestGetInto(string $endpoint, ?array $data, mixed $fd, int $timeout = 0): bool { - if (!empty($data)) { - $endpoint .= '?' . http_build_query($data); - } - if ($timeout == 0) { - $timeout = $this->timeout; - } - - $this->resetTowards($endpoint, $timeout); - curl_setopt($this->inner, CURLOPT_FAILONERROR, true); - curl_setopt($this->inner, CURLOPT_FOLLOWLOCATION, false); - curl_setopt($this->inner, CURLOPT_FILE, $fd); - curl_setopt($this->inner, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); - $this->setSizeLimit(); - $ret = curl_exec($this->inner); - - if ($ret === false) { - if (curl_errno($this->inner) === CURLE_ABORTED_BY_CALLBACK) { - return false; - } - - throw new \RuntimeException(curl_error($this->inner)); - } - return true; - } -} diff --git a/inc/service/captcha-queries.php b/inc/service/captcha-queries.php index cd9a1b84..76d7acd8 100644 --- a/inc/service/captcha-queries.php +++ b/inc/service/captcha-queries.php @@ -1,7 +1,7 @@