fetch.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <?php
  2. /**
  3. * This file contain fetch class, which is used to communicate with NTFY.sh
  4. * REST api. It makes that HTTP request using buildin CURL extension is
  5. * much easier, and looks better in high level code.
  6. *
  7. * @package phpnotify
  8. * @author Cixo (Cixo Electronic)
  9. */
  10. namespace phpnotify;
  11. use \TypeError as TypeError;
  12. use \RuntimeException as RuntimeException;
  13. use \CurlHandle as CurlHandle;
  14. use \curl_init as curl_init;
  15. use \curl_setopt as curl_setopt;
  16. use \curl_close as curl_close;
  17. use \curl_exec as curl_exec;
  18. use \curl_error as curl_error;
  19. use \curl_errno as curl_errno;
  20. require('response.php');
  21. /**
  22. * This class is responsible for downloading data from the server. It uses
  23. * buildin CURL extension to make HTTP request. It not parsing response
  24. * directly, but use {@link response}
  25. */
  26. class fetch {
  27. /**
  28. * This store content of the requst body.
  29. * @var ?string
  30. */
  31. private ?string $content;
  32. /**
  33. * This store type of content.
  34. * @var ?string
  35. */
  36. private ?string $content_type;
  37. /**
  38. * This store method of the request.
  39. * @var string
  40. */
  41. private string $method;
  42. /**
  43. * This store url to fetch.
  44. * @var string
  45. */
  46. private string $url;
  47. /**
  48. * This create new fetch request. It is alias of constructor.
  49. *
  50. * @link fetch::__construct()
  51. * @static
  52. * @param string $url URL to fetch.
  53. * @return fetch New fetch object.
  54. */
  55. public static function create(string $url): object {
  56. return new self($url);
  57. }
  58. /**
  59. * This initialize new fetch request by given URL. Default method for
  60. * the request is GET. If do not want to use new, see create.
  61. *
  62. * @link fetch::create()
  63. * @param string $url URL to work with.
  64. */
  65. public function __construct(string $url) {
  66. $this->content = null;
  67. $this->content_type = null;
  68. $this->method = 'GET';
  69. $this->url = $url;
  70. }
  71. /**
  72. * This function could be use send array in the fetch request. Be careful
  73. * because this function verify that method of the request is not GET or
  74. * HEAD, which can not contain body. Property method must be set before.
  75. *
  76. * @param array $content Content which must be send.
  77. * @return fetch Itself to chain load.
  78. */
  79. public function send_array(array $content): object {
  80. $content = json_encode($content);
  81. $type = 'application/json';
  82. $this->send_raw($content, $type);
  83. return $this;
  84. }
  85. /**
  86. * This function is similar to {@link fetch::send_array()}, but work on
  87. * raw string data. Also content type must be set. Be careful, because
  88. * it check that method of the request is not GET or HEAD, which can
  89. * not contain body content.
  90. *
  91. * @param string $content Content of the body to send.
  92. * @param string $type Type of the content, like "text/plain".
  93. * @return fetch Self to chan loading.
  94. */
  95. public function send_raw(string $content, string $type): object {
  96. if ($this->method === 'GET' or $this->method === 'HEAD') {
  97. throw new TypeError('GET or HEAD request can not contain body.');
  98. }
  99. $this->content = $content;
  100. $this->content_type = $type;
  101. return $this;
  102. }
  103. /**
  104. * This function set method of the request. Be careful, because it check
  105. * that any content is not set, and when content is not null, but trying
  106. * to set GET or HEAD method, it throw TypeError.
  107. *
  108. * @param string $name Name of the method.
  109. * @return fetch Self to chain loading.
  110. */
  111. public function set_method(string $name): object {
  112. if ($this->content === null) {
  113. $this->method = $name;
  114. return $this;
  115. }
  116. if ($name === 'GET' || $name === 'HEAD') {
  117. throw new TypeError('GET or HEAD request can not contain body.');
  118. }
  119. $this->method = $name;
  120. return $this;
  121. }
  122. /**
  123. * That function make request to the server, from fetch config, which
  124. * had been config previously. It return response in parsed form, as
  125. * instance of response class. Be careful, it raise an RuntimeException
  126. * when server does not response correctly.
  127. *
  128. * @return response Response from the server.
  129. */
  130. public function request(): response {
  131. $request = curl_init($this->url);
  132. curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
  133. curl_setopt($request, CURLOPT_FAILONERROR, true);
  134. curl_setopt($request, CURLOPT_HEADER, true);
  135. curl_setopt($request,CURLOPT_CUSTOMREQUEST, $this->method);
  136. if ($this->content !== null) {
  137. $type = 'Content-Type: '.$this->content_type;
  138. $headers = [ $type ];
  139. curl_setopt($request, CURLOPT_HTTPHEADER, $headers);
  140. curl_setopt($request, CURLOPT_POSTFIELDS, $this->content);
  141. }
  142. $result = curl_exec($request);
  143. $error = curl_error($request);
  144. $error_number = curl_errno($request);
  145. curl_close($request);
  146. if ($result !== false and $error_number === 0) {
  147. return new response($result);
  148. }
  149. throw new RuntimeException(
  150. 'Can not fetch request. Error code '
  151. .strval($error_number)
  152. .': "'.$error.'".'
  153. );
  154. }
  155. }