Hace un tiempo te mostré un contador de visitas simple en PHP. Ahora te traigo una versión avanzada que brinda además gráficas y reportes.
Reporte de visitas y visitantes en PHP – Contador de visitas web
Como bien sabes, anteriormente hicimos un script para contar los visitantes y visitas, pero fue algo muy simple y no contaba con total precisión.
En el sistema que te mostraré ahora se van a contar las visitas y visitantes, además de mostrar una gráfica con la cantidad de visitas y visitantes que se hayan tenido en un período.
Del mismo modo se van a mostrar las páginas más vistas según determinada fecha, y del mismo modo vamos a ver cómo han visitado determinada página en un rango de fechas.
Todo el sistema que te presentaré es gratuito y open source, así que a través del post colocaré el código fuente.
Reporte de visitas
Reporte de visitas y visitantes en PHP – Contador de visitas web
Comencemos viendo el dashboard en donde podemos ver un resumen de las visitas de los usuarios. Tenemos una gráfica que muestra, a lo largo de un período de tiempo, las visitas y visitantes que hemos tenido.
Nosotros podemos cambiar el período de tiempo ya que por defecto el período es el mes actual de inicio a fin.
Además de ello, tenemos una segunda tarjeta en donde se muestran las páginas más visitadas en una fecha (por defecto hoy) junto con el total de visitas y visitantes. Igualmente podemos cambiar esta fecha para ver el reporte de otro día.
Si queremos podemos ver las estadísticas de una página en específico, filtrando además por fecha:
Visitas y visitantes de una página – Contador de visitas con PHP y JavaScript
Registrar visita
Para registrar una visita y contarla con PHP vamos a usar un poco de JavaScript. Los bots que indexan el contenido o generan la vista previa no ejecutan JavaScript, pero los usuarios legítimos sí. Así que vamos a hacer que el conteo se haga con JavaScript.
Lo único que tienes que hacer es incluir el siguiente código en todos los lugares donde quieras llevar el registro. Solo recuerda configurar correctamente la URL en donde se encuentra registrar_visita.php.
El código hace una petición al servidor con PHP para registrar la visita, usando la función nativa fetch.
(()=>{/*
Script que cuenta la visita y la envía al servidor con PHP
Solo tienes que incluir este script o código en todas las páginas en donde quieras registrar las visitas
y los visitantes
https://parzibyte.me/blog
*/
document.addEventListener("DOMContentLoaded",async()=>{try{// Preferiblemente debería ser la URL absoluta// Ejemplo: http://localhost/contador_visitas_php_avanzado/contador/registrar_visita.phpconst url ="./contador/registrar_visita.php";const payload ={pagina: document.title,url: window.location.href,};const respuestaRaw =awaitfetch(url,{method:"POST",body:JSON.stringify(payload),});const respuesta =await respuestaRaw.json();if(!respuesta){
console.log("Error registrando visita");}}catch(e){
console.log("Error registrando visita: "+ e);}});})();
En mi caso tengo el script de JS y el contador de PHP en el mismo directorio, por lo que puedo referirme al directorio hermano con ./.
Lo que se está guardando en nuestra base de datos es la IP del usuario, la fecha de la visita, el título de la página visitada y la URL de la misma. Pero no todos los datos vienen de un solo lugar.
Del lado del cliente tomamos el título y la URL, pero en el servidor guardamos la fecha junto con la IP del usuario en el siguiente script:
<?phpfunctionregistrarVisita($pagina,$url){$fecha=date("Y-m-d");$ip=$_SERVER["REMOTE_ADDR"]??"";$bd=obtenerConexion();$sentencia=$bd->prepare("INSERT INTO visitas(fecha, ip, pagina, url) VALUES(?, ?, ?, ?)");return$sentencia->execute([$fecha,$ip,$pagina,$url]);}
Ejemplo para contar visita
Por si no quedó claro, te muestro un ejemplo. Yo tengo el código de JavaScript en un archivo llamado contador.js. Luego, en mi página en donde quiero llevar el registro, lo incluyo:
<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Página de contacto</title></head><body><h1>Contacto</h1><ahref="index.html">Ir al inicio</a><p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Suscipit dolorum officiis ab dolores ipsam porro tenetur
eius soluta nobis voluptatibus debitis nulla, totam eveniet ipsa, saepe natus voluptate fuga. Exercitationem.
</p></body><!--
Incluir el script para contar la visita. Así de simple
--><scriptsrc="./contador.js"></script></html>
Y de este modo se va a registrar la visita cada que un usuario la visite, suponiendo que usa JavaScript y un navegador web decente.
Reportes de visitas y visitantes con PHP
Ya vimos cómo registrar la visita, ahora veamos lo necesario para obtener los datos. Lo único que necesitamos es hacer consultas a la tabla que registra las visitas. A continuación veremos las funciones que permiten:
Obtener el conteo de visitas y visitantes
Saber cuáles son las páginas más visitadas en un período de tiempo
Conocer cuántas visitas y visitantes hay en un período de tiempo, día con día
Obtener el registro de visitantes y visitas de una página específica dentro de un período de fechas
Repito que todos son consultas usando GROUP BY, COUNT, ORDER BY y consultas para filtrar las fechas lexicográficamente.
<?phpfunctionfechaInicioYFinDeMes(){$inicio=date("Y-m-01");$fin=date("Y-m-t");return[$inicio,$fin];}functionfechaHoy(){returndate("Y-m-d");}/*
Nota: está limitado a solo traer los 10 primeros registros, ordenados por las veces que se visitaron
*/functionobtenerPaginasVisitadasEnFecha($fecha){$consulta="SELECT COUNT(*) AS conteo_visitas, count(distinct ip) as conteo_visitantes, url, pagina
from visitas where fecha = ?
group by url, pagina
ORDER BY conteo_visitas DESC
LIMIT 10;";$bd=obtenerConexion();$sentencia=$bd->prepare($consulta);$sentencia->execute([$fecha]);return$sentencia->fetchAll();}functionobtenerConteoVisitasYVisitantesDePaginaEnRango($fechaInicio,$fechaFin,$url){return(object)["visitantes"=>obtenerConteoVisitantesDePaginaEnRango($fechaInicio,$fechaFin,$url),"visitas"=>obtenerConteoVisitasDePaginaEnRango($fechaInicio,$fechaFin,$url),];}functionobtenerConteoVisitantesDePaginaEnRango($fechaInicio,$fechaFin,$url){$bd=obtenerConexion();$sentencia=$bd->prepare("SELECT COUNT(DISTINCT ip) AS conteo FROM visitas WHERE fecha >= ? AND fecha <= ? AND url = ?");$sentencia->execute([$fechaInicio,$fechaFin,$url]);return$sentencia->fetchObject()->conteo;}functionobtenerConteoVisitasDePaginaEnRango($fechaInicio,$fechaFin,$url){$bd=obtenerConexion();$sentencia=$bd->prepare("SELECT COUNT(*) AS conteo FROM visitas WHERE fecha >= ? AND fecha <= ? AND url = ?");$sentencia->execute([$fechaInicio,$fechaFin,$url]);return$sentencia->fetchObject()->conteo;}functionobtenerVisitantesDePaginaEnRango($fechaInicio,$fechaFin,$url){$bd=obtenerConexion();$sentencia=$bd->prepare("SELECT fecha, COUNT(DISTINCT ip) AS conteo FROM visitas WHERE fecha >= ? AND fecha <= ? AND url = ? GROUP BY fecha");$sentencia->execute([$fechaInicio,$fechaFin,$url]);return$sentencia->fetchAll();}functionobtenerVisitasDePaginaEnRango($fechaInicio,$fechaFin,$url){$bd=obtenerConexion();$sentencia=$bd->prepare("SELECT fecha, COUNT(*) AS conteo FROM visitas WHERE fecha >= ? AND fecha <= ? AND url = ? GROUP BY fecha");$sentencia->execute([$fechaInicio,$fechaFin,$url]);return$sentencia->fetchAll();}functionobtenerConteoVisitasYVisitantesEnRango($fechaInicio,$fechaFin){return(object)["visitantes"=>obtenerConteoVisitantesEnRango($fechaInicio,$fechaFin),"visitas"=>obtenerConteoVisitasEnRango($fechaInicio,$fechaFin),];}functionobtenerConteoVisitantesEnRango($fechaInicio,$fechaFin){$bd=obtenerConexion();$sentencia=$bd->prepare("SELECT COUNT(DISTINCT ip) AS conteo FROM visitas WHERE fecha >= ? AND fecha <= ?");$sentencia->execute([$fechaInicio,$fechaFin]);return$sentencia->fetchObject()->conteo;}functionobtenerConteoVisitasEnRango($fechaInicio,$fechaFin){$bd=obtenerConexion();$sentencia=$bd->prepare("SELECT COUNT(*) AS conteo FROM visitas WHERE fecha >= ? AND fecha <= ?");$sentencia->execute([$fechaInicio,$fechaFin]);return$sentencia->fetchObject()->conteo;}functionobtenerVisitantesEnRango($fechaInicio,$fechaFin){$bd=obtenerConexion();$sentencia=$bd->prepare("SELECT fecha, COUNT(DISTINCT ip) AS conteo FROM visitas WHERE fecha >= ? AND fecha <= ? GROUP BY fecha");$sentencia->execute([$fechaInicio,$fechaFin]);return$sentencia->fetchAll();}functionobtenerVisitasEnRango($fechaInicio,$fechaFin){$bd=obtenerConexion();$sentencia=$bd->prepare("SELECT fecha, COUNT(*) AS conteo FROM visitas WHERE fecha >= ? AND fecha <= ? GROUP BY fecha");$sentencia->execute([$fechaInicio,$fechaFin]);return$sentencia->fetchAll();}functionregistrarVisita($pagina,$url){$fecha=date("Y-m-d");$ip=$_SERVER["REMOTE_ADDR"]??"";$bd=obtenerConexion();$sentencia=$bd->prepare("INSERT INTO visitas(fecha, ip, pagina, url) VALUES(?, ?, ?, ?)");return$sentencia->execute([$fecha,$ip,$pagina,$url]);}functionobtenerVariableDelEntorno($key){if(defined("_ENV_CACHE")){$vars=_ENV_CACHE;}else{$file="env.php";if(!file_exists($file)){thrownewException("El archivo de las variables de entorno ($file) no existe. Favor de crearlo");}$vars=parse_ini_file($file);define("_ENV_CACHE",$vars);}if(isset($vars[$key])){return$vars[$key];}else{thrownewException("La clave especificada (".$key.") no existe en el archivo de las variables de entorno");}}functionobtenerConexion(){$password=obtenerVariableDelEntorno("MYSQL_PASSWORD");$user=obtenerVariableDelEntorno("MYSQL_USER");$dbName=obtenerVariableDelEntorno("MYSQL_DATABASE_NAME");$database=newPDO('mysql:host=localhost;dbname='.$dbName,$user,$password);$database->query("set names utf8;");$database->setAttribute(PDO::ATTR_EMULATE_PREPARES,FALSE);$database->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);$database->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_OBJ);return$database;}
Como puedes ver en este código de PHP, tenemos varias consultas (ya sea INSERT o SELECT) a MySQL / MariaDB. Además, existen algunas funciones ayudantes que leen variables del archivo de entorno o trabajan con fechas.
Por cierto, cada IP distinta cuenta como un visitante distinto. Ya que un visitante siempre puede visitar distintas páginas, pero seguirá siendo un solo visitante aunque lleve varias visitas.
Código fuente del dashboard
La página principal en donde se muestra el reporte de visitas y visitantes está hecha con Bulma. El código es el siguiente:
<?phpinclude_once"encabezado.php";?><?phpinclude_once"funciones.php";$hoy=fechaHoy();list($inicio,$fin)=fechaInicioYFinDeMes();if(isset($_GET["inicio"])){$inicio=$_GET["inicio"];}if(isset($_GET["fin"])){$fin=$_GET["fin"];}if(isset($_GET["hoy"])){$hoy=$_GET["hoy"];}$visitasYVisitantes=obtenerConteoVisitasYVisitantesEnRango($hoy,$hoy);$paginas=obtenerPaginasVisitadasEnFecha($hoy);$visitantes=obtenerVisitantesEnRango($inicio,$fin);$visitas=obtenerVisitasEnRango($inicio,$fin);?><sectionclass="section"><divclass="columns"><divclass="column"><divclass="card"><headerclass="card-header"><pclass="card-header-title">
Estadísticas entre <?phpecho$inicio?> y <?phpecho$fin?></p></header><divclass="card-content"><divclass="content"><formaction="dashboard.php"><inputtype="hidden"name="hoy"value="<?phpecho$hoy?>"><divclass="field is-grouped"><pclass="control is-expanded"><label>Desde: </label><inputclass="input"type="date"name="inicio"value="<?phpecho$inicio?>"></p><pclass="control is-expanded"><label>Hasta: </label><inputclass="input"type="date"name="fin"value="<?phpecho$fin?>"></p><pclass="control"><!--La etiqueta es invisible a propósito para que tome el espacio y alinee el botón--><labelstyle="color: white;">ª</label><inputtype="submit"value="OK"class="button is-success input"></p></div></form><canvasid="grafica"></canvas></div></div><footerclass="card-footer"><smallclass="mx-2 my-2">By parzibyte</small></footer></div></div><divclass="column is-one-third "><divclass="card"><headerclass="card-header"><pclass="card-header-title">
Estadísticas de <?phpecho$hoy?></p></header><divclass="card-content"><divclass="content"><formaction="dashboard.php"class="mb-2"><inputtype="hidden"name="inicio"value="<?phpecho$inicio?>"><inputtype="hidden"name="fin"value="<?phpecho$fin?>"><divclass="field is-grouped"><pclass="control is-expanded"><label>Fecha: </label><inputclass="input"type="date"name="hoy"value="<?phpecho$hoy?>"></p><pclass="control"><!--La etiqueta es invisible a propósito para que tome el espacio y alinee el botón--><labelstyle="color: white;">ª</label><inputtype="submit"value="OK"class="button is-success input"></p></div></form><divclass="field is-grouped is-grouped-multiline"><divclass="control"><divclass="tags has-addons"><spanclass="tag is-success is-large">Visitas</span><spanclass="tag is-info is-large"><?phpecho$visitasYVisitantes->visitas?></span></div></div><divclass="control"><divclass="tags has-addons"><spanclass="tag is-warning is-large">Visitantes</span><spanclass="tag is-info is-large"><?phpecho$visitasYVisitantes->visitantes?></span></div></div></div><tableclass="table"><thead><tr><th>Página</th><th>Visitas</th><th>Visitantes</th><th>Estadísticas</th></tr></thead><tbody><?phpforeach($paginasas$pagina){?><tr><td><atarget="_blank"href="<?phpecho$pagina->url?>"><?phpecho$pagina->pagina?></a></td><td><?phpecho$pagina->conteo_visitas?></td><td><?phpecho$pagina->conteo_visitantes?></td><td><aclass="button is-info"href="visitas_url.php?url=<?phpechourlencode($pagina->url)?>"><iclass="fa fa-chart-area"></i></a></td></tr><?php}?></tbody></table></div></div><footerclass="card-footer"><smallclass="mx-2 my-2">By parzibyte</small></footer></div></div></div></section><scripttype="text/javascript">// Pasar variable de PHP a JSconst visitantes =<?phpechojson_encode($visitantes)?>;const visitas =<?phpechojson_encode($visitas)?>;// Obtener una referencia al elemento canvas del DOMconst $grafica = document.querySelector("#grafica");// Las etiquetas son las que van en el eje X. // Podemos mapear visitas o visitantes, ya que solo necesitamos las fechasconst etiquetas = visitas.map(visita=> visita.fecha);// Podemos tener varios conjuntos de datosconst datosVisitas ={label:"Visitas",data: visitas.map(visita=> visita.conteo),backgroundColor:'rgba(237,78,136, 0.2)',// Color de fondoborderColor:'rgba(237,78,136, 1)',// Color del bordeborderWidth:1,// Ancho del borde};const datosVisitantes ={label:"Visitantes",data: visitantes.map(visitante=> visitante.conteo),backgroundColor:'rgba(93,82,247, 0.2)',// Color de fondoborderColor:'rgba(93,82,247,1)',// Color del bordeborderWidth:1,// Ancho del borde};newChart($grafica,{type:'line',// Tipo de gráficadata:{labels: etiquetas,datasets:[
datosVisitas,
datosVisitantes,// Aquí más datos...]},options:{scales:{yAxes:[{ticks:{beginAtZero:true}}],},}});</script><?phpinclude_once"pie.php"?>
Para lograr que se muestre la gráfica y la lista de páginas visitadas estamos invocando a las funciones definidas en el archivo presentado con anterioridad y renderizando los datos a partir de lo que los métodos devuelvan.
Por cierto, el código que muestra las estadísticas de visitas de una página en un período de tiempo es el siguiente:
<?phpinclude_once"encabezado.php";?><?phpif(!isset($_GET["url"])){exit("No hay URL");}$url=urldecode($_GET["url"]);include_once"funciones.php";$hoy=fechaHoy();list($inicio,$fin)=fechaInicioYFinDeMes();if(isset($_GET["inicio"])){$inicio=$_GET["inicio"];}if(isset($_GET["fin"])){$fin=$_GET["fin"];}$visitasYVisitantes=obtenerConteoVisitasYVisitantesDePaginaEnRango($inicio,$fin,$url);$visitasYVisitantes=obtenerConteoVisitasYVisitantesEnRango($hoy,$hoy);$visitantes=obtenerVisitantesDePaginaEnRango($inicio,$fin,$url);$visitas=obtenerVisitasDePaginaEnRango($inicio,$fin,$url);?><sectionclass="section"><divclass="columns"><divclass="column"><divclass="card"><headerclass="card-header"><pclass="card-header-title">
Estadísticas para <?phpecho$url?> entre <?phpecho$inicio?> y <?phpecho$fin?></p></header><divclass="card-content"><divclass="content"><aclass="button is-info mb-2"href="dashboard.php"><iclass="fa fa-arrow-left"></i>
Volver</a><formaction="visitas_url.php"><inputtype="hidden"value="<?phpecho$url?>"name="url"><divclass="field is-grouped"><pclass="control is-expanded"><label>Desde: </label><inputclass="input"type="date"name="inicio"value="<?phpecho$inicio?>"></p><pclass="control is-expanded"><label>Hasta: </label><inputclass="input"type="date"name="fin"value="<?phpecho$fin?>"></p><pclass="control"><!--La etiqueta es invisible a propósito para que tome el espacio y alinee el botón--><labelstyle="color: white;">ª</label><inputtype="submit"value="Filtrar"class="button is-success input"></p></div></form><canvasid="grafica"></canvas></div></div><footerclass="card-footer"><smallclass="mx-2 my-2">By parzibyte</small></footer></div></div></div></section><scripttype="text/javascript">// Pasar variable de PHP a JSconst visitantes =<?phpechojson_encode($visitantes)?>;const visitas =<?phpechojson_encode($visitas)?>;// Obtener una referencia al elemento canvas del DOMconst $grafica = document.querySelector("#grafica");// Las etiquetas son las que van en el eje X. // Podemos mapear visitas o visitantes, ya que solo necesitamos las fechasconst etiquetas = visitas.map(visita=> visita.fecha);// Podemos tener varios conjuntos de datosconst datosVisitas ={label:"Visitas",data: visitas.map(visita=> visita.conteo),backgroundColor:'rgba(237,78,136, 0.2)',// Color de fondoborderColor:'rgba(237,78,136, 1)',// Color del bordeborderWidth:1,// Ancho del borde};const datosVisitantes ={label:"Visitantes",data: visitantes.map(visitante=> visitante.conteo),backgroundColor:'rgba(93,82,247, 0.2)',// Color de fondoborderColor:'rgba(93,82,247,1)',// Color del bordeborderWidth:1,// Ancho del borde};newChart($grafica,{type:'line',// Tipo de gráficadata:{labels: etiquetas,datasets:[
datosVisitas,
datosVisitantes,// Aquí más datos...]},options:{scales:{yAxes:[{ticks:{beginAtZero:true}}],},}});</script><?phpinclude_once"pie.php"?>
Instalación del software
Te dejo el código fuente completo en GitHub. Lo verdaderamente importante es el script que hace el registro de la visita y todo lo que está dentro de la carpeta llamada contador.
Una vez que tengas el código, las instrucciones son:
Dentro de contador, crea el archivo llamado env.php basándote en el archivo env.ejemplo.php
Crea una base de datos en MySQL / MariaDB y ten a la mano el usuario y contraseña para acceder a la misma
Coloca las credenciales de acceso a la base de datos dentro de env.php
Importa las tablas que están en esquema.sql y crea los índices
Ahora solo tienes que incluir a contador.js en cualquier lugar en donde quieras llevar registro de las visitas y visitantes. Recuerda configurar la ruta en caso de que coloques los archivos de manera distinta
Disfruta
Por aquí te dejo con más contenido sobre PHP, JS y MySQL.
Estoy aquí para ayudarte
Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto
No te pierdas ninguno de mis posts
Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
Hoy voy a mostrarte cómo contar las visitas de usuarios usando PHP. Será un contador sin bases de datos ni dependencias, usando solo PHP. Te aviso desde ahora que es algo muy simple y sencillo. Más adelante te traeré un ejemplo más avanzado y preciso, pero por ahora lo vamos…
Introducción En una clase que acabo de tomar tuve que investigar cómo respaldar una base de datos de MySQL desde PHP. Lo que terminé logrando es un script que hace un respaldo completo y genera un archivo que se guarda en el disco duro. Es decir, utilizando únicamente PHP respaldar…
En este post sobre la creación de gráficas (de línea, barras, pastel, etcétera) usando la librería Chart.js te enseñaré cómo crear una gráfica con datos traídos con AJAX. El lado del servidor estará escrito en PHP aunque estos datos pueden ser traídos desde cualquier API o endpoint. Así que básicamente…
En "javascript"
3 comentarios en “PHP – Contador de visitas avanzado con gráficas y reporte”
Sergio Gattelet
Hola .. muy bueno el sistema .. lo voy a implementar en mi pagina ..
quisiera consultarte si se podria como opcion para una proxima version .. implementar el tiempo que cada usuario permanece en la pagina .. esto seria de gran valor ..
Hola .. muy bueno el sistema .. lo voy a implementar en mi pagina ..
quisiera consultarte si se podria como opcion para una proxima version .. implementar el tiempo que cada usuario permanece en la pagina .. esto seria de gran valor ..
como lo implementarias en una web diseñada con laravel?
Escribiendo el código necesario para adaptarlo