This commit is contained in:
Lizandro Guarnizo
2026-01-21 23:55:49 -05:00
parent a70b8f36b5
commit ee016d62f5
5 changed files with 200 additions and 2 deletions
+4
View File
@@ -0,0 +1,4 @@
<?php
if (php_sapi_name() !== 'cli') header('Content-Type: application/json; charset=utf-8');
if (function_exists('writeLog')) writeLog('DEBUG','Health check called', ['uri' => $_SERVER['REQUEST_URI'] ?? '']);
echo json_encode(['ok'=>true,'uri'=>$_SERVER['REQUEST_URI'] ?? '']);
+26 -2
View File
@@ -1,8 +1,32 @@
<?php
file_put_contents(sys_get_temp_dir() . '/delete_template_entry.log', date('c') . " request=" . ($_SERVER['REQUEST_URI'] ?? 'cli') . "\n", FILE_APPEND);
require_once __DIR__ . '/../config/config_enhanced.php';
require_once __DIR__ . '/../config/config.php';
file_put_contents(sys_get_temp_dir() . '/delete_template_entry.log', date('c') . " included=config_enhanced\n", FILE_APPEND);
// Avoid including legacy config.php to prevent duplicate function declarations
if (!function_exists('getConfigFromDB') && file_exists(__DIR__ . '/../config/config.php')) {
require_once __DIR__ . '/../config/config.php';
file_put_contents(sys_get_temp_dir() . '/delete_template_entry.log', date('c') . " included=config_php_fallback\n", FILE_APPEND);
}
header('Content-Type: application/json; charset=utf-8');
if (php_sapi_name() !== 'cli') header('Content-Type: application/json; charset=utf-8');
// Global exception/shutdown handlers to capture fatal errors during HTTP execution
set_exception_handler(function($e){
if (function_exists('writeLog')) writeLog('ERROR', 'Unhandled exception in delete_template.php', ['message'=>$e->getMessage(), 'trace'=>$e->getTraceAsString()]);
if (php_sapi_name() !== 'cli') http_response_code(500);
echo json_encode(['success'=>false,'error'=>$e->getMessage()]);
exit;
});
register_shutdown_function(function(){
$err = error_get_last();
if ($err) {
if (function_exists('writeLog')) writeLog('ERROR', 'Shutdown error in delete_template.php', ['error' => $err]);
if (php_sapi_name() !== 'cli') {
http_response_code(500);
echo json_encode(['success'=>false,'error'=>$err['message']]);
}
}
});
// Bypass authentication when debug=true is provided in query string
$debugMode = isset($_GET['debug']) && $_GET['debug'] === 'true';
+148
View File
@@ -0,0 +1,148 @@
<?php
require_once __DIR__ . '/../config/config.php';
if (php_sapi_name() !== 'cli') header('Content-Type: application/json; charset=utf-8');
$input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
// minimal auth or debug
$debug = isset($_GET['debug']) && $_GET['debug'] === 'true';
if (!$debug && function_exists('requireAuthentication')) requireAuthentication();
$phone = $input['phone'] ?? ($input['phone_number'] ?? null);
$user_id = isset($input['user_id']) ? intval($input['user_id']) : null;
$raw = $input['text'] ?? $input['raw'] ?? null;
if (!$raw || (!$phone && !$user_id)) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'phone/user_id and text are required']);
exit;
}
// Normalize encoding - try to ensure UTF-8
if (!function_exists('normalize_text')) {
function normalize_text($s) {
if (empty($s)) return $s;
// If valid UTF-8, attempt to repair common mojibake (Ã, Â) before returning
if (mb_check_encoding($s, 'UTF-8')) {
if (preg_match('/Ã|Â/', $s)) {
$step = @iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $s);
if ($step) {
$step2 = @iconv('ISO-8859-1', 'UTF-8//TRANSLIT', $step);
if ($step2 && mb_check_encoding($step2, 'UTF-8')) return $step2;
}
}
return $s;
}
// Try latin1 -> utf8
$try = @iconv('ISO-8859-1', 'UTF-8//TRANSLIT', $s);
if ($try && mb_check_encoding($try, 'UTF-8')) return $try;
// Try CP1252
$try2 = @iconv('CP1252', 'UTF-8//TRANSLIT', $s);
if ($try2 && mb_check_encoding($try2, 'UTF-8')) return $try2;
// Fallback: utf8_decode then re-encode
$auto = mb_convert_encoding($s, 'UTF-8', 'auto');
// Try to repair common double-encoding mojibake (look for sequences like à or Â)
if (preg_match('/[\xC2\xC3][\x80-\xBF]/', $s) || preg_match('/Ã|Â/', $s)) {
$step = @iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $s);
if ($step) {
$step2 = @iconv('ISO-8859-1', 'UTF-8//TRANSLIT', $step);
if ($step2 && mb_check_encoding($step2, 'UTF-8')) return $step2;
}
}
return $auto;
}
}
$rawClean = normalize_text($raw);
// Parse key: value lines
$lines = preg_split('/\r?\n/', $rawClean);
$parsed = [];
foreach ($lines as $line) {
$line = trim($line);
if ($line === '') continue;
// Try separator ':' or '-'
if (strpos($line, ':') !== false) {
list($k,$v) = explode(':', $line, 2);
} elseif (strpos($line, '?') !== false && preg_match('/^\s*([^\?]+\?)\s*(.+)$/', $line, $m)) {
$k = $m[1]; $v = $m[2];
} else {
// last resort split by whitespace before last token
$parts = preg_split('/\s{2,}/', $line);
if (count($parts) === 2) { $k = $parts[0]; $v = $parts[1]; } else { continue; }
}
$k = trim($k);
$v = trim($v);
// normalize key and value encoding
$k = normalize_text($k);
$v = normalize_text($v);
$parsed[$k] = $v;
}
// Map expected questions (in Spanish) to fields
if (!function_exists('yesno_to_bool')) {
function yesno_to_bool($s) {
$s = mb_strtolower($s);
// Normalize common utf8 artifacts
$s = str_replace(['\u00a0','\xa0'], ' ', $s);
$s = trim($s);
if (in_array($s, ['si','sí','s','yes','y','true','1'])) return 1;
if (in_array($s, ['no','n','false','0'])) return 0;
return null;
}
}
$qeasy = null; $qhuman = null; $rating = null; $comment = null;
// try keys in parsed
foreach ($parsed as $k => $v) {
$kl = mb_strtolower($k);
if (strpos($kl, 'fue') !== false && strpos($kl, 'facil') !== false) {
$qeasy = yesno_to_bool($v);
} elseif (strpos($kl, 'asesor') !== false || strpos($kl, 'humano') !== false) {
$qhuman = yesno_to_bool($v);
} elseif (strpos($kl, 'calificaci') !== false || strpos($kl, 'calificacion') !== false || strpos($kl, 'calificaci') !== false) {
$rating = intval(preg_replace('/[^0-9]/','',$v));
} elseif (strpos($kl, 'coment') !== false) {
$comment = $v;
}
}
// fallback: try regex in raw
if ($qeasy === null) {
if (preg_match('/fue\s+([^,:\?]+)\s+interact/i', $rawClean, $m)) { $qeasy = yesno_to_bool($m[1]); }
}
if ($qhuman === null) {
if (preg_match('/asesor.*:\s*([^,\n]+)/i', $rawClean, $m)) { $qhuman = yesno_to_bool($m[1]); }
}
if ($rating === null) {
if (preg_match('/calificaci[oó]n[:\s]*([0-9]+)/i', $rawClean, $m)) { $rating = intval($m[1]); }
}
if ($comment === null) {
if (preg_match('/comentario[:\s]*(.+)$/i', $rawClean, $m)) { $comment = trim($m[1]); }
}
// Insert into DB
try {
$db = Database::getInstance();
$phoneNormalized = $phone ? preg_replace('/[^0-9+]/','',$phone) : null;
$now = date('Y-m-d H:i:s');
$data = [
'user_id' => $user_id,
'phone_number' => $phoneNormalized,
'q_easy_interact' => $qeasy,
'q_human_resolved' => $qhuman,
'rating' => $rating,
'comment' => $comment,
'raw_text' => $rawClean,
'created_at' => $now
];
$id = $db->insert('survey_responses', $data);
if (function_exists('writeLog')) writeLog('INFO', 'Survey response saved', ['id'=>$id, 'phone'=>$phoneNormalized, 'parsed'=>$parsed]);
echo json_encode(['success'=>true,'id'=>$id,'parsed'=>$parsed]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['success'=>false,'error'=>$e->getMessage()]);
}
+16
View File
@@ -19,6 +19,7 @@ define('DB_CHARSET', 'utf8mb4');
define('ADMIN_PASSWORD', '$2y$10$IXCY8Sm1xFkfhC6Y67Ahn.QLHxE.sjWfmTEOKFZdCN2a9s9YLVuGW'); // password123
// Función para cargar archivo .env
if (!function_exists('loadEnvFile')) {
function loadEnvFile($path) {
if (!file_exists($path)) {
return false;
@@ -41,22 +42,27 @@ function loadEnvFile($path) {
}
return true;
}
}
// Cargar .env si existe
loadEnvFile(__DIR__ . '/../.env');
// Función helper para obtener variables de entorno
if (!function_exists('env')) {
function env($key, $default = null) {
return $_ENV[$key] ?? getenv($key) ?: $default;
}
}
// Incluir clase Database
require_once __DIR__ . '/../classes/Database.php';
// Función para verificar si la instalación está completada
if (!function_exists('isInstallationCompleted')) {
function isInstallationCompleted() {
return file_exists(dirname(__DIR__) . '/.installation_completed');
}
}
// Función para obtener configuración desde base de datos
function getConfigFromDB($key, $default = null) {
@@ -516,11 +522,14 @@ function getAdminUsers() {
}
// Función para verificar login
if (!function_exists('isUserLoggedIn')) {
function isUserLoggedIn() {
return isset($_SESSION['admin_logged_in']) && $_SESSION['admin_logged_in'] === true;
}
}
// Función para verificar intentos de login
if (!function_exists('checkLoginAttempts')) {
function checkLoginAttempts($ip) {
$attemptsFile = dirname(__DIR__) . '/.login_attempts.json';
@@ -544,8 +553,10 @@ function checkLoginAttempts($ip) {
return $ipData['attempts'] < MAX_LOGIN_ATTEMPTS;
}
}
// Función para registrar intento de login fallido
if (!function_exists('recordFailedLogin')) {
function recordFailedLogin($ip) {
$attemptsFile = dirname(__DIR__) . '/.login_attempts.json';
@@ -566,8 +577,10 @@ function recordFailedLogin($ip) {
file_put_contents($attemptsFile, json_encode($attempts));
}
}
// Función para limpiar intentos de login exitoso
if (!function_exists('clearLoginAttempts')) {
function clearLoginAttempts($ip) {
$attemptsFile = dirname(__DIR__) . '/.login_attempts.json';
@@ -577,6 +590,7 @@ function clearLoginAttempts($ip) {
file_put_contents($attemptsFile, json_encode($attempts));
}
}
}
// Autoloader
spl_autoload_register(function ($class) {
@@ -782,6 +796,7 @@ function validateWhatsAppConfig() {
}
// Función para logging centralizado
if (!function_exists('writeLog')) {
function writeLog($level, $message, $context = []) {
if (!ENABLE_LOGGING) return;
@@ -803,6 +818,7 @@ function writeLog($level, $message, $context = []) {
file_put_contents($logDir . '/system.log', $logMessage, FILE_APPEND | LOCK_EX);
}
}
// Crear directorios necesarios
$requiredDirs = [
+6
View File
@@ -0,0 +1,6 @@
<?php
require_once __DIR__ . '/../config/config.php';
$db = Database::getInstance();
$t = $db->fetch('SELECT id, name FROM message_templates LIMIT 1');
if (!$t) { echo "No templates found\n"; exit(1); }
print_r($t);