Búsqueda instantánea con AJAX

37
17055

Volvemos nuevamente al tema de consultas en MySQL, haciendo uso de AJAX y PHP. En esta oportunidad veremos una busqueda instantánea. Quizás ha notado que algunos blogs tienen su sistema de busqueda de entradas(posts) y que los resultados de la busqueda se cargan en otra página. Aunque existen otros que los resultados aparecen en la misma página haciendo uso de AJAX. Pues bien eso es lo vamos a ver ahora.

Hay que tener en cuenta debemos hacer algunos cambios a nuestra base de datos. ¿Porqué? Cuando buscamos un sólo término o palabra no existe problema, podemos hacer uso de la sentencia SELECT … LIKE contenido=’termino’ OR titulo=’termino’.

Pero, ahora supongamos que queremos buscar una expresión, entonces se deberá buscar si el titulo o contenido del post lo contiene. En ese caso no haremos en trabajo con un simple LIKE debemos hacer algo mas.

Bien entonces empezemos…

Vamos definir los campos de la tabla, la cual usaremos para este ejemplo.

CREATE TABLE `post` (
`idpost` INT( 7 ) NOT NULL auto_increment ,
`titulo` VARCHAR( 70 ) NOT NULL ,
`contenido` TEXT NOT NULL ,
`autor` VARCHAR( 20 ) NOT NULL,
KEY `idpost` (`idpost`)
) TYPE = MYISAM ;

Bien ahora debemos de crear un índice FULLTEXT, que es útil para el segundo caso explicado, cuando buscamos expresiones o conjuntos de palabras en una tabla. Lo realizamos de la siguiente manera:

ALTER TABLE post ADD FULLTEXT(titulo, contenido); 

De esta manera cuando realicemos una busqueda, se trabajará en los dos campos que expecificamos dentro del FULLTEXT. Pero la instrucción de busqueda no será como con el LIKE, sino de la siguiente manera:

SELECT * FROM post WHERE MATCH(titulo, contenido) AGAINST ('$terminos) 

La función MATCH  …  AGAINST … , es usado en consultas en lenguaje natural parecido a como lo hacen los motores de búsqueda.

Nota: La funciónn MATCH … AGAINST … falla a veces cuando la expresión a buscar tiene solo una palabra. Para la busqueda de una sola palabra hacemos uso de LIKE.

Ahora a nuestra aplicación …

Vamos a definir los archivos que realizará el proceso:

  • conexion.php >> Datos de la conexión a la base de datos.
  • funciones.js >> El objeto XMLHttpRequest que usaremos y otras funciones en JavaScript.
  • index.php >> El archivo principal que contendrá el formulario de busqueda.
  • busqueda.php >> Realizará la busqueda en si, seleccionará la busqueda adecuada a la expresion ingresada.

conexion.php

Este archivo contiene los datos de la conexión. Recuerde cambiar los datos por los suyos si desea probarlos en su PC.

<?php 
   $bd_host = "localhost"; 
   $bd_usuario = "root"; 
   $bd_password = ""; 
   $bd_base = "ribosomatic"; 
   $con = mysql_connect($bd_host, $bd_usuario, $bd_password); 
   mysql_select_db($bd_base, $con); 
?>

funciones.js

Aquí se encuentran las funciones para llamar el objeto XMLHttpRequest y llamar al proceso de busqueda.

function nuevoAjax(){
	var xmlhttp=false;
 	try{
		xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
	}catch(e){
		try {
			xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
		}catch(E){
 			xmlhttp = false;
 		}
 	}
	
	if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
		xmlhttp = new XMLHttpRequest();
	}
   
	return xmlhttp;
}

function buscarDato(){
	resul = document.getElementById('resultado');
	bus=document.frmbusqueda.dato.value;
   
	ajax=nuevoAjax();
	ajax.open("POST", "busqueda.php",true);
	ajax.onreadystatechange=function() {
		if (ajax.readyState==4) {
			resul.innerHTML = ajax.responseText
		}
	}
	ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
	ajax.send("busqueda="+bus)
}

index.php

Definimos el archivo JavaScript que usará la página, es este caso funciones.js. Tambien definimos los estilos. En el evento onsubmit del formulario definimos la función JavaScript que llamará al proceso de busqueda.

