fix: compatibilidad PHP 7.4 — str_starts_with, str_contains, match, never, mixed

This commit is contained in:
Lizandro Guarnizo
2026-06-04 20:04:37 -05:00
parent 943e629120
commit 43f337ee34
5 changed files with 54 additions and 50 deletions
+18 -18
View File
@@ -332,26 +332,26 @@ HTML;
private static function typeLabel(string $field, string $type): string
{
if ($field === 'statuses') {
$cls = match ($type) {
'sent' => 'badge-blue',
'delivered' => 'badge-green',
'read' => 'badge-teal',
'failed' => 'badge-red',
default => 'badge-gray',
};
switch ($type) {
case 'sent': $cls = 'badge-blue'; break;
case 'delivered': $cls = 'badge-green'; break;
case 'read': $cls = 'badge-teal'; break;
case 'failed': $cls = 'badge-red'; break;
default: $cls = 'badge-gray'; break;
}
return '<span class="badge ' . $cls . '">' . self::h($type) . '</span>';
}
return match ($type) {
'text' => '💬 Texto',
'image' => '🖼️ Imagen',
'audio' => '🎵 Audio',
'video' => '🎥 Video',
'document' => '📄 Documento',
'location' => '📍 Ubicación',
'interactive' => '🔘 Interactivo',
'button' => '🔲 Botón',
default => self::h($type),
};
switch ($type) {
case 'text': return '&#128172; Texto';
case 'image': return '&#128247; Imagen';
case 'audio': return '&#127925; Audio';
case 'video': return '&#127916; Video';
case 'document': return '&#128196; Documento';
case 'location': return '&#128205; Ubicaci&oacute;n';
case 'interactive': return '&#128280; Interactivo';
case 'button': return '&#128306; Bot&oacute;n';
default: return self::h($type);
}
}
// ─── Render ───────────────────────────────────────────────────────────────
+29 -25
View File
@@ -92,11 +92,13 @@ class WpWebhook
$field = $change['field'] ?? '';
$value = $change['value'] ?? [];
match ($field) {
'messages', 'conversations' => self::handleMessages($value),
'statuses' => self::handleStatuses($value),
default => self::log('INFO', "Campo no manejado: $field"),
};
if ($field === 'messages' || $field === 'conversations') {
self::handleMessages($value);
} elseif ($field === 'statuses') {
self::handleStatuses($value);
} else {
self::log('INFO', "Campo no manejado: $field");
}
}
}
@@ -140,19 +142,19 @@ class WpWebhook
'display_phone' => $displayPhone,
];
match ($type) {
'text' => self::handleText($msg, $context),
'image' => self::handleMedia($msg, $context, 'image'),
'audio' => self::handleMedia($msg, $context, 'audio'),
'video' => self::handleMedia($msg, $context, 'video'),
'document' => self::handleMedia($msg, $context, 'document'),
'sticker' => self::handleMedia($msg, $context, 'sticker'),
'location' => self::handleLocation($msg, $context),
'interactive' => self::handleInteractive($msg, $context),
'button' => self::handleButton($msg, $context),
'reaction' => self::handleReaction($msg, $context),
default => self::log('INFO', "Tipo de mensaje no manejado: $type | from=$from"),
};
switch ($type) {
case 'text': self::handleText($msg, $context); break;
case 'image': self::handleMedia($msg, $context, 'image'); break;
case 'audio': self::handleMedia($msg, $context, 'audio'); break;
case 'video': self::handleMedia($msg, $context, 'video'); break;
case 'document': self::handleMedia($msg, $context, 'document'); break;
case 'sticker': self::handleMedia($msg, $context, 'sticker'); break;
case 'location': self::handleLocation($msg, $context); break;
case 'interactive': self::handleInteractive($msg, $context); break;
case 'button': self::handleButton($msg, $context); break;
case 'reaction': self::handleReaction($msg, $context); break;
default: self::log('INFO', "Tipo de mensaje no manejado: $type | from=$from"); break;
}
}
// Estados que pueden venir dentro del mismo field 'messages'
@@ -198,11 +200,13 @@ class WpWebhook
private static function handleInteractive(array $msg, array $ctx): void
{
$iType = $msg['interactive']['type'] ?? '';
$reply = match ($iType) {
'button_reply' => $msg['interactive']['button_reply'] ?? [],
'list_reply' => $msg['interactive']['list_reply'] ?? [],
default => [],
};
if ($iType === 'button_reply') {
$reply = $msg['interactive']['button_reply'] ?? [];
} elseif ($iType === 'list_reply') {
$reply = $msg['interactive']['list_reply'] ?? [];
} else {
$reply = [];
}
$preview = $iType . ': ' . json_encode($reply);
self::log('MSG', "[INTERACTIVE/$iType] {$ctx['from']} | reply=" . json_encode($reply));
self::saveWebhookLog('messages', $ctx['from'], $ctx['name'], 'interactive', $preview);
@@ -262,7 +266,7 @@ class WpWebhook
}
$sigHeader = $_SERVER['HTTP_X_HUB_SIGNATURE_256'] ?? '';
if (!str_starts_with($sigHeader, 'sha256=')) {
if (strpos($sigHeader, 'sha256=') !== 0) {
self::respond(401, ['error' => 'Firma ausente']);
}
@@ -366,7 +370,7 @@ class WpWebhook
}
}
private static function respond(int $code, array $body): never
private static function respond(int $code, array $body): void
{
http_response_code($code);
header('Content-Type: application/json; charset=utf-8');
+3 -3
View File
@@ -15,10 +15,10 @@ declare(strict_types=1);
foreach ($lines as $line) {
$line = trim($line);
// Ignorar comentarios
if ($line === '' || str_starts_with($line, '#')) {
if ($line === '' || strpos($line, '#') === 0) {
continue;
}
if (!str_contains($line, '=')) {
if (strpos($line, '=') === false) {
continue;
}
[$key, $value] = explode('=', $line, 2);
@@ -32,7 +32,7 @@ declare(strict_types=1);
}
})();
function env(string $key, mixed $default = null): mixed
function env(string $key, $default = null)
{
return $_ENV[$key] ?? getenv($key) ?: $default;
}
+2 -2
View File
@@ -5,13 +5,13 @@ $base = '';
if (file_exists(__DIR__ . '/.env')) {
foreach (file(__DIR__ . '/.env') as $line) {
$line = trim($line);
if (str_starts_with($line, 'APP_BASE=')) {
if (strpos($line, 'APP_BASE=') === 0) {
$base = rtrim(trim(explode('=', $line, 2)[1]), '/');
break;
}
}
}
if ($base !== '' && str_starts_with($_SERVER['REQUEST_URI'], $base)) {
if ($base !== '' && strpos($_SERVER['REQUEST_URI'], $base) === 0) {
$_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], strlen($base)) ?: '/';
}
require_once __DIR__ . '/public/index.php';
+2 -2
View File
@@ -19,7 +19,7 @@ class Auth
?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION']
?? '';
if (!str_starts_with($header, 'Bearer ')) {
if (strpos($header, 'Bearer ') !== 0) {
self::abort(401, 'Token de autorización requerido.');
}
@@ -78,7 +78,7 @@ class Auth
return base64_decode(strtr($data, '-_', '+/'));
}
private static function abort(int $code, string $message): never
private static function abort(int $code, string $message): void
{
http_response_code($code);
header('Content-Type: application/json; charset=utf-8');