Skip to content

Commit 4db96b7

Browse files
committed
Fix BC with sending photo in Telegram by file_id
1 parent f1ac295 commit 4db96b7

File tree

4 files changed

+205
-24
lines changed

4 files changed

+205
-24
lines changed

src/Symfony/Component/Notifier/Bridge/Telegram/README.md

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@ With a Telegram message, you can use the `TelegramOptions` class to add
5454
[message options](https://core.telegram.org/bots/api).
5555

5656
```php
57-
use Symfony\Component\Notifier\Bridge\Telegram\Reply\Markup\Button\InlineKeyboardButton;
58-
use Symfony\Component\Notifier\Bridge\Telegram\Reply\Markup\InlineKeyboardMarkup;
5957
use Symfony\Component\Notifier\Bridge\Telegram\TelegramOptions;
6058
use Symfony\Component\Notifier\Message\ChatMessage;
6159

@@ -76,15 +74,32 @@ $chatMessage->options($telegramOptions);
7674
$chatter->send($chatMessage);
7775
```
7876

77+
[Telegram supports 3 ways](https://core.telegram.org/bots/api#sending-files) for passing photo:
78+
79+
* Pass image HTTP URL to Telegram
80+
```
81+
$telegramOptions = (new TelegramOptions())
82+
->photo('https://symfony.com/favicons/android-chrome-192x192.png');
83+
```
84+
* Pass Telegram file_id
85+
```
86+
$telegramOptions = (new TelegramOptions())
87+
->photo('ABCDEF');
88+
```
89+
* Post the file using multipart/form-data
90+
```
91+
$telegramOptions = (new TelegramOptions())
92+
->uploadPhoto('files/android-chrome-192x192.png');
93+
```
94+
95+
7996
Adding Location to a Message
8097
----------------------------
8198

8299
With a Telegram message, you can use the `TelegramOptions` class to add
83100
[message options](https://core.telegram.org/bots/api).
84101

85102
```php
86-
use Symfony\Component\Notifier\Bridge\Telegram\Reply\Markup\Button\InlineKeyboardButton;
87-
use Symfony\Component\Notifier\Bridge\Telegram\Reply\Markup\InlineKeyboardMarkup;
88103
use Symfony\Component\Notifier\Bridge\Telegram\TelegramOptions;
89104
use Symfony\Component\Notifier\Message\ChatMessage;
90105

src/Symfony/Component/Notifier/Bridge/Telegram/TelegramOptions.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@ public function photo(string $url): static
112112
return $this;
113113
}
114114

115+
/**
116+
* @return $this
117+
*/
118+
public function uploadPhoto(string $path): static
119+
{
120+
$this->options['upload_photo'] = $path;
121+
122+
return $this;
123+
}
124+
115125
/**
116126
* @return $this
117127
*/

src/Symfony/Component/Notifier/Bridge/Telegram/TelegramTransport.php

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,15 @@ protected function doSend(MessageInterface $message): SentMessage
7777
$options['text'] = preg_replace('/([_*\[\]()~`>#+\-=|{}.!])/', '\\\\$1', $message->getSubject());
7878
}
7979

80+
if (isset($options['upload_photo'])) {
81+
$options['photo'] = fopen($options['upload_photo'], 'r');
82+
$optionsContainer = 'body';
83+
unset($options['upload_photo']);
84+
}
85+
8086
if (isset($options['photo'])) {
8187
$options['caption'] = $options['text'];
8288
unset($options['text']);
83-
if ($this->isPhotoPrivate($options['photo'])) {
84-
$options['photo'] = fopen($options['photo'], 'r');
85-
$optionsContainer = 'body';
86-
}
8789
}
8890

8991
$endpoint = sprintf('https://%s/bot%s/%s', $this->getEndpoint(), $this->token, $this->getPath($options));
@@ -133,12 +135,4 @@ private function getAction(array $options): string
133135
default => 'post',
134136
};
135137
}
136-
137-
private function isPhotoPrivate(string $photo): bool
138-
{
139-
return match (parse_url($photo, \PHP_URL_SCHEME)) {
140-
'http', 'https' => false,
141-
default => true,
142-
};
143-
}
144138
}

src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportTest.php

Lines changed: 170 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ public function testSendWithMarkdownShouldEscapeSpecialCharacters()
331331
$transport->send(new ChatMessage('I contain special characters _ * [ ] ( ) ~ ` > # + - = | { } . ! to send.'));
332332
}
333333

334-
public function testSendPhotoWithOptions()
334+
public function testSendPhotoByHttpUrlWithOptions()
335335
{
336336
$response = $this->createMock(ResponseInterface::class);
337337
$response->expects($this->exactly(2))
@@ -412,7 +412,169 @@ public function testSendPhotoWithOptions()
412412
$this->assertEquals('telegram://api.telegram.org?channel=testChannel', $sentMessage->getTransport());
413413
}
414414