<html>
	<head>
   	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
   	<title>Untitled Document</title>
   	<script type="text/javascript" src="funciones.js"></script>
   	<style type="text/css">
		legend {
			font-family: Verdana, Arial, Helvetica, sans-serif;
			font-weight: bold;
			font-size: 12px;
		}
		.titulo{
			width:20%;
		}
		.contenido{
			width:60%;
		}
		.autor{
			width:15%;
		}
		</style>
	</head>
  <body>
    <form name="frmbusqueda" action="" onsubmit="buscarDato(); return false">
    <div align="center">Termino a buscar:
    <input type="text" name="dato" /> 
    </div>
    </form>
    <fieldset><legend>Resultado</legend>
    <div id="resultado"></div>
    </fieldset>
  </body>
</html>

busqueda.php

Este es el archivo principal, dependiendo del término o expresiones ingresadas buscará haciendo uso de un simple LIKE o MATCH … AGAINST.

<?php
   require('conexion.php');
   $busqueda=$_POST['busqueda'];
   if ($busqueda<>''){
   	//numero de palabras
   	$trozos=explode(" ",$busqueda);
   	$numero=count($trozos);
   	if ($numero==1) {
   		$cadbusca="SELECT * FROM post WHERE CONTENIDO LIKE '%$busqueda%' OR TITULO LIKE '%$busqueda%' LIMIT 10;";
   	} elseif ($numero>1) {
   		$cadbusca="SELECT * , MATCH ( TITULO, CONTENIDO ) AGAINST ( '$busqueda' ) AS Score FROM post WHERE MATCH ( TITULO, CONTENIDO ) AGAINST ( '$busqueda' ) ORDER BY Score DESC LIMIT 50;";
   	}
   
   	function limitarPalabras($cadena, $longitud, $elipsis = "..."){
   	$palabras = explode(' ', $cadena);
   	if (count($palabras) > $longitud)
   		return implode(' ', array_slice($palabras, 0, $longitud)) . $elipsis;
   	else
   	return $cadena;
   	}
?>
<table border="1px">
<tbody>
	<tr>
	<td class="titulo">Titulo</td>
	<td class="contenido">Contenido</td>
	<td class="autor">Autor</td>
	</tr>
<?php
   	$result=mysql_query($cadbusca, $con);
   	$i=1;
   	while ($row = mysql_fetch_array($result)){
	   echo "
	   <tr>
	   <td class=\"titulo\">".$row['titulo']."</td>
	   <td class=\"contenido\">".limitarPalabras($row['contenido'],20)."</td>
	   <td class=\"autor\">".$row['autor']."</td>
	   </tr>";
	   $i++;
   	}
?>
</tbody>
</table>
<?php
//cierra el if inicial
}
?> 

Esta es una forma de combinar AJAX con proceso un poco mas avanzados de PHP y consultas MySQL. Pueden descargar el código, y el ejemplo más visible es nuestro propio sistema de búsqueda, por supuesto, mejorado y con algunas características extras.

