Skip to content

Commit 987b6ed

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

File tree

4 files changed

+206
-24
lines changed

4 files changed

+206
-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: 171 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,170 @@ 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+
497+
public function testSendPhotoByUrlWithOptions()
498+
{
499+
$response = $this->createMock(ResponseInterface::class);
500+
$response->expects($this->exactly(2))
501+
->method('getStatusCode')
502+
->willReturn(200);
503+
504+
$content = <<<JSON
505+
{
506+
"ok": true,
507+
"result": {
508+
"message_id": 1,
509+
"from": {
510+
"id": 12345678,
511+
"is_bot": true,
512+
"first_name": "YourBot",
513+
"username": "YourBot"
514+
},
515+
"chat": {
516+
"id": 1234567890,
517+
"first_name": "John",
518+
"last_name": "Doe",
519+
"username": "JohnDoe",
520+
"type": "private"
521+
},
522+
"date": 1459958199,
523+
"photo": [
524+
{
525+
"file_id": "ABCDEF",
526+
"file_unique_id" : "ABCDEF1",
527+
"file_size": 1378,
528+
"width": 90,
529+
"height": 51
530+
},
531+
{
532+
"file_id": "ABCDEF",
533+
"file_unique_id" : "ABCDEF2",
534+
"file_size": 19987,
535+
"width": 320,
536+
"height": 180
537+
}
538+
],
539+
"caption": "Hello from Bot!"
540+
}
541+
}
542+
JSON;
543+
544+
$response->expects($this->once())
545+
->method('getContent')
546+
->willReturn($content)
547+
;
548+
549+
$expectedBody = [
550+
'photo' => 'https://image.ur.l/',
551+
'has_spoiler' => true,
552+
'chat_id' => 'testChannel',
553+
'parse_mode' => 'MarkdownV2',
554+
'caption' => 'testMessage',
555+
];
556+
557+
$client = new MockHttpClient(function (string $method, string $url, array $options = []) use ($response, $expectedBody): ResponseInterface {
558+
$this->assertStringEndsWith('/sendPhoto', $url);
559+
$this->assertSame($expectedBody, json_decode($options['body'], true));
560+
561+
return $response;
562+
});
563+
564+
$transport = self::createTransport($client, 'testChannel');
565+
566+
$messageOptions = new TelegramOptions();
567+
$messageOptions
568+
->photo('https://image.ur.l/')
569+
->hasSpoiler(true)
570+
;
571+
572+
$sentMessage = $transport->send(new ChatMessage('testMessage', $messageOptions));
573+
574+
$this->assertEquals(1, $sentMessage->getMessageId());
575+
$this->assertEquals('telegram://api.telegram.org?channel=testChannel', $sentMessage->getTransport());
576+
}
577+
578+
public function testSendPhotoByUploadWithOptions()
416579
{
417580
$response = $this->createMock(ResponseInterface::class);
418581
$response->expects($this->exactly(2))
@@ -470,11 +633,6 @@ public function testSendLocalPhotoWithOptions()
470633

471634
$this->assertSame('Content-Length: 576', $options['normalized_headers']['content-length'][0]);
472635
$expectedBody = <<<BODY
473-
--{$matches['boundary']}
474-
Content-Disposition: form-data; name="photo"; filename="fixtures.png"
475-
Content-Type: image/png
476-
477-
%s
478636
--{$matches['boundary']}
479637
Content-Disposition: form-data; name="has_spoiler"
480638
@@ -488,6 +646,11 @@ public function testSendLocalPhotoWithOptions()
488646
489647
MarkdownV2
490648
--{$matches['boundary']}
649+
Content-Disposition: form-data; name="photo"; filename="fixtures.png"
650+
Content-Type: image/png
651+
652+
%s
653+
--{$matches['boundary']}
491654
Content-Disposition: form-data; name="caption"
492655
493656
testMessage
@@ -510,7 +673,7 @@ public function testSendLocalPhotoWithOptions()
510673

511674
$messageOptions = new TelegramOptions();
512675
$messageOptions
513-
->photo(__DIR__.'/fixtures.png')
676+
->uploadPhoto(__DIR__.'/fixtures.png')
514677
->hasSpoiler(true)
515678
;
516679

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