You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

245 lines
5.9 KiB

1 year ago
  1. <?php
  2. /**
  3. * This file is part of the PHP Telegram Bot example-bot package.
  4. * https://github.com/php-telegram-bot/example-bot/
  5. *
  6. * (c) PHP Telegram Bot Team
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. /**
  12. * User "/date" command
  13. *
  14. * Shows the date and time of the location passed as the parameter.
  15. *
  16. * A Google API key is required for this command!
  17. * You can be set in your config.php file:
  18. * ['commands']['configs']['date'] => ['google_api_key' => 'your_google_api_key_here']
  19. */
  20. namespace Longman\TelegramBot\Commands\UserCommands;
  21. use GuzzleHttp\Client;
  22. use GuzzleHttp\Exception\RequestException;
  23. use Longman\TelegramBot\Commands\UserCommand;
  24. use Longman\TelegramBot\Entities\ServerResponse;
  25. use Longman\TelegramBot\Exception\TelegramException;
  26. use Longman\TelegramBot\Request;
  27. use Longman\TelegramBot\TelegramLog;
  28. class DateCommand extends UserCommand
  29. {
  30. /**
  31. * @var string
  32. */
  33. protected $name = 'date';
  34. /**
  35. * @var string
  36. */
  37. protected $description = 'Show date/time by location';
  38. /**
  39. * @var string
  40. */
  41. protected $usage = '/date <location>';
  42. /**
  43. * @var string
  44. */
  45. protected $version = '1.5.0';
  46. /**
  47. * Guzzle Client object
  48. *
  49. * @var Client
  50. */
  51. private $client;
  52. /**
  53. * Base URI for Google Maps API
  54. *
  55. * @var string
  56. */
  57. private $google_api_base_uri = 'https://maps.googleapis.com/maps/api/';
  58. /**
  59. * The Google API Key from the command config
  60. *
  61. * @var string
  62. */
  63. private $google_api_key;
  64. /**
  65. * Date format
  66. *
  67. * @var string
  68. */
  69. private $date_format = 'd-m-Y H:i:s';
  70. /**
  71. * Get coordinates of passed location
  72. *
  73. * @param string $location
  74. *
  75. * @return array
  76. */
  77. private function getCoordinates($location): array
  78. {
  79. $path = 'geocode/json';
  80. $query = ['address' => urlencode($location)];
  81. if ($this->google_api_key !== null) {
  82. $query['key'] = $this->google_api_key;
  83. }
  84. try {
  85. $response = $this->client->get($path, ['query' => $query]);
  86. } catch (RequestException $e) {
  87. TelegramLog::error($e->getMessage());
  88. return [];
  89. }
  90. if (!($data = $this->validateResponseData($response->getBody()))) {
  91. return [];
  92. }
  93. $result = $data['results'][0];
  94. $lat = $result['geometry']['location']['lat'];
  95. $lng = $result['geometry']['location']['lng'];
  96. $acc = $result['geometry']['location_type'];
  97. $types = $result['types'];
  98. return [$lat, $lng, $acc, $types];
  99. }
  100. /**
  101. * Get date for location passed via coordinates
  102. *
  103. * @param string $lat
  104. * @param string $lng
  105. *
  106. * @return array
  107. * @throws \Exception
  108. */
  109. private function getDate($lat, $lng): array
  110. {
  111. $path = 'timezone/json';
  112. $date_utc = new \DateTimeImmutable(null, new \DateTimeZone('UTC'));
  113. $timestamp = $date_utc->format('U');
  114. $query = [
  115. 'location' => urlencode($lat) . ',' . urlencode($lng),
  116. 'timestamp' => urlencode($timestamp),
  117. ];
  118. if ($this->google_api_key !== null) {
  119. $query['key'] = $this->google_api_key;
  120. }
  121. try {
  122. $response = $this->client->get($path, ['query' => $query]);
  123. } catch (RequestException $e) {
  124. TelegramLog::error($e->getMessage());
  125. return [];
  126. }
  127. if (!($data = $this->validateResponseData($response->getBody()))) {
  128. return [];
  129. }
  130. $local_time = $timestamp + $data['rawOffset'] + $data['dstOffset'];
  131. return [$local_time, $data['timeZoneId']];
  132. }
  133. /**
  134. * Evaluate the response data and see if the request was successful
  135. *
  136. * @param string $data
  137. *
  138. * @return array
  139. */
  140. private function validateResponseData($data): array
  141. {
  142. if (empty($data)) {
  143. return [];
  144. }
  145. $data = json_decode($data, true);
  146. if (empty($data)) {
  147. return [];
  148. }
  149. if (isset($data['status']) && $data['status'] !== 'OK') {
  150. return [];
  151. }
  152. return $data;
  153. }
  154. /**
  155. * Get formatted date at the passed location
  156. *
  157. * @param string $location
  158. *
  159. * @return string
  160. * @throws \Exception
  161. */
  162. private function getFormattedDate($location): string
  163. {
  164. if ($location === null || $location === '') {
  165. return 'The time in nowhere is never';
  166. }
  167. [$lat, $lng] = $this->getCoordinates($location);
  168. if (empty($lat) || empty($lng)) {
  169. return 'It seems that in "' . $location . '" they do not have a concept of time.';
  170. }
  171. [$local_time, $timezone_id] = $this->getDate($lat, $lng);
  172. $date_utc = new \DateTimeImmutable(gmdate('Y-m-d H:i:s', $local_time), new \DateTimeZone($timezone_id));
  173. return 'The local time in ' . $timezone_id . ' is: ' . $date_utc->format($this->date_format);
  174. }
  175. /**
  176. * Main command execution
  177. *
  178. * @return ServerResponse
  179. * @throws TelegramException
  180. */
  181. public function execute(): ServerResponse
  182. {
  183. // First we set up the necessary member variables.
  184. $this->client = new Client(['base_uri' => $this->google_api_base_uri]);
  185. if (($this->google_api_key = trim($this->getConfig('google_api_key'))) === '') {
  186. $this->google_api_key = null;
  187. }
  188. $message = $this->getMessage();
  189. $chat_id = $message->getChat()->getId();
  190. $location = $message->getText(true);
  191. $text = 'You must specify location in format: /date <city>';
  192. if ($location !== '') {
  193. $text = $this->getFormattedDate($location);
  194. }
  195. $data = [
  196. 'chat_id' => $chat_id,
  197. 'text' => $text,
  198. ];
  199. return Request::sendMessage($data);
  200. }
  201. }