37 COMENTARIOS

  1. Hola, oye tengo una duda (soy newbie en esto de php y mysql):
    Tanto en éste como en tus ejemplos anteriores, no es necesario cerrar la conexión con la base de datos? Hay algún problema si no se cierra al finalizar cierta acción? Cerrar la base de datos después de cada acción incrementaría la seguridad?? Gracias!
    P.D.: Tus artículos están excelentes!!

  2. Hola Battousai, cerrar la conexión dependerá del numero de peticiones a la base de datos mysql y por ende al servidor que lo contiene. Si por ejemplo la colocas en un servidor web y tu pagina recibe muchas visitas que generan constantes sentencias mysql, entonces es necesario usar la instruccion mysql_close(), es una buena practica; pero el ejemplo era instructivo e iba de frente al grano en lo que respecta a Ajax. Pero repito, es una buen practica cerrar la conexión. Saludos risas

  3. hola. estoy ocupando tu codigo en un buscador de libros, en cuya base de datos esta el dcodigo del libro (un numero de 5 digitos), el titulo y el autor. me interesa que lagente pueda buscar tanto por codigo , titulo autor. para esto puse bajo el textbox de busqueda tres radiobuttons, asi el codifo del formulario queda:
    < code >
    < form name="frmbusqueda" action="" onsubmit="buscarDato(); return false" >
    < div align="center" >

    < input type="text" name="dato" / >
    < br / >

    < input type="radio" name="eleccion" value="1" > Codigo
    < input type="radio" name="eleccion" value="2" > Titulo
    < input type="radio" name="eleccion" value="3" > Autor

    < /div >
    < /form >

    < fieldset >< legend >Resultado< /legend >
    < div id="resultado" >< /div >
    < /fieldset >
    < /code >

    en funciones.js cambie por lo siguiente:

    function buscarDato(){
    resul = document.getElementById(‘resultado’);

    bus=document.frmbusqueda.dato.value;
    //aca esta el campo de los radiobuttons
    elect=document.frmbusqueda.eleccion.value;
    ajax=nuevoAjax();
    ajax.open(“POST”, “busqueda.php”,true);
    ajax.onreadystatechange=function() {
    if (ajax.readyState==4) {
    resul.innerHTML = ajax.responseText
    }
    }
    ajax.setRequestHeader(“Content-Type”,”application/x-www-form-urlencoded”);

    //aqui los mando
    ajax.send(“busqueda=” bus “

  4. perdon, se cortó ,ahora sigo:
    aqui mando la info del textobox y del radio button
    ajax.send(“busqueda=” bus “

  5. cuando busco dos terminos me sale asi

    Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in C:AppServwwwcarpetausqueda.php on line 37

  6. Hola a todos. La verdad es que soy totalmente neófito en esto y lo que hice fue bajar el archivo zip lo extraje y modifique para adaptarlo a mi base de datos. El tema es que evidentemente lo hice mal ya cuando realizo una búsqueda solo me aparece una tabla con los nombres de Expediente, Apellido, Estado (las tablas se llaman en mysql expte, apel, obs_estado_causas) pero vacío, es decir no tira nada de nada. Por ej busco el apellido GOMEZ y en vez de salir en el campo de expediente el numero del mismo en el campo apellido el apellido GOMEZ y en el campo de estado la descripcion que se encuentra en el mismo campo de la bbdd solo aparece vacío y nada más que los títulos de las tablas, Expediente/Apellido/Estado.
    mi página donde tengo alojado el formulario es http://www.estudio.260mb.com/estudio/busqueda/index.php si entran fijense que es lo que quiero decir. mientras tanto intentaré darme cuenta que es lo que modifique mal en cada uno de los archivos que baje, Saludos a todos

  7. y para hacer una busqueda con ajax conel onkeyup + para que salga el listao (esto lo hice) pero para que cuando hago paginacion al listado no funciona al darle siguiente sale ,alguna ayudita

  8. Muy buen aporte, me corre bien.

    Quedaría excelente si el listado desplegado de la consulta en cada registro tubiera un link a otra página, para que con un pase de la variable ID hiciera una consulta detallada del registro.

    Alguien sabe como poner el link, pasenlo ¡¡¡PLEASEEEEEEEEEE!!!.

    ->->->->->->-Y que Dios lo vendiga.

  9. me encanto el ejemplo de la busqueda instantanea y modifique el codigo para me buscara datos en los ejercicios que tienen la tabla empleados…y me surgio un problema… desde este archivo de consulta veo todo bien…pero cuando quiero agregar un registro con el ejemplo del “Inserción de Datos con AJAX y POO con PHP” me muestra mal las tildes y las eñes desde esta consulta … pero en la busqueda instantanea se ve bien… como puedo solucionar esto???? help me please

  10. hola, queria comentaros que si cambias

    Termino a buscar:

    por

    Termino a buscar:

    cada vez que pulseis una tecla se realiza la acción y entonces si que es instantánea

  11. Hola una consulta, soy nueva en esto y quisiera saber si hay una forma, de cuando te arroje los resultados de la busqueda poder cliquear el nombre y se coloque solo en l input ? como se puede hacer? porfis una ayudita??

  12. que parte del codigo tengo q modificar para que me busque varias palabras ps pongo en la caja de texto dos palabras (por ejm del contenido)y no me muestra nada como hago para solucionar esto

  13. Excelente código, hay alguna manera de resaltar los resultados en negrita u otro color?
    Muchisimas gracias.

  14. Esto…
    todo lo que cuentas està muy bien, pero que pasa con la latencia del servidor MySQL?
    porque yo estoy aplicando esto para hacer una consulta permanente a la base de datos y ese tema me peocupa un poquito.

  15. Gracias al creador de este post sobre búsquedas instantáneas porque está muy sencillo y fácil de entender.

    Y gracias a DiegoVG por dar la corrección que faltaba para que funcionara como una búsqueda instantánea

  16. Funciona bien, lo he adaptado a un sistema de ventas que estoy desarrollando en php y hago la búsqueda de manera instantánea. Pero luego de todo tengo un pequeño problemilla…cuando en la base de datos hay acentos diacríticos o la letra ñ entonces al hacer la búsqueda si escribo solo la letra ñ por ejemplo no me encuentra ninguna palabra, pero si escribo la letra n si me lo incluye, lo mismo pasa con los acentos o tildes, si escribo avión no me lo encuentra pero si lo pongo sin tilde si me lo encuentra, la tilde no me preocupa, pero si la “ñ”. ¿Cómo hago para que me la detecte?…Pensé en una validación por cada caracter que se ingresara y que si escribe ñ que sea como que escribe n, pero ni eso me imagino como implementarlo.

  17. miren tengo un algoritmo de busqueda mi objetivo es cargar los archivos en una carpeta y sus nombres en una base de datos ya hace lo que quiero pero tengo que repetir la ultima letra para que aparezca mi archivo alguien puede decirme como puedo hacerle para que al pulsar una tecla me mande archivos relacionados a lo que busco este es mi algoritmo.
    formulario.html

    Buscar:

    ///////////////////////ajax.js///////////////////////////////////
    function nuevoAjax(){
    var xmlhttp=false;
    try{
    xmlhttp = new ActiveXObject(“Msxml2.XMLHTTP”);
    }catch(e){
    try {
    xmlhttp = new ActiveXObject(“Microsoft.XMLHTTP”);
    }catch(E){
    xmlhttp = false;
    } }
    if (!xmlhttp && typeof XMLHttpRequest!=’undefined’) {
    xmlhttp = new XMLHttpRequest();
    }
    return xmlhttp;}

    function consulta(){

    capa = document.getElementById(‘g’);
    variable=document.b.x.value;
    ajax=nuevoAjax();
    ajax.open(“POST”, “buscar.php”,true);
    ajax.onreadystatechange=function() {
    if (ajax.readyState==4) {
    capa.innerHTML = ajax.responseText
    } }
    ajax.setRequestHeader(“Content-Type”,”application/x-www-form-urlencoded”);
    ajax.send(“z=”+variable)

    }

    ///////////////////////////////busqueda.php////////////////////////////////

    require(“conexion.php”);
    $path=”arc/”;
    $handle = opendir($path);
    while (false !== ($file = readdir($handle))) {
    if ($file != “.” && $file != “..”) {
    }
    }
    $consul=mysql_query(“select*from pdf where descripcion=’$_POST[z]'”) or die (“error en la sentencia”);
    while($row=mysql_fetch_array($consul)){
    //$file=$row[“nombre”];
    $enlace = “http://davis.com/sistema/casi/busqueda/arc/”.$row[“nombre”];
    echo ““.$row[“nombre”].”
    “;
    }

  18. Gracias por el aporte. Funciona pero no instantaneamente.

    Para encontrar un texto debo escribirlo y presinar Enter, alli es que hace la busqueda.

    Pense que la busqueda aparecia a medida que unio escribe.

    Atento a cualquier comentario.

    Igualmente Muy valioso.

  19. Funciona muy bien el sistema para búsqueda. Pero sólo una observación: Las tildes no las muestra

  20. Excelente tutorial, quería añadirle que la palabra buscada se resalte con fondo amarillo. Cómo se haría eso?. Muchas Gracias

  21. El código funciona perfectamente!!!

    Muchas Gracias!!!

    Una consulta, se podría que al darle clic sobre el resultado deseado me permita copiar el contenido de su titulo e insertarlo en otro input???

  22. Tú código me marca un error en la linea 37 del aerchico de busuqueda a que se debe?

    Warning: mysql_fetch_array() expects parameter 1 to be resource, boolean given in C:\xampp\htdocs\BusquedaAjax\busqueda.php on line 37

Comments are closed.