Skip to content

Commit 1cab6e3

Browse files
committed
[domain] outgoing MMS support
1 parent 331e12d commit 1cab6e3

8 files changed

Lines changed: 358 additions & 12 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
## [Unreleased]
6+
7+
### New Features
8+
9+
#### MMS
10+
11+
- **Outgoing MMS support** — send MMS messages with an optional subject, text body, and base64-encoded attachments. Pass an `MmsMessage` instead of text to `Message` or `MessageBuilder`; subject, text, and attachment content are encrypted when using `Encryptor`.
12+
```php
13+
$mms = new MmsMessage('Subject', 'Text', [
14+
new MmsAttachment('image/png', base64_encode($data), 'picture.png'),
15+
]);
16+
17+
$state = $client->SendMessage(new Message($mms, ['+15550100']));
18+
```

‎README.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ A modern PHP client for the [SMSGate](https://sms-gate.app) API: send SMS messag
1111

1212
## 📖 About
1313

14-
`capcom6/android-sms-gateway` is a type-safe PHP library for the SMSGate 3rd-party API. It covers messages (send, state, listing, cancellation), inbox refresh with attachment download, devices, webhooks, settings, logs, health checks, and the JWT token lifecycle, with a fluent `MessageBuilder` for message construction and an optional `Encryptor` for end-to-end encryption. Works with any PSR-18 HTTP client (Guzzle, curl, or others) and PHP 7.4+.
14+
`capcom6/android-sms-gateway` is a type-safe PHP library for the SMSGate 3rd-party API. It covers SMS and MMS messages (send, state, listing, cancellation), inbox refresh with attachment download, devices, webhooks, settings, logs, health checks, and the JWT token lifecycle, with a fluent `MessageBuilder` for message construction and an optional `Encryptor` for end-to-end encryption. Works with any PSR-18 HTTP client (Guzzle, curl, or others) and PHP 7.4+.
1515

1616
## 📚 Table of Contents
1717

@@ -32,6 +32,8 @@ A modern PHP client for the [SMSGate](https://sms-gate.app) API: send SMS messag
3232
## ⭐ Features
3333

3434
- Fluent `MessageBuilder` for messages and `SettingsBuilder` for settings
35+
- SMS messages with delivery reports, priority, TTL, and message cancellation
36+
- Outgoing MMS messages with subject, text, and attachments
3537
- PSR-18 HTTP client and PSR-17 factories, auto-discovered
3638
- Basic and JWT authentication with token generation and revocation
3739
- Webhooks, devices, settings, logs, and health checks

‎src/Domain/Message.php‎

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,18 @@ class Message implements SerializableInterface {
1313
* Message ID, will be generated automatically if not set
1414
*/
1515
private ?string $id;
16+
1617
/**
1718
* Message text
1819
* Long message will be divided into parts
1920
*/
2021
private string $message;
22+
/**
23+
* MMS message content (mutually exclusive with text/data messages)
24+
* @var MmsMessage|null
25+
*/
26+
private ?MmsMessage $mmsMessage;
27+
2128
/**
2229
* Time to live in seconds
2330
* If message is not received by device in this time, it will be failed
@@ -50,10 +57,11 @@ class Message implements SerializableInterface {
5057
private ?string $validUntil;
5158

5259
/**
60+
* @param string|MmsMessage $message
5361
* @param array<string> $phoneNumbers
5462
*/
5563
public function __construct(
56-
string $message,
64+
$message,
5765
array $phoneNumbers,
5866
?string $id = null,
5967
?int $ttl = null,
@@ -67,14 +75,30 @@ public function __construct(
6775
}
6876

6977
$this->id = $id;
70-
$this->message = $message;
7178
$this->ttl = $ttl;
7279
$this->simNumber = $simNumber;
7380
$this->withDeliveryReport = $withDeliveryReport;
7481
$this->phoneNumbers = $phoneNumbers;
7582
$this->isEncrypted = false;
7683
$this->priority = $priority;
7784
$this->validUntil = $validUntil;
85+
86+
if ($message instanceof MmsMessage) {
87+
$this->mmsMessage = $message;
88+
$this->message = '';
89+
} else {
90+
$this->message = $message;
91+
$this->mmsMessage = null;
92+
}
93+
}
94+
95+
96+
/**
97+
* Get MMS message content (null if not set)
98+
* @return MmsMessage|null
99+
*/
100+
public function MmsMessage(): ?MmsMessage {
101+
return $this->mmsMessage;
78102
}
79103

80104
public function Encrypt(Encryptor $encryptor): self {
@@ -88,19 +112,46 @@ public function Encrypt(Encryptor $encryptor): self {
88112
fn(string $phoneNumber) => $encryptor->Encrypt($phoneNumber),
89113
$this->phoneNumbers
90114
);
115+
116+
if ($this->mmsMessage !== null) {
117+
$this->mmsMessage = new MmsMessage(
118+
$this->mmsMessage->Subject() !== null
119+
? $encryptor->Encrypt($this->mmsMessage->Subject())
120+
: null,
121+
$this->mmsMessage->Text() !== null
122+
? $encryptor->Encrypt($this->mmsMessage->Text())
123+
: null,
124+
array_map(
125+
fn(MmsAttachment $attachment) => new MmsAttachment(
126+
$attachment->ContentType(),
127+
$encryptor->Encrypt($attachment->Data()),
128+
$attachment->Name() !== null
129+
? $encryptor->Encrypt($attachment->Name())
130+
: null
131+
),
132+
$this->mmsMessage->Attachments()
133+
)
134+
);
135+
}
136+
91137
return $this;
92138
}
93139

94140
public function ToObject(): object {
95141
$obj = (object) [
96142
'id' => $this->id,
97-
'message' => $this->message,
98143
'simNumber' => $this->simNumber,
99144
'withDeliveryReport' => $this->withDeliveryReport,
100145
'isEncrypted' => $this->isEncrypted,
101146
'phoneNumbers' => $this->phoneNumbers,
102147
];
103148

149+
if ($this->mmsMessage !== null) {
150+
$obj->mmsMessage = $this->mmsMessage->ToObject();
151+
} else {
152+
$obj->message = $this->message;
153+
}
154+
104155
if ($this->priority !== null) {
105156
$obj->priority = $this->priority;
106157
}

‎src/Domain/MessageBuilder.php‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ class MessageBuilder {
1414
private ?string $id = null;
1515

1616
/**
17-
* @var string
17+
* @var string|MmsMessage
1818
*/
19-
private string $message;
19+
private $message;
2020

2121
/**
2222
* @var int|null
@@ -50,10 +50,10 @@ class MessageBuilder {
5050
private ?string $validUntil = null;
5151

5252
/**
53-
* @param string $message
53+
* @param string|MmsMessage $message
5454
* @param array<string> $phoneNumbers
5555
*/
56-
public function __construct(string $message, array $phoneNumbers) {
56+
public function __construct($message, array $phoneNumbers) {
5757
$this->message = $message;
5858
$this->phoneNumbers = $phoneNumbers;
5959
}
@@ -72,10 +72,10 @@ public function setId(?string $id): self {
7272
/**
7373
* Set message text
7474
*
75-
* @param string $message
75+
* @param string|MmsMessage $message
7676
* @return $this
7777
*/
78-
public function setMessage(string $message): self {
78+
public function setMessage($message): self {
7979
$this->message = $message;
8080
return $this;
8181
}

‎src/Domain/MmsAttachment.php‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
namespace AndroidSmsGateway\Domain;
4+
5+
/**
6+
* A single attachment of an MMS message.
7+
*/
8+
final class MmsAttachment {
9+
/**
10+
* MIME type of the attachment (e.g. image/png)
11+
* @var string
12+
*/
13+
private string $contentType;
14+
15+
/**
16+
* Base64-encoded attachment content
17+
* @var string
18+
*/
19+
private string $data;
20+
21+
/**
22+
* Optional file name of the attachment
23+
* @var string|null
24+
*/
25+
private ?string $name;
26+
27+
/**
28+
* @param string $contentType MIME type of the attachment (e.g. image/png)
29+
* @param string $data Base64-encoded attachment content
30+
* @param string|null $name Optional file name of the attachment
31+
*/
32+
public function __construct(string $contentType, string $data, ?string $name = null) {
33+
$this->contentType = $contentType;
34+
$this->data = $data;
35+
$this->name = $name;
36+
}
37+
38+
public function ContentType(): string {
39+
return $this->contentType;
40+
}
41+
42+
public function Data(): string {
43+
return $this->data;
44+
}
45+
46+
public function Name(): ?string {
47+
return $this->name;
48+
}
49+
50+
public function ToObject(): \stdClass {
51+
$obj = (object) [
52+
'contentType' => $this->contentType,
53+
'name' => $this->name,
54+
'data' => $this->data,
55+
];
56+
57+
if ($this->name === null) {
58+
unset($obj->name);
59+
}
60+
61+
return $obj;
62+
}
63+
}

‎src/Domain/MmsMessage.php‎

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
namespace AndroidSmsGateway\Domain;
4+
5+
/**
6+
* An MMS message with optional subject, text and attachments.
7+
*/
8+
final class MmsMessage {
9+
/**
10+
* Optional subject of the MMS
11+
* @var string|null
12+
*/
13+
private ?string $subject;
14+
15+
/**
16+
* Optional text body of the MMS
17+
* @var string|null
18+
*/
19+
private ?string $text;
20+
21+
/**
22+
* List of attachments. Omitted entirely from the wire when empty.
23+
* @var array<MmsAttachment>
24+
*/
25+
private array $attachments;
26+
27+
/**
28+
* @param string|null $subject Optional subject of the MMS
29+
* @param string|null $text Optional text body of the MMS
30+
* @param array<MmsAttachment> $attachments List of attachments
31+
*/
32+
public function __construct(?string $subject = null, ?string $text = null, array $attachments = []) {
33+
$this->subject = $subject;
34+
$this->text = $text;
35+
$this->attachments = $attachments;
36+
}
37+
38+
public function Subject(): ?string {
39+
return $this->subject;
40+
}
41+
42+
public function Text(): ?string {
43+
return $this->text;
44+
}
45+
46+
/**
47+
* @return array<MmsAttachment>
48+
*/
49+
public function Attachments(): array {
50+
return $this->attachments;
51+
}
52+
53+
public function ToObject(): \stdClass {
54+
$obj = (object) [
55+
'subject' => $this->subject,
56+
'text' => $this->text,
57+
'attachments' => array_map(
58+
static fn(MmsAttachment $attachment) => $attachment->ToObject(),
59+
$this->attachments
60+
),
61+
];
62+
63+
if ($this->subject === null) {
64+
unset($obj->subject);
65+
}
66+
67+
if ($this->text === null) {
68+
unset($obj->text);
69+
}
70+
71+
if (count($this->attachments) === 0) {
72+
unset($obj->attachments);
73+
}
74+
75+
return $obj;
76+
}
77+
}

‎tests/ClientTest.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public function testServer(): void {
113113
);
114114
$client = new Client($login, $password, Client::DEFAULT_URL, $curlClient);
115115

116-
$message = new Message(date('Y-m-d H:i:s'), [$phoneNumber]);
116+
$message = new Message('Test message from `client-php`' . PHP_EOL . date('Y-m-d H:i:s'), [$phoneNumber]);
117117

118118
$messageState = $client->SendMessage($message);
119119
$this->assertInstanceOf(MessageState::class, $messageState);

0 commit comments

Comments
 (0)