|string $body
264 | *
265 | * @return static
266 | */
267 | #[Override]
268 | public function setBody(array | string $body) : static
269 | {
270 | if (\is_array($body)) {
271 | $body = \http_build_query($body);
272 | }
273 | return parent::setBody($body);
274 | }
275 |
276 | /**
277 | * Set body with JSON data.
278 | *
279 | * @param mixed $data
280 | * @param int|null $flags [optional]
281 | * Bitmask consisting of JSON_FORCE_OBJECT,
282 | * JSON_HEX_AMP,
283 | * JSON_HEX_APOS,
284 | * JSON_HEX_QUOT,
285 | * JSON_HEX_TAG,
286 | * JSON_INVALID_UTF8_IGNORE,
287 | * JSON_INVALID_UTF8_SUBSTITUTE,
288 | * JSON_INVALID_UTF8_SUBSTITUTE,
289 | * JSON_NUMERIC_CHECK,
290 | * JSON_PARTIAL_OUTPUT_ON_ERROR,
291 | * JSON_PRESERVE_ZERO_FRACTION,
292 | * JSON_PRETTY_PRINT,
293 | * JSON_THROW_ON_ERROR,
294 | * JSON_UNESCAPED_LINE_TERMINATORS,
295 | * JSON_UNESCAPED_SLASHES,
296 | * JSON_UNESCAPED_UNICODE.
297 | *
298 | * Default is JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
299 | * when null. JSON_THROW_ON_ERROR is enforced by default.
300 | * @param int<1,max> $depth [optional] Set the maximum depth. Must be greater than zero.
301 | *
302 | * @see https://www.php.net/manual/en/function.json-encode.php
303 | * @see https://www.php.net/manual/en/json.constants.php
304 | *
305 | * @throws JsonException if json_encode() fails
306 | *
307 | * @return static
308 | */
309 | public function setJson(mixed $data, ?int $flags = null, int $depth = 512) : static
310 | {
311 | if ($flags === null) {
312 | $flags = $this->getJsonFlags();
313 | }
314 | $data = \json_encode($data, $flags | \JSON_THROW_ON_ERROR, $depth);
315 | $this->setContentType('application/json');
316 | $this->setBody($data);
317 | return $this;
318 | }
319 |
320 | /**
321 | * Set POST data simulating a browser request.
322 | *
323 | * @param array $data
324 | *
325 | * @return static
326 | */
327 | public function setPost(array $data) : static
328 | {
329 | $this->setMethod(Method::POST);
330 | $this->setBody($data);
331 | return $this;
332 | }
333 |
334 | #[Pure]
335 | public function hasFiles() : bool
336 | {
337 | return !empty($this->files);
338 | }
339 |
340 | /**
341 | * Get files for upload.
342 | *
343 | * @return array
344 | */
345 | #[Pure]
346 | public function getFiles() : array
347 | {
348 | return $this->files;
349 | }
350 |
351 | /**
352 | * Set files for upload.
353 | *
354 | * @param array $files Fields as keys, files (CURLFile,
355 | * CURLStringFile or string filename) as values.
356 | * Multi-dimensional array is allowed.
357 | *
358 | * @throws InvalidArgumentException for invalid file path
359 | *
360 | * @return static
361 | */
362 | public function setFiles(array $files) : static
363 | {
364 | $this->setMethod(Method::POST);
365 | $this->setContentType('multipart/form-data');
366 | $this->files = $files;
367 | return $this;
368 | }
369 |
370 | /**
371 | * Set the Content-Type header.
372 | *
373 | * @param string $mime
374 | * @param string|null $charset
375 | *
376 | * @return static
377 | */
378 | public function setContentType(string $mime, ?string $charset = 'UTF-8') : static
379 | {
380 | $this->setHeader(
381 | RequestHeader::CONTENT_TYPE,
382 | $mime . ($charset ? '; charset=' . $charset : '')
383 | );
384 | return $this;
385 | }
386 |
387 | /**
388 | * @param Cookie $cookie
389 | *
390 | * @return static
391 | */
392 | #[Override]
393 | public function setCookie(Cookie $cookie) : static
394 | {
395 | parent::setCookie($cookie);
396 | $this->setCookieHeader();
397 | return $this;
398 | }
399 |
400 | /**
401 | * @param array $cookies
402 | *
403 | * @return static
404 | */
405 | #[Override]
406 | public function setCookies(array $cookies) : static
407 | {
408 | return parent::setCookies($cookies);
409 | }
410 |
411 | /**
412 | * @param string $name
413 | *
414 | * @return static
415 | */
416 | #[Override]
417 | public function removeCookie(string $name) : static
418 | {
419 | parent::removeCookie($name);
420 | $this->setCookieHeader();
421 | return $this;
422 | }
423 |
424 | /**
425 | * @param array $names
426 | *
427 | * @return static
428 | */
429 | #[Override]
430 | public function removeCookies(array $names) : static
431 | {
432 | parent::removeCookies($names);
433 | $this->setCookieHeader();
434 | return $this;
435 | }
436 |
437 | /**
438 | * @return static
439 | */
440 | protected function setCookieHeader() : static
441 | {
442 | $line = [];
443 | foreach ($this->getCookies() as $cookie) {
444 | $line[] = $cookie->getName() . '=' . $cookie->getValue();
445 | }
446 | if ($line) {
447 | $line = \implode('; ', $line);
448 | return $this->setHeader(RequestHeader::COOKIE, $line);
449 | }
450 | return $this->removeHeader(RequestHeader::COOKIE);
451 | }
452 |
453 | /**
454 | * @param string $name
455 | * @param string $value
456 | *
457 | * @return static
458 | */
459 | #[Override]
460 | public function setHeader(string $name, string $value) : static
461 | {
462 | return parent::setHeader($name, $value);
463 | }
464 |
465 | /**
466 | * @param array $headers
467 | *
468 | * @return static
469 | */
470 | #[Override]
471 | public function setHeaders(array $headers) : static
472 | {
473 | return parent::setHeaders($headers);
474 | }
475 |
476 | /**
477 | * @param string $name
478 | *
479 | * @return static
480 | */
481 | #[Override]
482 | public function removeHeader(string $name) : static
483 | {
484 | return parent::removeHeader($name);
485 | }
486 |
487 | /**
488 | * @return static
489 | */
490 | #[Override]
491 | public function removeHeaders() : static
492 | {
493 | return parent::removeHeaders();
494 | }
495 |
496 | /**
497 | * Set Authorization header with Basic type.
498 | *
499 | * @param string $username
500 | * @param string $password
501 | *
502 | * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
503 | *
504 | * @return static
505 | */
506 | public function setBasicAuth(
507 | string $username,
508 | #[SensitiveParameter]
509 | string $password
510 | ) : static {
511 | return $this->setHeader(
512 | RequestHeader::AUTHORIZATION,
513 | 'Basic ' . \base64_encode($username . ':' . $password)
514 | );
515 | }
516 |
517 | /**
518 | * Set Authorization header with Bearer type.
519 | *
520 | * @param string $token
521 | *
522 | * @return static
523 | */
524 | public function setBearerAuth(#[SensitiveParameter] string $token) : static
525 | {
526 | return $this->setHeader(
527 | RequestHeader::AUTHORIZATION,
528 | 'Bearer ' . $token
529 | );
530 | }
531 |
532 | /**
533 | * Set the User-Agent header.
534 | *
535 | * @param string|null $userAgent
536 | *
537 | * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent
538 | *
539 | * @return static
540 | */
541 | public function setUserAgent(?string $userAgent = null) : static
542 | {
543 | $userAgent ??= 'Aplus HTTP Client';
544 | return $this->setHeader(RequestHeader::USER_AGENT, $userAgent);
545 | }
546 |
547 | /**
548 | * Set a callback to write the response body with chunks.
549 | *
550 | * Used to write data to files, databases, etc...
551 | *
552 | * NOTE: Using this function makes the Response body, returned in the
553 | * {@see Client::run()} method, be set with an empty string.
554 | *
555 | * @param callable $callback A callback with the response body $data chunk
556 | * as first argument and the CurlHandle as the second. Return is not
557 | * necessary.
558 | *
559 | * @return static
560 | */
561 | public function setDownloadFunction(callable $callback) : static
562 | {
563 | $function = static function (\CurlHandle $handle, string $data) use ($callback) : int {
564 | $callback($data, $handle);
565 | return \strlen($data);
566 | };
567 | $this->setOption(\CURLOPT_WRITEFUNCTION, $function);
568 | return $this;
569 | }
570 |
571 | /**
572 | * Set a filename to download the file.
573 | *
574 | * @param string $filename The filename
575 | * @param bool $overwrite Set true to allow to overwrite the file
576 | *
577 | * @throws RuntimeException if $overwrite is false and the file exists
578 | *
579 | * @return static
580 | */
581 | public function setDownloadFile(string $filename, bool $overwrite = false) : static
582 | {
583 | $isFile = \is_file($filename);
584 | if ($isFile && $overwrite === false) {
585 | throw new RuntimeException('File path already exists: ' . $filename);
586 | }
587 | if ($isFile) {
588 | \unlink($filename);
589 | }
590 | $this->setDownloadFunction(static function (string $data) use ($filename) : void {
591 | \file_put_contents($filename, $data, \FILE_APPEND);
592 | });
593 | return $this;
594 | }
595 |
596 | /**
597 | * Set curl options.
598 | *
599 | * @param int $option A curl constant
600 | * @param mixed $value
601 | *
602 | * @see Client::$defaultOptions
603 | *
604 | * @return static
605 | */
606 | public function setOption(int $option, mixed $value) : static
607 | {
608 | if ($this->isCheckingOptions()) {
609 | $this->checkOption($option, $value);
610 | }
611 | $this->options[$option] = $value;
612 | return $this;
613 | }
614 |
615 | /**
616 | * Set many curl options.
617 | *
618 | * @param array $options Curl constants as keys and their respective values
619 | *
620 | * @return static
621 | */
622 | public function setOptions(array $options) : static
623 | {
624 | foreach ($options as $option => $value) {
625 | $this->setOption($option, $value);
626 | }
627 | return $this;
628 | }
629 |
630 | /**
631 | * Get default options replaced by custom.
632 | *
633 | * @return array
634 | */
635 | public function getOptions() : array
636 | {
637 | $options = \array_replace($this->defaultOptions, $this->options);
638 | $options[\CURLOPT_PROTOCOLS] = \CURLPROTO_HTTPS | \CURLPROTO_HTTP;
639 | $options[\CURLOPT_HTTP_VERSION] = match ($this->getProtocol()) {
640 | Protocol::HTTP_1_0 => \CURL_HTTP_VERSION_1_0,
641 | Protocol::HTTP_1_1 => \CURL_HTTP_VERSION_1_1,
642 | Protocol::HTTP_2_0 => \CURL_HTTP_VERSION_2_0,
643 | Protocol::HTTP_2 => \CURL_HTTP_VERSION_2,
644 | default => throw new InvalidArgumentException(
645 | 'Invalid Request Protocol: ' . $this->getProtocol()
646 | )
647 | };
648 | switch ($this->getMethod()) {
649 | case Method::POST:
650 | $options[\CURLOPT_POST] = true;
651 | $options[\CURLOPT_POSTFIELDS] = $this->getPostAndFiles();
652 | break;
653 | case Method::DELETE:
654 | case Method::PATCH:
655 | case Method::PUT:
656 | $options[\CURLOPT_POSTFIELDS] = $this->getBody();
657 | break;
658 | }
659 | $options[\CURLOPT_CUSTOMREQUEST] = $this->getMethod();
660 | $options[\CURLOPT_HEADER] = false;
661 | $options[\CURLOPT_URL] = $this->getUrl()->toString();
662 | $options[\CURLOPT_HTTPHEADER] = $this->getHeaderLines();
663 | return $options;
664 | }
665 |
666 | public function getOption(int $option) : mixed
667 | {
668 | return $this->getOptions()[$option] ?? null;
669 | }
670 |
671 | /**
672 | * Returns string if the Request has not files and curl will set the
673 | * Content-Type header to application/x-www-form-urlencoded. If the Request
674 | * has files, returns an array and curl will set the Content-Type to
675 | * multipart/form-data.
676 | *
677 | * If the Request has files, the $post and $files arrays are converted to
678 | * the array_simple format. Because curl does not understand the PHP
679 | * multi-dimensional arrays.
680 | *
681 | * @see https://www.php.net/manual/en/function.curl-setopt.php CURLOPT_POSTFIELDS
682 | * @see ArraySimple::convert()
683 | *
684 | * @return array|string
685 | */
686 | public function getPostAndFiles() : array | string
687 | {
688 | if (!$this->hasFiles()) {
689 | return $this->getBody();
690 | }
691 | \parse_str($this->getBody(), $post);
692 | $post = ArraySimple::convert($post);
693 | foreach ($post as &$value) {
694 | $value = (string) $value;
695 | }
696 | unset($value);
697 | $files = ArraySimple::convert($this->getFiles());
698 | foreach ($files as $field => &$file) {
699 | // @phpstan-ignore-next-line
700 | if ($file instanceof CURLFile || $file instanceof CURLStringFile) {
701 | continue;
702 | }
703 | if (!\is_file($file)) {
704 | throw new InvalidArgumentException(
705 | "Field '{$field}' does not match a file: {$file}"
706 | );
707 | }
708 | $file = new CURLFile(
709 | $file,
710 | \mime_content_type($file) ?: 'application/octet-stream',
711 | \basename($file)
712 | );
713 | }
714 | unset($file);
715 | return \array_replace($post, $files);
716 | }
717 |
718 | public function setGetInfo(bool $get = true) : static
719 | {
720 | $this->getInfo = $get;
721 | return $this;
722 | }
723 |
724 | public function isGettingInfo() : bool
725 | {
726 | return $this->getInfo;
727 | }
728 |
729 | /**
730 | * @param bool $check
731 | *
732 | * @return static
733 | */
734 | public function setCheckOptions(bool $check = true) : static
735 | {
736 | $this->checkOptions = $check;
737 | return $this;
738 | }
739 |
740 | public function isCheckingOptions() : bool
741 | {
742 | return $this->checkOptions;
743 | }
744 |
745 | /**
746 | * @param int $option The curl option
747 | * @param mixed $value The curl option value
748 | *
749 | * @throws InvalidArgumentException if the option value does not match the
750 | * expected type
751 | * @throws OutOfBoundsException if the option is invalid
752 | */
753 | protected function checkOption(int $option, mixed $value) : void
754 | {
755 | $types = [
756 | 'bool' => [
757 | \CURLOPT_AUTOREFERER,
758 | \CURLOPT_COOKIESESSION,
759 | \CURLOPT_CERTINFO,
760 | \CURLOPT_CONNECT_ONLY,
761 | \CURLOPT_CRLF,
762 | \CURLOPT_DISALLOW_USERNAME_IN_URL,
763 | \CURLOPT_DNS_SHUFFLE_ADDRESSES,
764 | \CURLOPT_HAPROXYPROTOCOL,
765 | \CURLOPT_SSH_COMPRESSION,
766 | \CURLOPT_DNS_USE_GLOBAL_CACHE,
767 | \CURLOPT_FAILONERROR,
768 | \CURLOPT_SSL_FALSESTART,
769 | \CURLOPT_FILETIME,
770 | \CURLOPT_FOLLOWLOCATION,
771 | \CURLOPT_FORBID_REUSE,
772 | \CURLOPT_FRESH_CONNECT,
773 | \CURLOPT_FTP_USE_EPRT,
774 | \CURLOPT_FTP_USE_EPSV,
775 | \CURLOPT_FTP_CREATE_MISSING_DIRS,
776 | \CURLOPT_FTPAPPEND,
777 | \CURLOPT_TCP_NODELAY,
778 | // CURLOPT_FTPASCII,
779 | \CURLOPT_FTPLISTONLY,
780 | \CURLOPT_HEADER,
781 | \CURLINFO_HEADER_OUT,
782 | \CURLOPT_HTTP09_ALLOWED,
783 | \CURLOPT_HTTPGET,
784 | \CURLOPT_HTTPPROXYTUNNEL,
785 | \CURLOPT_HTTP_CONTENT_DECODING,
786 | \CURLOPT_KEEP_SENDING_ON_ERROR,
787 | // CURLOPT_MUTE,
788 | \CURLOPT_NETRC,
789 | \CURLOPT_NOBODY,
790 | \CURLOPT_NOPROGRESS,
791 | \CURLOPT_NOSIGNAL,
792 | \CURLOPT_PATH_AS_IS,
793 | \CURLOPT_PIPEWAIT,
794 | \CURLOPT_POST,
795 | \CURLOPT_PUT,
796 | \CURLOPT_RETURNTRANSFER,
797 | \CURLOPT_SASL_IR,
798 | \CURLOPT_SSL_ENABLE_ALPN,
799 | \CURLOPT_SSL_ENABLE_NPN,
800 | \CURLOPT_SSL_VERIFYPEER,
801 | \CURLOPT_SSL_VERIFYSTATUS,
802 | \CURLOPT_PROXY_SSL_VERIFYPEER,
803 | \CURLOPT_SUPPRESS_CONNECT_HEADERS,
804 | \CURLOPT_TCP_FASTOPEN,
805 | \CURLOPT_TFTP_NO_OPTIONS,
806 | \CURLOPT_TRANSFERTEXT,
807 | \CURLOPT_UNRESTRICTED_AUTH,
808 | \CURLOPT_UPLOAD,
809 | \CURLOPT_VERBOSE,
810 | ],
811 | 'int' => [
812 | \CURLOPT_BUFFERSIZE,
813 | \CURLOPT_CONNECTTIMEOUT,
814 | \CURLOPT_CONNECTTIMEOUT_MS,
815 | \CURLOPT_DNS_CACHE_TIMEOUT,
816 | \CURLOPT_EXPECT_100_TIMEOUT_MS,
817 | \CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS,
818 | \CURLOPT_FTPSSLAUTH,
819 | \CURLOPT_HEADEROPT,
820 | \CURLOPT_HTTP_VERSION,
821 | \CURLOPT_HTTPAUTH,
822 | \CURLOPT_INFILESIZE,
823 | \CURLOPT_LOW_SPEED_LIMIT,
824 | \CURLOPT_LOW_SPEED_TIME,
825 | \CURLOPT_MAXCONNECTS,
826 | \CURLOPT_MAXREDIRS,
827 | \CURLOPT_PORT,
828 | \CURLOPT_POSTREDIR,
829 | \CURLOPT_PROTOCOLS,
830 | \CURLOPT_PROXYAUTH,
831 | \CURLOPT_PROXYPORT,
832 | \CURLOPT_PROXYTYPE,
833 | \CURLOPT_REDIR_PROTOCOLS,
834 | \CURLOPT_RESUME_FROM,
835 | \CURLOPT_SOCKS5_AUTH,
836 | \CURLOPT_SSL_OPTIONS,
837 | \CURLOPT_SSL_VERIFYHOST,
838 | \CURLOPT_SSLVERSION,
839 | \CURLOPT_PROXY_SSL_OPTIONS,
840 | \CURLOPT_PROXY_SSL_VERIFYHOST,
841 | \CURLOPT_PROXY_SSLVERSION,
842 | \CURLOPT_STREAM_WEIGHT,
843 | \CURLOPT_TCP_KEEPALIVE,
844 | \CURLOPT_TCP_KEEPIDLE,
845 | \CURLOPT_TCP_KEEPINTVL,
846 | \CURLOPT_TIMECONDITION,
847 | \CURLOPT_TIMEOUT,
848 | \CURLOPT_TIMEOUT_MS,
849 | \CURLOPT_TIMEVALUE,
850 | \CURLOPT_TIMEVALUE_LARGE,
851 | \CURLOPT_MAX_RECV_SPEED_LARGE,
852 | \CURLOPT_MAX_SEND_SPEED_LARGE,
853 | \CURLOPT_SSH_AUTH_TYPES,
854 | \CURLOPT_IPRESOLVE,
855 | \CURLOPT_FTP_FILEMETHOD,
856 | ],
857 | 'string' => [
858 | \CURLOPT_ABSTRACT_UNIX_SOCKET,
859 | \CURLOPT_CAINFO,
860 | \CURLOPT_CAPATH,
861 | \CURLOPT_COOKIE,
862 | \CURLOPT_COOKIEFILE,
863 | \CURLOPT_COOKIEJAR,
864 | \CURLOPT_COOKIELIST,
865 | \CURLOPT_CUSTOMREQUEST,
866 | \CURLOPT_DEFAULT_PROTOCOL,
867 | \CURLOPT_DNS_INTERFACE,
868 | \CURLOPT_DNS_LOCAL_IP4,
869 | \CURLOPT_DNS_LOCAL_IP6,
870 | \CURLOPT_DOH_URL,
871 | \CURLOPT_EGDSOCKET,
872 | \CURLOPT_ENCODING,
873 | \CURLOPT_FTPPORT,
874 | \CURLOPT_INTERFACE,
875 | \CURLOPT_KEYPASSWD,
876 | \CURLOPT_KRB4LEVEL,
877 | \CURLOPT_LOGIN_OPTIONS,
878 | \CURLOPT_PINNEDPUBLICKEY,
879 | \CURLOPT_POSTFIELDS,
880 | \CURLOPT_PRIVATE,
881 | \CURLOPT_PRE_PROXY,
882 | \CURLOPT_PROXY,
883 | \CURLOPT_PROXY_SERVICE_NAME,
884 | \CURLOPT_PROXY_CAINFO,
885 | \CURLOPT_PROXY_CAPATH,
886 | \CURLOPT_PROXY_CRLFILE,
887 | \CURLOPT_PROXY_KEYPASSWD,
888 | \CURLOPT_PROXY_PINNEDPUBLICKEY,
889 | \CURLOPT_PROXY_SSLCERT,
890 | \CURLOPT_PROXY_SSLCERTTYPE,
891 | \CURLOPT_PROXY_SSL_CIPHER_LIST,
892 | \CURLOPT_PROXY_TLS13_CIPHERS,
893 | \CURLOPT_PROXY_SSLKEY,
894 | \CURLOPT_PROXY_SSLKEYTYPE,
895 | \CURLOPT_PROXY_TLSAUTH_PASSWORD,
896 | \CURLOPT_PROXY_TLSAUTH_TYPE,
897 | \CURLOPT_PROXY_TLSAUTH_USERNAME,
898 | \CURLOPT_PROXYUSERPWD,
899 | \CURLOPT_RANDOM_FILE,
900 | \CURLOPT_RANGE,
901 | \CURLOPT_REFERER,
902 | \CURLOPT_SERVICE_NAME,
903 | \CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
904 | \CURLOPT_SSH_PUBLIC_KEYFILE,
905 | \CURLOPT_SSH_PRIVATE_KEYFILE,
906 | \CURLOPT_SSL_CIPHER_LIST,
907 | \CURLOPT_SSLCERT,
908 | \CURLOPT_SSLCERTPASSWD,
909 | \CURLOPT_SSLCERTTYPE,
910 | \CURLOPT_SSLENGINE,
911 | \CURLOPT_SSLENGINE_DEFAULT,
912 | \CURLOPT_SSLKEY,
913 | \CURLOPT_SSLKEYPASSWD,
914 | \CURLOPT_SSLKEYTYPE,
915 | \CURLOPT_TLS13_CIPHERS,
916 | \CURLOPT_UNIX_SOCKET_PATH,
917 | \CURLOPT_URL,
918 | \CURLOPT_USERAGENT,
919 | \CURLOPT_USERNAME,
920 | \CURLOPT_PASSWORD,
921 | \CURLOPT_USERPWD,
922 | \CURLOPT_XOAUTH2_BEARER,
923 | ],
924 | 'array' => [
925 | \CURLOPT_CONNECT_TO,
926 | \CURLOPT_HTTP200ALIASES,
927 | \CURLOPT_HTTPHEADER,
928 | \CURLOPT_POSTQUOTE,
929 | \CURLOPT_PROXYHEADER,
930 | \CURLOPT_QUOTE,
931 | \CURLOPT_RESOLVE,
932 | ],
933 | 'fopen' => [
934 | \CURLOPT_FILE,
935 | \CURLOPT_INFILE,
936 | \CURLOPT_STDERR,
937 | \CURLOPT_WRITEHEADER,
938 | ],
939 | 'function' => [
940 | \CURLOPT_HEADERFUNCTION,
941 | // CURLOPT_PASSWDFUNCTION,
942 | \CURLOPT_PROGRESSFUNCTION,
943 | \CURLOPT_READFUNCTION,
944 | \CURLOPT_WRITEFUNCTION,
945 | ],
946 | 'curl_share_init' => [
947 | \CURLOPT_SHARE,
948 | ],
949 | ];
950 | foreach ($types as $type => $constants) {
951 | foreach ($constants as $constant) {
952 | if ($option !== $constant) {
953 | continue;
954 | }
955 | if ($value === null) {
956 | return;
957 | }
958 | $valid = match ($type) {
959 | 'bool' => \is_bool($value),
960 | 'int' => \is_int($value),
961 | 'string' => \is_string($value),
962 | 'array' => \is_array($value),
963 | 'fopen' => \is_resource($value),
964 | 'function' => \is_callable($value),
965 | 'curl_share_init' => $value instanceof \CurlShareHandle
966 | };
967 | if ($valid) {
968 | return;
969 | }
970 | $message = match ($type) {
971 | 'bool' => 'The value of option %d should be of bool type',
972 | 'int' => 'The value of option %d should be of int type',
973 | 'string' => 'The value of option %d should be of string type',
974 | 'array' => 'The value of option %d should be of array type',
975 | 'fopen' => 'The value of option %d should be a fopen() resource',
976 | 'function' => 'The value of option %d should be a callable',
977 | 'curl_share_init' => 'The value of option %d should be a result of curl_share_init()'
978 | };
979 | throw new InvalidArgumentException(\sprintf($message, $option));
980 | }
981 | }
982 | throw new OutOfBoundsException('Invalid curl constant option: ' . $option);
983 | }
984 | }
985 |
--------------------------------------------------------------------------------