Crear un reporte con FPDF usando PHP y MySQL

Stay hungry, stay foolish

Steve Jobs

En este post realizaremos un historial clínico de un paciente, en el cual contendrá los datos generales del paciente y un listado de las consultas médicas que realizo, el historial estará en formato PDF. Para realizar esto utilizaremos: el lenguaje de programación PHP, el gestor de base de datos MySQL y la librería FPDF. Lo primero es realizar nuestra base de datos la cual llamaremos clínica, en donde contendrá las siguientes tablas y la siguiente estructura. Tabla pacientes

CREATE TABLE IF NOT EXISTS `pacientes` (
`id_paciente` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`clave` varchar(10) NOT NULL,
`nombre` varchar(80) NOT NULL,
`apellido_paterno` varchar(80) NOT NULL,
`apellido_materno` varchar(80) NOT NULL,
`sexo` varchar(2) NOT NULL,
`domicilio` text NOT NULL,
PRIMARY KEY (`id_paciente`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

Tabla médicos

CREATE TABLE IF NOT EXISTS `medicos` (
`id_medico` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`cedula` varchar(10) NOT NULL,
`nombre_medico` varchar(200) NOT NULL,
PRIMARY KEY (`id_medico`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

Tabla consultas_medicas

CREATE TABLE IF NOT EXISTS `consultas_medicas` (
`id_consulta` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`fecha_consulta` date NOT NULL,
`id_paciente` int(5) NOT NULL,
`id_medico` int(5) NOT NULL,
`consultorio` varchar(20) NOT NULL,
`diagnostico` text NOT NULL,
PRIMARY KEY (`id_consulta`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

Des pues creamos los siguientes archivos: conexion.php Contiene los parámetros para conectarse a la base de datos y realiza las conexiones.

<php class DB{ 	var $conect; 	var $BaseDatos; 	var $Servidor; 	var $Usuario; 	var $Clave; 	function DB(){ 		$this--->BaseDatos = "clinica";
$this->Servidor = "localhost";
$this->Usuario = "clinic";
$this->Clave = "clinica123";
}

function conectar() {
if(!($con=@mysql_connect($this->Servidor,$this->Usuario,$this->Clave))){
echo"Error al conectar a la base de datos";
exit();
}
if (!@mysql_select_db($this->BaseDatos,$con)){
echo "Error al seleccionar la base de datos";
exit();
}
$this->conect=$con;
return true;
}
}
?>

index.php Realiza el listado de los pacientes en la base de datos y envía la orden de generar el archivo PDF, para ello manda el identificador del paciente por medio de la url y lo recibe el archivo reporte_historial.php por $_GET.

<?php
include_once("conexion.php");

$con = new DB;
$pacientes = $con->conectar();
$strConsulta = "SELECT id_paciente, clave, nombre, apellido_paterno, apellido_materno from pacientes";
$pacientes = mysql_query($strConsulta);
$numfilas = mysql_num_rows($pacientes);

echo '<table cellpadding="0" cellspacing="0" width="100%">';
echo '<thead><tr><td>No.</td><td>CLAVE</td><td>NOMBRE</td><td>HISTORIAL</td></tr></thead>';
for ($i=0; $i<$numfilas; $i++)
{
$fila = mysql_fetch_array($pacientes);
$numlista = $i + 1;
echo '<tr><td>'.$numlista.'</td>';
echo '<td>'.$fila['clave'].'</td>';
echo '<td>'.$fila['nombre'].' '.$fila['apellido_paterno'].' '.$fila['apellido_materno'].'</td>';
echo '<td><a href="reporte_historial.php?id='.$fila['id_paciente'].'">ver</a></td></tr>';
}
echo "</table>";
?>

reporte_historial.php Realiza el reporte mediante la librería FPDF. 1. En la primera parte llamamos a la libreria fpdf y al archivo conexion para conectar php con la base de datos.

<?php // incluimos la libreria fpdf
require('fpdf/fpdf.php');
// incluimos la conexion a la base de datos
require('conexion.php');

2. Le insertamos una clase que tiene las siguientes funciones: crear tablas, encabezado y pie. Esta clase fue tomada de los tutoriales de la página oficial de la librería FPDF. Ya que la función multiCell no permite ordenarse por tablas y la función Cell solo funciona en un solo renglón y no mostraría cuando hay muchos más caracteres.

 class PDF extends FPDF { var $widths; var $aligns; function SetWidths($w) { 	$this->widths=$w;
}

function SetAligns($a)
{
$this->aligns=$a;
}

function Row($data)
{
$nb=0;
for($i=0;$iNbLines($this->widths[$i],$data[$i]));
$h=4*$nb;
$this->CheckPageBreak($h);
for($i=0;$iwidths[$i];
$a=isset($this->aligns[$i]) ? $this->aligns[$i] : 'L';
$x=$this->GetX();
$y=$this->GetY();
$this->Rect($x,$y,$w,$h);
$this->MultiCell($w,4,$data[$i],0,$a);
$this->SetXY($x+$w,$y);
}
$this->Ln($h);
}

function CheckPageBreak($h)
{
if($this->GetY()+$h>$this->PageBreakTrigger)
$this->AddPage($this->CurOrientation);
}

function NbLines($w,$txt)
{
$cw=&$this->CurrentFont['cw'];
if($w==0)
$w=$this->w-$this->rMargin-$this->x;
$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
$s=str_replace("\r",'',$txt);
$nb=strlen($s);
if($nb>0 and $s[$nb-1]=="\n")
$nb--;
$sep=-1;
$i=0;
$j=0;
$l=0;
$nl=1;
while($i$wmax)
{
if($sep==-1)
{
if($i==$j)
$i++;
}
else
$i=$sep+1;
$sep=-1;
$j=$i;
$l=0;
$nl++;
}
else
$i++;
}
return $nl;
}

function Header()
{
$this->SetFont('Arial','',10);
$this->Text(65,14,'Clinica el sol naciente',0,'C', 0);
$this->Ln(30);
}

function Footer()
{
$this->SetY(-15);
$this->SetFont('Arial','B',8);
$this->Cell(100,10,'Historial medico',0,0,'L');
}
}

3. Recibir el id del paciente, para ello lo obtenemos mediante $_GET.

$paciente= $_GET['id'];

4. Mostrar los datos del paciente.

// creamos el objeto FPDF
$pdf=new PDF('L','mm','Letter'); // vertical, milimetros y tamaño
$pdf->Open();
$pdf->AddPage(); // agregamos la pagina
$pdf->SetMargins(20,20,20); // definimos los margenes en este caso estan en milimetros
$pdf->Ln(10); // dejamos un pequeño espacio de 10 milimetros

// Realizamos la consulta
$con = new DB;
$pacientes = $con->conectar();
// $paciente contiene el id del paciente a consultar, obtiene los datos de la tabla pacientes
$strConsulta = "SELECT * from pacientes where id_paciente =  '$paciente'";
$pacientes = mysql_query($strConsulta);
$fila = mysql_fetch_array($pacientes);
// listamos los datos con Cell
$pdf->SetFont('Arial','',12); // definimos el tipo de letra y el tamaño
// Cell esta formado por (posición de inicio, ancho, texto, borde, cambio de linea, posición del texto)
$pdf->Cell(0,6,'Clave: '.$fila['clave'],0,1);
$pdf->Cell(0,6,'Nombre: '.$fila['nombre'].' '.$fila['apellido_paterno'].' '.$fila['apellido_materno'],0,1);
$pdf->Cell(0,6,'Sexo: '.$fila['sexo'],0,1);
$pdf->Cell(0,6,'Domicilio: '.$fila['domicilio'],0,1);
$pdf->Ln(10);

5. Listar el historial del paciente Para listar el historial medico en forma de tablas llamaremos a las funciones antes declaradas de la siguientes forma, primero creamos el encabezado de nuestra tabla de la siguiente manera:

// Para realizar esto utilizaremos la funcion Row()
$pdf->SetFont('Arial','',10);
// tipo y tamaño de letra
$pdf->SetWidths(array(60, 60, 60, 60));
// Definimos el tamaño de las columnas, tomando en cuenta que las declaramos en milimetros, ya que nuestra hoja esta en milimetros.
$pdf->Row(array('FECHA', 'MEDICO', 'CONSULTORIO', 'DIAGNOSTICO'));
// creamos nuestra fila con las columnas fecha(fecha de la visita al medico), medico(nombre del medico que nos atendio), consultorio y el diagnostico en esa visita.

Despues de crear el encabezado de nuestra tabla obtendremos el historial desde la base de datos y lo mostraremos en nuestro archivo pdf creado, seguiremos utilizando la función Row().

$historial = $con->conectar(); // Creamos nuestra conexión a la base de datos
// Realizamos nuestra consulta
$strConsulta = "SELECT consultas_medicas.fecha_consulta, consultas_medicas.consultorio, consultas_medicas.diagnostico, medicos.nombre_medico
FROM consultas_medicas
Inner Join pacientes ON consultas_medicas.id_paciente = pacientes.id_paciente
Inner Join medicos ON consultas_medicas.id_medico = medicos.id_medico
WHERE pacientes.id_paciente = '$paciente'";
// ejecutamos la consulta
$historial = mysql_query($strConsulta);
// listamos la tabla de historial de visitas de cada paciente
$numfilas = mysql_num_rows($historial);
for ($i=0; $iRow(array($fila['fecha_consulta'], $fila['consultorio'], $fila['nombre_medico'], $fila['diagnostico']));
}
//La ultima linea
$pdf->Output(); lo que hace es cerrar el archivo y enviarlo al navegador.

Actualizacones:

  • Se colorean la filas de titulo y las de datos en el historial en pdf, para realizar esto se le agrego el valor true al parametro fill dentro de la función MultiCell que es la que permite heredar de SetFillColor el color de fondo en formato rgb.

A continuación les dejo el código y la base de datos para descargar. Descarga: Mediafire – reporte_clinicaMega – reporte_clinica.

código de respuesta al comentario de por que tantos echo:

<?php
include_once("conexion.php");
 
$con = new DB;
$pacientes = $con->conectar();
$strConsulta = "SELECT id_paciente, clave, nombre, apellido_paterno, apellido_materno from pacientes";
$pacientes = mysql_query($strConsulta);
$numfilas = mysql_num_rows($pacientes);
 ?>
<table cellpadding="0" cellspacing="0" width="100%">
<thead><tr><td>No.</td><td>CLAVE</td><td>NOMBRE</td><td>HISTORIAL</td></tr></thead>
<?php
for ($i=0; $i<$numfilas; $i++)
{
$fila = mysql_fetch_array($pacientes);
$numlista = $i + 1;
?>
<tr><td><?php echo $numlista; ?></td>';
<td><?php echo $fila['clave']; ?></td>';
<td><?php echo $fila['nombre'].' '.$fila['apellido_paterno'].' '.$fila['apellido_materno']; ?></td>
<td><a href="reporte_historial.php?id=<?php echo $fila['id_paciente']; ?>">ver</a></td></tr>
<?php
}
?>
</table>

Actualización a MySQLi

// Archivo conexion.php
class Conexion{
    //Creamos un método estático que no necesita ser instanciado
    public static function con(){
     
    //new mysqli creamos o instanciamos el objeto mysqli
    //new mysqli('servidor','usuario','contraseña','nombre de la BD');
        $con=new mysqli("localhost", "root", "", "clinica");
             
       //llamamos a la conexión y hacemos una consulta para utilizar UTF-8
        $con->set_charset('utf8');
 
       //devolvemos la conexión para que pueda ser utilizada en otros métodos
        return $con; 
    }
}

El listado dentro del archivo index.php

include_once("conexion.php");

	$con = new Conexion;
	$conectar = $con->con();
	$strConsulta = "SELECT id_paciente, clave, nombre, apellido_paterno, apellido_materno from pacientes";
	$pacientes = $conectar->query($strConsulta);
	$numlista = 0;
	
	echo '<table cellpadding="0" cellspacing="0" width="100%">';
	echo '<thead><tr><td>No.</td><td>CLAVE</td><td>NOMBRE</td><td>HISTORIAL</td></tr></thead>';
	foreach ($pacientes as $fila)
	{
		$numlista++;
		echo '<tr><td>'.$numlista.'</td>';
		echo '<td>'.$fila['clave'].'</td>';
        echo '<td>'.$fila['nombre'].' '.$fila['apellido_paterno'].' '.$fila['apellido_materno'].'</td>';
		echo '<td><a href="reporte_historial.php?id='.$fila['id_paciente'].'">ver</a></td></tr>';
	}
	echo "</table>";

EL reporte_historial.php

require('fpdf/fpdf.php');
require('conexion.php');
class PDF extends FPDF
{
var $widths;
var $aligns;

function SetWidths($w)
{
	$this->widths=$w;
}

function SetAligns($a)
{
	$this->aligns=$a;
}

function Row($data)
{
	$nb=0;
	for($i=0;$i<count($data);$i++)
		$nb=max($nb,$this->NbLines($this->widths[$i],$data[$i]));
	$h=5*$nb;
	//Issue a page break first if needed
	$this->CheckPageBreak($h);
	//Draw the cells of the row
	for($i=0;$i<count($data);$i++)
	{
		$w=$this->widths[$i];
		$a=isset($this->aligns[$i]) ? $this->aligns[$i] : 'L';
		//Save the current position
		$x=$this->GetX();
		$y=$this->GetY();		
		$this->Rect($x,$y,$w,$h);
		$this->MultiCell($w,5,$data[$i],0,$a,'true');
		//Put the position to the right of the cell
		$this->SetXY($x+$w,$y);
	}
	$this->Ln($h);
}

function CheckPageBreak($h)
{
	if($this->GetY()+$h>$this->PageBreakTrigger)
		$this->AddPage($this->CurOrientation);
}

function NbLines($w,$txt)
{
	$cw=&$this->CurrentFont['cw'];
	if($w==0)
		$w=$this->w-$this->rMargin-$this->x;
	$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
	$s=str_replace("\r",'',$txt);
	$nb=strlen($s);
	if($nb>0 and $s[$nb-1]=="\n")
		$nb--;
	$sep=-1;
	$i=0;
	$j=0;
	$l=0;
	$nl=1;
	while($i<$nb)
	{
		$c=$s[$i];
		if($c=="\n")
		{
			$i++;
			$sep=-1;
			$j=$i;
			$l=0;
			$nl++;
			continue;
		}
		if($c==' ')
			$sep=$i;
		$l+=$cw[$c];
		if($l>$wmax)
		{
			if($sep==-1)
			{
				if($i==$j)
					$i++;
			}
			else
				$i=$sep+1;
			$sep=-1;
			$j=$i;
			$l=0;
			$nl++;
		}
		else
			$i++;
	}
	return $nl;
}

function Header()
{
	$this->SetFont('Arial','',10);
	$this->Text(20,14,'Historial clinico',0,'C', 0);
	$this->Ln(30);
}

function Footer()
{
	$this->SetY(-15);
	$this->SetFont('Arial','B',8);
	$this->Cell(100,10,'Historial medico',0,0,'L');
}

}

	$paciente= $_GET['id'];
	$con = new Conexion;
	$conectar = $con->con();	
	$strConsulta = "SELECT * from pacientes where id_paciente =  '$paciente'";
	$pacientes = $conectar->query($strConsulta);
	$fila = $pacientes->fetch_array();

	$pdf=new PDF('L','mm','Letter');
	$pdf->Open();
	$pdf->AddPage();
	$pdf->SetMargins(20,20,20);
	$pdf->Ln(10);

    $pdf->SetFont('Arial','',12);
    $pdf->Cell(0,6,'Clave: '.$fila['clave'],0,1);
	$pdf->Cell(0,6,'Nombre: '.$fila['nombre'].' '.$fila['apellido_paterno'].' '.$fila['apellido_materno'],0,1);
	$pdf->Cell(0,6,'Sexo: '.$fila['sexo'],0,1); 
	$pdf->Cell(0,6,'Domicilio: '.$fila['domicilio'],0,1); 
	
	$pdf->Ln(10);
	
	$pdf->SetWidths(array(65, 60, 55, 50, 20));
	$pdf->SetFont('Arial','B',10);
	$pdf->SetFillColor(85,107,47);
    $pdf->SetTextColor(255);

		for($i=0;$i<1;$i++)
			{
				$pdf->Row(array('FECHA', 'MEDICO', 'CONSULTORIO', 'DIAGNOSTICO'));
			}
	
	$strConsulta = "SELECT consultas_medicas.fecha_consulta, consultas_medicas.consultorio, consultas_medicas.diagnostico, medicos.nombre_medico 
	FROM consultas_medicas 
	Inner Join pacientes ON consultas_medicas.id_paciente = pacientes.id_paciente 
	Inner Join medicos ON consultas_medicas.id_medico = medicos.id_medico
	WHERE pacientes.id_paciente = '$paciente'";
	
	$historial = $conectar->query($strConsulta);
	$numfilas = $historial->num_rows;
	
	for ($i=0; $i<$numfilas; $i++)
		{
			$fila = $historial->fetch_array();
			$pdf->SetFont('Arial','',10);
			
			if($i%2 == 1)
			{
				$pdf->SetFillColor(153,255,153);
    			$pdf->SetTextColor(0);
				$pdf->Row(array($fila['fecha_consulta'], $fila['nombre_medico'], $fila['consultorio'], $fila['diagnostico']));
			}
			else
			{
				$pdf->SetFillColor(102,204,51);
    			$pdf->SetTextColor(0);
				$pdf->Row(array($fila['fecha_consulta'], $fila['nombre_medico'], $fila['consultorio'], $fila['diagnostico']));
			}
		}

$pdf->Output();

Descargar reporte con mysqli.