Descarga/Visualización de dato byteA (pdf) desde un boton de un cuadro

Hola! en la base de datos tengo tuplas que contienen un campo byteA.
Este dato es un PDF.
Muestro los datos de la tabla y si ese campo no se nulo en el cuadro detallado muestro un botón.
Al presionar ese botón debería poder verse en una pestaña o ventana extra el PDF asociado a dicha tupla.

Para una sola tupla en particular, pude realizar esta tarea, mostrando un enlace a la url del pdf que se crea al editar el registro en un formulario:


	$datos = $this->get_relacion()->tabla('docentes')->get();
	$pdf = $this->get_relacion()->tabla('docentes')->get_blob('cv');
	if (isset($pdf)) {
		manipulacion_pdf::crear_archivo_temporal_pdf($this->s__temp_archivo_pdf, $pdf);
		$datos['cv'] = "<a href='{$this->s__temp_archivo_pdf['url']}' target='_blank'>PDF Asociado</a>";
	} else {
		$datos['cv'] = null;
	}
	$form->set_datos($datos);

Este código funciona.

Por otro lado, al intentar algo similar en el botón de cuadro, no he podido hacerlo:


function evt__cuadro__pdf_asociado ($seleccion)
{
	$this->dep('ordenanzas')->cargar($seleccion);
	$pdf = $this->dep('ordenanzas')->get_blob('pdf');
	if (isset($pdf)) {
		$pdf_temp = manipulacion_pdf::crear_archivo_temporal_pdf($this->s__temp_archivo_pdf, $pdf);
		if (isset($this->s__temp_archivo_pdf)) {
			header('Content-Description: File Transfer');
			header('Content-Type: application/octet-stream');
			header('Content-Disposition: attachment; filename='.basename($this->s__temp_archivo_pdf['path']));
			header('Content-Transfer-Encoding: binary');
			header('Expires: 0');
			header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
			header('Pragma: public');
			header('Content-Length: ' . filesize($this->s__temp_archivo_pdf['path']));
			ob_clean();
			flush();
			readfile($this->s__temp_archivo_pdf['path']);
			exit();
		}
	}
}

No funciona, mostrando basura en la página.
Sin embargo, el PDF se descarga correctamente en la carpeta www/temp.

He probado con:


header("Content-Type: application/force-download");
header('Content-Disposition: attachment;
filename="'.basename($this->s__temp_archivo_pdf['path']));
header("Content-Transfer-Encoding: binary");
header('Cache-Control: private');
header('Pragma: no-cache');
header('Expires: 0');
readfile($this->s__temp_archivo_pdf['path']);

o con:


header("Content-Type: application/pdf");

obteniendo siempre el mismo resultado.

He querido probar de hacer un intermedio entre las 2 alternativas y que el botón simule un click en un enlace con algo como


toba::vinculador()->navegar_a({proyecto}, $this->s__temp_archivo_pdf['url']);

obligandolo a navegar a una página en blanco con el PDF como contenido, ya que creo sería la solución ideal, pero no he podido obtener ningún resultado.

Alguna idea?

Hola Martin,

te diria que si pensas previsualizar el pdf en una pestaña o ventana nueva, no utilices la misma operacion, esto es… que le vinculo en el cuadro te lleve a otro lado y en el item de destino haces lo que haga falta.

Tene en cuenta que el procesamiento normal, va a enviar los headers cuando intente sacar el menu de la aplicacion asi que quizas para cuando llega al evento… si no activaste el retraso de headers eso ya se envio y por tanto se espera HTML, no el formato pdf. Por tanto, te recomendaria que le especifiques un servicio a dicho vinculo o como te dije arriba, que directamente utilices un item distinto.

Finalmente, no entiendo mucho la existencia de esta sentencia:

if (isset($this->s__temp_archivo_pdf)) 

Dicha variable no la pasas como parametro a la funcion “crear_archivo_temporal_pdf” para explicitar el path/url donde va a quedar el archivo?, ciertamente va a estar seteada en ese caso.

Saludos

Entiendo la idea.

Genero el PDF desde la base de datos.
Llamo a una operacion de PHP plano que genere el header.
Entiendo que podria llamarla de la forma:


toba::vinculador()->navegar_a({proyecto}, {operacion php_plana}, [archivopdf => $this->s__temp_archivo_pdf['url']]);

Como hago para capturar el parámetro en archivopdf en el php_plano?

Anteriormente he hecho algo similar con un txt, pero no sé si aplicaría:


<?php
$sql = "SELECT ...";
$datos			= toba::db()->consultar($sql);
$temp_fecha		= date('Ymd-Hi');
$temp_archivo	= toba::proyecto()->get_www_temp($temp_fecha.'.txt');
$archivo		= fopen($temp_archivo['path'], 'wb');
$cantidad		= count($datos);
foreach ($datos as $iteracion=>$fila) {
	if (isset($fila['dato']) && $fila['dato'] != '') {
		$texto = $fila['dato'];
		if ($iteracion < $cantidad - 1) {
			$texto .= "\n";
		}
		fwrite($archivo, $texto);
	}
}
fclose($archivo);
header("Content-Type: application/force-download");
header('Content-Disposition: attachment; filename="'.basename($temp_archivo['url']).'"');
header("Content-Transfer-Encoding: binary");
header('Cache-Control: private');
header('Pragma: no-cache');
header('Expires: 0');
readfile($temp_archivo['path']);
exit;
?>

Estimo que es similar, solo que en lugar de utilizar el archivo que armo en el momento, tomo el pdf creado en la operación anterior. Ahora bien, como capturo la url pasada como parámetro en un php como el que muestro?

Hola Martin,

si lo estas disparando con un evento, porque no configurar directamente en el evento el vinculo?.. digamos, el destino es fijo, hacer una redireccion por codigo no te suma nada.

Como hago para capturar el parámetro en archivopdf en el php_plano? Estimo que es similar, solo que en lugar de utilizar el archivo que armo en el momento, tomo el pdf creado en la operación anterior. Ahora bien, como capturo la url pasada como parámetro en un php como el que muestro?

El tema es, tiene algun beneficio que crees el pdf en la operacion anterior?.. porque no pasar el parametro con el que se debe recuperar dicho registro y listo?, si el pdf lo tenes en un blob en la bd, es solamente leerlo y mandarlo a disco, bien lo podes hacer en el php_plano… va digo, me parece que te complicas de gusto. Ademas pasar el nombre de un archivo, va a ser mas propenso a alguna cuestion tipo ‘…/…/…/…/etc/passwd’ que si solo pasas un id, que no esta exento de riesgos tampoco pero lo podes controlar mejor.

En cuanto a como recuperas el parametro, con el metodo

toba::memoria()->get_parametro(nombre)

Saludos