Passed
Push — master ( 47a2b4...584dd8 )
by Shahrad
02:17
created
src/lib/Telegram.php 1 patch
Indentation   +361 added lines, -361 removed lines patch added patch discarded remove patch
@@ -18,366 +18,366 @@
 block discarded – undo
18 18
 class Telegram
19 19
 {
20 20
 
21
-	/**
22
-	 * @var string
23
-	 */
24
-	private string $api_key;
25
-
26
-	/**
27
-	 * @var string
28
-	 */
29
-	public static string $VERSION = 'v1.0.0';
30
-
31
-	/**
32
-	 * Telegram constructor.
33
-	 *
34
-	 * @param string $api_key
35
-	 */
36
-	public function __construct(string $api_key = '')
37
-	{
38
-		if ($api_key === '') {
39
-			$env_file = $this->getEnvFilePath();
40
-			$api_key = DotEnv::load($env_file)->get('TELEGRAM_API_KEY');
41
-		}
42
-
43
-		if (empty($api_key) || !is_string($api_key)) {
44
-			throw new TelegramException('API Key is required');
45
-		}
46
-
47
-		DotEnv::put('TG_CURRENT_KEY', ($this->api_key = $api_key));
48
-		DotEnv::put('TELEGRAM_API_KEY', ($this->api_key = $api_key));
49
-	}
50
-
51
-	/**
52
-	 * Get env file path and return it
53
-	 *
54
-	 * @return string
55
-	 */
56
-	private function getEnvFilePath(): string
57
-	{
58
-		$defaultEnvPaths = [
59
-			$_SERVER['DOCUMENT_ROOT'] . '/.env',
60
-			getcwd() . '/../.env',
61
-			getcwd() . '/.env',
62
-		];
63
-
64
-		foreach ($defaultEnvPaths as $path) {
65
-			if (file_exists($path)) {
66
-				return $path;
67
-			}
68
-		}
69
-
70
-		return '';
71
-	}
72
-
73
-	/**
74
-	 * Get API key from temporary ENV variable
75
-	 *
76
-	 * @return ?string
77
-	 */
78
-	public static function getApiKey(): ?string
79
-	{
80
-		return DotEnv::get('TG_CURRENT_KEY');
81
-	}
82
-
83
-	/**
84
-	 * Get bot info from given API key
85
-	 *
86
-	 * @return Response
87
-	 * @throws TelegramException
88
-	 */
89
-	public function getInfo(): Response
90
-	{
91
-		$result = Request::getMe();
92
-
93
-		if (!$result->isOk()) {
94
-			throw new TelegramException($result->getErrorCode() . ': ' . $result->getDescription());
95
-		}
96
-
97
-		return $result;
98
-	}
99
-
100
-	/**
101
-	 * Set Webhook for bot
102
-	 *
103
-	 * @param string $url
104
-	 * @param array $data Optional parameters.
105
-	 * @return Response
106
-	 * @throws TelegramException
107
-	 */
108
-	public function setWebhook(string $url, array $data = []): Response
109
-	{
110
-		if ($url === '') {
111
-			throw new TelegramException('Hook url is empty!');
112
-		}
113
-
114
-		if (!str_starts_with($url, 'https://')) {
115
-			throw new TelegramException('Hook url must start with https://');
116
-		}
117
-
118
-		$data = array_intersect_key($data, array_flip([
119
-			'certificate',
120
-			'ip_address',
121
-			'max_connections',
122
-			'allowed_updates',
123
-			'drop_pending_updates',
124
-		]));
125
-		$data['url'] = $url;
126
-
127
-		$result = Request::setWebhook($data);
128
-
129
-		if (!$result->isOk()) {
130
-			throw new TelegramException(
131
-				'Webhook was not set! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
132
-			);
133
-		}
134
-
135
-		return $result;
136
-	}
137
-
138
-	/**
139
-	 * Delete any assigned webhook
140
-	 *
141
-	 * @param array $data
142
-	 * @return Response
143
-	 * @throws TelegramException
144
-	 */
145
-	public function deleteWebhook(array $data = []): Response
146
-	{
147
-		$result = Request::deleteWebhook($data);
148
-
149
-		if (!$result->isOk()) {
150
-			throw new TelegramException(
151
-				'Webhook was not deleted! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
152
-			);
153
-		}
154
-
155
-		return $result;
156
-	}
157
-
158
-	/**
159
-	 * This method sets the admin username. and will be used to send you a message if the bot is not working.
160
-	 *
161
-	 * @param int $chat_id
162
-	 * @return void
163
-	 */
164
-	public function setAdmin(int $chat_id): void
165
-	{
166
-		defined('TG_ADMIN_ID') or define('TG_ADMIN_ID', $chat_id);
167
-	}
168
-
169
-	/**
170
-	 * Get input from stdin and return it
171
-	 *
172
-	 * @return ?string
173
-	 */
174
-	public static function getInput(): ?string
175
-	{
176
-		return file_get_contents('php://input') ?? null;
177
-	}
178
-
179
-	/**
180
-	 * This method will convert a string to an update object
181
-	 *
182
-	 * @param string $input The input string
183
-	 * @param string $apiKey The API key
184
-	 * @return Update|false
185
-	 */
186
-	public static function processUpdate(string $input, string $apiKey): Update|false
187
-	{
188
-		if (empty($input)) {
189
-			throw new TelegramException(
190
-				'Input is empty! Please check your code and try again.'
191
-			);
192
-		}
193
-
194
-		if (!self::validateToken($apiKey)) {
195
-			throw new TelegramException(
196
-				'Invalid token! Please check your code and try again.'
197
-			);
198
-		}
199
-
200
-		if (self::validateWebData($apiKey, $input)) {
201
-			if (Common::isUrlEncode($input)) {
202
-				$web_data = Common::urlDecode($input);
203
-			}
204
-
205
-			if (Common::isJson($input)) {
206
-				$web_data = json_decode($input, true);
207
-			}
208
-
209
-			$input = json_encode([
210
-				'web_data' => $web_data,
211
-			]);
212
-		}
213
-
214
-		if (!Common::isJson($input)) {
215
-			throw new TelegramException(
216
-				'Input is not a valid JSON string! Please check your code and try again.'
217
-			);
218
-		}
219
-
220
-		$input = json_decode($input, true);
221
-
222
-		return new Update($input);
223
-	}
224
-
225
-	/**
226
-	 * Validate webapp data from is from Telegram
227
-	 *
228
-	 * @link https://core.telegram.org/bots/webapps#validating-data-received-via-the-web-app
229
-	 *
230
-	 * @param string $token The bot token
231
-	 * @param string $body The message body from getInput()
232
-	 * @return bool
233
-	 */
234
-	public static function validateWebData(string $token, string $body): bool
235
-	{
236
-		if (!Common::isJson($body)) {
237
-			$raw_data = rawurldecode(str_replace('_auth=', '', $body));
238
-			$data = Common::urlDecode($raw_data);
239
-
240
-			if (empty($data['user'])) {
241
-				return false;
242
-			}
243
-
244
-			$data['user'] = urldecode($data['user']);
245
-
246
-		} else {
247
-			$data = json_decode($body, true);
248
-
249
-			if (empty($data['user'])) {
250
-				return false;
251
-			}
252
-
253
-			$data['user'] = json_encode($data['user']);
254
-		}
255
-
256
-		$data_check_string = "auth_date={$data['auth_date']}\nquery_id={$data['query_id']}\nuser={$data['user']}";
257
-		$secret_key = hash_hmac('sha256', $token, "WebAppData", true);
258
-
259
-		return hash_hmac('sha256', $data_check_string, $secret_key) == $data['hash'];
260
-	}
261
-
262
-	/**
263
-	 * Get the update from input
264
-	 *
265
-	 * @return Update|false
266
-	 */
267
-	public static function getUpdate(): Update|false
268
-	{
269
-		$input = self::getInput();
270
-		if (empty($input)) return false;
271
-		return Telegram::processUpdate($input, self::getApiKey());
272
-	}
273
-
274
-	/**
275
-	 * Validate the token
276
-	 *
277
-	 * @param string $token (e.g. 123456789:ABC-DEF1234ghIkl-zyx57W2v1u123ew11) {digit}:{alphanumeric[34]}
278
-	 * @return bool
279
-	 */
280
-	public static function validateToken(string $token): bool
281
-	{
282
-		preg_match_all('/([0-9]+:[a-zA-Z0-9-_]+)/', $token, $matches);
283
-		return count($matches[0]) == 1;
284
-	}
285
-
286
-	/**
287
-	 * Pass the update to the given webhook handler
288
-	 *
289
-	 * @param WebhookHandler $webhook_handler The webhook handler
290
-	 * @param ?Update $update By default, it will get the update from input
291
-	 * @return void
292
-	 */
293
-	public function fetchWith(WebhookHandler $webhook_handler, ?Update $update = null): void
294
-	{
295
-		if (is_subclass_of($webhook_handler, WebhookHandler::class)) {
296
-			if ($update === null) $update = self::getUpdate();
297
-			$webhook_handler->resolve($update);
298
-		}
299
-	}
300
-
301
-	/**
302
-	 * Get token from env file.
303
-	 *
304
-	 * @param string $file
305
-	 * @return ?string
306
-	 */
307
-	protected function getTokenFromEnvFile(string $file): ?string
308
-	{
309
-		if (!file_exists($file)) return null;
310
-		return DotEnv::load($file)::get('TELEGRAM_API_KEY');
311
-	}
312
-
313
-	/**
314
-	 * Debug mode
315
-	 *
316
-	 * @param ?int $admin_id Fill this or use setAdmin()
317
-	 * @return void
318
-	 */
319
-	public static function setDebugMode(?int $admin_id = null): void
320
-	{
321
-		error_reporting(E_ALL);
322
-		ini_set('display_errors', 1);
323
-
324
-		defined('DEBUG_MODE') or define('DEBUG_MODE', true);
325
-		if ($admin_id) {
326
-			defined('TG_ADMIN_ID') or define('TG_ADMIN_ID', $admin_id);
327
-		}
328
-
329
-		set_exception_handler(function ($exception) {
330
-
331
-			if (defined('DEBUG_MODE') && DEBUG_MODE) {
332
-
333
-				TelegramLog::error(($message = sprintf(
334
-					"%s(%d): %s\n%s",
335
-					$exception->getFile(),
336
-					$exception->getLine(),
337
-					$exception->getMessage(),
338
-					$exception->getTraceAsString()
339
-				)));
340
-
341
-				echo '<b>TelegramError:</b> ' . $message;
342
-
343
-				if (defined('TG_ADMIN_ID') && TG_ADMIN_ID) {
344
-					$input = getenv('TG_CURRENT_UPDATE') ?? self::getInput();
345
-					$update = self::processUpdate($input, self::getApiKey());
346
-
347
-					file_put_contents(
348
-						($file = getcwd() . '/' . uniqid('error_') . '.log'),
349
-						$message . PHP_EOL . PHP_EOL . $update->getRawData(false)
350
-					);
351
-
352
-					Request::sendMessage([
353
-						'chat_id' => TG_ADMIN_ID,
354
-						'text' => $message,
355
-					]);
356
-
357
-					Request::sendDocument([
358
-						'chat_id' => TG_ADMIN_ID,
359
-						'document' => $file,
360
-					]);
361
-
362
-					unlink($file);
363
-				}
364
-
365
-			} else {
366
-				throw $exception;
367
-			}
368
-
369
-		});
370
-	}
371
-
372
-	/**
373
-	 * Just another echo
374
-	 *
375
-	 * @param string $text
376
-	 * @return void
377
-	 */
378
-	public static function echo(string $text): void
379
-	{
380
-		echo $text;
381
-	}
21
+    /**
22
+     * @var string
23
+     */
24
+    private string $api_key;
25
+
26
+    /**
27
+     * @var string
28
+     */
29
+    public static string $VERSION = 'v1.0.0';
30
+
31
+    /**
32
+     * Telegram constructor.
33
+     *
34
+     * @param string $api_key
35
+     */
36
+    public function __construct(string $api_key = '')
37
+    {
38
+        if ($api_key === '') {
39
+            $env_file = $this->getEnvFilePath();
40
+            $api_key = DotEnv::load($env_file)->get('TELEGRAM_API_KEY');
41
+        }
42
+
43
+        if (empty($api_key) || !is_string($api_key)) {
44
+            throw new TelegramException('API Key is required');
45
+        }
46
+
47
+        DotEnv::put('TG_CURRENT_KEY', ($this->api_key = $api_key));
48
+        DotEnv::put('TELEGRAM_API_KEY', ($this->api_key = $api_key));
49
+    }
50
+
51
+    /**
52
+     * Get env file path and return it
53
+     *
54
+     * @return string
55
+     */
56
+    private function getEnvFilePath(): string
57
+    {
58
+        $defaultEnvPaths = [
59
+            $_SERVER['DOCUMENT_ROOT'] . '/.env',
60
+            getcwd() . '/../.env',
61
+            getcwd() . '/.env',
62
+        ];
63
+
64
+        foreach ($defaultEnvPaths as $path) {
65
+            if (file_exists($path)) {
66
+                return $path;
67
+            }
68
+        }
69
+
70
+        return '';
71
+    }
72
+
73
+    /**
74
+     * Get API key from temporary ENV variable
75
+     *
76
+     * @return ?string
77
+     */
78
+    public static function getApiKey(): ?string
79
+    {
80
+        return DotEnv::get('TG_CURRENT_KEY');
81
+    }
82
+
83
+    /**
84
+     * Get bot info from given API key
85
+     *
86
+     * @return Response
87
+     * @throws TelegramException
88
+     */
89
+    public function getInfo(): Response
90
+    {
91
+        $result = Request::getMe();
92
+
93
+        if (!$result->isOk()) {
94
+            throw new TelegramException($result->getErrorCode() . ': ' . $result->getDescription());
95
+        }
96
+
97
+        return $result;
98
+    }
99
+
100
+    /**
101
+     * Set Webhook for bot
102
+     *
103
+     * @param string $url
104
+     * @param array $data Optional parameters.
105
+     * @return Response
106
+     * @throws TelegramException
107
+     */
108
+    public function setWebhook(string $url, array $data = []): Response
109
+    {
110
+        if ($url === '') {
111
+            throw new TelegramException('Hook url is empty!');
112
+        }
113
+
114
+        if (!str_starts_with($url, 'https://')) {
115
+            throw new TelegramException('Hook url must start with https://');
116
+        }
117
+
118
+        $data = array_intersect_key($data, array_flip([
119
+            'certificate',
120
+            'ip_address',
121
+            'max_connections',
122
+            'allowed_updates',
123
+            'drop_pending_updates',
124
+        ]));
125
+        $data['url'] = $url;
126
+
127
+        $result = Request::setWebhook($data);
128
+
129
+        if (!$result->isOk()) {
130
+            throw new TelegramException(
131
+                'Webhook was not set! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
132
+            );
133
+        }
134
+
135
+        return $result;
136
+    }
137
+
138
+    /**
139
+     * Delete any assigned webhook
140
+     *
141
+     * @param array $data
142
+     * @return Response
143
+     * @throws TelegramException
144
+     */
145
+    public function deleteWebhook(array $data = []): Response
146
+    {
147
+        $result = Request::deleteWebhook($data);
148
+
149
+        if (!$result->isOk()) {
150
+            throw new TelegramException(
151
+                'Webhook was not deleted! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
152
+            );
153
+        }
154
+
155
+        return $result;
156
+    }
157
+
158
+    /**
159
+     * This method sets the admin username. and will be used to send you a message if the bot is not working.
160
+     *
161
+     * @param int $chat_id
162
+     * @return void
163
+     */
164
+    public function setAdmin(int $chat_id): void
165
+    {
166
+        defined('TG_ADMIN_ID') or define('TG_ADMIN_ID', $chat_id);
167
+    }
168
+
169
+    /**
170
+     * Get input from stdin and return it
171
+     *
172
+     * @return ?string
173
+     */
174
+    public static function getInput(): ?string
175
+    {
176
+        return file_get_contents('php://input') ?? null;
177
+    }
178
+
179
+    /**
180
+     * This method will convert a string to an update object
181
+     *
182
+     * @param string $input The input string
183
+     * @param string $apiKey The API key
184
+     * @return Update|false
185
+     */
186
+    public static function processUpdate(string $input, string $apiKey): Update|false
187
+    {
188
+        if (empty($input)) {
189
+            throw new TelegramException(
190
+                'Input is empty! Please check your code and try again.'
191
+            );
192
+        }
193
+
194
+        if (!self::validateToken($apiKey)) {
195
+            throw new TelegramException(
196
+                'Invalid token! Please check your code and try again.'
197
+            );
198
+        }
199
+
200
+        if (self::validateWebData($apiKey, $input)) {
201
+            if (Common::isUrlEncode($input)) {
202
+                $web_data = Common::urlDecode($input);
203
+            }
204
+
205
+            if (Common::isJson($input)) {
206
+                $web_data = json_decode($input, true);
207
+            }
208
+
209
+            $input = json_encode([
210
+                'web_data' => $web_data,
211
+            ]);
212
+        }
213
+
214
+        if (!Common::isJson($input)) {
215
+            throw new TelegramException(
216
+                'Input is not a valid JSON string! Please check your code and try again.'
217
+            );
218
+        }
219
+
220
+        $input = json_decode($input, true);
221
+
222
+        return new Update($input);
223
+    }
224
+
225
+    /**
226
+     * Validate webapp data from is from Telegram
227
+     *
228
+     * @link https://core.telegram.org/bots/webapps#validating-data-received-via-the-web-app
229
+     *
230
+     * @param string $token The bot token
231
+     * @param string $body The message body from getInput()
232
+     * @return bool
233
+     */
234
+    public static function validateWebData(string $token, string $body): bool
235
+    {
236
+        if (!Common::isJson($body)) {
237
+            $raw_data = rawurldecode(str_replace('_auth=', '', $body));
238
+            $data = Common::urlDecode($raw_data);
239
+
240
+            if (empty($data['user'])) {
241
+                return false;
242
+            }
243
+
244
+            $data['user'] = urldecode($data['user']);
245
+
246
+        } else {
247
+            $data = json_decode($body, true);
248
+
249
+            if (empty($data['user'])) {
250
+                return false;
251
+            }
252
+
253
+            $data['user'] = json_encode($data['user']);
254
+        }
255
+
256
+        $data_check_string = "auth_date={$data['auth_date']}\nquery_id={$data['query_id']}\nuser={$data['user']}";
257
+        $secret_key = hash_hmac('sha256', $token, "WebAppData", true);
258
+
259
+        return hash_hmac('sha256', $data_check_string, $secret_key) == $data['hash'];
260
+    }
261
+
262
+    /**
263
+     * Get the update from input
264
+     *
265
+     * @return Update|false
266
+     */
267
+    public static function getUpdate(): Update|false
268
+    {
269
+        $input = self::getInput();
270
+        if (empty($input)) return false;
271
+        return Telegram::processUpdate($input, self::getApiKey());
272
+    }
273
+
274
+    /**
275
+     * Validate the token
276
+     *
277
+     * @param string $token (e.g. 123456789:ABC-DEF1234ghIkl-zyx57W2v1u123ew11) {digit}:{alphanumeric[34]}
278
+     * @return bool
279
+     */
280
+    public static function validateToken(string $token): bool
281
+    {
282
+        preg_match_all('/([0-9]+:[a-zA-Z0-9-_]+)/', $token, $matches);
283
+        return count($matches[0]) == 1;
284
+    }
285
+
286
+    /**
287
+     * Pass the update to the given webhook handler
288
+     *
289
+     * @param WebhookHandler $webhook_handler The webhook handler
290
+     * @param ?Update $update By default, it will get the update from input
291
+     * @return void
292
+     */
293
+    public function fetchWith(WebhookHandler $webhook_handler, ?Update $update = null): void
294
+    {
295
+        if (is_subclass_of($webhook_handler, WebhookHandler::class)) {
296
+            if ($update === null) $update = self::getUpdate();
297
+            $webhook_handler->resolve($update);
298
+        }
299
+    }
300
+
301
+    /**
302
+     * Get token from env file.
303
+     *
304
+     * @param string $file
305
+     * @return ?string
306
+     */
307
+    protected function getTokenFromEnvFile(string $file): ?string
308
+    {
309
+        if (!file_exists($file)) return null;
310
+        return DotEnv::load($file)::get('TELEGRAM_API_KEY');
311
+    }
312
+
313
+    /**
314
+     * Debug mode
315
+     *
316
+     * @param ?int $admin_id Fill this or use setAdmin()
317
+     * @return void
318
+     */
319
+    public static function setDebugMode(?int $admin_id = null): void
320
+    {
321
+        error_reporting(E_ALL);
322
+        ini_set('display_errors', 1);
323
+
324
+        defined('DEBUG_MODE') or define('DEBUG_MODE', true);
325
+        if ($admin_id) {
326
+            defined('TG_ADMIN_ID') or define('TG_ADMIN_ID', $admin_id);
327
+        }
328
+
329
+        set_exception_handler(function ($exception) {
330
+
331
+            if (defined('DEBUG_MODE') && DEBUG_MODE) {
332
+
333
+                TelegramLog::error(($message = sprintf(
334
+                    "%s(%d): %s\n%s",
335
+                    $exception->getFile(),
336
+                    $exception->getLine(),
337
+                    $exception->getMessage(),
338
+                    $exception->getTraceAsString()
339
+                )));
340
+
341
+                echo '<b>TelegramError:</b> ' . $message;
342
+
343
+                if (defined('TG_ADMIN_ID') && TG_ADMIN_ID) {
344
+                    $input = getenv('TG_CURRENT_UPDATE') ?? self::getInput();
345
+                    $update = self::processUpdate($input, self::getApiKey());
346
+
347
+                    file_put_contents(
348
+                        ($file = getcwd() . '/' . uniqid('error_') . '.log'),
349
+                        $message . PHP_EOL . PHP_EOL . $update->getRawData(false)
350
+                    );
351
+
352
+                    Request::sendMessage([
353
+                        'chat_id' => TG_ADMIN_ID,
354
+                        'text' => $message,
355
+                    ]);
356
+
357
+                    Request::sendDocument([
358
+                        'chat_id' => TG_ADMIN_ID,
359
+                        'document' => $file,
360
+                    ]);
361
+
362
+                    unlink($file);
363
+                }
364
+
365
+            } else {
366
+                throw $exception;
367
+            }
368
+
369
+        });
370
+    }
371
+
372
+    /**
373
+     * Just another echo
374
+     *
375
+     * @param string $text
376
+     * @return void
377
+     */
378
+    public static function echo(string $text): void
379
+    {
380
+        echo $text;
381
+    }
382 382
 
383 383
 }
384 384
\ No newline at end of file
Please login to merge, or discard this patch.