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.

158 lines
4.1 KiB

  1. <?php
  2. namespace p3k\XRay;
  3. class Fetch {
  4. private $http;
  5. public function __construct($http) {
  6. $this->http = $http;
  7. }
  8. public function fetch($url, $opts=[]) {
  9. if(isset($opts['timeout']))
  10. $this->http->set_timeout($opts['timeout']);
  11. if(isset($opts['max_redirects']))
  12. $this->http->set_max_redirects($opts['max_redirects']);
  13. // Attempt some basic URL validation
  14. $scheme = parse_url($url, PHP_URL_SCHEME);
  15. if(!in_array($scheme, ['http','https'])) {
  16. return [
  17. 'error_code' => 400,
  18. 'error' => 'invalid_url',
  19. 'error_description' => 'Only http and https URLs are supported'
  20. ];
  21. }
  22. $host = parse_url($url, PHP_URL_HOST);
  23. if(!$host) {
  24. return [
  25. 'error_code' => 400,
  26. 'error' => 'invalid_url',
  27. 'error_description' => 'The URL provided was not valid'
  28. ];
  29. }
  30. $url = normalize_url($url);
  31. $host = parse_url($url, PHP_URL_HOST);
  32. // Check if this is a Twitter URL and if they've provided API credentials, use the API
  33. if(Formats\Twitter::matches_host($url)) {
  34. return $this->_fetch_tweet($url, $opts);
  35. }
  36. if(Formats\GitHub::matches_host($url)) {
  37. return $this->_fetch_github($url, $opts);
  38. }
  39. // Special-case appspot.com URLs to not follow redirects.
  40. // https://cloud.google.com/appengine/docs/php/urlfetch/
  41. if(!should_follow_redirects($url)) {
  42. $this->http->set_max_redirects(0);
  43. $this->http->set_transport(new \p3k\HTTP\Stream());
  44. } else {
  45. $this->http->set_transport(new \p3k\HTTP\Curl());
  46. }
  47. $headers = [];
  48. if(isset($opts['token']))
  49. $headers[] = 'Authorization: Bearer ' . $opts['token'];
  50. $result = $this->http->get($url, $headers);
  51. if($result['error']) {
  52. return [
  53. 'error' => $result['error'],
  54. 'error_description' => $result['error_description'],
  55. 'url' => $result['url'],
  56. 'code' => $result['code'],
  57. ];
  58. }
  59. if(trim($result['body']) == '') {
  60. if($result['code'] == 410) {
  61. // 410 Gone responses are valid and should not return an error
  62. return $this->respond($response, 200, [
  63. 'TODO' => [
  64. ],
  65. 'url' => $result['url'],
  66. 'code' => $result['code']
  67. ]);
  68. }
  69. return [
  70. 'error' => 'no_content',
  71. 'error_description' => 'We did not get a response body when fetching the URL',
  72. 'url' => $result['url'],
  73. 'code' => $result['code']
  74. ];
  75. }
  76. // Check for HTTP 401/403
  77. if($result['code'] == 401) {
  78. return [
  79. 'error' => 'unauthorized',
  80. 'error_description' => 'The URL returned "HTTP 401 Unauthorized"',
  81. 'url' => $result['url'],
  82. 'code' => $result['code']
  83. ];
  84. }
  85. if($result['code'] == 403) {
  86. return [
  87. 'error' => 'forbidden',
  88. 'error_description' => 'The URL returned "HTTP 403 Forbidden"',
  89. 'url' => $result['url'],
  90. 'code' => $result['code']
  91. ];
  92. }
  93. return [
  94. 'url' => $result['url'],
  95. 'body' => $result['body'],
  96. 'code' => $result['code'],
  97. ];
  98. }
  99. private function _fetch_tweet($url, $opts) {
  100. $fields = ['twitter_api_key','twitter_api_secret','twitter_access_token','twitter_access_token_secret'];
  101. $creds = [];
  102. foreach($fields as $f) {
  103. if(isset($opts[$f]))
  104. $creds[$f] = $opts[$f];
  105. }
  106. if(count($creds) < 4) {
  107. return [
  108. 'error_code' => 400,
  109. 'error' => 'missing_parameters',
  110. 'error_description' => 'All 4 Twitter credentials must be included in the request'
  111. ];
  112. }
  113. $tweet = Formats\Twitter::fetch($url, $creds);
  114. if(!$tweet) {
  115. return [
  116. 'error' => 'twitter_error',
  117. 'error_description' => $e->getMessage()
  118. ];
  119. }
  120. return [
  121. 'url' => $url,
  122. 'body' => $tweet,
  123. 'code' => 200,
  124. ];
  125. }
  126. private function _fetch_github($url, $opts) {
  127. $fields = ['github_access_token'];
  128. $creds = [];
  129. foreach($fields as $f) {
  130. if(isset($opts[$f]))
  131. $creds[$f] = $opts[$f];
  132. }
  133. return Formats\GitHub::fetch($this->http, $url, $creds);
  134. }
  135. }