diff --git a/Shared/Infrastructure/Scripts/validate-fix-lists.php b/Shared/Infrastructure/Scripts/validate-fix-lists.php new file mode 100644 index 00000000..2d4026ff --- /dev/null +++ b/Shared/Infrastructure/Scripts/validate-fix-lists.php @@ -0,0 +1,347 @@ + 'localhost', + 'database' => 'preciosunitarios_seo', + 'username' => 'preciosunitarios_seo', + 'password' => 'ACl%EEFd=V-Yvb??', + 'charset' => 'utf8mb4' +]; + +$output_dir = '/tmp/list-fix-validation'; +$sample_size = 5; + +echo "==============================================\n"; +echo " VALIDADOR DE CORRECCIONES\n"; +echo " Fecha: " . date('Y-m-d H:i:s') . "\n"; +echo "==============================================\n\n"; + +// Crear directorio de salida +if (!is_dir($output_dir)) { + mkdir($output_dir, 0755, true); +} + +// Limpiar archivos anteriores +array_map('unlink', glob("$output_dir/*.html")); + +/** + * Detectar problemas en HTML + */ +function detectIssues(string $html): array { + $issues = []; + libxml_use_internal_errors(true); + + $doc = new DOMDocument('1.0', 'UTF-8'); + $wrapped = '
' . $html . '
'; + $doc->loadHTML('' . $wrapped, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); + libxml_clear_errors(); + + $validChildren = ['li', 'script', 'template']; + + foreach (['ul', 'ol'] as $listTag) { + foreach ($doc->getElementsByTagName($listTag) as $list) { + foreach ($list->childNodes as $child) { + if ($child->nodeType === XML_ELEMENT_NODE) { + $tagName = strtolower($child->nodeName); + if (!in_array($tagName, $validChildren)) { + $issues[] = "<$listTag> contiene <$tagName>"; + } + } + } + } + } + + return $issues; +} + +/** + * Corregir listas mal formadas + */ +function fixMalformedLists(string $html): array { + $result = ['fixed' => false, 'html' => $html, 'changes' => 0, 'details' => []]; + + libxml_use_internal_errors(true); + $doc = new DOMDocument('1.0', 'UTF-8'); + $wrapped = '
' . $html . '
'; + $doc->loadHTML('' . $wrapped, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); + libxml_clear_errors(); + + $lists = []; + foreach ($doc->getElementsByTagName('ul') as $ul) { $lists[] = $ul; } + foreach ($doc->getElementsByTagName('ol') as $ol) { $lists[] = $ol; } + + $changes = 0; + $validChildren = ['li', 'script', 'template']; + + foreach ($lists as $list) { + $nodesToProcess = []; + foreach ($list->childNodes as $child) { + if ($child->nodeType === XML_ELEMENT_NODE) { + $tagName = strtolower($child->nodeName); + if (!in_array($tagName, $validChildren)) { + $nodesToProcess[] = $child; + } + } + } + + foreach ($nodesToProcess as $node) { + $tagName = strtolower($node->nodeName); + $prevLi = null; + $prev = $node->previousSibling; + + while ($prev) { + if ($prev->nodeType === XML_ELEMENT_NODE && strtolower($prev->nodeName) === 'li') { + $prevLi = $prev; + break; + } + $prev = $prev->previousSibling; + } + + if ($prevLi) { + $prevLi->appendChild($node); + $result['details'][] = "Movido <$tagName> dentro del
  • anterior"; + $changes++; + } else { + $newLi = $doc->createElement('li'); + $list->insertBefore($newLi, $node); + $newLi->appendChild($node); + $result['details'][] = "Envuelto <$tagName> en nuevo
  • "; + $changes++; + } + } + } + + if ($changes > 0) { + $wrapper = $doc->getElementById('temp-wrapper'); + if ($wrapper) { + $innerHTML = ''; + foreach ($wrapper->childNodes as $child) { + $innerHTML .= $doc->saveHTML($child); + } + $result['html'] = $innerHTML; + $result['fixed'] = true; + $result['changes'] = $changes; + } + } + + return $result; +} + +/** + * Generar HTML wrapper para visualización + */ +function wrapForVisualization(string $content, string $title, string $status): string { + $statusColor = $status === 'error' ? '#dc3545' : '#28a745'; + return << + + + + + $title + + + +
    $status
    +
    + $content +
    + + +HTML; +} + +// Conectar a DB +$conn = new mysqli($db_config['host'], $db_config['username'], $db_config['password'], $db_config['database']); +$conn->set_charset($db_config['charset']); + +if ($conn->connect_error) { + die("Error de conexión: " . $conn->connect_error); +} + +echo "✓ Conexión establecida\n\n"; + +// Buscar posts con problemas +$query = "SELECT id, page, html FROM datos_seo_pagina WHERE html IS NOT NULL AND html != '' ORDER BY id LIMIT 500"; +$result = $conn->query($query); + +$samples = []; +while ($row = $result->fetch_assoc()) { + $issues = detectIssues($row['html']); + if (!empty($issues) && count($samples) < $sample_size) { + $samples[] = $row; + } +} + +echo "Encontrados " . count($samples) . " posts con problemas para validar\n\n"; + +$comparison_data = []; + +foreach ($samples as $idx => $post) { + $id = $post['id']; + $url = $post['page']; + $html_before = $post['html']; + + echo "─────────────────────────────────\n"; + echo "POST $id: $url\n"; + + // Detectar problemas antes + $issues_before = detectIssues($html_before); + echo " Problemas ANTES: " . count($issues_before) . "\n"; + + // Aplicar corrección + $fixResult = fixMalformedLists($html_before); + $html_after = $fixResult['html']; + + // Detectar problemas después + $issues_after = detectIssues($html_after); + echo " Problemas DESPUÉS: " . count($issues_after) . "\n"; + echo " Cambios aplicados: " . $fixResult['changes'] . "\n"; + + // Guardar archivos HTML + $file_before = "$output_dir/post_{$id}_BEFORE.html"; + $file_after = "$output_dir/post_{$id}_AFTER.html"; + + file_put_contents($file_before, wrapForVisualization( + $html_before, + "Post $id - ANTES (con errores)", + "ANTES: " . count($issues_before) . " problemas de listas" + )); + + file_put_contents($file_after, wrapForVisualization( + $html_after, + "Post $id - DESPUÉS (corregido)", + "DESPUÉS: " . count($issues_after) . " problemas - " . $fixResult['changes'] . " correcciones aplicadas" + )); + + echo " ✓ Archivos generados:\n"; + echo " - $file_before\n"; + echo " - $file_after\n"; + + // Guardar datos para reporte + $comparison_data[] = [ + 'id' => $id, + 'url' => $url, + 'issues_before' => count($issues_before), + 'issues_after' => count($issues_after), + 'changes' => $fixResult['changes'], + 'file_before' => "post_{$id}_BEFORE.html", + 'file_after' => "post_{$id}_AFTER.html" + ]; +} + +// Generar reporte comparativo +$report_html = << + + + + Reporte de Validación - Corrección de Listas + + + +

    Reporte de Validación - Corrección de Listas HTML

    + +
    + Instrucciones: +
      +
    1. Abre cada par de archivos (ANTES/DESPUÉS) en el navegador
    2. +
    3. Verifica que el contenido se muestre correctamente
    4. +
    5. Las listas (fondo amarillo) deben contener solo items (fondo verde)
    6. +
    7. Si todo se ve bien, la corrección es segura
    8. +
    +
    + + + + + + + + + + + + + +HTML; + +foreach ($comparison_data as $data) { + $status_class = $data['issues_after'] == 0 ? 'success' : ($data['issues_after'] < $data['issues_before'] ? 'warning' : 'error'); + + $report_html .= << + + + + + + + +HTML; +} + +$report_html .= << +
    IDURLProblemas AntesProblemas DespuésCambiosArchivos
    {$data['id']}{$data['url']}{$data['issues_before']}{$data['issues_after']}{$data['changes']} + ANTES | + DESPUÉS +
    + +

    Generado: {$_SERVER['REQUEST_TIME_FLOAT']}

    + + +HTML; + +$report_file = "$output_dir/comparison_report.html"; +file_put_contents($report_file, $report_html); + +echo "\n─────────────────────────────────\n"; +echo "REPORTE GENERADO:\n"; +echo " $report_file\n\n"; +echo "Para revisar, descarga el directorio:\n"; +echo " scp -r VPSContabo:$output_dir ./validation/\n\n"; + +$conn->close(); +echo "✓ Validación completada.\n";