116 lines
3.7 KiB
PHP
116 lines
3.7 KiB
PHP
<?php
|
||
// /sms/wa_client.php
|
||
declare(strict_types=1);
|
||
|
||
namespace Sms;
|
||
|
||
final class WaClient
|
||
{
|
||
private string $phoneId;
|
||
private string $token;
|
||
private int $timeout;
|
||
|
||
public function __construct(array $cfg)
|
||
{
|
||
$this->phoneId = $cfg['phone_number_id'] ?? '';
|
||
$this->token = $cfg['access_token'] ?? '';
|
||
$this->timeout = (int)($cfg['timeout'] ?? 20);
|
||
|
||
if ($this->phoneId === '' || $this->token === '') {
|
||
throw new \RuntimeException('Config WhatsApp incomplète: phone_number_id / access_token manquants.');
|
||
}
|
||
}
|
||
|
||
/** Normalise en format international chiffres-only (WhatsApp: pas de "+") */
|
||
public static function normalizePhone(string $raw): string
|
||
{
|
||
$n = preg_replace('/\D+/', '', $raw ?? '');
|
||
// Ex: numéro FR commençant par 0 -> remplace 0 initial par 33
|
||
if (preg_match('/^0\d{9}$/', $n)) {
|
||
$n = '33' . substr($n, 1);
|
||
}
|
||
return $n;
|
||
}
|
||
|
||
/**
|
||
* Envoi d’un template Utility.
|
||
* $templateName: ex. 'notification_rdv'
|
||
* $lang: 'ru' (ou celui déclaré/validé chez Meta)
|
||
* $to: numéro destinataire (06..., +33..., 336..., etc.)
|
||
* $bodyParams: tableau des valeurs pour {{1}}, {{2}}, ...
|
||
*/
|
||
public function sendTemplate(string $templateName, string $lang, string $to, array $bodyParams, ?array $buttonUrlParams = null): array
|
||
{
|
||
$toNorm = self::normalizePhone($to);
|
||
if ($toNorm === '' || strlen($toNorm) < 8) {
|
||
throw new \InvalidArgumentException('Numéro destinataire invalide.');
|
||
}
|
||
|
||
// BODY params
|
||
$components = [[
|
||
'type' => 'body',
|
||
'parameters' => array_map(fn($t) => ['type'=>'text','text'=>(string)$t], $bodyParams)
|
||
]];
|
||
|
||
// BUTTON URL params (facultatif)
|
||
// $buttonUrlParams attendu sous la forme: ['0' => ['123']] // index "0" => [ valeurs pour {{1}}, {{2}} si existait ]
|
||
if ($buttonUrlParams) {
|
||
foreach ($buttonUrlParams as $index => $values) {
|
||
$params = array_map(fn($t) => ['type'=>'text','text'=>(string)$t], (array)$values);
|
||
$components[] = [
|
||
'type' => 'button',
|
||
'sub_type' => 'url',
|
||
'index' => (string)$index,
|
||
'parameters' => $params,
|
||
];
|
||
}
|
||
}
|
||
|
||
$payload = [
|
||
'messaging_product' => 'whatsapp',
|
||
'to' => $toNorm,
|
||
'type' => 'template',
|
||
'template' => [
|
||
'name' => $templateName,
|
||
'language' => ['code' => $lang],
|
||
'components' => $components,
|
||
]
|
||
];
|
||
|
||
$json = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||
|
||
$ch = curl_init("https://graph.facebook.com/v23.0/{$this->phoneId}/messages");
|
||
curl_setopt_array($ch, [
|
||
CURLOPT_HTTPHEADER => [
|
||
"Authorization: Bearer {$this->token}",
|
||
"Content-Type: application/json",
|
||
"Accept: application/json",
|
||
"Expect:",
|
||
"Connection: close",
|
||
],
|
||
CURLOPT_POST => true,
|
||
CURLOPT_POSTFIELDS => $json,
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_TIMEOUT => $this->timeout,
|
||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
||
CURLOPT_SSL_VERIFYPEER => true,
|
||
CURLOPT_SSL_VERIFYHOST => 2,
|
||
]);
|
||
|
||
$resp = curl_exec($ch);
|
||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
$err = curl_error($ch);
|
||
curl_close($ch);
|
||
|
||
$data = json_decode($resp ?? '', true);
|
||
|
||
return [
|
||
'http_code' => $code,
|
||
'error' => $err ?: null,
|
||
'response' => $data ?? $resp,
|
||
'payload' => $payload,
|
||
];
|
||
}
|
||
|
||
}
|