'sha256=' . hash_hmac('sha256', $body, $sec); $valida = function (string $header, string $body, string $sec): bool { if ($sec === '' || ! str_starts_with($header, 'sha256=')) return false; return hash_equals(hash_hmac('sha256', $body, $sec), substr($header, 7)); }; assert($valida($firmar($payload, $secret), $payload, $secret) === true, 'firma correcta debe pasar'); assert($valida($firmar($payload, $secret), $payload . ' ', $secret) === false, 'cuerpo alterado debe fallar'); assert($valida($firmar($payload, 'otro'), $payload, $secret) === false, 'secreto distinto debe fallar'); assert($valida($firmar($payload, $secret), $payload, '') === false, 'sin secreto debe fallar cerrado'); assert($valida('', $payload, $secret) === false, 'sin cabecera debe fallar'); assert($valida(hash_hmac('sha256', $payload, $secret), $payload, $secret) === false, 'sin prefijo sha256= debe fallar'); // ── Teclado numerado: mismo mapeo que TelegramBotService::numerarTeclado() ── $numerar = function (array $teclado): array { $mapa = []; $lineas = []; $n = 1; foreach ($teclado as $fila) { foreach ($fila as $boton) { if (! isset($boton['callback_data'])) continue; $mapa[(string) $n] = $boton['callback_data']; $lineas[] = "{$n}. {$boton['text']}"; $n++; } } return [$mapa, $lineas]; }; [$mapa, $lineas] = $numerar([ [['text' => 'Ver Servicios', 'callback_data' => 'svc_list'], ['text' => 'Promociones', 'callback_data' => 'promo_list']], [['text' => 'Recargar', 'callback_data' => 'rec_init']], ]); assert($lineas === ['1. Ver Servicios', '2. Promociones', '3. Recargar'], 'numeración corrida por filas'); assert($mapa['2'] === 'promo_list', 'el número devuelve el callback correcto'); assert($mapa['3'] === 'rec_init', 'la segunda fila sigue la numeración'); assert(count($mapa) === 3, 'un número por botón'); assert(! isset($mapa['4']), 'no inventa opciones'); [$vacio, $sinLineas] = $numerar([[['text' => 'sin accion']]]); assert($vacio === [] && $sinLineas === [], 'botones sin callback_data se ignoran'); echo "OK: 6 casos de firma + 6 de teclado numerado\n";