415-
public function testSendLocalPhotoWithOptions()
415+
public function testSendPhotoByFileIdWithOptions()
416+
{
417+
$response = $this->createMock(ResponseInterface::class);
418+
$response->expects($this->exactly(2))
419+
->method('getStatusCode')
420+
->willReturn(200);
421+
422+
$content = <<<JSON
423+
{
424+
"ok": true,
425+
"result": {
426+
"message_id": 1,
427+
"from": {
428+
"id": 12345678,
429+
"is_bot": true,
430+
"first_name": "YourBot",
431+
"username": "YourBot"
432+
},
433+
"chat": {
434+
"id": 1234567890,
435+
"first_name": "John",
436+
"last_name": "Doe",
437+
"username": "JohnDoe",
438+
"type": "private"
439+
},
440+
"date": 1459958199,
441+
"photo": [
442+
{
443+
"file_id": "ABCDEF",
444+
"file_unique_id" : "ABCDEF1",
445+
"file_size": 1378,
446+
"width": 90,
447+
"height": 51
448+
},
449+
{
450+
"file_id": "ABCDEF",
451+
"file_unique_id" : "ABCDEF2",
452+
"file_size": 19987,
453+
"width": 320,
454+
"height": 180
455+
}
456+
],
457+
"caption": "Hello from Bot!"
458+
}
459+
}
460+
JSON;
461+
462+
$response->expects($this->once())
463+
->method('getContent')
464+
->willReturn($content)
465+
;
466+
467+
$expectedBody = [
468+
'photo' => 'ABCDEF',
469+
'has_spoiler' => true,
470+
'chat_id' => 'testChannel',
471+
'parse_mode' => 'MarkdownV2',
472+
'caption' => 'testMessage',
473+
];
474+
475+
$client = new MockHttpClient(function (string $method, string $url, array $options = []) use ($response, $expectedBody): ResponseInterface {
476+
$this->assertStringEndsWith('/sendPhoto', $url);
477+
$this->assertSame($expectedBody, json_decode($options['body'], true));
478+
479+
return $response;
480+
});
481+
482+
$transport = self::createTransport($client, 'testChannel');
483+
484+
$messageOptions = new TelegramOptions();
485+
$messageOptions
486+
->photo('ABCDEF')
487+
->hasSpoiler(true)
488+
;
489+
490+
$sentMessage = $transport->send(new ChatMessage('testMessage', $messageOptions));
491+
492+
$this->assertEquals(1, $sentMessage->getMessageId());
493+
$this->assertEquals('telegram://api.telegram.org?channel=testChannel', $sentMessage->getTransport());
494+
}
495+
496+
public function testSendPhotoByUrlWithOptions()
497+
{
498+
$response = $this->createMock(ResponseInterface::class);
499+
$response->expects($this->exactly(2))
500+
->method('getStatusCode')
501+
->willReturn(200);
502+
503+
$content = <<<JSON
504+
{
505+
"ok": true,
506+
"result": {
507+
"message_id": 1,
508+
"from": {
509+
"id": 12345678,
510+
"is_bot": true,
511+
"first_name": "YourBot",
512+
"username": "YourBot"
513+
},
514+
"chat": {
515+
"id": 1234567890,
516+
"first_name": "John",
517+
"last_name": "Doe",
518+
"username": "JohnDoe",
519+
"type": "private"
520+
},
521+
"date": 1459958199,
522+
"photo": [
523+
{
524+
"file_id": "ABCDEF",
525+
"file_unique_id" : "ABCDEF1",
526+
"file_size": 1378,
527+
"width": 90,
528+
"height": 51
529+
},
530+
{
531+
"file_id": "ABCDEF",
532+
"file_unique_id" : "ABCDEF2",
533+
"file_size": 19987,
534+
"width": 320,
535+
"height": 180
536+
}
537+
],
538+
"caption": "Hello from Bot!"
539+
}
540+
}
541+
JSON;
542+
543+
$response->expects($this->once())
544+
->method('getContent')
545+
->willReturn($content)
546+
;
547+
548+
$expectedBody = [
549+
'photo' => 'https://image.ur.l/',
550+
'has_spoiler' => true,
551+
'chat_id' => 'testChannel',
552+
'parse_mode' => 'MarkdownV2',
553+
'caption' => 'testMessage',
554+
];
555+
556+
$client = new MockHttpClient(function (string $method, string $url, array $options = []) use ($response, $expectedBody): ResponseInterface {
557+
$this->assertStringEndsWith('/sendPhoto', $url);
558+
$this->assertSame($expectedBody, json_decode($options['body'], true));
559+
560+
return $response;
561+
});
562+
563+
$transport = self::createTransport($client, 'testChannel');
564+
565+
$messageOptions = new TelegramOptions();
566+
$messageOptions
567+
->photo('https://image.ur.l/')
568+
->hasSpoiler(true)
569+
;
570+
571+
$sentMessage = $transport->send(new ChatMessage('testMessage', $messageOptions));
572+
573+
$this->assertEquals(1, $sentMessage->getMessageId());
574+
$this->assertEquals('telegram://api.telegram.org?channel=testChannel', $sentMessage->getTransport());
575+
}
576+
577+
public function testSendPhotoByUploadWithOptions()
416578
{
417579
$response = $this->createMock(ResponseInterface::class);
418580
$response->expects($this->exactly(2))
@@ -470,11 +632,6 @@ public function testSendLocalPhotoWithOptions()
470632

471633
$this->assertSame('Content-Length: 576', $options['normalized_headers']['content-length'][0]);
472634
$expectedBody = <<<BODY
473-
--{$matches['boundary']}
474-
Content-Disposition: form-data; name="photo"; filename="fixtures.png"
475-
Content-Type: image/png
476-
477-
%s
478635
--{$matches['boundary']}
479636
Content-Disposition: form-data; name="has_spoiler"
480637
@@ -488,6 +645,11 @@ public function testSendLocalPhotoWithOptions()
488645
489646
MarkdownV2
490647
--{$matches['boundary']}
648+
Content-Disposition: form-data; name="photo"; filename="fixtures.png"
649+
Content-Type: image/png
650+
651+
%s
652+
--{$matches['boundary']}
491653
Content-Disposition: form-data; name="caption"
492654
493655
testMessage
@@ -510,7 +672,7 @@ public function testSendLocalPhotoWithOptions()
510672

511673
$messageOptions = new TelegramOptions();
512674
$messageOptions
513-
->photo(__DIR__.'/fixtures.png')
675+
->uploadPhoto(__DIR__.'/fixtures.png')
514676
->hasSpoiler(true)
515677
;
516678

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy