1212
1313use GuzzleHttp \Client ;
1414use GuzzleHttp \Exception \RequestException ;
15+ use GuzzleHttp \Psr7 \Stream ;
1516use Longman \TelegramBot \Entities \File ;
17+ use Longman \TelegramBot \Entities \InputMedia \InputMedia ;
1618use Longman \TelegramBot \Entities \ServerResponse ;
1719use Longman \TelegramBot \Exception \InvalidBotTokenException ;
1820use Longman \TelegramBot \Exception \TelegramException ;
@@ -126,6 +128,13 @@ class Request
126128 */
127129 private static $ limiter_interval ;
128130
131+ /**
132+ * Get the current action that is being executed
133+ *
134+ * @var string
135+ */
136+ private static $ current_action ;
137+
129138 /**
130139 * Available actions to send
131140 *
@@ -213,6 +222,30 @@ class Request
213222 'getMe ' ,
214223 ];
215224
225+ /**
226+ * Available fields for InputFile helper
227+ *
228+ * This is basically the list of all fields that allow InputFile objects
229+ * for which input can be simplified by providing local path directly as string.
230+ *
231+ * @var array
232+ */
233+ private static $ input_file_fields = [
234+ 'setWebhook ' => ['certificate ' ],
235+ 'sendPhoto ' => ['photo ' ],
236+ 'sendAudio ' => ['audio ' , 'thumb ' ],
237+ 'sendDocument ' => ['document ' , 'thumb ' ],
238+ 'sendVideo ' => ['video ' , 'thumb ' ],
239+ 'sendAnimation ' => ['animation ' , 'thumb ' ],
240+ 'sendVoice ' => ['voice ' , 'thumb ' ],
241+ 'sendVideoNote ' => ['video_note ' , 'thumb ' ],
242+ 'setChatPhoto ' => ['photo ' ],
243+ 'sendSticker ' => ['sticker ' ],
244+ 'uploadStickerFile ' => ['png_sticker ' ],
245+ 'createNewStickerSet ' => ['png_sticker ' ],
246+ 'addStickerToSet ' => ['png_sticker ' ],
247+ ];
248+
216249 /**
217250 * Initialize
218251 *
@@ -318,29 +351,116 @@ public static function generateGeneralFakeServerResponse(array $data = [])
318351 * @param array $data
319352 *
320353 * @return array
354+ * @throws TelegramException
321355 */
322356 private static function setUpRequestParams (array $ data )
323357 {
324358 $ has_resource = false ;
325359 $ multipart = [];
326360
327- // Convert any nested arrays into JSON strings.
328- array_walk ($ data , function (&$ item ) {
329- is_array ($ item ) && $ item = json_encode ($ item );
330- });
361+ foreach ($ data as $ key => &$ item ) {
362+ if ($ key === 'media ' ) {
363+ // Magical media input helper.
364+ $ item = self ::mediaInputHelper ($ item , $ has_resource , $ multipart );
365+ } elseif (array_key_exists (self ::$ current_action , self ::$ input_file_fields ) && in_array ($ key , self ::$ input_file_fields [self ::$ current_action ], true )) {
366+ // Allow absolute paths to local files.
367+ if (is_string ($ item ) && file_exists ($ item )) {
368+ $ item = new Stream (self ::encodeFile ($ item ));
369+ }
370+ } elseif (is_array ($ item )) {
371+ // Convert any nested arrays into JSON strings.
372+ $ item = json_encode ($ item );
373+ }
331374
332- //Reformat data array in multipart way if it contains a resource
333- foreach ($ data as $ key => $ item ) {
334- $ has_resource |= (is_resource ($ item ) || $ item instanceof \GuzzleHttp \Psr7 \Stream);
375+ // Reformat data array in multipart way if it contains a resource
376+ $ has_resource |= (is_resource ($ item ) || $ item instanceof Stream);
335377 $ multipart [] = ['name ' => $ key , 'contents ' => $ item ];
336378 }
379+
337380 if ($ has_resource ) {
338381 return ['multipart ' => $ multipart ];
339382 }
340383
341384 return ['form_params ' => $ data ];
342385 }
343386
387+ /**
388+ * Magical input media helper to simplify passing media.
389+ *
390+ * This allows the following:
391+ * Request::editMessageMedia([
392+ * ...
393+ * 'media' => new InputMediaPhoto([
394+ * 'caption' => 'Caption!',
395+ * 'media' => Request::encodeFile($local_photo),
396+ * ]),
397+ * ]);
398+ * and
399+ * Request::sendMediaGroup([
400+ * 'media' => [
401+ * new InputMediaPhoto(['media' => Request::encodeFile($local_photo_1)]),
402+ * new InputMediaPhoto(['media' => Request::encodeFile($local_photo_2)]),
403+ * new InputMediaVideo(['media' => Request::encodeFile($local_video_1)]),
404+ * ],
405+ * ]);
406+ * and even
407+ * Request::sendMediaGroup([
408+ * 'media' => [
409+ * new InputMediaPhoto(['media' => $local_photo_1]),
410+ * new InputMediaPhoto(['media' => $local_photo_2]),
411+ * new InputMediaVideo(['media' => $local_video_1]),
412+ * ],
413+ * ]);
414+ *
415+ * @param mixed $item
416+ * @param bool $has_resource
417+ * @param array $multipart
418+ *
419+ * @return mixed
420+ */
421+ private static function mediaInputHelper ($ item , &$ has_resource , array &$ multipart )
422+ {
423+ $ was_array = is_array ($ item );
424+ $ was_array || $ item = [$ item ];
425+
426+ foreach ($ item as $ media_item ) {
427+ if (!($ media_item instanceof InputMedia)) {
428+ continue ;
429+ }
430+
431+ $ media = $ media_item ->getMedia ();
432+
433+ // Allow absolute paths to local files.
434+ if (is_string ($ media ) && file_exists ($ media )) {
435+ $ media = new Stream (self ::encodeFile ($ media ));
436+ }
437+
438+ if (is_resource ($ media ) || $ media instanceof Stream) {
439+ $ has_resource = true ;
440+ $ rnd_key = uniqid ('media_ ' , false );
441+ $ multipart [] = ['name ' => $ rnd_key , 'contents ' => $ media ];
442+
443+ // We're literally overwriting the passed media data!
444+ $ media_item ->media = 'attach:// ' . $ rnd_key ;
445+ $ media_item ->raw_data ['media ' ] = 'attach:// ' . $ rnd_key ;
446+ }
447+ }
448+
449+ $ was_array || $ item = reset ($ item );
450+
451+ return json_encode ($ item );
452+ }
453+
454+ /**
455+ * Get the current action that's being executed
456+ *
457+ * @return string
458+ */
459+ public static function getCurrentAction ()
460+ {
461+ return self ::$ current_action ;
462+ }
463+
344464 /**
345465 * Execute HTTP Request
346466 *
@@ -373,7 +493,7 @@ public static function execute($action, array $data = [])
373493 TelegramLog::update ($ result );
374494 }
375495 } catch (RequestException $ e ) {
376- $ result = ( $ e ->getResponse () ) ? (string ) $ e ->getResponse ()->getBody () : '' ;
496+ $ result = $ e ->getResponse () ? (string ) $ e ->getResponse ()->getBody () : '' ;
377497 } finally {
378498 //Logging verbose debug output
379499 TelegramLog::endDebugLogTempStream ('Verbose HTTP Request output: ' . PHP_EOL . '%s ' . PHP_EOL );
@@ -470,8 +590,11 @@ public static function send($action, array $data = [])
470590
471591 self ::limitTelegramRequests ($ action , $ data );
472592
593+ // Remember which action is currently being executed.
594+ self ::$ current_action = $ action ;
595+
473596 $ raw_response = self ::execute ($ action , $ data );
474- $ response = json_decode ($ raw_response , true );
597+ $ response = json_decode ($ raw_response , true );
475598
476599 if (null === $ response ) {
477600 TelegramLog::debug ($ raw_response );
@@ -484,6 +607,9 @@ public static function send($action, array $data = [])
484607 throw new InvalidBotTokenException ();
485608 }
486609
610+ // Reset current action after completion.
611+ self ::$ current_action = null ;
612+
487613 return $ response ;
488614 }
489615
0 commit comments