Files
whatsapp/legacy/install_integrated.php
2026-01-28 03:09:52 -05:00

438 lines
20 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Instalador con Schema Integrado
* Evita problemas de parsing del archivo schema.sql
* Desarrollado por U-Site.app
* Fecha: 14 de noviembre de 2025
*/
// Verificar si ya está instalado
if (file_exists('.installation_completed')) {
header('Location: login.php');
exit('Sistema ya instalado');
}
$step = $_GET['step'] ?? 'form';
$errors = [];
$success = [];
function generatePassword($length = 12) {
return bin2hex(random_bytes($length / 2));
}
$adminPassword = generatePassword(12);
// Schema SQL integrado (evita problemas de parsing)
$integratedSchema = [
// Crear tablas principales
"CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
phone_number VARCHAR(20) UNIQUE NOT NULL,
name VARCHAR(100),
email VARCHAR(100),
status ENUM('active', 'inactive', 'blocked') DEFAULT 'active',
current_menu_id INT NULL,
current_step INT DEFAULT 0,
session_data JSON,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_phone (phone_number),
INDEX idx_status (status)
)",
"CREATE TABLE IF NOT EXISTS conversations (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
message_id VARCHAR(100),
direction ENUM('incoming', 'outgoing') NOT NULL,
message_type ENUM('text', 'image', 'audio', 'video', 'document', 'template') DEFAULT 'text',
content TEXT,
media_url VARCHAR(500),
status ENUM('sent', 'delivered', 'read', 'failed') DEFAULT 'sent',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
INDEX idx_user (user_id),
INDEX idx_created (created_at)
)",
"CREATE TABLE IF NOT EXISTS menus (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
title VARCHAR(200) NOT NULL,
description TEXT,
parent_id INT NULL,
is_root BOOLEAN DEFAULT FALSE,
is_active BOOLEAN DEFAULT TRUE,
order_position INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (parent_id) REFERENCES menus(id) ON DELETE CASCADE,
INDEX idx_parent (parent_id),
INDEX idx_active (is_active)
)",
"CREATE TABLE IF NOT EXISTS menu_options (
id INT AUTO_INCREMENT PRIMARY KEY,
menu_id INT NOT NULL,
option_number INT NOT NULL,
text VARCHAR(200) NOT NULL,
action_type ENUM('menu', 'message', 'api_call', 'end') NOT NULL,
action_value VARCHAR(500),
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (menu_id) REFERENCES menus(id) ON DELETE CASCADE,
UNIQUE KEY unique_menu_option (menu_id, option_number)
)",
"CREATE TABLE IF NOT EXISTS system_config (
id INT AUTO_INCREMENT PRIMARY KEY,
config_key VARCHAR(100) UNIQUE NOT NULL,
config_value TEXT,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)",
"CREATE TABLE IF NOT EXISTS autoresponses (
id INT AUTO_INCREMENT PRIMARY KEY,
trigger_type ENUM('keyword', 'menu_selection', 'welcome') NOT NULL,
trigger_value VARCHAR(200),
response_text TEXT NOT NULL,
response_type ENUM('text', 'template') DEFAULT 'text',
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)",
"CREATE TABLE IF NOT EXISTS webhook_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
request_body TEXT,
response_body TEXT,
status_code INT,
ip_address VARCHAR(45),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_created (created_at)
)"
];
$initialData = [
// Configuración inicial
"INSERT IGNORE INTO system_config (config_key, config_value, description) VALUES
('whatsapp_token', 'TU_TOKEN_AQUI', 'Token de WhatsApp Business API'),
('whatsapp_phone_number_id', 'TU_PHONE_ID_AQUI', 'ID del número de teléfono'),
('webhook_verify_token', 'mi_token_secreto_123', 'Token de verificación del webhook'),
('welcome_message', '¡Hola! 👋 Bienvenido. Escribe *menu* para ver opciones.', 'Mensaje de bienvenida'),
('business_name', 'Mi Empresa', 'Nombre de la empresa'),
('app_installed', '1', 'Marca de instalación completada'),
('install_date', NOW(), 'Fecha de instalación')",
// Menú principal
"INSERT IGNORE INTO menus (id, name, title, description, is_root, order_position) VALUES
(1, 'main_menu', '🏠 Menú Principal', 'Menú principal del sistema', TRUE, 1)",
// Opciones del menú principal
"INSERT IGNORE INTO menu_options (menu_id, option_number, text, action_type, action_value) VALUES
(1, 1, '📋 Información', 'message', 'Gracias por contactarnos. Un representante te atenderá pronto.'),
(1, 2, '📞 Soporte', 'message', 'Para soporte técnico, describe tu consulta y te ayudaremos.'),
(1, 0, '❌ Salir', 'end', 'Gracias por contactarnos. ¡Hasta pronto!')",
// Respuestas automáticas
"INSERT IGNORE INTO autoresponses (trigger_type, trigger_value, response_text) VALUES
('keyword', 'menu', 'Aquí tienes nuestro menú principal:'),
('keyword', 'hola', '¡Hola! 👋 Escribe *menu* para ver opciones.'),
('welcome', '', '¡Bienvenido! 👋 Escribe *menu* para comenzar.')"
];
if ($step === 'install' && $_POST) {
$dbHost = trim($_POST['db_host'] ?? 'localhost');
$dbPort = trim($_POST['db_port'] ?? '3306');
$dbName = trim($_POST['db_name'] ?? '');
$dbUser = trim($_POST['db_user'] ?? '');
$dbPass = $_POST['db_pass'] ?? '';
// Validar
if (empty($dbName)) $errors[] = "Nombre de BD requerido";
if (empty($dbUser)) $errors[] = "Usuario requerido";
if (empty($dbPass)) $errors[] = "Contraseña requerida";
if (empty($errors)) {
try {
// Conectar
$dsn = "mysql:host={$dbHost};port={$dbPort};dbname={$dbName};charset=utf8mb4";
$pdo = new PDO($dsn, $dbUser, $dbPass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
$success[] = "✅ Conexión exitosa a '{$dbName}'";
// Ejecutar schema - PASO 1: Crear solo las tablas
$tablesCreated = 0;
$creationErrors = [];
echo "<script>console.log('Iniciando creación de tablas...');</script>";
foreach ($integratedSchema as $index => $sql) {
try {
echo "<script>console.log('Ejecutando SQL: " . substr($sql, 0, 50) . "...');</script>";
$result = $pdo->exec($sql);
$tablesCreated++;
// Extraer nombre de tabla para log
if (preg_match('/CREATE TABLE IF NOT EXISTS (\w+)/', $sql, $matches)) {
$tableName = $matches[1];
$success[] = "✅ Tabla '{$tableName}' creada/verificada";
// Verificar que la tabla realmente existe
try {
$checkQuery = "DESCRIBE `{$tableName}`";
$pdo->query($checkQuery);
} catch (PDOException $e) {
$creationErrors[] = "❌ Error verificando tabla '{$tableName}': " . $e->getMessage();
}
}
// Pequeña pausa para evitar problemas de timing
usleep(100000); // 0.1 segundos
} catch (PDOException $e) {
$errorMsg = $e->getMessage();
if (strpos($errorMsg, 'already exists') === false) {
$creationErrors[] = "❌ Error en tabla " . ($index + 1) . ": " . $errorMsg;
} else {
$tablesCreated++; // Contar como creada si ya existe
}
}
}
// Mostrar errores de creación si los hay
if (!empty($creationErrors)) {
foreach ($creationErrors as $error) {
$errors[] = $error;
}
}
// Solo continuar si se crearon las tablas principales
$essentialTables = ['users', 'conversations', 'menus', 'system_config'];
$missingTables = [];
foreach ($essentialTables as $table) {
try {
$pdo->query("DESCRIBE `{$table}`");
} catch (PDOException $e) {
$missingTables[] = $table;
}
}
if (!empty($missingTables)) {
$errors[] = "❌ Tablas esenciales no creadas: " . implode(', ', $missingTables);
$errors[] = "️ Intenta ejecutar el SQL manualmente en phpMyAdmin primero";
} else {
$success[] = "✅ Todas las tablas esenciales verificadas";
// PASO 2: Insertar datos solo si las tablas existen
$dataInserted = 0;
foreach ($initialData as $sql) {
try {
$pdo->exec($sql);
$dataInserted++;
} catch (PDOException $e) {
$errorMsg = $e->getMessage();
if (strpos($errorMsg, 'Duplicate entry') === false) {
$errors[] = "⚠️ Error insertando datos: " . $errorMsg;
}
}
}
$success[] = "✅ {$tablesCreated} tablas procesadas, {$dataInserted} conjuntos de datos insertados";
}
// Actualizar config.php
$configFile = 'config/config.php';
if (file_exists($configFile)) {
$config = file_get_contents($configFile);
$config = preg_replace("/define\('DB_HOST',\s*'[^']*'\);/", "define('DB_HOST', '$dbHost');", $config);
$config = preg_replace("/define\('DB_PORT',\s*'[^']*'\);/", "define('DB_PORT', '$dbPort');", $config);
$config = preg_replace("/define\('DB_NAME',\s*'[^']*'\);/", "define('DB_NAME', '$dbName');", $config);
$config = preg_replace("/define\('DB_USER',\s*'[^']*'\);/", "define('DB_USER', '$dbUser');", $config);
$config = preg_replace("/define\('DB_PASS',\s*'[^']*'\);/", "define('DB_PASS', '$dbPass');", $config);
$config = preg_replace("/define\('ADMIN_PASSWORD',\s*'[^']*'\);/", "define('ADMIN_PASSWORD', '" . password_hash($adminPassword, PASSWORD_DEFAULT) . "');", $config);
// Auto-detectar URL
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https://' : 'http://';
$host = $_SERVER['HTTP_HOST'];
$path = dirname($_SERVER['SCRIPT_NAME']);
$autoUrl = $protocol . $host . $path;
$config = preg_replace("/define\('APP_URL',\s*'[^']*'\);/", "define('APP_URL', '$autoUrl');", $config);
if (file_put_contents($configFile, $config)) {
$success[] = "✅ Configuración actualizada";
} else {
$errors[] = "❌ No se pudo actualizar config.php";
}
}
// Verificar instalación
if (empty($errors)) {
try {
$userCount = $pdo->query("SELECT COUNT(*) FROM users")->fetchColumn();
$configCount = $pdo->query("SELECT COUNT(*) FROM system_config")->fetchColumn();
$success[] = "✅ Verificación: {$userCount} usuarios, {$configCount} configuraciones";
// Marcar como instalado
file_put_contents('.installation_completed', date('Y-m-d H:i:s'));
// Credenciales
$credentials = "USUARIO: admin\nCONTRASEÑA: {$adminPassword}\nFECHA: " . date('Y-m-d H:i:s');
file_put_contents('CREDENCIALES.txt', $credentials);
$success[] = "✅ Instalación completada exitosamente";
$step = 'completed';
} catch (Exception $e) {
$errors[] = "❌ Error en verificación: " . $e->getMessage();
}
}
} catch (PDOException $e) {
$errors[] = "❌ Error de conexión: " . $e->getMessage();
}
}
}
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🔧 Instalador Integrado</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<style>
body { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; }
.install-card { background: rgba(255,255,255,0.95); border-radius: 15px; }
.btn-primary { background: #667eea; border: none; }
</style>
</head>
<body class="d-flex align-items-center">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="install-card shadow-lg p-4">
<?php if ($step === 'form'): ?>
<div class="text-center mb-4">
<h2><i class="fas fa-cogs me-2"></i>Instalador con Schema Integrado</h2>
<p class="text-muted">Evita problemas de parsing del archivo schema.sql</p>
</div>
<div class="alert alert-info">
<i class="fas fa-info-circle me-2"></i>
<strong>Ventajas de este instalador:</strong>
<ul class="mb-0 mt-2">
<li>✅ Schema SQL integrado en el código</li>
<li>✅ No depende de archivos externos</li>
<li>✅ Ejecución paso a paso controlada</li>
<li>✅ Manejo de errores mejorado</li>
</ul>
</div>
<form method="POST" action="?step=install">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label"><i class="fas fa-server me-2"></i>Host</label>
<input type="text" class="form-control" name="db_host" value="localhost" required>
</div>
<div class="col-md-6">
<label class="form-label"><i class="fas fa-plug me-2"></i>Puerto</label>
<input type="text" class="form-control" name="db_port" value="3306" required>
</div>
<div class="col-md-6">
<label class="form-label"><i class="fas fa-database me-2"></i>Base de datos</label>
<input type="text" class="form-control" name="db_name" placeholder="usite_whatsapp_bot" required>
<small class="text-muted">Debe existir previamente</small>
</div>
<div class="col-md-6">
<label class="form-label"><i class="fas fa-user me-2"></i>Usuario</label>
<input type="text" class="form-control" name="db_user" placeholder="usite_usuario" required>
</div>
<div class="col-12">
<label class="form-label"><i class="fas fa-key me-2"></i>Contraseña</label>
<input type="password" class="form-control" name="db_pass" required>
</div>
</div>
<div class="text-center mt-4">
<div class="alert alert-success">
<strong><i class="fas fa-user-shield me-2"></i>Credenciales de Admin:</strong><br>
<strong>Usuario:</strong> admin<br>
<strong>Contraseña:</strong> <code><?= $adminPassword ?></code>
</div>
<button type="submit" class="btn btn-primary btn-lg">
<i class="fas fa-rocket me-2"></i>Instalar con Schema Integrado
</button>
</div>
</form>
<?php elseif ($step === 'install'): ?>
<div class="text-center mb-4">
<h2><i class="fas fa-cog fa-spin me-2"></i>Instalando...</h2>
</div>
<?php if (!empty($errors)): ?>
<div class="alert alert-danger">
<h5><i class="fas fa-exclamation-triangle me-2"></i>Errores:</h5>
<?php foreach ($errors as $error): ?>
<div><?= htmlspecialchars($error) ?></div>
<?php endforeach; ?>
<hr>
<a href="?step=form" class="btn btn-outline-danger">Reintentar</a>
</div>
<?php endif; ?>
<?php if (!empty($success)): ?>
<div class="alert alert-success">
<h5><i class="fas fa-check-circle me-2"></i>Progreso:</h5>
<?php foreach ($success as $msg): ?>
<div><?= htmlspecialchars($msg) ?></div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php elseif ($step === 'completed'): ?>
<div class="text-center mb-4">
<h2 class="text-success"><i class="fas fa-check-circle me-2"></i>¡Instalación Exitosa!</h2>
<p class="text-muted">Sistema WhatsApp Bot instalado correctamente</p>
</div>
<div class="row g-4">
<div class="col-md-6">
<h5><i class="fas fa-key me-2 text-success"></i>Credenciales</h5>
<div class="alert alert-success">
<strong>Usuario:</strong> admin<br>
<strong>Contraseña:</strong> <code><?= $adminPassword ?></code><br>
<small>Guardadas en CREDENCIALES.txt</small>
</div>
</div>
<div class="col-md-6">
<h5><i class="fas fa-rocket me-2 text-primary"></i>Acciones</h5>
<div class="d-grid gap-2">
<a href="index.php" class="btn btn-primary">Panel de Control</a>
<a href="test.php" class="btn btn-outline-success">Probar Sistema</a>
<a href="login.php" class="btn btn-outline-info">Iniciar Sesión</a>
</div>
</div>
</div>
<div class="alert alert-info mt-4">
<i class="fas fa-info-circle me-2"></i>
<strong>Próximos pasos:</strong> Configura tu token de WhatsApp en el panel de administración.
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
</body>
</html>