| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- <?php
- /**
- * This file contain fetch class, which is used to communicate with NTFY.sh
- * REST api. It makes that HTTP request using buildin CURL extension is
- * much easier, and looks better in high level code.
- *
- * @package phpnotify
- * @author Cixo (Cixo Electronic)
- */
- namespace phpnotify;
- use \TypeError as TypeError;
- use \RuntimeException as RuntimeException;
- use \CurlHandle as CurlHandle;
- use \curl_init as curl_init;
- use \curl_setopt as curl_setopt;
- use \curl_close as curl_close;
- use \curl_exec as curl_exec;
- use \curl_error as curl_error;
- use \curl_errno as curl_errno;
- require('response.php');
- /**
- * This class is responsible for downloading data from the server. It uses
- * buildin CURL extension to make HTTP request. It not parsing response
- * directly, but use {@link response}
- */
- class fetch {
-
- /**
- * This store content of the requst body.
- * @var ?string
- */
- private ?string $content;
- /**
- * This store type of content.
- * @var ?string
- */
- private ?string $content_type;
- /**
- * This store method of the request.
- * @var string
- */
- private string $method;
- /**
- * This store url to fetch.
- * @var string
- */
- private string $url;
- /**
- * This store headers of the request.
- * @var array
- */
- private array $headers;
- /**
- * This create new fetch request. It is alias of constructor.
- *
- * @link fetch::__construct()
- * @static
- * @param string $url URL to fetch.
- * @return fetch New fetch object.
- */
- public static function create(string $url): object {
- return new self($url);
- }
- /**
- * This initialize new fetch request by given URL. Default method for
- * the request is GET. If do not want to use new, see create.
- *
- * @link fetch::create()
- * @param string $url URL to work with.
- */
- public function __construct(string $url) {
- $this->content = null;
- $this->content_type = null;
- $this->method = 'GET';
- $this->headers = array();
- $this->url = $url;
- }
- /**
- * This function could be use send array in the fetch request. Be careful
- * because this function verify that method of the request is not GET or
- * HEAD, which can not contain body. Property method must be set before.
- *
- * @param array $content Content which must be send.
- * @return fetch Itself to chain load.
- */
- public function send_array(array $content): object {
- $content = json_encode($content);
- $type = 'application/json';
- $this->send_raw($content, $type);
- return $this;
-
- }
- /**
- * This function is similar to {@link fetch::send_array()}, but work on
- * raw string data. Also content type must be set. Be careful, because
- * it check that method of the request is not GET or HEAD, which can
- * not contain body content.
- *
- * @param string $content Content of the body to send.
- * @param string $type Type of the content, like "text/plain".
- * @return fetch Self to chan loading.
- */
- public function send_raw(string $content, string $type): object {
- if ($this->method === 'GET' or $this->method === 'HEAD') {
- throw new TypeError('GET or HEAD request can not contain body.');
- }
- $this->content = $content;
- $this->content_type = $type;
- return $this;
- }
- /**
- * That add new header to the request. Name of the header must be full
- * featured header name, like 'Cache-Control'. It also had been validated
- * and when name had been blacklisted, it raise RuntimeException. It also
- * raise RuntimeException when name has any white chars. Content had been
- * validating, and it could not have new lines. Name and content would be
- * trimed before processing.
- *
- * Blacklisted headers:
- * Content-Type, Content-Length
- *
- * @param string $name Name of the header.
- * @param string $content Content of the header.
- * @return fetch Self to chain processing.
- */
- public function add_header(string $name, string $content): object {
- $name = trim($name);
- $content = trim($content);
- if (strpos($name, ' ') !== false) {
- throw new RuntimeException(
- 'Header "'.$name.'" contains white char.'
- );
- }
- $check_content = strpos($content, ' ') !== false;
- $check_content = $check_content || strpos($content, "\r") !== false;
- $check_content = $check_content || strpos($content, "\n") !== false;
- if ($check_content) {
- throw new RuntimeException(
- 'Header content "'.$content.'" contains invalid white char.'
- );
- }
- if ($name === 'Content-Type') {
- throw new RuntimeException('Content-Type header is automatic.');
- }
- if ($name === 'Content-Lenght') {
- throw new RuntimeException('Content-Lenght header is automatic.');
- }
- $header = $name.': '.$content;
- array_push($this->headers, $header);
-
- return $this;
- }
- /**
- * This function set method of the request. Be careful, because it check
- * that any content is not set, and when content is not null, but trying
- * to set GET or HEAD method, it throw TypeError.
- *
- * @param string $name Name of the method.
- * @return fetch Self to chain loading.
- */
- public function set_method(string $name): object {
- if ($this->content === null) {
- $this->method = $name;
- return $this;
- }
- if ($name === 'GET' || $name === 'HEAD') {
- throw new TypeError('GET or HEAD request can not contain body.');
- }
- $this->method = $name;
- return $this;
- }
-
- /**
- * That function make request to the server, from fetch config, which
- * had been config previously. It return response in parsed form, as
- * instance of response class. Be careful, it raise an RuntimeException
- * when server does not response correctly.
- *
- * @return response Response from the server.
- */
- public function request(): response {
- $headers = $this->headers;
- $request = curl_init($this->url);
- curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($request, CURLOPT_FAILONERROR, true);
- curl_setopt($request, CURLOPT_HEADER, true);
- curl_setopt($request,CURLOPT_CUSTOMREQUEST, $this->method);
- if ($this->content !== null) {
- array_push($headers, 'Content-Type: '.$this->content_type);
- curl_setopt($request, CURLOPT_POSTFIELDS, $this->content);
- }
- curl_setopt($request, CURLOPT_HTTPHEADER, $headers);
-
- $result = curl_exec($request);
- $error = curl_error($request);
- $error_number = curl_errno($request);
-
- curl_close($request);
-
- if ($result !== false and $error_number === 0) {
- return new response($result);
- }
- throw new RuntimeException(
- 'Can not fetch request. Error code '
- .strval($error_number)
- .': "'.$error.'".'
- );
- }
- }
|