├── src └── lib │ ├── Utils │ ├── ErrorHandler.php │ ├── ApiRequest.php │ └── WebSocket.php │ ├── Api.php │ └── Features │ └── Ticker.php ├── package.json ├── Sample.php ├── composer.json ├── LICENSE └── README.md /src/lib/Utils/ErrorHandler.php: -------------------------------------------------------------------------------- 1 | strtotime('+10 second', time()) // Required 7 | ]; 8 | 9 | try { 10 | 11 | // Initialization for our ticker 12 | $CDApi = new CoinDesk\Api(); 13 | 14 | // If you need only one tick 15 | $OneTick = $CDApi->ticker()->getOneTick(); 16 | echo "
" . json_encode($OneTick, JSON_PRETTY_PRINT) . "
"; 17 | 18 | // Connect to the stream channel 19 | $CDApi->ticker()->setTicker(function (array $Coins) { 20 | echo "
" . json_encode($Coins, JSON_PRETTY_PRINT) . "
"; 21 | }, $Settings); 22 | 23 | } catch (Exception $e) { 24 | 25 | // Throw out exceptions 26 | echo "Error: " . $e->getMessage(); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shahradelahi/coindesk-ticker", 3 | "description": "A PHP library to get realtime prices from CoinDesk.", 4 | "keywords": [ 5 | "coindesk", 6 | "price", 7 | "crypto", 8 | "ticker", 9 | "php" 10 | ], 11 | "type": "library", 12 | "homepage": "https://github.com/shahradelahi/coindesk-ticker", 13 | "license": "MIT", 14 | "support": { 15 | "issues": "https://github.com/shahradelahi/coindesk-ticker/issues", 16 | "source": "https://github.com/shahradelahi/coindesk-ticker" 17 | }, 18 | "authors": [ 19 | { 20 | "name": "Shahrad Elahi", 21 | "homepage": "https://github.com/shahradelahi" 22 | } 23 | ], 24 | "require": { 25 | "php": ">=8.0", 26 | "ext-openssl": "*", 27 | "ext-curl": "*" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "coindesk-ticker\\": "src/lib/" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Shahrad Elahi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/lib/Api.php: -------------------------------------------------------------------------------- 1 | ApiRequest = $this->ApiRequest ?: new ApiRequest(); 37 | return $this->ApiRequest; 38 | } 39 | 40 | /** 41 | * @return Ticker 42 | */ 43 | public function ticker(): Ticker 44 | { 45 | $this->Ticker = $this->Ticker ?: new Ticker(); 46 | return $this->Ticker; 47 | } 48 | 49 | /** 50 | * It's just current price of Bitcoin in 3 different pairs. 51 | * Pairs: USD, EUR, GBP 52 | * 53 | * @return array 54 | */ 55 | public function getCurrentPrice(): array 56 | { 57 | return $this->getApiRequest()->sendRequest("bpi/currentprice.json"); 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /src/lib/Utils/ApiRequest.php: -------------------------------------------------------------------------------- 1 | 'application/json', 25 | 'Content-Type' => 'application/json', 26 | 'Pragma: ' => 'no-cache' 27 | ]; 28 | 29 | /** 30 | * @param string $endpoint 31 | * @param array $parameters 32 | * @return array 33 | */ 34 | public function sendRequest(string $endpoint, array $parameters = []): array 35 | { 36 | $queryString = http_build_query($parameters); // query string encode the parameters 37 | 38 | $endPointUrl = $this->apiPath . $endpoint . "?" . $queryString; // create the request URL 39 | 40 | $curl = curl_init(); // Get cURL resource 41 | 42 | // Set cURL options 43 | curl_setopt_array($curl, array( 44 | CURLOPT_URL => $endPointUrl, // set the request URL 45 | CURLOPT_HTTPHEADER => $this->headers, // set the headers 46 | CURLOPT_RETURNTRANSFER => 1 // ask for raw response instead of bool 47 | )); 48 | 49 | $response = curl_exec($curl); // Send the request, save the response 50 | curl_close($curl); // Close request 51 | 52 | return json_decode($response, true); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/lib/Features/Ticker.php: -------------------------------------------------------------------------------- 1 | WebSocket = new WebSocket(); 24 | } 25 | 26 | /** 27 | * @param array $settings 28 | */ 29 | private function Initialization(array $settings): void 30 | { 31 | ini_set('max_execution_time', '0'); 32 | $this->CloseTime = $settings['close_time'] ?: 0; 33 | } 34 | 35 | private function subscribeChannel(WebSocket $WebSocket, $Connection): void 36 | { 37 | usleep(500 * 1000); 38 | $WebSocket->websocket_write($Connection, '{"type":"hello","version":"2","id":1}'); 39 | usleep(500 * 1000); 40 | $WebSocket->websocket_write($Connection, '{"type":"sub","path":"/v2/ticker/all","id":2}'); 41 | usleep(500 * 1000); 42 | } 43 | 44 | /** 45 | * @return bool 46 | * @throws Exception 47 | */ 48 | private function makeConnection(): bool 49 | { 50 | if ($this->Connection = $this->WebSocket->websocket_open('production.api.coindesk.com', 443, '', $errstr, 10, true)) { 51 | 52 | // Starting for receiver 53 | return true; 54 | 55 | 56 | } else { 57 | throw new Exception("Connection Failed: $errstr"); 58 | } 59 | } 60 | 61 | /** 62 | * @param $Query 63 | * @param array $Settings 64 | * @throws Exception 65 | */ 66 | public function setTicker($Query, array $Settings): void 67 | { 68 | $this->Initialization($Settings); 69 | if ($this->makeConnection()) { 70 | 71 | // Subscribe to stream 72 | $this->subscribeChannel($this->WebSocket, $this->Connection); 73 | 74 | // Starting for receiver 75 | while ($this->CloseTime > time()) { 76 | $message = $this->WebSocket->websocket_read($this->Connection, $errstr); 77 | if ($message != "") { 78 | $JsonMessage = json_decode($message, true); 79 | if ($JsonMessage['type'] == "pub") { 80 | $Query($JsonMessage['message']); 81 | } 82 | } 83 | } 84 | 85 | } 86 | } 87 | 88 | /** 89 | * @throws Exception 90 | */ 91 | public function getOneTick(): array|bool 92 | { 93 | $oneTick = false; 94 | if ($this->makeConnection()) { 95 | 96 | // Subscribe to stream 97 | $this->subscribeChannel($this->WebSocket, $this->Connection); 98 | 99 | // Setup close timer 100 | $this->CloseTime = strtotime('+10 second', time()); 101 | 102 | // Starting for receiver 103 | while ($this->CloseTime > time()) { 104 | $message = $this->WebSocket->websocket_read($this->Connection, $errstr); 105 | if ($message != "") { 106 | $JsonMessage = json_decode($message, true); 107 | if ($JsonMessage['type'] == "pub") { 108 | 109 | $oneTick = $JsonMessage['message']; 110 | break; 111 | 112 | } 113 | } 114 | } 115 | 116 | } 117 | 118 | return $oneTick; 119 | } 120 | 121 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > **Help wanted:** This library is officially depreciated and will only be actively maintained by the community.
***Pull requests are welcome.*** 2 | 3 | # PHP CoinDesk Price Ticker 4 | 5 | This project is for catching realtime cryptocurrency prices form [CoinDesk](https://www.coindesk.com/). 6 | 7 | **NOTE:** Not recommended for non PHP-Cli, But anyway it's work well. 8 | 9 | #### Requirements 10 | 11 | ``` 12 | ext-openssl: * 13 | ext-curl: * 14 | ext-json: * 15 | php: >=8.0 16 | ``` 17 | 18 | #### Installation 19 | 20 | ``` 21 | composer require shahradelahi/coindesk-ticker 22 | ``` 23 | 24 |
25 | Click for help with installation 26 | 27 | ## Install Composer 28 | 29 | If the above step didn't work, install composer and try again. 30 | 31 | #### Debian / Ubuntu 32 | 33 | ``` 34 | sudo apt-get install curl php-curl 35 | curl -s http://getcomposer.org/installer | php 36 | php composer.phar install 37 | ``` 38 | 39 | Composer not found? Use this command instead: 40 | 41 | ``` 42 | php composer.phar require "shahradelahi/coindesk-ticker" 43 | ``` 44 | 45 | #### Windows: 46 | 47 | [Download installer for Windows](https://github.com/jaggedsoft/php-binance-api/#installing-on-windows) 48 | 49 |
50 | 51 | #### Getting started 52 | 53 | `composer require shahradelahi/coindesk-ticker` 54 | 55 | ```php 56 | require 'vendor/autoload.php'; 57 | $CDApi = new CoinDesk\Api(); 58 | ``` 59 | 60 | ======= 61 | 62 | #### Price Streaming 63 | 64 | Return ticks of the all supported cryptocurrencies in [CoinDesk](https://www.coindesk.com/), and it has a timer for 65 | closing the streamer, make sure you will fill it. 66 | 67 | ```php 68 | $Settings = [ 69 | 'close_time' => strtotime('+30 minute', time()) // Required 70 | ]; 71 | 72 | $CDApi->ticker()->setTicker(function (array $Tick) { 73 | 74 | // Print out the ticks 75 | echo "
" . json_encode($Tick, JSON_PRETTY_PRINT) . "
"; 76 | 77 | }, $Settings); 78 | ``` 79 | 80 |
81 | View Response 82 | 83 | ```json 84 | [ 85 | { 86 | "iso": "BTC", 87 | "name": "Bitcoin", 88 | "slug": "bitcoin", 89 | "change": { 90 | "percent": -4.896072815000544, 91 | "value": -2041.6934352962 92 | }, 93 | "ohlc": { 94 | "o": 41700.6346196656, 95 | "h": 41808.4166996006, 96 | "l": 39292.9291308613, 97 | "c": 39826.5392045181 98 | }, 99 | "circulatingSupply": 18773462.54282542, 100 | "marketCap": 747682041966.3883, 101 | "ts": 1627900353000 102 | }, 103 | { 104 | "iso": "ETH", 105 | "name": "Ethereum", 106 | "slug": "ethereum", 107 | "change": { 108 | "percent": -0.040842089316403665, 109 | "value": -1.0614868266 110 | }, 111 | "ohlc": { 112 | "o": 2599.0022655374, 113 | "h": 2698.4745999226, 114 | "l": 2511.0200978405, 115 | "c": 2601.7565990196 116 | }, 117 | "circulatingSupply": 116933867.71823, 118 | "marketCap": 304233461984.79083, 119 | "ts": 1627900353000 120 | } 121 | ] 122 | ``` 123 | 124 |
125 | 126 | #### One-Tick 127 | 128 | Returns a single tick of the streaming method, and the response is exactly the response of the streamer. 129 | 130 | ```php 131 | $OneTick = $CDApi->ticker()->getOneTick(); 132 | echo "
" . json_encode($OneTick, JSON_PRETTY_PRINT) . "
"; 133 | ``` 134 | 135 |
136 | View Response 137 | 138 | ```json 139 | [ 140 | { 141 | "iso": "BTC", 142 | "name": "Bitcoin", 143 | "slug": "bitcoin", 144 | "change": { 145 | "percent": -4.896072815000544, 146 | "value": -2041.6934352962 147 | }, 148 | "ohlc": { 149 | "o": 41700.6346196656, 150 | "h": 41808.4166996006, 151 | "l": 39292.9291308613, 152 | "c": 39826.5392045181 153 | }, 154 | "circulatingSupply": 18773462.54282542, 155 | "marketCap": 747682041966.3883, 156 | "ts": 1627900353000 157 | }, 158 | { 159 | "iso": "ETH", 160 | "name": "Ethereum", 161 | "slug": "ethereum", 162 | "change": { 163 | "percent": -0.040842089316403665, 164 | "value": -1.0614868266 165 | }, 166 | "ohlc": { 167 | "o": 2599.0022655374, 168 | "h": 2698.4745999226, 169 | "l": 2511.0200978405, 170 | "c": 2601.7565990196 171 | }, 172 | "circulatingSupply": 116933867.71823, 173 | "marketCap": 304233461984.79083, 174 | "ts": 1627900353000 175 | } 176 | ] 177 | ``` 178 | 179 |
180 | 181 | #### BPI Current Price 182 | 183 | It's just current price of Bitcoin in 3 different pairs. 184 | 185 | **Pairs:** USD, EUR, GBP 186 | 187 | ```php 188 | $CurrentPrice = $CDApi->getCurrentPrice(); 189 | echo "
" . json_encode($CurrentPrice, JSON_PRETTY_PRINT) . "
"; 190 | ``` 191 | 192 |
193 | View Response 194 | 195 | ```json 196 | { 197 | "time": { 198 | "updated": "Aug 2, 2021 11:08:00 UTC", 199 | "updatedISO": "2021-08-02T11:08:00+00:00", 200 | "updateduk": "Aug 2, 2021 at 12:08 BST" 201 | }, 202 | "disclaimer": "This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org", 203 | "chartName": "Bitcoin", 204 | "bpi": { 205 | "USD": { 206 | "code": "USD", 207 | "symbol": "$", 208 | "rate": "39,517.8017", 209 | "description": "United States Dollar", 210 | "rate_float": 39517.8017 211 | }, 212 | "GBP": { 213 | "code": "GBP", 214 | "symbol": "£", 215 | "rate": "28,430.0549", 216 | "description": "British Pound Sterling", 217 | "rate_float": 28430.0549 218 | }, 219 | "EUR": { 220 | "code": "EUR", 221 | "symbol": "€", 222 | "rate": "33,233.9180", 223 | "description": "Euro", 224 | "rate_float": 33233.918 225 | } 226 | } 227 | } 228 | ``` 229 | 230 |
231 | -------------------------------------------------------------------------------- /src/lib/Utils/WebSocket.php: -------------------------------------------------------------------------------- 1 | = 0x7E) { 197 | $ext_len = 2; 198 | if ($payload_len == 0x7F) $ext_len = 8; 199 | $header = fread($sp, $ext_len); 200 | if (!$header) { 201 | $error_string = "Reading header extension from websocket failed."; 202 | return false; 203 | } 204 | 205 | // Set extented paylod length 206 | $payload_len = 0; 207 | for ($i = 0; $i < $ext_len; $i++) 208 | $payload_len += ord($header[$i]) << ($ext_len - $i - 1) * 8; 209 | } 210 | 211 | // Get Mask key 212 | if ($masked) { 213 | $mask = fread($sp, 4); 214 | if (!$mask) { 215 | $error_string = "Reading header mask from websocket failed."; 216 | return false; 217 | } 218 | } 219 | 220 | // Get payload 221 | $frame_data = ''; 222 | while ($payload_len > 0) { 223 | $frame = fread($sp, $payload_len); 224 | if (!$frame) { 225 | $error_string = "Reading from websocket failed."; 226 | return false; 227 | } 228 | $payload_len -= strlen($frame); 229 | $frame_data .= $frame; 230 | } 231 | 232 | // Handle ping requests (sort of) send pong and continue to read 233 | if ($opcode == 9) { 234 | // Assamble header: FINal 0x80 | Opcode 0x0A + Mask on 0x80 with zero payload 235 | fwrite($sp, chr(0x8A) . chr(0x80) . pack("N", rand(1, 0x7FFFFFFF))); 236 | continue; 237 | 238 | // Close 239 | } elseif ($opcode == 8) { 240 | fclose($sp); 241 | 242 | // 0 = continuation frame, 1 = text frame, 2 = binary frame 243 | } elseif ($opcode < 3) { 244 | // Unmask data 245 | $data_len = strlen($frame_data); 246 | if ($masked) 247 | for ($i = 0; $i < $data_len; $i++) 248 | $data .= $frame_data[$i] ^ $mask[$i % 4]; 249 | else 250 | $data .= $frame_data; 251 | 252 | } else 253 | continue; 254 | 255 | } while (!$final); 256 | 257 | return $data; 258 | } 259 | 260 | } --------------------------------------------------------------------------------