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, ]; } }