Script PHP para el formulario buscador

El buscador PHP (archivo buscador.php) se compone de una página php/html para contener el formulario, recibir la cadena y opciones de búsqueda y al mismo tiempo llamar a la función buscar() ubicada en el script buscador-indices.php Ese script y los archivos indice-web.txt e indice-claves.txt deben situarse en una carpeta fuera de la raíz del sitio por motivos de seguridad. Aunque en la descarga de los archivos del tema anterior se ubican todos dentro de la misma carpeta. Veámos como es el inicio de la página para el formulario del buscador:

<?php 
//Iniciamos sesión
session_start();
//Incluimos el script del buscador
include_once("buscador-indices.php");
//Variables para los campos recibidos desde el formulario
$cadena_busqueda = "";
$pagina = -1;
$opciones_seleccion = array("documento", "apartados");
$seleccion = "documento";
$opciones_tipo_busqueda = array("alguna", "todas-orden", 
    "todas-desorden", "cadena-completa");
$tipo_busqueda = "alguna";
$palabras_completas = false;
$sensible_mayusculas = false;
$accion = "";
//Variables para los resultados
$resultado = "";
$cad_traza = "";
$tiempo = 0;
//Recogemos el post
if (isset($_POST)){
    foreach($_POST as $campo => $valor){
        $valor = htmlspecialchars($valor);
        switch ($campo){
            case "cadena-busqueda":
                $cadena_busqueda = $valor;
                break;
            case "pagina":
                $pagina = $valor;
                $accion = "buscar";
                break;
            case "seleccion":
                if (in_array($valor, $opciones_seleccion)){
                    $seleccion = $valor;
                }
                break;
            case "tipo-busqueda":
                if (in_array($valor, $opciones_tipo_busqueda)){
                    $tipo_busqueda = $valor;
                }
                break;
            case "palabras-completas":
                $palabras_completas = true;
                break;
            case "sensible-mayusculas":
                $sensible_mayusculas = true;
                break;
            case "buscar":
                $accion = "buscar";
                break;

        }
    }
}
if ($accion == "buscar"){
    //Lanzamos el buscador que nos devuelve un array
    $arr_busca = buscar($cadena_busqueda, $pagina, $seleccion,
                $tipo_busqueda, $palabras_completas, $sensible_mayusculas);
    if ($arr_busca["error"]){
        $pagina = -1;
        $resultado = $arr_busca["mensaje"];
    } else {
        $pagina = $arr_busca["pagina"];
        $resultado = "";
        $tiempo = "";
        if ($arr_busca["mensaje"] != ""){
            $resultado = $arr_busca["mensaje"];
        } else {
            $tiempo = 'Encontrados '.$arr_busca["num-docs"].' documentos en '.
                       $arr_busca["lapso"].' milisegundos. '.$arr_busca["cortado"];
            $resultado = $arr_busca["resultado"];
        }
        $cad_traza = $arr_busca["cad-traza"];
    }
}
echo '<?xml version="1.0" encoding="UTF-8"?>';
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">
<head>    
    ... Sigue el HTML con el formulario del buscador
    que se expone más abajo ...
    

Una vez iniciada la sesión incluimos el script buscador-indices.php. Luego inicializamos las variables y recogemos lo que venga en el POST, es decir, lo que el usuario haya enviado en el formulario. Una variable recoge el botón de envío del formulario y nos permite llamar a la función buscar() del script buscador-indices.php. Esta función devuelve un array con las siguientes claves:

array("error" => $error, 
"mensaje" => $mensaje, 
"resultado" => $resultado,
"pagina"=>$pagina, 
"num-docs"=>$num_docs, 
"lapso"=>$lapso, 
"cortado"=>$cortado, 
"cad-traza"=>$cad_traza);    
    

Si no hay error se presenta el resultado que es el literal HTML de los 10 resultados encontrados para esa página. La variable "cortado" contiene el patrón de búsqueda que, en su caso, pudo haber sido cortado por cumplir el tiempo límite. También se obtiene una cadena de traza con los tiempos de ejecución.

Código HTML para el formulario buscador

