1: <?php
2:
3: namespace OpenCloud\Common\Request;
4:
5: use OpenCloud\Common\Base;
6: use OpenCloud\Common\Lang;
7: use OpenCloud\Common\Exceptions\HttpRetryError;
8: use OpenCloud\Common\Exceptions\HttpUrlError;
9: use OpenCloud\Common\Exceptions\HttpTimeoutError;
10: use OpenCloud\Common\Exceptions\HttpError;
11:
12: 13: 14: 15: 16: 17: 18: 19: 20:
21: class Curl extends Base implements HttpRequestInterface
22: {
23:
24: private $url;
25: private $method;
26: private $handle;
27: private $retries = 0;
28: private = array();
29: private = array();
30:
31: 32: 33: 34: 35: 36: 37: 38: 39:
40: public function __construct($url, $method = 'GET', array $options = array())
41: {
42: $this->url = $url;
43: $this->method = $method;
44: $this->handle = curl_init($url);
45:
46:
47: $this->setOption(CURLOPT_CUSTOMREQUEST, $method);
48:
49: foreach($options as $opt => $value) {
50: $this->getLogger()->info(Lang::translate('Setting option {key}={val}'), array(
51: 'key' => $opt,
52: 'val' => $value
53: ));
54: $this->setOption($opt, $value);
55: }
56:
57:
58: if (RAXSDK_SSL_VERIFYHOST != 2) {
59: $this->getLogger()->warning("WARNING: RAXSDK_SSL_VERIFYHOST has reduced security, value [{value}]", array(
60: 'value' => RAXSDK_SSL_VERIFYHOST
61: ));
62: }
63:
64: if (RAXSDK_SSL_VERIFYPEER !== true) {
65: $this->getLogger()->warning("WARNING: RAXSDK_SSL_VERIFYPEER has reduced security");
66: }
67:
68:
69: $this->setOption(CURLOPT_SSL_VERIFYHOST, RAXSDK_SSL_VERIFYHOST);
70: $this->setOption(CURLOPT_SSL_VERIFYPEER, RAXSDK_SSL_VERIFYPEER);
71:
72: if (defined('RAXSDK_CACERTPEM') && file_exists(RAXSDK_CACERTPEM)) {
73: $this->setOption(CURLOPT_CAINFO, RAXSDK_CACERTPEM);
74: }
75:
76:
77:
78: if ($method === 'HEAD') {
79: $this->setOption(CURLOPT_NOBODY, true);
80: }
81:
82:
83: $this->setOption(CURLOPT_FOLLOWLOCATION, true);
84:
85:
86: $this->setOption(CURLOPT_HEADER, false);
87:
88:
89: $this->setOption(CURLOPT_HEADERFUNCTION, array($this, '_get_header_cb'));
90:
91:
92: $this->setOption(CURLOPT_RETURNTRANSFER, true);
93:
94:
95: $this->setConnectTimeout(RAXSDK_CONNECTTIMEOUT);
96: $this->setHttpTimeout(RAXSDK_TIMEOUT);
97: }
98:
99: 100: 101: 102: 103: 104:
105: public function setOption($name, $value)
106: {
107: return curl_setopt($this->handle, $name, $value);
108: }
109:
110: 111: 112: 113: 114: 115: 116: 117: 118: 119:
120: public function setConnectTimeout($value)
121: {
122: $this->setOption(CURLOPT_CONNECTTIMEOUT, $value);
123: }
124:
125: 126: 127: 128: 129: 130: 131: 132: 133: 134:
135: public function setHttpTimeout($value)
136: {
137: $this->setOption(CURLOPT_TIMEOUT, $value);
138: }
139:
140: 141: 142: 143: 144: 145:
146: public function setRetries($value)
147: {
148: $this->retries = $value;
149: }
150:
151: 152: 153: 154: 155: 156: 157: 158:
159: public function ($array)
160: {
161: if (!is_array($array)) {
162: throw new HttpError(Lang::translate(
163: 'Value passed to CurlRequest::setheaders() must be array'
164: ));
165: }
166:
167: foreach ($array as $name => $value) {
168: $this->setHeader($name, $value);
169: }
170: }
171:
172: 173: 174: 175: 176: 177: 178: 179: 180:
181: public function ($name, $value)
182: {
183: $this->headers[$name] = $value;
184: }
185:
186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197:
198: public function execute()
199: {
200:
201: $headarr = array();
202:
203: foreach ($this->headers as $name => $value) {
204: $headarr[] = $name.': '.$value;
205: }
206:
207: $this->setOption(CURLOPT_HTTPHEADER, $headarr);
208:
209:
210: $try_counter = 0;
211:
212: do {
213: $data = curl_exec($this->handle);
214: if (curl_errno($this->handle) && ($try_counter<$this->retries)) {
215: $this->getLogger()->info(Lang::translate('Curl error [%d]; retrying [%s]'), array(
216: 'error' => curl_errno($this->handle),
217: 'url' => $this->url
218: ));
219: }
220:
221: } while((++$try_counter <= $this->retries) && (curl_errno($this->handle) != 0));
222:
223:
224: if ($this->retries && curl_errno($this->handle)) {
225: throw new HttpRetryError(sprintf(
226: Lang::translate('No more retries available, last error [%d]'),
227: curl_errno($this->handle)
228: ));
229: }
230:
231:
232: switch(curl_errno($this->handle)) {
233: case 0:
234:
235: break;
236: case 3:
237: throw new HttpUrlError(sprintf(Lang::translate('Malformed URL [%s]'), $this->url));
238: break;
239: case 28:
240:
241: throw new HttpTimeoutError(Lang::translate('Operation timed out; check RAXSDK_TIMEOUT value'));
242: break;
243: default:
244: throw new HttpError(sprintf(
245: Lang::translate('HTTP error on [%s], curl code [%d] message [%s]'),
246: $this->url,
247: curl_errno($this->handle),
248: curl_error($this->handle)
249: ));
250: }
251:
252:
253: return new Response\Http($this, $data);
254: }
255:
256: 257: 258:
259: public function info()
260: {
261: return curl_getinfo($this->handle);
262: }
263:
264: 265: 266:
267: public function errno()
268: {
269: return curl_errno($this->handle);
270: }
271:
272: 273: 274:
275: public function error()
276: {
277: return curl_error($this->handle);
278: }
279:
280: 281: 282:
283: public function close()
284: {
285: return curl_close($this->handle);
286: }
287:
288: 289: 290:
291: public function ()
292: {
293: return $this->returnheaders;
294: }
295:
296: 297: 298: 299: 300: 301:
302: public function ($ch, $header)
303: {
304: $this->returnheaders[] = $header;
305: return strlen($header);
306: }
307:
308: }
309: