Estoy ejecutando un sitio web de php 8 en el servicio de aplicaciones web de Linux en Azure. Cuando el usuario presiona un botón, quiero crear un archivo sobre la marcha (leer datos de db) y descargarlo. En cambio, está mostrando contenido en la página. Aquí está el código
header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Type: text/csv; charset=utf-8'); header("Content-Disposition: attachment; filename=geodata.csv"); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize("geodata.csv")); $file = fopen('php://output', 'w') or die ("Unable to create file in write mode"); if (ob_get_contents()) ob_end_clean(); fputcsv($output, array('name','loc','zip'), chr(6)); $mrows = mysqli_query($myconnection, "SELECT name,loc,zip FROM geo_tbl WHERE sp = 'FL'"); while ($mrow = mysqli_fetch_assoc($mrows)) { fputcsv($file, $mrow, chr(6)); } fclose($file); readfile("geodata.csv"); exit();Gracias
Veo varios problemas con el código:
Como ya señaló Alan, tiene encabezados Content-Type duplicados. Si está guardando el archivo como un archivo adjunto, realmente puede usar cualquiera de los dos.
Emite su mensaje de die después de haber configurado el encabezado Content-Type para un archivo csv para que el mensaje no se muestre correctamente. Por lo tanto, debe hacer la instrucción fopen antes de configurar el encabezado del contenido.
Está enviando parte de su salida a la variable $output en lugar de $file con la instrucción fputcsv($output, array('name','loc','zip'), chr(6)); y esa variable no parece estar definida.
Está configurando un encabezado Content-Length con header('Content-Length: ' . filesize("geodata.csv")); pero en este punto no tienes idea de cuál es la longitud del contenido.
Debe poner comillas dobles alrededor de su nombre de archivo en el encabezado Content-Disposition .
Aunque no son errores, en sí , está recuperando las filas con fetch_assoc , por lo que $mrow contendrá claves y valores. Realmente solo necesitas usar fetch_row . También cuestiono su uso de chr(6) , que es un carácter ACK, como delimitador de columna. ¿Posiblemente quiso decir chr(9) , una TAB?
Creo que lo siguiente es todo lo que necesitas:
<?php //define (DELIMITER, chr(9)); // Shouldn't it be this? define (DELIMITER, chr(6)); if (ob_get_contents()) { ob_end_clean(); } $file = fopen('php://output', 'w') or die ("Unable to create file in write mode"); header('Content-Type: text/csv'); header('Content-Disposition: attachment; filename="geodata.csv"'); header('Pragma: no-cache'); header('Expires: 0'); fputcsv($file, array('name','loc','zip'), DELIMITER); $mrows = mysqli_query($myconnection, "SELECT name,loc,zip FROM geo_tbl WHERE sp = 'FL'"); while ($mrow = mysqli_fetch_row($mrows)) { fputcsv($file, $mrow, DELIMITER); } fclose($file);Cuando el usuario presiona un botón
Simplemente agregue el atributo de descarga a su botón, debería funcionar de inmediato.
<a href="link/to/your/file.csv" download="filename.csv">Download link</a>https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-download
Como han dicho otros, hay varios problemas con su código.
Pero si simplemente elimina el segundo encabezado de tipo de contenido y lo mantiene como application/octet-stream , esto debería forzar una descarga.
Sin embargo, la longitud de su contenido no se informará correctamente. Quizás lea el contenido en una variable, luego tome la longitud de esa cadena como el encabezado content-length .