Adapters
10 years ago
Providers
9 years ago
Autoload.php
10 years ago
Embera.php
10 years ago
FakeResponse.php
10 years ago
Formatter.php
10 years ago
HttpRequest.php
10 years ago
Oembed.php
10 years ago
Providers.php
10 years ago
Url.php
10 years ago
HttpRequest.php
166 lines
| 1 | <?php |
| 2 | /** |
| 3 | * HttpRequest.php |
| 4 | * |
| 5 | * @package Embera |
| 6 | * @author Michael Pratt <pratt@hablarmierda.net> |
| 7 | * @link http://www.michael-pratt.com/ |
| 8 | * |
| 9 | * For the full copyright and license information, please view the LICENSE |
| 10 | * file that was distributed with this source code. |
| 11 | */ |
| 12 | |
| 13 | namespace Embera; |
| 14 | |
| 15 | /** |
| 16 | * This class is in charge of doing http requests. Its a very minimal |
| 17 | * wrapper for curl or file_get_contents |
| 18 | */ |
| 19 | class HttpRequest |
| 20 | { |
| 21 | /** @var array Array with custom curl/fopen options */ |
| 22 | protected $config = array(); |
| 23 | |
| 24 | /** @var string User Agent String */ |
| 25 | protected $userAgent = 'Mozilla/5.0 PHP/Embera'; |
| 26 | |
| 27 | /** |
| 28 | * Constructor |
| 29 | * |
| 30 | * @param array $config |
| 31 | * @return void |
| 32 | */ |
| 33 | public function __construct(array $config = array()) |
| 34 | { |
| 35 | $this->config = array_merge(array( |
| 36 | 'curl' => array(), |
| 37 | 'fopen' => array(), |
| 38 | 'force_redirects' => false, |
| 39 | 'prefer_curl' => true, |
| 40 | ), $config); |
| 41 | } |
| 42 | |
| 43 | /** |
| 44 | * Executes http requests |
| 45 | * |
| 46 | * @param string $url |
| 47 | * @param array $params Additional parameters for the respective part |
| 48 | * @return string |
| 49 | * |
| 50 | * @throws Exception when an error ocurred or if no way to do a request exists |
| 51 | */ |
| 52 | public function fetch($url, array $params = array()) |
| 53 | { |
| 54 | $params = array_merge(array( |
| 55 | 'curl' => array(), |
| 56 | 'fopen' => array(), |
| 57 | ), $params); |
| 58 | |
| 59 | if (function_exists('curl_init') && $this->config['prefer_curl']) { |
| 60 | return $this->curl($url, $params['curl']); |
| 61 | } |
| 62 | |
| 63 | return $this->fileGetContents($url, $params['fopen']); |
| 64 | } |
| 65 | |
| 66 | /** |
| 67 | * Uses Curl to fetch data from an url |
| 68 | * |
| 69 | * @param string $url |
| 70 | * @param array $params Additional parameters for the respective part |
| 71 | * @return string |
| 72 | * |
| 73 | * @throws Exception when the returned status code is not 200 or no data was found |
| 74 | */ |
| 75 | protected function curl($url, array $params = array()) |
| 76 | { |
| 77 | // Not using array_merge here because that function reindexes numeric keys |
| 78 | $options = $params + $this->config['curl'] + array( |
| 79 | CURLOPT_USERAGENT => $this->userAgent, |
| 80 | CURLOPT_ENCODING => '', |
| 81 | CURLOPT_FOLLOWLOCATION => true, |
| 82 | ); |
| 83 | |
| 84 | $options[CURLOPT_URL] = $url; |
| 85 | $options[CURLOPT_HEADER] = true; |
| 86 | $options[CURLOPT_RETURNTRANSFER] = 1; |
| 87 | |
| 88 | // CURLOPT_FOLLOWLOCATION doesnt play well with open_basedir/safe_mode |
| 89 | if (ini_get('safe_mode') || ini_get('open_basedir')) { |
| 90 | $options[CURLOPT_FOLLOWLOCATION] = false; |
| 91 | $options[CURLOPT_TIMEOUT] = 15; |
| 92 | $this->config['force_redirects'] = true; |
| 93 | } |
| 94 | |
| 95 | $handler = curl_init(); |
| 96 | curl_setopt_array($handler, $options); |
| 97 | $response = curl_exec($handler); |
| 98 | |
| 99 | $status = curl_getinfo($handler, CURLINFO_HTTP_CODE); |
| 100 | $headerSize = curl_getinfo($handler, CURLINFO_HEADER_SIZE); |
| 101 | |
| 102 | $header = substr($response, 0, $headerSize); |
| 103 | $body = substr($response, $headerSize); |
| 104 | curl_close($handler); |
| 105 | |
| 106 | if ($this->config['force_redirects'] && in_array($status, array('301', '302'))) { |
| 107 | |
| 108 | if (preg_match('~(?:location|uri): ?([^\n]+)~i', $header, $matches)) { |
| 109 | |
| 110 | $url = trim($matches['1']); |
| 111 | |
| 112 | // Relative redirections |
| 113 | if (substr($url, 0, 1) == '/') { |
| 114 | $parsed = parse_url($options[CURLOPT_URL]); |
| 115 | $url = $parsed['scheme'] . '://' . rtrim($parsed['host'], '/') . $url; |
| 116 | } |
| 117 | |
| 118 | return $this->curl($url, $options); |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | if (empty($body) || !in_array($status, array('200'))) { |
| 123 | throw new \Exception($status . ': Invalid response for ' . $url); |
| 124 | } |
| 125 | |
| 126 | return $body; |
| 127 | } |
| 128 | |
| 129 | /** |
| 130 | * Uses file_get_contents to fetch data from an url |
| 131 | * |
| 132 | * @param string $url |
| 133 | * @param array $params Additional parameters for the respective part |
| 134 | * @return string |
| 135 | * |
| 136 | * @throws Exception when allow_url_fopen is disabled or when no data was returned |
| 137 | */ |
| 138 | protected function fileGetContents($url, array $params = array()) |
| 139 | { |
| 140 | if (!ini_get('allow_url_fopen')) { |
| 141 | throw new \Exception('Could not execute lookup, allow_url_fopen is disabled'); |
| 142 | } |
| 143 | |
| 144 | if (!filter_var($url, FILTER_VALIDATE_URL)) { |
| 145 | throw new \Exception('Invalid url ' . $url); |
| 146 | } |
| 147 | |
| 148 | $defaultOptions = array( |
| 149 | 'method' => 'GET', |
| 150 | 'user_agent' => $this->userAgent, |
| 151 | 'follow_location' => 1, |
| 152 | 'max_redirects' => 20, |
| 153 | 'timeout' => 40 |
| 154 | ); |
| 155 | |
| 156 | $context = array('http' => array_merge($defaultOptions, $this->config['fopen'], $params)); |
| 157 | if ($data = file_get_contents($url, false, stream_context_create($context))) { |
| 158 | return $data; |
| 159 | } |
| 160 | |
| 161 | throw new \Exception('Invalid Server Response from ' . $url); |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | ?> |
| 166 |