solo - php descargar archivo automaticamente
Forzar la descarga de archivos en PHP-dentro del marco de Joomla (4)
Agregue este método a su controlador:
function exportcsv() {
$model = & $this->getModel(''export'');
$model->exportToCSV();
}
A continuación, agregue un nuevo modelo llamado export.php, código a continuación. Tendrá que cambiar o extender el código a su situación.
<?php
/**
* @package TTVideo
* @author Martin Rose
* @website www.toughtomato.com
* @version 2.0
* @copyright Copyright (C) 2010 Open Source Matters. All rights reserved.
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
*/
//No direct acesss
defined(''_JEXEC'') or die();
jimport(''joomla.application.component.model'');
jimport( ''joomla.filesystem.file'' );
jimport( ''joomla.filesystem.archive'' );
jimport( ''joomla.environment.response'' );
class TTVideoModelExport extends JModel
{
function exportToCSV() {
$files = array();
$file = $this->__createCSVFile(''#__ttvideo'');
if ($file != '''') $files[] .= $file;
$file = $this->__createCSVFile(''#__ttvideo_ratings'');
if ($file != '''') $files[] .= $file;
$file = $this->__createCSVFile(''#__ttvideo_settings'');
if ($file != '''') $files[] .= $file;
// zip up csv files to be delivered
$random = rand(1, 99999);
$archive_filename = JPATH_SITE.DS.''tmp''.DS.''ttvideo_''. strval($random) .''_''.date(''Y-m-d'').''.zip'';
$this->__zip($files, $archive_filename);
// deliver file
$this->__deliverFile($archive_filename);
// clean up
JFile::delete($archive_filename);
foreach($files as $file) JFile::delete(JPATH_SITE.DS.''tmp''.DS.$file);
}
private function __createCSVFile($table_name) {
$db = $this->getDBO();
$csv_output = '''';
// get table column names
$db->setQuery("SHOW COLUMNS FROM `$table_name`");
$columns = $db->loadObjectList();
foreach ($columns as $column) {
$csv_output .= $column->Field.''; '';
}
$csv_output .= "/n";
// get table data
$db->setQuery("SELECT * FROM `$table_name`");
$rows = $db->loadObjectList();
$num_rows = count($rows);
if ($num_rows > 0) {
foreach($rows as $row) {
foreach($row as $col_name => $value) {
$csv_output .= $value.''; '';
}
$csv_output .= "/n";
}
}
$filename = substr($table_name, 3).''.csv'';
$file = JPATH_SITE.DS.''tmp''.DS.$filename;
// write file to temp directory
if (JFile::write($file, $csv_output)) return $filename;
else return '''';
}
private function __deliverFile($archive_filename) {
$filesize = filesize($archive_filename);
JResponse::setHeader(''Content-Type'', ''application/zip'');
JResponse::setHeader(''Content-Transfer-Encoding'', ''Binary'');
JResponse::setHeader(''Content-Disposition'', ''attachment; filename=ttvideo_''.date(''Y-m-d'').''.zip'');
JResponse::setHeader(''Content-Length'', $filesize);
echo JFile::read($archive_filename);
}
/* creates a compressed zip file */
private function __zip($files, $destination = '''') {
$zip_adapter = & JArchive::getAdapter(''zip''); // compression type
$filesToZip[] = array();
foreach ($files as $file) {
$data = JFile::read(JPATH_SITE.DS.''tmp''.DS.$file);
$filesToZip[] = array(''name'' => $file, ''data'' => $data);
}
if (!$zip_adapter->create( $destination, $filesToZip, array() )) {
global $mainframe;
$mainframe->enqueueMessage(''Error creating zip file.'', ''message'');
}
}
}
?>
A continuación, vaya a su view.php predeterminado y agregue un botón personalizado, por ejemplo
// custom export to set raw format for download
$bar = & JToolBar::getInstance(''toolbar'');
$bar->appendButton( ''Link'', ''export'', ''Export CSV'', ''index.php?option=com_ttvideo&task=export&format=raw'' );
¡Buena suerte!
Tengo un código PHP que ejecuta una consulta en una base de datos, guarda los resultados en un archivo csv y luego permite que el usuario descargue el archivo. El problema es que el archivo csv contiene páginas HTML alrededor del contenido csv real.
He leído todas las preguntas relacionadas aquí, incluso esta . Lamentablemente, mi código existe en Joomla, por lo que incluso si trato de redireccionar a una página que no contiene más que encabezados, Joomla automáticamente lo rodea con su propio código de navegación. Esto solo ocurre en el momento de la descarga; si miro el archivo csv que está guardado en el servidor, no contiene el HTML.
¿Alguien puede ayudarme con una forma de forzar una descarga del archivo csv real tal como está en el servidor, en lugar de como lo está editando el navegador? Intenté usar la ubicación del encabezado, así:
header(''Location: '' . $filename);
pero abre el archivo en el navegador, en lugar de forzar el diálogo de guardar.
Aquí está mi código actual:
//set dynamic filename
$filename = "customers.csv";
//open file to write csv
$fp = fopen($filename, ''w'');
//get all data
$query = "select
c.firstname,c.lastname,c.email as customer_email,
a.email as address_email,c.phone as customer_phone,
a.phone as address_phone,
a.company,a.address1,a.address2,a.city,a.state,a.zip, c.last_signin
from {$dbpre}customers c
left join {$dbpre}customers_addresses a on c.id = a.customer_id order by c.last_signin desc";
$votes = mysql_query($query) or die ("File: " . __FILE__ . "<br />Line: " . __LINE__ . "<p>{$query}<p>" . mysql_error());
$counter = 1;
while ($row = mysql_fetch_array($votes,1)) {
//put header row
if ($counter == 1){
$headerRow = array();
foreach ($row as $key => $val)
$headerRow[] = $key;
fputcsv($fp, $headerRow);
}
//put data row
fputcsv($fp, $row);
$counter++;
}
//close file
fclose($fp);
//redirect to file
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$filename);
header("Content-Transfer-Encoding: binary");
readfile($filename);
exit;
EDITAR La URL completa se ve así:
http://mysite.com/administrator/index.php?option=com_eimcart&task=customers
con el enlace de descarga real que se ve así:
http://mysite.com/administrator/index.php?option=com_eimcart&task=customers&subtask=export
MÁS EDICIONES Aquí hay una foto de la página en la que está el código; el archivo generado todavía está tirando en el html para el submenú. El código para el enlace seleccionado (Exportar como CSV) es ahora
index.php?option=com_eimcart&task=customers&subtask=export&format=raw
Ahora aquí hay una captura de pantalla del archivo guardado y guardado:
Se redujo durante la carga aquí, pero el texto resaltado en amarillo es el código html para el subnav (enumerar clientes, agregar nuevo cliente, exportar como csv). Así es como se ve mi código completo ahora; si pudiera deshacerme de ese último bit de html, sería perfecto.
$fp= fopen("php://output", ''w'');
$query = "select c.firstname,c.lastname,c.email as customer_email,
a.email as address_email,c.phone as customer_phone,
a.phone as address_phone, a.company, a.address1,
a.address2,a.city,a.state,a.zip,c.last_signin
from {$dbpre}customers c
left join {$dbpre}customers_addresses a on c.id = a.customer_id
order by c.last_signin desc";
$votes = mysql_query($query) or die ("File: " . __FILE__ . "<br />Line: " . __LINE__ . "<p>{$query}<p>" . mysql_error());
$counter = 1;
//redirect to file
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=customers.csv");
header("Content-Transfer-Encoding: binary");
while ($row = mysql_fetch_array($votes,1)) {
//put header row
if ($counter == 1){
$headerRow = array();
foreach ($row as $key => $val)
$headerRow[] = $key;
fputcsv($fp, $headerRow);
}
//put data row
fputcsv($fp, $row);
$counter++;
}
//close file
fclose($fp);
ACTUALIZACIÓN PARA BJORN
Aquí está el código (creo) que funcionó para mí. Use el parámetro RAW en el enlace que llama a la acción:
index.php?option=com_eimcart&task=customers&subtask=export&format=raw
Debido a que esto era de procedimiento, nuestro enlace estaba en un archivo llamado customers.php, que se ve así:
switch ($r[''subtask'']){
case ''add'':
case ''edit'':
//if the form is submitted then go to validation
include("subnav.php");
if ($r[''custFormSubmitted''] == "true")
include("validate.php");
else
include("showForm.php");
break;
case ''delete'':
include("subnav.php");
include("process.php");
break;
case ''resetpass'':
include("subnav.php");
include("resetpassword");
break;
case ''export'':
include("export_csv.php");
break;
default:
include("subnav.php");
include("list.php");
break;
}
Entonces, cuando un usuario hace clic en el enlace de arriba, el archivo export_csv.php se incluye automáticamente. Ese archivo contiene todo el código actual:
<?
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=customers.csv");
header("Content-Transfer-Encoding: binary");
$fp= fopen("php://output", ''w'');
//get all data
$query = "select
c.firstname,c.lastname,c.email as customer_email,
a.email as address_email,c.phone as customer_phone,
a.phone as address_phone,
a.company,a.address1,a.address2,a.city,a.state,a.zip, c.last_signin
from {$dbpre}customers c
left join {$dbpre}customers_addresses a on c.id = a.customer_id order by c.last_signin desc";
$votes = mysql_query($query) or die ("File: " . __FILE__ . "<br />Line: " . __LINE__ . "<p>{$query}<p>" . mysql_error());
$counter = 1;
while ($row = mysql_fetch_array($votes,1)) {
//put header row
if ($counter == 1){
$headerRow = array();
foreach ($row as $key => $val)
$headerRow[] = $key;
fputcsv($fp, $headerRow);
}
//put data row
fputcsv($fp, $row);
$counter++;
}
//close file
fclose($fp);
Este es un código de muestra que acabo de cocinar para ayudarte. Úselo como un método de acción en su controlador.
function get_csv() {
$file = JPATH_ADMINISTRATOR . DS . ''test.csv'';
// Test to ensure that the file exists.
if(!file_exists($file)) die("I''m sorry, the file doesn''t seem to exist.");
// Send file headers
header("Content-type: text/csv");
header("Content-Disposition: attachment;filename=test.csv");
// Send the file contents.
readfile($file);
}
Esto por sí solo no será suficiente, porque el archivo que descargue aún contendrá el html circundante. Para deshacerse de él y solo recibir el contenido del archivo csv, debe agregar format = raw parameter a su solicitud. En mi caso, el método está dentro del componente com_csvexample, por lo que la url sería:
/index.php?option=com_csvexample&task=get_csv&format=raw
EDITAR
Para evitar el uso de un sustituto de archivo intermedio
//set dynamic filename
$filename = "customers.csv";
//open file to write csv
$fp = fopen($filename, ''w'');
con
//open the output stream for writing
//this will allow using fputcsv later in the code
$fp= fopen("php://output", ''w'');
Con este método, debe mover el código que envía los encabezados antes de escribir nada en la salida. Tampoco necesitará la llamada a la función readfile
.
Otra forma de generar datos CSV en una aplicación Joomla es crear una vista utilizando CSV en lugar de formato HTML. Es decir, crea un archivo de la siguiente manera:
components / com_mycomp / views / something / view.csv.php
Y agregue contenido similar al siguiente:
<?php
// No direct access
defined(''_JEXEC'') or die;
jimport( ''joomla.application.component.view'');
class MyCompViewSomething extends JViewLegacy // Assuming a recent version of Joomla!
{
function display($tpl = null)
{
// Set document properties
$document = &JFactory::getDocument();
$document->setMimeEncoding(''text/csv'');
JResponse::setHeader(''Content-disposition'', ''inline; filename="something.csv"'', true);
// Output UTF-8 BOM
echo "/xEF/xBB/xBF";
// Output some data
echo "field1, field2, ''abc 123'', foo, bar/r/n";
}
}
?>
A continuación, puede crear enlaces de descarga de archivos de la siguiente manera:
/index.php?option=com_mycomp&view=something&format=csv
Ahora, tendrá razón al cuestionar la parte ''en línea'' en la disposición del contenido. Si recuerdo correctamente al escribir este código hace algunos años, tuve problemas con la opción ''archivo adjunto''. Este enlace que acabo de buscar en Google ahora me resultaba familiar como el controlador para ello: https://dotanything.wordpress.com/2008/05/30/content-disposition-attachment-vs-inline/ . He estado usando ''en línea'' desde entonces y todavía me piden que guarde el archivo de manera apropiada desde cualquier navegador con el que realice la prueba. No he intentado usar ''attachment'' en algún momento recientemente, por lo que puede funcionar bien ahora, por supuesto (¡el enlace ahora tiene 7 años!)
Puede usar mod_cern_meta
de Apache para agregar encabezados HTTP a archivos estáticos. Content-Disposition: attachment
. Los necesarios archivos .htaccess
y .meta
pueden ser creados por PHP.