diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/default/assets/vendors/theme-widgets/vendor/abraham/twitteroauth/src/TwitterOAuth.php	Sat May 31 09:21:51 2025 +0800
@@ -0,0 +1,465 @@
+<?php
+/**
+ * The most popular PHP library for use with the Twitter OAuth REST API.
+ *
+ * @license MIT
+ */
+namespace Abraham\TwitterOAuth;
+
+use Abraham\TwitterOAuth\Util\JsonDecoder;
+
+/**
+ * TwitterOAuth class for interacting with the Twitter API.
+ *
+ * @author Abraham Williams <[email protected]>
+ */
+class TwitterOAuth extends Config
+{
+    const API_VERSION = '1.1';
+    const API_HOST = 'https://api.twitter.com';
+    const UPLOAD_HOST = 'https://upload.twitter.com';
+    const UPLOAD_CHUNK = 40960; // 1024 * 40
+
+    /** @var Response details about the result of the last request */
+    private $response;
+    /** @var string|null Application bearer token */
+    private $bearer;
+    /** @var Consumer Twitter application details */
+    private $consumer;
+    /** @var Token|null User access token details */
+    private $token;
+    /** @var HmacSha1 OAuth 1 signature type used by Twitter */
+    private $signatureMethod;
+
+    /**
+     * Constructor
+     *
+     * @param string      $consumerKey      The Application Consumer Key
+     * @param string      $consumerSecret   The Application Consumer Secret
+     * @param string|null $oauthToken       The Client Token (optional)
+     * @param string|null $oauthTokenSecret The Client Token Secret (optional)
+     */
+    public function __construct($consumerKey, $consumerSecret, $oauthToken = null, $oauthTokenSecret = null)
+    {
+        $this->resetLastResponse();
+        $this->signatureMethod = new HmacSha1();
+        $this->consumer = new Consumer($consumerKey, $consumerSecret);
+        if (!empty($oauthToken) && !empty($oauthTokenSecret)) {
+            $this->token = new Token($oauthToken, $oauthTokenSecret);
+        }
+        if (empty($oauthToken) && !empty($oauthTokenSecret)) {
+            $this->bearer = $oauthTokenSecret;
+        }
+    }
+
+    /**
+     * @param string $oauthToken
+     * @param string $oauthTokenSecret
+     */
+    public function setOauthToken($oauthToken, $oauthTokenSecret)
+    {
+        $this->token = new Token($oauthToken, $oauthTokenSecret);
+    }
+
+    /**
+     * @return string|null
+     */
+    public function getLastApiPath()
+    {
+        return $this->response->getApiPath();
+    }
+
+    /**
+     * @return int
+     */
+    public function getLastHttpCode()
+    {
+        return $this->response->getHttpCode();
+    }
+
+    /**
+     * @return array
+     */
+    public function getLastXHeaders()
+    {
+        return $this->response->getXHeaders();
+    }
+
+    /**
+     * @return array|object|null
+     */
+    public function getLastBody()
+    {
+        return $this->response->getBody();
+    }
+
+    /**
+     * Resets the last response cache.
+     */
+    public function resetLastResponse()
+    {
+        $this->response = new Response();
+    }
+
+    /**
+     * Make URLs for user browser navigation.
+     *
+     * @param string $path
+     * @param array  $parameters
+     *
+     * @return string
+     */
+    public function url($path, array $parameters)
+    {
+        $this->resetLastResponse();
+        $this->response->setApiPath($path);
+        $query = http_build_query($parameters);
+        return sprintf('%s/%s?%s', self::API_HOST, $path, $query);
+    }
+
+    /**
+     * Make /oauth/* requests to the API.
+     *
+     * @param string $path
+     * @param array  $parameters
+     *
+     * @return array
+     * @throws TwitterOAuthException
+     */
+    public function oauth($path, array $parameters = [])
+    {
+        $response = [];
+        $this->resetLastResponse();
+        $this->response->setApiPath($path);
+        $url = sprintf('%s/%s', self::API_HOST, $path);
+        $result = $this->oAuthRequest($url, 'POST', $parameters);
+
+        if ($this->getLastHttpCode() != 200) {
+            throw new TwitterOAuthException($result);
+        }
+
+        parse_str($result, $response);
+        $this->response->setBody($response);
+
+        return $response;
+    }
+
+    /**
+     * Make /oauth2/* requests to the API.
+     *
+     * @param string $path
+     * @param array  $parameters
+     *
+     * @return array|object
+     */
+    public function oauth2($path, array $parameters = [])
+    {
+        $method = 'POST';
+        $this->resetLastResponse();
+        $this->response->setApiPath($path);
+        $url = sprintf('%s/%s', self::API_HOST, $path);
+        $request = Request::fromConsumerAndToken($this->consumer, $this->token, $method, $url, $parameters);
+        $authorization = 'Authorization: Basic ' . $this->encodeAppAuthorization($this->consumer);
+        $result = $this->request($request->getNormalizedHttpUrl(), $method, $authorization, $parameters);
+        $response = JsonDecoder::decode($result, $this->decodeJsonAsArray);
+        $this->response->setBody($response);
+        return $response;
+    }
+
+    /**
+     * Make GET requests to the API.
+     *
+     * @param string $path
+     * @param array  $parameters
+     *
+     * @return array|object
+     */
+    public function get($path, array $parameters = [])
+    {
+        return $this->http('GET', self::API_HOST, $path, $parameters);
+    }
+
+    /**
+     * Make POST requests to the API.
+     *
+     * @param string $path
+     * @param array  $parameters
+     *
+     * @return array|object
+     */
+    public function post($path, array $parameters = [])
+    {
+        return $this->http('POST', self::API_HOST, $path, $parameters);
+    }
+
+    /**
+     * Make DELETE requests to the API.
+     *
+     * @param string $path
+     * @param array  $parameters
+     *
+     * @return array|object
+     */
+    public function delete($path, array $parameters = [])
+    {
+        return $this->http('DELETE', self::API_HOST, $path, $parameters);
+    }
+
+    /**
+     * Make PUT requests to the API.
+     *
+     * @param string $path
+     * @param array  $parameters
+     *
+     * @return array|object
+     */
+    public function put($path, array $parameters = [])
+    {
+        return $this->http('PUT', self::API_HOST, $path, $parameters);
+    }
+
+    /**
+     * Upload media to upload.twitter.com.
+     *
+     * @param string $path
+     * @param array  $parameters
+     * @param boolean  $chunked
+     *
+     * @return array|object
+     */
+    public function upload($path, array $parameters = [], $chunked = false)
+    {
+        if ($chunked) {
+            return $this->uploadMediaChunked($path, $parameters);
+        } else {
+            return $this->uploadMediaNotChunked($path, $parameters);
+        }
+    }
+
+    /**
+     * Private method to upload media (not chunked) to upload.twitter.com.
+     *
+     * @param string $path
+     * @param array  $parameters
+     *
+     * @return array|object
+     */
+    private function uploadMediaNotChunked($path, array $parameters)
+    {
+        $file = file_get_contents($parameters['media']);
+        $base = base64_encode($file);
+        $parameters['media'] = $base;
+        return $this->http('POST', self::UPLOAD_HOST, $path, $parameters);
+    }
+
+    /**
+     * Private method to upload media (chunked) to upload.twitter.com.
+     *
+     * @param string $path
+     * @param array  $parameters
+     *
+     * @return array|object
+     */
+    private function uploadMediaChunked($path, array $parameters)
+    {
+        // Init
+        $init = $this->http('POST', self::UPLOAD_HOST, $path, [
+            'command' => 'INIT',
+            'media_type' => $parameters['media_type'],
+            'total_bytes' => filesize($parameters['media'])
+        ]);
+        // Append
+        $segment_index = 0;
+        $media = fopen($parameters['media'], 'rb');
+        while (!feof($media))
+        {
+            $this->http('POST', self::UPLOAD_HOST, 'media/upload', [
+                'command' => 'APPEND',
+                'media_id' => $init->media_id_string,
+                'segment_index' => $segment_index++,
+                'media_data' => base64_encode(fread($media, self::UPLOAD_CHUNK))
+            ]);
+        }
+        fclose($media);
+        // Finalize
+        $finalize = $this->http('POST', self::UPLOAD_HOST, 'media/upload', [
+            'command' => 'FINALIZE',
+            'media_id' => $init->media_id_string
+        ]);
+        return $finalize;
+    }
+
+    /**
+     * @param string $method
+     * @param string $host
+     * @param string $path
+     * @param array  $parameters
+     *
+     * @return array|object
+     */
+    private function http($method, $host, $path, array $parameters)
+    {
+        $this->resetLastResponse();
+        $url = sprintf('%s/%s/%s.json', $host, self::API_VERSION, $path);
+        $this->response->setApiPath($path);
+        $result = $this->oAuthRequest($url, $method, $parameters);
+        $response = JsonDecoder::decode($result, $this->decodeJsonAsArray);
+        $this->response->setBody($response);
+        return $response;
+    }
+
+    /**
+     * Format and sign an OAuth / API request
+     *
+     * @param string $url
+     * @param string $method
+     * @param array  $parameters
+     *
+     * @return string
+     * @throws TwitterOAuthException
+     */
+    private function oAuthRequest($url, $method, array $parameters)
+    {
+        $request = Request::fromConsumerAndToken($this->consumer, $this->token, $method, $url, $parameters);
+        if (array_key_exists('oauth_callback', $parameters)) {
+            // Twitter doesn't like oauth_callback as a parameter.
+            unset($parameters['oauth_callback']);
+        }
+        if ($this->bearer === null) {
+            $request->signRequest($this->signatureMethod, $this->consumer, $this->token);
+            $authorization = $request->toHeader();
+        } else {
+            $authorization = 'Authorization: Bearer ' . $this->bearer;
+        }
+        return $this->request($request->getNormalizedHttpUrl(), $method, $authorization, $parameters);
+    }
+
+    /**
+     * Make an HTTP request
+     *
+     * @param string $url
+     * @param string $method
+     * @param string $authorization
+     * @param array $postfields
+     *
+     * @return string
+     * @throws TwitterOAuthException
+     */
+    private function request($url, $method, $authorization, array $postfields)
+    {
+        /* Curl settings */
+        $options = [
+            // CURLOPT_VERBOSE => true,
+            CURLOPT_CAINFO => __DIR__ . DIRECTORY_SEPARATOR . 'cacert.pem',
+            CURLOPT_CONNECTTIMEOUT => $this->connectionTimeout,
+            CURLOPT_HEADER => true,
+            CURLOPT_HTTPHEADER => ['Accept: application/json', $authorization, 'Expect:'],
+            CURLOPT_RETURNTRANSFER => true,
+            CURLOPT_SSL_VERIFYHOST => 2,
+            CURLOPT_SSL_VERIFYPEER => true,
+            CURLOPT_TIMEOUT => $this->timeout,
+            CURLOPT_URL => $url,
+            CURLOPT_USERAGENT => $this->userAgent,
+        ];
+
+        /* Remove CACert file when in a PHAR file. */
+        if ($this->pharRunning()) {
+            unset($options[CURLOPT_CAINFO]);
+        }
+
+        if($this->gzipEncoding) {
+            $options[CURLOPT_ENCODING] = 'gzip';
+        }
+
+        if (!empty($this->proxy)) {
+            $options[CURLOPT_PROXY] = $this->proxy['CURLOPT_PROXY'];
+            $options[CURLOPT_PROXYUSERPWD] = $this->proxy['CURLOPT_PROXYUSERPWD'];
+            $options[CURLOPT_PROXYPORT] = $this->proxy['CURLOPT_PROXYPORT'];
+            $options[CURLOPT_PROXYAUTH] = CURLAUTH_BASIC;
+            $options[CURLOPT_PROXYTYPE] = CURLPROXY_HTTP;
+        }
+
+        switch ($method) {
+            case 'GET':
+                break;
+            case 'POST':
+                $options[CURLOPT_POST] = true;
+                $options[CURLOPT_POSTFIELDS] = Util::buildHttpQuery($postfields);
+                break;
+            case 'DELETE':
+                $options[CURLOPT_CUSTOMREQUEST] = 'DELETE';
+                break;
+            case 'PUT':
+                $options[CURLOPT_CUSTOMREQUEST] = 'PUT';
+                break;
+        }
+
+        if (in_array($method, ['GET', 'PUT', 'DELETE']) && !empty($postfields)) {
+            $options[CURLOPT_URL] .= '?' . Util::buildHttpQuery($postfields);
+        }
+
+
+        $curlHandle = curl_init();
+        curl_setopt_array($curlHandle, $options);
+        $response = curl_exec($curlHandle);
+
+        // Throw exceptions on cURL errors.
+        if (curl_errno($curlHandle) > 0) {
+            throw new TwitterOAuthException(curl_error($curlHandle), curl_errno($curlHandle));
+        }
+
+        $this->response->setHttpCode(curl_getinfo($curlHandle, CURLINFO_HTTP_CODE));
+        $parts = explode("\r\n\r\n", $response);
+        $responseBody = array_pop($parts);
+        $responseHeader = array_pop($parts);
+        $this->response->setHeaders($this->parseHeaders($responseHeader));
+
+        curl_close($curlHandle);
+
+        return $responseBody;
+    }
+
+    /**
+     * Get the header info to store.
+     *
+     * @param string $header
+     *
+     * @return array
+     */
+    private function parseHeaders($header)
+    {
+        $headers = [];
+        foreach (explode("\r\n", $header) as $line) {
+            if (strpos($line, ':') !== false) {
+                list ($key, $value) = explode(': ', $line);
+                $key = str_replace('-', '_', strtolower($key));
+                $headers[$key] = trim($value);
+            }
+        }
+        return $headers;
+    }
+
+    /**
+     * Encode application authorization header with base64.
+     *
+     * @param Consumer $consumer
+     *
+     * @return string
+     */
+    private function encodeAppAuthorization(Consumer $consumer)
+    {
+        $key = rawurlencode($consumer->key);
+        $secret = rawurlencode($consumer->secret);
+        return base64_encode($key . ':' . $secret);
+    }
+
+    /**
+     * Is the code running from a Phar module.
+     *
+     * @return boolean
+     */
+    private function pharRunning()
+    {
+        return class_exists('Phar') && \Phar::running(false) !== '';
+    }
+}