Mercurial > nebulaweb3
comparison default/assets/vendors/theme-widgets/vendor/abraham/twitteroauth/src/TwitterOAuth.php @ 0:1d038bc9b3d2 default tip
Up:default
author | Liny <dev@neowd.com> |
---|---|
date | Sat, 31 May 2025 09:21:51 +0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1d038bc9b3d2 |
---|---|
1 <?php | |
2 /** | |
3 * The most popular PHP library for use with the Twitter OAuth REST API. | |
4 * | |
5 * @license MIT | |
6 */ | |
7 namespace Abraham\TwitterOAuth; | |
8 | |
9 use Abraham\TwitterOAuth\Util\JsonDecoder; | |
10 | |
11 /** | |
12 * TwitterOAuth class for interacting with the Twitter API. | |
13 * | |
14 * @author Abraham Williams <[email protected]> | |
15 */ | |
16 class TwitterOAuth extends Config | |
17 { | |
18 const API_VERSION = '1.1'; | |
19 const API_HOST = 'https://api.twitter.com'; | |
20 const UPLOAD_HOST = 'https://upload.twitter.com'; | |
21 const UPLOAD_CHUNK = 40960; // 1024 * 40 | |
22 | |
23 /** @var Response details about the result of the last request */ | |
24 private $response; | |
25 /** @var string|null Application bearer token */ | |
26 private $bearer; | |
27 /** @var Consumer Twitter application details */ | |
28 private $consumer; | |
29 /** @var Token|null User access token details */ | |
30 private $token; | |
31 /** @var HmacSha1 OAuth 1 signature type used by Twitter */ | |
32 private $signatureMethod; | |
33 | |
34 /** | |
35 * Constructor | |
36 * | |
37 * @param string $consumerKey The Application Consumer Key | |
38 * @param string $consumerSecret The Application Consumer Secret | |
39 * @param string|null $oauthToken The Client Token (optional) | |
40 * @param string|null $oauthTokenSecret The Client Token Secret (optional) | |
41 */ | |
42 public function __construct($consumerKey, $consumerSecret, $oauthToken = null, $oauthTokenSecret = null) | |
43 { | |
44 $this->resetLastResponse(); | |
45 $this->signatureMethod = new HmacSha1(); | |
46 $this->consumer = new Consumer($consumerKey, $consumerSecret); | |
47 if (!empty($oauthToken) && !empty($oauthTokenSecret)) { | |
48 $this->token = new Token($oauthToken, $oauthTokenSecret); | |
49 } | |
50 if (empty($oauthToken) && !empty($oauthTokenSecret)) { | |
51 $this->bearer = $oauthTokenSecret; | |
52 } | |
53 } | |
54 | |
55 /** | |
56 * @param string $oauthToken | |
57 * @param string $oauthTokenSecret | |
58 */ | |
59 public function setOauthToken($oauthToken, $oauthTokenSecret) | |
60 { | |
61 $this->token = new Token($oauthToken, $oauthTokenSecret); | |
62 } | |
63 | |
64 /** | |
65 * @return string|null | |
66 */ | |
67 public function getLastApiPath() | |
68 { | |
69 return $this->response->getApiPath(); | |
70 } | |
71 | |
72 /** | |
73 * @return int | |
74 */ | |
75 public function getLastHttpCode() | |
76 { | |
77 return $this->response->getHttpCode(); | |
78 } | |
79 | |
80 /** | |
81 * @return array | |
82 */ | |
83 public function getLastXHeaders() | |
84 { | |
85 return $this->response->getXHeaders(); | |
86 } | |
87 | |
88 /** | |
89 * @return array|object|null | |
90 */ | |
91 public function getLastBody() | |
92 { | |
93 return $this->response->getBody(); | |
94 } | |
95 | |
96 /** | |
97 * Resets the last response cache. | |
98 */ | |
99 public function resetLastResponse() | |
100 { | |
101 $this->response = new Response(); | |
102 } | |
103 | |
104 /** | |
105 * Make URLs for user browser navigation. | |
106 * | |
107 * @param string $path | |
108 * @param array $parameters | |
109 * | |
110 * @return string | |
111 */ | |
112 public function url($path, array $parameters) | |
113 { | |
114 $this->resetLastResponse(); | |
115 $this->response->setApiPath($path); | |
116 $query = http_build_query($parameters); | |
117 return sprintf('%s/%s?%s', self::API_HOST, $path, $query); | |
118 } | |
119 | |
120 /** | |
121 * Make /oauth/* requests to the API. | |
122 * | |
123 * @param string $path | |
124 * @param array $parameters | |
125 * | |
126 * @return array | |
127 * @throws TwitterOAuthException | |
128 */ | |
129 public function oauth($path, array $parameters = []) | |
130 { | |
131 $response = []; | |
132 $this->resetLastResponse(); | |
133 $this->response->setApiPath($path); | |
134 $url = sprintf('%s/%s', self::API_HOST, $path); | |
135 $result = $this->oAuthRequest($url, 'POST', $parameters); | |
136 | |
137 if ($this->getLastHttpCode() != 200) { | |
138 throw new TwitterOAuthException($result); | |
139 } | |
140 | |
141 parse_str($result, $response); | |
142 $this->response->setBody($response); | |
143 | |
144 return $response; | |
145 } | |
146 | |
147 /** | |
148 * Make /oauth2/* requests to the API. | |
149 * | |
150 * @param string $path | |
151 * @param array $parameters | |
152 * | |
153 * @return array|object | |
154 */ | |
155 public function oauth2($path, array $parameters = []) | |
156 { | |
157 $method = 'POST'; | |
158 $this->resetLastResponse(); | |
159 $this->response->setApiPath($path); | |
160 $url = sprintf('%s/%s', self::API_HOST, $path); | |
161 $request = Request::fromConsumerAndToken($this->consumer, $this->token, $method, $url, $parameters); | |
162 $authorization = 'Authorization: Basic ' . $this->encodeAppAuthorization($this->consumer); | |
163 $result = $this->request($request->getNormalizedHttpUrl(), $method, $authorization, $parameters); | |
164 $response = JsonDecoder::decode($result, $this->decodeJsonAsArray); | |
165 $this->response->setBody($response); | |
166 return $response; | |
167 } | |
168 | |
169 /** | |
170 * Make GET requests to the API. | |
171 * | |
172 * @param string $path | |
173 * @param array $parameters | |
174 * | |
175 * @return array|object | |
176 */ | |
177 public function get($path, array $parameters = []) | |
178 { | |
179 return $this->http('GET', self::API_HOST, $path, $parameters); | |
180 } | |
181 | |
182 /** | |
183 * Make POST requests to the API. | |
184 * | |
185 * @param string $path | |
186 * @param array $parameters | |
187 * | |
188 * @return array|object | |
189 */ | |
190 public function post($path, array $parameters = []) | |
191 { | |
192 return $this->http('POST', self::API_HOST, $path, $parameters); | |
193 } | |
194 | |
195 /** | |
196 * Make DELETE requests to the API. | |
197 * | |
198 * @param string $path | |
199 * @param array $parameters | |
200 * | |
201 * @return array|object | |
202 */ | |
203 public function delete($path, array $parameters = []) | |
204 { | |
205 return $this->http('DELETE', self::API_HOST, $path, $parameters); | |
206 } | |
207 | |
208 /** | |
209 * Make PUT requests to the API. | |
210 * | |
211 * @param string $path | |
212 * @param array $parameters | |
213 * | |
214 * @return array|object | |
215 */ | |
216 public function put($path, array $parameters = []) | |
217 { | |
218 return $this->http('PUT', self::API_HOST, $path, $parameters); | |
219 } | |
220 | |
221 /** | |
222 * Upload media to upload.twitter.com. | |
223 * | |
224 * @param string $path | |
225 * @param array $parameters | |
226 * @param boolean $chunked | |
227 * | |
228 * @return array|object | |
229 */ | |
230 public function upload($path, array $parameters = [], $chunked = false) | |
231 { | |
232 if ($chunked) { | |
233 return $this->uploadMediaChunked($path, $parameters); | |
234 } else { | |
235 return $this->uploadMediaNotChunked($path, $parameters); | |
236 } | |
237 } | |
238 | |
239 /** | |
240 * Private method to upload media (not chunked) to upload.twitter.com. | |
241 * | |
242 * @param string $path | |
243 * @param array $parameters | |
244 * | |
245 * @return array|object | |
246 */ | |
247 private function uploadMediaNotChunked($path, array $parameters) | |
248 { | |
249 $file = file_get_contents($parameters['media']); | |
250 $base = base64_encode($file); | |
251 $parameters['media'] = $base; | |
252 return $this->http('POST', self::UPLOAD_HOST, $path, $parameters); | |
253 } | |
254 | |
255 /** | |
256 * Private method to upload media (chunked) to upload.twitter.com. | |
257 * | |
258 * @param string $path | |
259 * @param array $parameters | |
260 * | |
261 * @return array|object | |
262 */ | |
263 private function uploadMediaChunked($path, array $parameters) | |
264 { | |
265 // Init | |
266 $init = $this->http('POST', self::UPLOAD_HOST, $path, [ | |
267 'command' => 'INIT', | |
268 'media_type' => $parameters['media_type'], | |
269 'total_bytes' => filesize($parameters['media']) | |
270 ]); | |
271 // Append | |
272 $segment_index = 0; | |
273 $media = fopen($parameters['media'], 'rb'); | |
274 while (!feof($media)) | |
275 { | |
276 $this->http('POST', self::UPLOAD_HOST, 'media/upload', [ | |
277 'command' => 'APPEND', | |
278 'media_id' => $init->media_id_string, | |
279 'segment_index' => $segment_index++, | |
280 'media_data' => base64_encode(fread($media, self::UPLOAD_CHUNK)) | |
281 ]); | |
282 } | |
283 fclose($media); | |
284 // Finalize | |
285 $finalize = $this->http('POST', self::UPLOAD_HOST, 'media/upload', [ | |
286 'command' => 'FINALIZE', | |
287 'media_id' => $init->media_id_string | |
288 ]); | |
289 return $finalize; | |
290 } | |
291 | |
292 /** | |
293 * @param string $method | |
294 * @param string $host | |
295 * @param string $path | |
296 * @param array $parameters | |
297 * | |
298 * @return array|object | |
299 */ | |
300 private function http($method, $host, $path, array $parameters) | |
301 { | |
302 $this->resetLastResponse(); | |
303 $url = sprintf('%s/%s/%s.json', $host, self::API_VERSION, $path); | |
304 $this->response->setApiPath($path); | |
305 $result = $this->oAuthRequest($url, $method, $parameters); | |
306 $response = JsonDecoder::decode($result, $this->decodeJsonAsArray); | |
307 $this->response->setBody($response); | |
308 return $response; | |
309 } | |
310 | |
311 /** | |
312 * Format and sign an OAuth / API request | |
313 * | |
314 * @param string $url | |
315 * @param string $method | |
316 * @param array $parameters | |
317 * | |
318 * @return string | |
319 * @throws TwitterOAuthException | |
320 */ | |
321 private function oAuthRequest($url, $method, array $parameters) | |
322 { | |
323 $request = Request::fromConsumerAndToken($this->consumer, $this->token, $method, $url, $parameters); | |
324 if (array_key_exists('oauth_callback', $parameters)) { | |
325 // Twitter doesn't like oauth_callback as a parameter. | |
326 unset($parameters['oauth_callback']); | |
327 } | |
328 if ($this->bearer === null) { | |
329 $request->signRequest($this->signatureMethod, $this->consumer, $this->token); | |
330 $authorization = $request->toHeader(); | |
331 } else { | |
332 $authorization = 'Authorization: Bearer ' . $this->bearer; | |
333 } | |
334 return $this->request($request->getNormalizedHttpUrl(), $method, $authorization, $parameters); | |
335 } | |
336 | |
337 /** | |
338 * Make an HTTP request | |
339 * | |
340 * @param string $url | |
341 * @param string $method | |
342 * @param string $authorization | |
343 * @param array $postfields | |
344 * | |
345 * @return string | |
346 * @throws TwitterOAuthException | |
347 */ | |
348 private function request($url, $method, $authorization, array $postfields) | |
349 { | |
350 /* Curl settings */ | |
351 $options = [ | |
352 // CURLOPT_VERBOSE => true, | |
353 CURLOPT_CAINFO => __DIR__ . DIRECTORY_SEPARATOR . 'cacert.pem', | |
354 CURLOPT_CONNECTTIMEOUT => $this->connectionTimeout, | |
355 CURLOPT_HEADER => true, | |
356 CURLOPT_HTTPHEADER => ['Accept: application/json', $authorization, 'Expect:'], | |
357 CURLOPT_RETURNTRANSFER => true, | |
358 CURLOPT_SSL_VERIFYHOST => 2, | |
359 CURLOPT_SSL_VERIFYPEER => true, | |
360 CURLOPT_TIMEOUT => $this->timeout, | |
361 CURLOPT_URL => $url, | |
362 CURLOPT_USERAGENT => $this->userAgent, | |
363 ]; | |
364 | |
365 /* Remove CACert file when in a PHAR file. */ | |
366 if ($this->pharRunning()) { | |
367 unset($options[CURLOPT_CAINFO]); | |
368 } | |
369 | |
370 if($this->gzipEncoding) { | |
371 $options[CURLOPT_ENCODING] = 'gzip'; | |
372 } | |
373 | |
374 if (!empty($this->proxy)) { | |
375 $options[CURLOPT_PROXY] = $this->proxy['CURLOPT_PROXY']; | |
376 $options[CURLOPT_PROXYUSERPWD] = $this->proxy['CURLOPT_PROXYUSERPWD']; | |
377 $options[CURLOPT_PROXYPORT] = $this->proxy['CURLOPT_PROXYPORT']; | |
378 $options[CURLOPT_PROXYAUTH] = CURLAUTH_BASIC; | |
379 $options[CURLOPT_PROXYTYPE] = CURLPROXY_HTTP; | |
380 } | |
381 | |
382 switch ($method) { | |
383 case 'GET': | |
384 break; | |
385 case 'POST': | |
386 $options[CURLOPT_POST] = true; | |
387 $options[CURLOPT_POSTFIELDS] = Util::buildHttpQuery($postfields); | |
388 break; | |
389 case 'DELETE': | |
390 $options[CURLOPT_CUSTOMREQUEST] = 'DELETE'; | |
391 break; | |
392 case 'PUT': | |
393 $options[CURLOPT_CUSTOMREQUEST] = 'PUT'; | |
394 break; | |
395 } | |
396 | |
397 if (in_array($method, ['GET', 'PUT', 'DELETE']) && !empty($postfields)) { | |
398 $options[CURLOPT_URL] .= '?' . Util::buildHttpQuery($postfields); | |
399 } | |
400 | |
401 | |
402 $curlHandle = curl_init(); | |
403 curl_setopt_array($curlHandle, $options); | |
404 $response = curl_exec($curlHandle); | |
405 | |
406 // Throw exceptions on cURL errors. | |
407 if (curl_errno($curlHandle) > 0) { | |
408 throw new TwitterOAuthException(curl_error($curlHandle), curl_errno($curlHandle)); | |
409 } | |
410 | |
411 $this->response->setHttpCode(curl_getinfo($curlHandle, CURLINFO_HTTP_CODE)); | |
412 $parts = explode("\r\n\r\n", $response); | |
413 $responseBody = array_pop($parts); | |
414 $responseHeader = array_pop($parts); | |
415 $this->response->setHeaders($this->parseHeaders($responseHeader)); | |
416 | |
417 curl_close($curlHandle); | |
418 | |
419 return $responseBody; | |
420 } | |
421 | |
422 /** | |
423 * Get the header info to store. | |
424 * | |
425 * @param string $header | |
426 * | |
427 * @return array | |
428 */ | |
429 private function parseHeaders($header) | |
430 { | |
431 $headers = []; | |
432 foreach (explode("\r\n", $header) as $line) { | |
433 if (strpos($line, ':') !== false) { | |
434 list ($key, $value) = explode(': ', $line); | |
435 $key = str_replace('-', '_', strtolower($key)); | |
436 $headers[$key] = trim($value); | |
437 } | |
438 } | |
439 return $headers; | |
440 } | |
441 | |
442 /** | |
443 * Encode application authorization header with base64. | |
444 * | |
445 * @param Consumer $consumer | |
446 * | |
447 * @return string | |
448 */ | |
449 private function encodeAppAuthorization(Consumer $consumer) | |
450 { | |
451 $key = rawurlencode($consumer->key); | |
452 $secret = rawurlencode($consumer->secret); | |
453 return base64_encode($key . ':' . $secret); | |
454 } | |
455 | |
456 /** | |
457 * Is the code running from a Phar module. | |
458 * | |
459 * @return boolean | |
460 */ | |
461 private function pharRunning() | |
462 { | |
463 return class_exists('Phar') && \Phar::running(false) !== ''; | |
464 } | |
465 } |