Commit 990485bf authored by Armando Lüscher's avatar Armando Lüscher

Merge pull request #214 from noplanman/guzzleify

Introduce Guzzle
parents bc068cb1 e66eb190
...@@ -464,10 +464,14 @@ Inside *examples/Commands/* there are some samples that show how to use types. ...@@ -464,10 +464,14 @@ Inside *examples/Commands/* there are some samples that show how to use types.
#### Commands Configuration #### Commands Configuration
With this method you can set some command specific parameters, for With this method you can set some command specific parameters:
example, google geocode/timezone api key for date command:
```php ```php
//Google geocode/timezone API key for date command
$telegram->setCommandConfig('date', ['google_api_key' => 'your_google_api_key_here']); $telegram->setCommandConfig('date', ['google_api_key' => 'your_google_api_key_here']);
//OpenWeatherMap API key for weather command
$telegram->setCommandConfig('weather', ['owm_api_key' => 'your_owm_api_key_here']);
``` ```
### Admin Commands ### Admin Commands
......
...@@ -21,7 +21,8 @@ ...@@ -21,7 +21,8 @@
"php": ">=5.5.0", "php": ">=5.5.0",
"ext-pdo": "*", "ext-pdo": "*",
"ext-curl": "*", "ext-curl": "*",
"monolog/monolog": "^1.19" "monolog/monolog": "^1.19",
"guzzlehttp/guzzle": "~6.0"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
......
...@@ -4,9 +4,180 @@ ...@@ -4,9 +4,180 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "49fc795b5cdb1b689416910c6bed4023", "hash": "3d67bf3fdb85b051d8f76a6098654143",
"content-hash": "b0ad7b5aff6fea3eb03b195779708bda", "content-hash": "e896da909d596879e7fcf1a2b7898113",
"packages": [ "packages": [
{
"name": "guzzlehttp/guzzle",
"version": "6.2.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "d094e337976dff9d8e2424e8485872194e768662"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/d094e337976dff9d8e2424e8485872194e768662",
"reference": "d094e337976dff9d8e2424e8485872194e768662",
"shasum": ""
},
"require": {
"guzzlehttp/promises": "~1.0",
"guzzlehttp/psr7": "~1.1",
"php": ">=5.5.0"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "~4.0",
"psr/log": "~1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.2-dev"
}
},
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle is a PHP HTTP client library",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"rest",
"web service"
],
"time": "2016-03-21 20:02:09"
},
{
"name": "guzzlehttp/promises",
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "c10d860e2a9595f8883527fa0021c7da9e65f579"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/c10d860e2a9595f8883527fa0021c7da9e65f579",
"reference": "c10d860e2a9595f8883527fa0021c7da9e65f579",
"shasum": ""
},
"require": {
"php": ">=5.5.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle promises library",
"keywords": [
"promise"
],
"time": "2016-05-18 16:56:05"
},
{
"name": "guzzlehttp/psr7",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "31382fef2889136415751badebbd1cb022a4ed72"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/31382fef2889136415751badebbd1cb022a4ed72",
"reference": "31382fef2889136415751badebbd1cb022a4ed72",
"shasum": ""
},
"require": {
"php": ">=5.4.0",
"psr/http-message": "~1.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "PSR-7 message implementation",
"keywords": [
"http",
"message",
"stream",
"uri"
],
"time": "2016-04-13 19:56:01"
},
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
"version": "1.19.0", "version": "1.19.0",
...@@ -85,6 +256,55 @@ ...@@ -85,6 +256,55 @@
], ],
"time": "2016-04-12 18:29:35" "time": "2016-04-12 18:29:35"
}, },
{
"name": "psr/http-message",
"version": "1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"time": "2015-05-04 20:22:00"
},
{ {
"name": "psr/log", "name": "psr/log",
"version": "1.0.0", "version": "1.0.0",
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
namespace Longman\TelegramBot\Commands\UserCommands; namespace Longman\TelegramBot\Commands\UserCommands;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Longman\TelegramBot\Commands\UserCommand; use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Exception\TelegramException; use Longman\TelegramBot\Exception\TelegramException;
use Longman\TelegramBot\Request; use Longman\TelegramBot\Request;
...@@ -25,16 +27,29 @@ class DateCommand extends UserCommand ...@@ -25,16 +27,29 @@ class DateCommand extends UserCommand
protected $name = 'date'; protected $name = 'date';
protected $description = 'Show date/time by location'; protected $description = 'Show date/time by location';
protected $usage = '/date <location>'; protected $usage = '/date <location>';
protected $version = '1.2.1'; protected $version = '1.3.0';
protected $public = true;
/**#@-*/ /**#@-*/
/** /**
* Base URL for Google Maps API * Guzzle Client object
*
* @var \GuzzleHttp\Client
*/
private $client;
/**
* Base URI for Google Maps API
*
* @var string
*/
private $google_api_base_uri = 'https://maps.googleapis.com/maps/api/';
/**
* The Google API Key from the command config
* *
* @var string * @var string
*/ */
private $base_url = 'https://maps.googleapis.com/maps/api'; private $google_api_key;
/** /**
* Date format * Date format
...@@ -52,32 +67,28 @@ class DateCommand extends UserCommand ...@@ -52,32 +67,28 @@ class DateCommand extends UserCommand
*/ */
private function getCoordinates($location) private function getCoordinates($location)
{ {
$url = $this->base_url . '/geocode/json?'; $path = 'geocode/json';
$params = 'address=' . urlencode($location); $query = ['address' => urlencode($location)];
$google_api_key = $this->getConfig('google_api_key'); if ($this->google_api_key !== null) {
if (!empty($google_api_key)) { $query['key'] = $this->google_api_key;
$params .= '&key=' . $google_api_key;
} }
$data = $this->request($url . $params); try {
if (empty($data)) { $response = $this->client->get($path, ['query' => $query]);
return false; } catch (RequestException $e) {
throw new TelegramException($e->getMessage());
} }
$data = json_decode($data, true); if (!($result = $this->validateResponseData($response->getBody()))) {
if (empty($data)) {
return false;
}
if ($data['status'] !== 'OK') {
return false; return false;
} }
$lat = $data['results'][0]['geometry']['location']['lat']; $result = $result['results'][0];
$lng = $data['results'][0]['geometry']['location']['lng']; $lat = $result['geometry']['location']['lat'];
$acc = $data['results'][0]['geometry']['location_type']; $lng = $result['geometry']['location']['lng'];
$types = $data['results'][0]['types']; $acc = $result['geometry']['location_type'];
$types = $result['types'];
return [$lat, $lng, $acc, $types]; return [$lat, $lng, $acc, $types];
} }
...@@ -92,20 +103,44 @@ class DateCommand extends UserCommand ...@@ -92,20 +103,44 @@ class DateCommand extends UserCommand
*/ */
private function getDate($lat, $lng) private function getDate($lat, $lng)
{ {
$url = $this->base_url . '/timezone/json?'; $path = 'timezone/json';
$date_utc = new \DateTime(null, new \DateTimeZone("UTC"));
$date_utc = new \DateTime(null, new \DateTimeZone('UTC'));
$timestamp = $date_utc->format('U'); $timestamp = $date_utc->format('U');
$params = 'location=' . urlencode($lat) . ',' . urlencode($lng) . '&timestamp=' . urlencode($timestamp); $query = [
'location' => urlencode($lat) . ',' . urlencode($lng),
'timestamp' => urlencode($timestamp)
];
$google_api_key = $this->getConfig('google_api_key'); if ($this->google_api_key !== null) {
if (!empty($google_api_key)) { $query['key'] = $this->google_api_key;
$params .= '&key=' . $google_api_key; }
try {
$response = $this->client->get($path, ['query' => $query]);
} catch (RequestException $e) {
throw new TelegramException($e->getMessage());
}
if (!($result = $this->validateResponseData($response->getBody()))) {
return false;
} }
$data = $this->request($url . $params); $local_time = $timestamp + $result['rawOffset'] + $result['dstOffset'];
return [$local_time, $result['timeZoneId']];
}
/**
* Evaluate the response data and see if the request was successful
*
* @param string $data
*
* @return bool|array
*/
private function validateResponseData($data)
{
if (empty($data)) { if (empty($data)) {
return false; return false;
} }
...@@ -115,13 +150,11 @@ class DateCommand extends UserCommand ...@@ -115,13 +150,11 @@ class DateCommand extends UserCommand
return false; return false;
} }
if ($data['status'] !== 'OK') { if (isset($data['status']) && $data['status'] !== 'OK') {
return false; return false;
} }
$local_time = $timestamp + $data['rawOffset'] + $data['dstOffset']; return $data;
return [$local_time, $data['timeZoneId']];
} }
/** /**
...@@ -150,56 +183,31 @@ class DateCommand extends UserCommand ...@@ -150,56 +183,31 @@ class DateCommand extends UserCommand
return 'The local time in ' . $timezone_id . ' is: ' . $date_utc->format($this->date_format); return 'The local time in ' . $timezone_id . ' is: ' . $date_utc->format($this->date_format);
} }
/**
* Perform a simple cURL request
*
* @param string $url
*
* @return object
*/
private function request($url)
{
$ch = curl_init();
$curlConfig = [CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true];
curl_setopt_array($ch, $curlConfig);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_code !== 200) {
throw new TelegramException('Error receiving data from url');
}
curl_close($ch);
return $response;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function execute() public function execute()
{ {
//First we set up the necessary member variables.
$this->client = new Client(['base_uri' => $this->google_api_base_uri]);
if (($this->google_api_key = trim($this->getConfig('google_api_key'))) === '') {
$this->google_api_key = null;
}
$message = $this->getMessage(); $message = $this->getMessage();
$chat_id = $message->getChat()->getId(); $chat_id = $message->getChat()->getId();
$message_id = $message->getMessageId(); $location = $message->getText(true);
$text = $message->getText(true);
if (empty($text)) { if (empty($location)) {
$text = 'You must specify location in format: /date <city>'; $text = 'You must specify location in format: /date <city>';
} else { } else {
$date = $this->getformattedDate($text); $text = $this->getformattedDate($location);
if (empty($date)) {
$text = 'Can not find date for location: ' . $text;
} else {
$text = $date;
}
} }
$data = [ $data = [
'chat_id' => $chat_id, 'chat_id' => $chat_id,
'reply_to_message_id' => $message_id, 'text' => $text,
'text' => $text,
]; ];
return Request::sendMessage($data); return Request::sendMessage($data);
......
...@@ -10,7 +10,10 @@ ...@@ -10,7 +10,10 @@
namespace Longman\TelegramBot\Commands\UserCommands; namespace Longman\TelegramBot\Commands\UserCommands;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Longman\TelegramBot\Commands\UserCommand; use Longman\TelegramBot\Commands\UserCommand;
use Longman\TelegramBot\Exception\TelegramException;
use Longman\TelegramBot\Request; use Longman\TelegramBot\Request;
/** /**
...@@ -24,89 +27,79 @@ class WeatherCommand extends UserCommand ...@@ -24,89 +27,79 @@ class WeatherCommand extends UserCommand
protected $name = 'weather'; protected $name = 'weather';
protected $description = 'Show weather by location'; protected $description = 'Show weather by location';
protected $usage = '/weather <location>'; protected $usage = '/weather <location>';
protected $version = '1.0.1'; protected $version = '1.1.0';
protected $public = true;
/**#@-*/ /**#@-*/
/** /**
* Get weather using cURL request * Base URI for OpenWeatherMap API
*
* @var string
*/
private $owm_api_base_uri = 'http://api.openweathermap.org/data/2.5/';
/**
* Get weather data using HTTP request
* *
* @param string $location * @param string $location
* *
* @return object * @return string
*/ */
private function getWeather($location) private function getWeatherData($location)
{ {
$url = 'http://api.openweathermap.org/data/2.5/weather?q=' . $location . '&units=metric'; $client = new Client(['base_uri' => $this->owm_api_base_uri]);
$path = 'weather';
$ch = curl_init(); $query = [
$curlConfig = [ 'q' => $location,
CURLOPT_URL => $url, 'units' => 'metric',
CURLOPT_RETURNTRANSFER => true, 'APPID' => trim($this->getConfig('owm_api_key')),
]; ];
curl_setopt_array($ch, $curlConfig); try {
$response = curl_exec($ch); $response = $client->get($path, ['query' => $query]);
} catch (RequestException $e) {
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); throw new TelegramException($e->getMessage());
if ($http_code !== 200) {
throw new \Exception('Error receiving data from url');
} }
curl_close($ch);
return $response; return (string)$response->getBody();
} }
/** /**
* Get weather string * Get weather string from weather data
* *
* @param string $location * @param array $data
* *
* @return bool|string * @return bool|string
*/ */
private function getWeatherString($location) private function getWeatherString(array $data)
{ {
if (empty($location)) {
return false;
}
try { try {
$data = $this->getWeather($location); if (empty($data) || $data['cod'] !== 200) {
$decode = json_decode($data, true);
if (empty($decode) || $decode['cod'] != 200) {
return false; return false;
} }
$city = $decode['name']; //http://openweathermap.org/weather-conditions
$country = $decode['sys']['country']; $conditions = [
$temp = 'The temperature in ' . $city . ' (' . $country . ') is ' . $decode['main']['temp'] . '°C'; 'clear' => ' ☀️',
$conditions = 'Current conditions are: ' . $decode['weather'][0]['description']; 'clouds' => ' ☁️',
'rain' => ' ☔',
switch (strtolower($decode['weather'][0]['main'])) { 'drizzle' => ' ☔',
case 'clear': 'thunderstorm' => ' ⚡️',
$conditions .= ' ☀'; 'snow' => ' ❄️',
break; ];
$conditions_now = strtolower($data['weather'][0]['main']);
case 'clouds':
$conditions .= ' ☁☁'; return sprintf(
break; 'The temperature in %1$s (%2$s) is %3$s°C' . "\n" .
'Current conditions are: %4$s%5$s',
case 'rain': $data['name'], //city
$conditions .= ' ☔'; $data['sys']['country'], //country
break; $data['main']['temp'], //temperature
$data['weather'][0]['description'], //description of weather
case 'thunderstorm': (isset($conditions[$conditions_now])) ? $conditions[$conditions_now] : ''
$conditions .= ' ☔☔☔☔'; );
break;
}
$result = $temp . "\n" . $conditions;
} catch (\Exception $e) { } catch (\Exception $e) {
$result = ''; return false;
} }
return $result;
} }
/** /**
...@@ -115,26 +108,27 @@ class WeatherCommand extends UserCommand ...@@ -115,26 +108,27 @@ class WeatherCommand extends UserCommand
public function execute() public function execute()
{ {
$message = $this->getMessage(); $message = $this->getMessage();
$chat_id = $message->getChat()->getId(); $chat_id = $message->getChat()->getId();
$message_id = $message->getMessageId(); $text = '';
$text = $message->getText(true);
if (trim($this->getConfig('owm_api_key'))) {
if (empty($text)) { if ($location = trim($message->getText(true))) {
$text = 'You must specify location in format: /weather <city>'; if ($weather_data = json_decode($this->getWeatherData($location), true)) {
} else { $text = $this->getWeatherString($weather_data);
$weather = $this->getWeatherString($text); }
if (empty($weather)) { if (!$text) {
$text = 'Can not find weather for location: ' . $text; $text = 'Cannot find weather for location: ' . $location;
}
} else { } else {
$text = $weather; $text = 'You must specify location in format: /weather <city>';
} }
} else {
$text = 'OpenWeatherMap API key not defined.';
} }
$data = [ $data = [
'chat_id' => $chat_id, 'chat_id' => $chat_id,
'reply_to_message_id' => $message_id, 'text' => $text,
'text' => $text,
]; ];
return Request::sendMessage($data); return Request::sendMessage($data);
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
namespace Longman\TelegramBot; namespace Longman\TelegramBot;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Longman\TelegramBot\Entities\File; use Longman\TelegramBot\Entities\File;
use Longman\TelegramBot\Entities\ServerResponse; use Longman\TelegramBot\Entities\ServerResponse;
use Longman\TelegramBot\Exception\TelegramException; use Longman\TelegramBot\Exception\TelegramException;
...@@ -23,6 +25,20 @@ class Request ...@@ -23,6 +25,20 @@ class Request
*/ */
private static $telegram; private static $telegram;
/**
* URI of the Telegram API
*
* @var string
*/
private static $api_base_uri = 'https://api.telegram.org';
/**
* Guzzle Client object
*
* @var \GuzzleHttp\Client
*/
private static $client;
/** /**
* Input value of the request * Input value of the request
* *
...@@ -31,13 +47,11 @@ class Request ...@@ -31,13 +47,11 @@ class Request
private static $input; private static $input;
/** /**
* Available methods to request * Available actions to send
*
* @todo Possibly rename to "actions"?
* *
* @var array * @var array
*/ */
private static $methods = [ private static $actions = [
'getUpdates', 'getUpdates',
'setWebhook', 'setWebhook',
'getMe', 'getMe',
...@@ -66,7 +80,7 @@ class Request ...@@ -66,7 +80,7 @@ class Request
'answerInlineQuery', 'answerInlineQuery',
'editMessageText', 'editMessageText',
'editMessageCaption', 'editMessageCaption',
'editMessageReplyMarkup' 'editMessageReplyMarkup',
]; ];
/** /**
...@@ -78,29 +92,12 @@ class Request ...@@ -78,29 +92,12 @@ class Request
{ {
if (is_object($telegram)) { if (is_object($telegram)) {
self::$telegram = $telegram; self::$telegram = $telegram;
self::$client = new Client(['base_uri' => self::$api_base_uri]);
} else { } else {
throw new TelegramException('Telegram pointer is empty!'); throw new TelegramException('Telegram pointer is empty!');
} }
} }
/**
* Set raw input data string
*
* @todo Possibly set this to private, since getInput overwrites the input anyway
* @todo Why the "| $input == false"?
*
* @param string $input
*/
public static function setInputRaw($input)
{
if (is_string($input) | $input == false) {
self::$input = $input;
TelegramLog::update(self::$input);
} else {
throw new TelegramException('Input must be a string!');
}
}
/** /**
* Set input from custom input or stdin and return it * Set input from custom input or stdin and return it
* *
...@@ -108,11 +105,19 @@ class Request ...@@ -108,11 +105,19 @@ class Request
*/ */
public static function getInput() public static function getInput()
{ {
if ($input = self::$telegram->getCustomInput()) { // First check if a custom input has been set, else get the PHP input.
self::setInputRaw($input); if (!($input = self::$telegram->getCustomInput())) {
$input = file_get_contents('php://input');
}
// Make sure we have a string to work with.
if (is_string($input)) {
self::$input = $input;
} else { } else {
self::setInputRaw(file_get_contents('php://input')); throw new TelegramException('Input must be a string!');
} }
TelegramLog::update(self::$input);
return self::$input; return self::$input;
} }
...@@ -155,64 +160,39 @@ class Request ...@@ -155,64 +160,39 @@ class Request
} }
/** /**
* Execute cURL call * Execute HTTP Request
* *
* @param string $action Action to execute * @param string $action Action to execute
* @param array|null $data Data to attach to the execution * @param array|null $data Data to attach to the execution
* *
* @return mixed Result of the cURL call * @return mixed Result of the HTTP Request
*/ */
public static function executeCurl($action, array $data = null) public static function execute($action, array $data = null)
{ {
$ch = curl_init(); $debug_handle = TelegramLog::getDebugLogTempStream();
if ($ch === false) {
throw new TelegramException('Curl failed to initialize');
}
$curlConfig = [ try {
CURLOPT_URL => 'https://api.telegram.org/bot' . self::$telegram->getApiKey() . '/' . $action, //Fix so that the keyboard markup is a string, not an object
CURLOPT_POST => true, if (isset($data['reply_markup']) && !is_string($data['reply_markup'])) {
CURLOPT_RETURNTRANSFER => true, $data['reply_markup'] = (string)$data['reply_markup'];
CURLOPT_SAFE_UPLOAD => true, }
];
if (!empty($data)) {
$curlConfig[CURLOPT_POSTFIELDS] = $data;
}
if (TelegramLog::isDebugLogActive()) { $response = self::$client->post(
$verbose_curl_output = fopen('php://temp', 'w+'); '/bot' . self::$telegram->getApiKey() . '/' . $action,
$curlConfig[CURLOPT_VERBOSE] = true; ['debug' => $debug_handle, 'form_params' => $data]
$curlConfig[CURLOPT_STDERR] = $verbose_curl_output; );
} catch (RequestException $e) {
throw new TelegramException($e->getMessage());
} finally {
//Logging verbose debug output
TelegramLog::endDebugLogTempStream("Verbose HTTP Request output:\n%s\n");
} }
curl_setopt_array($ch, $curlConfig); $result = $response->getBody();
$result = curl_exec($ch);
//Logging curl requests
if (TelegramLog::isDebugLogActive()) {
rewind($verbose_curl_output);
$verboseLog = stream_get_contents($verbose_curl_output);
fclose($verbose_curl_output);
TelegramLog::debug('Verbose curl output:' . "\n" . htmlspecialchars($verboseLog) . "\n");
}
//Logging getUpdates Update //Logging getUpdates Update
if ($action == 'getUpdates') { if ($action === 'getUpdates') {
//Will be Logged in Update steam TelegramLog::update($result);
self::setInputRaw($result);
}
$curl_error = curl_error($ch);
$curl_errno = curl_errno($ch);
curl_close($ch);
if ($result === false) {
throw new TelegramException($curl_error, $curl_errno);
}
if (empty($result) | is_null($result)) {
throw new TelegramException('Empty server response');
} }
return $result; return $result;
...@@ -230,46 +210,27 @@ class Request ...@@ -230,46 +210,27 @@ class Request
$path = $file->getFilePath(); $path = $file->getFilePath();
//Create the directory //Create the directory
$basepath = self::$telegram->getDownloadPath(); $loc_path = self::$telegram->getDownloadPath() . '/' . $path;
$loc_path = $basepath . '/' . $path;
$dirname = dirname($loc_path); $dirname = dirname($loc_path);
if (!is_dir($dirname)) { if (!is_dir($dirname) && !mkdir($dirname, 0755, true)) {
if (!mkdir($dirname, 0755, true)) { throw new TelegramException('Directory ' . $dirname . ' can\'t be created');
throw new TelegramException('Directory ' . $dirname . ' can\'t be created');
}
}
//Open file to write
$fp = fopen($loc_path, 'w+');
if ($fp === false) {
throw new TelegramException('File can\'t be created');
} }
$ch = curl_init(); $debug_handle = TelegramLog::getDebugLogTempStream();
if ($ch === false) {
throw new TelegramException('Curl failed to initialize');
}
$curlConfig = [ try {
CURLOPT_URL => 'https://api.telegram.org/file/bot' . self::$telegram->getApiKey() . '/' . $path, $response = self::$client->get(
CURLOPT_RETURNTRANSFER => true, '/file/bot' . self::$telegram->getApiKey() . '/' . $path,
CURLOPT_HEADER => 0, ['debug' => $debug_handle, 'sink' => $loc_path]
CURLOPT_BINARYTRANSFER => true, );
CURLOPT_CONNECTTIMEOUT => 10, } catch (RequestException $e) {
CURLOPT_FILE => $fp, throw new TelegramException($e->getMessage());
]; } finally {
//Logging verbose debug output
curl_setopt_array($ch, $curlConfig); TelegramLog::endDebugLogTempStream("Verbose HTTP File Download Request output:\n%s\n");
$result = curl_exec($ch);
if ($result === false) {
throw new TelegramException(curl_error($ch), curl_errno($ch));
} }
//Close curl
curl_close($ch);
//Close local file
fclose($fp);
return (filesize($loc_path) > 0); return (filesize($loc_path) > 0);
} }
...@@ -289,7 +250,6 @@ class Request ...@@ -289,7 +250,6 @@ class Request
* Send command * Send command
* *
* @todo Fake response doesn't need json encoding? * @todo Fake response doesn't need json encoding?
* @todo Rename "methods" to "actions"
* *
* @param string $action * @param string $action
* @param array|null $data * @param array|null $data
...@@ -298,8 +258,8 @@ class Request ...@@ -298,8 +258,8 @@ class Request
*/ */
public static function send($action, array $data = null) public static function send($action, array $data = null)
{ {
if (!in_array($action, self::$methods)) { if (!in_array($action, self::$actions)) {
throw new TelegramException('This method doesn\'t exist!'); throw new TelegramException('The action ' . $action . ' doesn\'t exist!');
} }
$bot_name = self::$telegram->getBotName(); $bot_name = self::$telegram->getBotName();
...@@ -309,7 +269,7 @@ class Request ...@@ -309,7 +269,7 @@ class Request
return new ServerResponse($fake_response, $bot_name); return new ServerResponse($fake_response, $bot_name);
} }
$response = json_decode(self::executeCurl($action, $data), true); $response = json_decode(self::execute($action, $data), true);
if (is_null($response)) { if (is_null($response)) {
throw new TelegramException('Telegram returned an invalid response! Please your bot name and api token.'); throw new TelegramException('Telegram returned an invalid response! Please your bot name and api token.');
......
...@@ -55,6 +55,13 @@ class TelegramLog ...@@ -55,6 +55,13 @@ class TelegramLog
*/ */
static protected $update_log_path = null; static protected $update_log_path = null;
/**
* Temporary stream handle for debug log
*
* @var null
*/
static protected $debug_log_temp_stream_handle = null;
/** /**
* Initialize * Initialize
* *
...@@ -120,6 +127,41 @@ class TelegramLog ...@@ -120,6 +127,41 @@ class TelegramLog
return self::$monolog->pushHandler(new StreamHandler(self::$debug_log_path, Logger::DEBUG)); return self::$monolog->pushHandler(new StreamHandler(self::$debug_log_path, Logger::DEBUG));
} }
/**
* Get the stream handle of the temporary debug output
*
* @return mixed The stream if debug is active, else false
*/
public static function getDebugLogTempStream()
{
if (self::$debug_log_temp_stream_handle === null) {
if (self::isDebugLogActive()) {
self::$debug_log_temp_stream_handle = fopen('php://temp', 'w+');
} else {
return false;
}
}
return self::$debug_log_temp_stream_handle;
}
/**
* Write the temporary debug stream to log and close the stream handle
*
* @param string $message Message (with placeholder) to write to the debug log
*/
public static function endDebugLogTempStream($message = '%s')
{
if (self::$debug_log_temp_stream_handle !== null) {
rewind(self::$debug_log_temp_stream_handle);
self::debug(sprintf(
$message,
stream_get_contents(self::$debug_log_temp_stream_handle)
));
fclose(self::$debug_log_temp_stream_handle);
self::$debug_log_temp_stream_handle = null;
}
}
/** /**
* Initialize update log * Initialize update log
* *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment