You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

127 lines
4.3 KiB

  1. <?php
  2. namespace p3k;
  3. class HTTPCurl {
  4. public $timeout = 4;
  5. public $max_redirects = 8;
  6. public function get($url, $headers=[]) {
  7. $ch = curl_init($url);
  8. $this->_set_curlopts($ch, $url);
  9. if($headers)
  10. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  11. $response = curl_exec($ch);
  12. $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
  13. return array(
  14. 'code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
  15. 'headers' => self::parse_headers(trim(substr($response, 0, $header_size))),
  16. 'body' => substr($response, $header_size),
  17. 'error' => self::error_string_from_code(curl_errno($ch)),
  18. 'error_description' => curl_error($ch),
  19. 'error_code' => curl_errno($ch),
  20. 'url' => curl_getinfo($ch, CURLINFO_EFFECTIVE_URL),
  21. );
  22. }
  23. public function post($url, $body, $headers=[]) {
  24. $ch = curl_init($url);
  25. $this->_set_curlopts($ch, $url);
  26. curl_setopt($ch, CURLOPT_POST, true);
  27. curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
  28. if($headers)
  29. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  30. $response = curl_exec($ch);
  31. $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
  32. return array(
  33. 'code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
  34. 'headers' => self::parse_headers(trim(substr($response, 0, $header_size))),
  35. 'body' => substr($response, $header_size),
  36. 'error' => self::error_string_from_code(curl_errno($ch)),
  37. 'error_description' => curl_error($ch),
  38. 'error_code' => curl_errno($ch),
  39. 'url' => curl_getinfo($ch, CURLINFO_EFFECTIVE_URL),
  40. );
  41. }
  42. public function head($url) {
  43. $ch = curl_init($url);
  44. $this->_set_curlopts($ch, $url);
  45. curl_setopt($ch, CURLOPT_NOBODY, true);
  46. $response = curl_exec($ch);
  47. return array(
  48. 'code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
  49. 'headers' => self::parse_headers(trim($response)),
  50. 'error' => self::error_string_from_code(curl_errno($ch)),
  51. 'error_description' => curl_error($ch),
  52. 'error_code' => curl_errno($ch),
  53. 'url' => curl_getinfo($ch, CURLINFO_EFFECTIVE_URL),
  54. );
  55. }
  56. private function _set_curlopts($ch, $url) {
  57. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  58. curl_setopt($ch, CURLOPT_HEADER, true);
  59. // Special-case appspot.com URLs to not follow redirects.
  60. // https://cloud.google.com/appengine/docs/php/urlfetch/
  61. if(should_follow_redirects($url)) {
  62. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  63. curl_setopt($ch, CURLOPT_MAXREDIRS, $this->max_redirects);
  64. } else {
  65. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
  66. }
  67. curl_setopt($ch, CURLOPT_TIMEOUT_MS, round($this->timeout * 1000));
  68. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 2000);
  69. }
  70. public static function error_string_from_code($code) {
  71. switch($code) {
  72. case 0:
  73. return '';
  74. case CURLE_COULDNT_RESOLVE_HOST:
  75. return 'dns_error';
  76. case CURLE_COULDNT_CONNECT:
  77. return 'connect_error';
  78. case CURLE_OPERATION_TIMEDOUT:
  79. return 'timeout';
  80. case CURLE_SSL_CONNECT_ERROR:
  81. return 'ssl_error';
  82. case CURLE_SSL_CERTPROBLEM:
  83. return 'ssl_cert_error';
  84. case CURLE_SSL_CIPHER:
  85. return 'ssl_unsupported_cipher';
  86. case CURLE_SSL_CACERT:
  87. return 'ssl_cert_error';
  88. case CURLE_TOO_MANY_REDIRECTS:
  89. return 'too_many_redirects';
  90. default:
  91. return 'unknown';
  92. }
  93. }
  94. public static function parse_headers($headers) {
  95. $retVal = array();
  96. $fields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', $headers));
  97. foreach($fields as $field) {
  98. if(preg_match('/([^:]+): (.+)/m', $field, $match)) {
  99. $match[1] = preg_replace_callback('/(?<=^|[\x09\x20\x2D])./', function($m) {
  100. return strtoupper($m[0]);
  101. }, strtolower(trim($match[1])));
  102. // If there's already a value set for the header name being returned, turn it into an array and add the new value
  103. $match[1] = preg_replace_callback('/(?<=^|[\x09\x20\x2D])./', function($m) {
  104. return strtoupper($m[0]);
  105. }, strtolower(trim($match[1])));
  106. if(isset($retVal[$match[1]])) {
  107. if(!is_array($retVal[$match[1]]))
  108. $retVal[$match[1]] = array($retVal[$match[1]]);
  109. $retVal[$match[1]][] = $match[2];
  110. } else {
  111. $retVal[$match[1]] = trim($match[2]);
  112. }
  113. }
  114. }
  115. return $retVal;
  116. }
  117. }