El resto de la página contiene estilo CSS, Javascript para manejar la página y el propio formulario del buscador. El estilo CSS se aplica usando PHP para insertar el nombre de clase que se declara como constante en el buscador-indices.php. Por ejemplo, a los apartados de los resultados con la descripción se les aplica este estilo en el elemento <style> del <head> de la página:

.<?php echo PREFIJOCLASS; ?>description {
    font-size: 0.85em;
}

El Javascript contenido en el elemento <script> del <head> de la página es exclusivamente para controlar el aspecto del documento, especialmente para mostrar y ocultar opciones así como para solicitar una página en uno de los botones de la barra navegadora de páginas que tiene este aspecto:

botonera

Se observa que capturé esta pantalla con el cursor situado en el botón de la página 4, indicando la barra de estado que ese elemento activa el javascript pagina(4). Entonces usamos la función restando uno del número de página pues en el script buscador-indices.php las páginas se referencian desde la cero:

function pagina(numero){
    document.forms["principal"]["pagina"].value = parseInt(numero - 1);
    document.forms["principal"].submit();
}

Poco más hay que decir acerca del Javascript. Si acaso que incluimos dos funciones que unifican el comportamiento de los navegadores. Estas son nodoPadre() para encontrar el padre de un elemento y arrayClassName() para obtener una colección de elementos según un nombre de clase, que forman parte del módulo general.js y que he extraido aquí para que en su caso no tenga necesidad de vincular el módulo completo si no le es necesario.

En cuanto al formulario del buscador tampoco tiene ningún secreto. Ponemos aquí todo lo que está en el <body> de la página aunque omitiendo algunos campos del formulario y la traza de tiempo para abreviar:

<div id="contenido-interior">
    <div><b>BUSCAR</b> 
        <div id="masmenos" title="Mostrar opciones" 
        onclick="mostrarOcultarOpciones(this)">
            <code>[+]</code> Opciones
        </div>
    </div>
    <form  name="principal" id="principal" action="buscador.php" 
    method="post"">
        <label style="display: block">Cadena de búsqueda:
            <input type="text" name="cadena-busqueda" 
            id="cadena-busqueda"
            class="val-" size="75" maxlength="75" 
            value="<?php echo $cadena_busqueda; ?>" />
        </label>
        <input type="hidden" name="pagina" id="pagina"
        value="<?php echo $pagina; ?>" />
        ... siguen otros campos de formulario ...
        <input type="submit" name="buscar" value="Buscar" />
    </form>
    ... aquí va la traza de tiempo ...  
    <div id="resultados">
        <?php echo $resultado; ?>
    </div>
</div>    
    

El buscador de ejemplo finalmente tendrá un aspecto como esta captura de pantalla tras lanzar una búsqueda:

aspecto buscador

En la URL de cada resultado aparece el dominio localhost al que se antepone www, pero cuando se ejecute desde su servidor real ahí aparecerá el nombre del dominio, insertándose con 'http://www.'.$_SERVER["SERVER_NAME"]. Si no quiere que se incluyan las www entonces debe modificarlo en la función componer_pagina() del script buscador-indices.php.

Aspectos de seguridad del formulario

Esta página de ejemplo contiene el formulario para recoger la cadena y opciones de búsqueda pero no tiene en cuenta todas las medidas de seguridad que, por otro lado, si existen en el de este sitio www.wextensible.com. Ahí uso todo lo explicado en los temas sobre formularios seguros, capítulo de validar formulario. Sobre el tema de sesiones y cookies puede ver más en PHP: Sesiones. En este formulario de ejemplo he preferido evitar agregarle las medidas de seguridad para poder explicarlo mejor.

Pero en caso de realizar una implementación de este formulario no debe olvidar esas medidas de seguridad. Aunque los valores recibidos del formulario se hacen mediante POST y se filtran todas las entradas con htmlspecialchars(), e incluso en el módulo buscador-indices.php se aplica htmlentities() a la cadena de búsqueda aunque con otro propósito, realmente debe considerar usar algún sistema más potente para el filtrado de datos, como el expuesto en los enlaces anteriores.


En los siguientes temas se expone con mayor profundidad algunos detalles de diseño del módulo buscador-indices.php, aunque no necesitará conocerlos para implementarlo tal como hemos expuesto hasta aquí.