curl.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. <?php namespace Lib;
  2. class HTTPUnexpectedResponse extends \Exception {
  3. static $ecode = array(
  4. 100 => 'Continue',
  5. 101 => 'Switching Protocols',
  6. 102 => 'Processing', // WebDAV; RFC 2518
  7. 200 => 'OK',
  8. 201 => 'Created',
  9. 202 => 'Accepted',
  10. 203 => 'Non-Authoritative Information', // since HTTP/1.1
  11. 204 => 'No Content',
  12. 205 => 'Reset Content',
  13. 206 => 'Partial Content',
  14. 207 => 'Multi-Status', // WebDAV; RFC 4918
  15. 208 => 'Already Reported', // WebDAV; RFC 5842
  16. 226 => 'IM Used', // RFC 3229
  17. 300 => 'Multiple Choices',
  18. 301 => 'Moved Permanently',
  19. 302 => 'Found',
  20. 303 => 'See Other', // since HTTP/1.1
  21. 304 => 'Not Modified',
  22. 305 => 'Use Proxy', // since HTTP/1.1
  23. 306 => 'Switch Proxy',
  24. 307 => 'Temporary Redirect', // since HTTP/1.1
  25. 308 => 'Permanent Redirect', // approved as experimental RFC
  26. 400 => 'Bad Request',
  27. 401 => 'Unauthorized',
  28. 402 => 'Payment Required',
  29. 403 => 'Forbidden',
  30. 404 => 'Not Found',
  31. 405 => 'Method Not Allowed',
  32. 406 => 'Not Acceptable',
  33. 407 => 'Proxy Authentication Required',
  34. 408 => 'Request Timeout',
  35. 409 => 'Conflict',
  36. 410 => 'Gone',
  37. 411 => 'Length Required',
  38. 412 => 'Precondition Failed',
  39. 413 => 'Request Entity Too Large',
  40. 414 => 'Request-URI Too Long',
  41. 415 => 'Unsupported Media Type',
  42. 416 => 'Requested Range Not Satisfiable',
  43. 417 => 'Expectation Failed',
  44. 418 => 'I\'m a teapot', // RFC 2324
  45. 419 => 'Authentication Timeout', // not in RFC 2616
  46. 420 => 'Enhance Your Calm', // Twitter
  47. 420 => 'Method Failure', // Spring Framework
  48. 422 => 'Unprocessable Entity', // WebDAV; RFC 4918
  49. 423 => 'Locked', // WebDAV; RFC 4918
  50. 424 => 'Failed Dependency', // WebDAV; RFC 4918
  51. 424 => 'Method Failure', // WebDAV)
  52. 425 => 'Unordered Collection', // Internet draft
  53. 426 => 'Upgrade Required', // RFC 2817
  54. 428 => 'Precondition Required', // RFC 6585
  55. 429 => 'Too Many Requests', // RFC 6585
  56. 431 => 'Request Header Fields Too Large', // RFC 6585
  57. 444 => 'No Response', // Nginx
  58. 449 => 'Retry With', // Microsoft
  59. 450 => 'Blocked by Windows Parental Controls', // Microsoft
  60. 451 => 'Redirect', // Microsoft
  61. 451 => 'Unavailable For Legal Reasons', // Internet draft
  62. 494 => 'Request Header Too Large', // Nginx
  63. 495 => 'Cert Error', // Nginx
  64. 496 => 'No Cert', // Nginx
  65. 497 => 'HTTP to HTTPS', // Nginx
  66. 499 => 'Client Closed Request', // Nginx
  67. 500 => 'Internal Server Error',
  68. 501 => 'Not Implemented',
  69. 502 => 'Bad Gateway',
  70. 503 => 'Service Unavailable',
  71. 504 => 'Gateway Timeout',
  72. 505 => 'HTTP Version Not Supported',
  73. 506 => 'Variant Also Negotiates', // RFC 2295
  74. 507 => 'Insufficient Storage', // WebDAV; RFC 4918
  75. 508 => 'Loop Detected', // WebDAV; RFC 5842
  76. 509 => 'Bandwidth Limit Exceeded', // Apache bw/limited extension
  77. 510 => 'Not Extended', // RFC 2774
  78. 511 => 'Network Authentication Required', // RFC 6585
  79. 598 => 'Network read timeout error', // Unknown
  80. 599 => 'Network connect timeout error', // Unknown
  81. );
  82. private $response;
  83. public function __construct($message, $code = 0, Exception $previous = null) {
  84. $this->response = $message;
  85. parent::__construct(HTTPUnexpectedResponse::$ecode[$code], $code, $previous);
  86. }
  87. public function __toString() {
  88. return __CLASS__ . ": [{$this->code} | {$this->message}]: {$this->response}\n";
  89. }
  90. public function getResponse() {
  91. return $this->response;
  92. }
  93. }
  94. class NotAuthorizedException extends HTTPUnexpectedResponse {
  95. public function __construct($message, Exception $previous = null) {
  96. parent::__contruct($message, 401, $previous);
  97. }
  98. }
  99. trait Curl {
  100. protected $url;
  101. protected $token;
  102. protected $user_agent = "Gogs PHP Api Client/0.0 (compatible; LINUX)";
  103. protected $timeout = 30;
  104. protected $max_redirects = 4;
  105. private function array_2_params(array $params) {
  106. return join("&", array_map(function($k, $v) {
  107. return sprintf("%s=%s", $k, rawurlencode(is_bool($v) ? ($v ? "true" : "false") : $v ));
  108. }, array_keys($params), $params));
  109. }
  110. private function array_2_json(array $params) {
  111. return json_encode($params);
  112. }
  113. protected function method(string $method, string &$req, string $scope, array $params, bool $ret) {
  114. $c = curl_init();
  115. if (!$c) {
  116. return false;
  117. }
  118. $headers = array(
  119. sprintf("Authorization: token %s", $this->token),
  120. );
  121. $url = sprintf("%s%s", $this->url, $scope);
  122. if (in_array($method, array("DELETE", "PATCH", "POST"))) {
  123. $json = $this->array_2_json($params);
  124. curl_setopt($c, CURLOPT_CUSTOMREQUEST, $method);
  125. curl_setopt($c, CURLOPT_POSTFIELDS, $json);
  126. echo sprintf("JSON: %s", $json);
  127. array_unshift($headers, "Content-Type: application/json");
  128. array_push($headers, "Content-Length: " . strlen($json));
  129. var_dump($headers);
  130. } else {
  131. $url .= "?" . $this->array_2_params($params);
  132. }
  133. echo sprintf("%s: %s\n", $method, $url);
  134. curl_setopt($c, CURLOPT_USERAGENT, $this->user_agent);
  135. curl_setopt($c, CURLOPT_URL, $url);
  136. curl_setopt($c, CURLOPT_HTTPHEADER, $headers);
  137. curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
  138. curl_setopt($c, CURLOPT_TIMEOUT, $this->timeout);
  139. curl_setopt($c, CURLOPT_MAXREDIRS, $this->max_redirects);
  140. curl_setopt($c, CURLOPT_FOLLOWLOCATION, true);
  141. $req = curl_exec($c);
  142. $status_code = curl_getinfo($c, CURLINFO_HTTP_CODE);
  143. curl_close($c);
  144. return $status_code;
  145. }
  146. protected function authorized($scope) {
  147. $ret = "";
  148. if ($this->method("GET", $ret, $scope, array(), false) == 401) {
  149. throw new NotAuthorizedException("Not authorized", 401);
  150. }
  151. return true;
  152. }
  153. private function post($scope = "", $params = array()) {
  154. $req = "";
  155. $code = $this->method("POST", $req, $scope, $params, true);
  156. switch ($code) {
  157. case 200:
  158. case 201:
  159. return $req;
  160. case 401:
  161. throw new NotAuthorizedException($req);
  162. default:
  163. throw new HTTPUnexpectedResponse($req, $code);
  164. }
  165. }
  166. private function delete($scope = "") {
  167. $req = "";
  168. $code = $this->method("DELETE", $req, $scope, array(), true);
  169. switch ($code) {
  170. case 200:
  171. case 204:
  172. return $req;
  173. case 401:
  174. throw new NotAuthorizedException($req);
  175. default:
  176. throw new HTTPUnexpectedResponse($req, $code);
  177. }
  178. }
  179. private function get($scope = "", $params = array()) {
  180. $req = "";
  181. $code = $this->method("GET", $req, $scope, $params, true);
  182. switch ($code) {
  183. case 200:
  184. return $req;
  185. case 401:
  186. throw new NotAuthorizedException($req);
  187. default:
  188. throw new HTTPUnexpectedResponse($req, $code);
  189. }
  190. }
  191. }