I have this PHP script (process.php):
<?php
// Include necessary libraries for database, PDF generation, and ZIP compression.
require_once('db_connection.php');
require_once('tcpdf/tcpdf.php');
if (isset($_POST['submit'])) {
// Get uploaded file data
$csvFile = $_FILES['csv_file']['tmp_name'];
// Initialize progress variables
$totalRecords = count(file($csvFile)) - 1; // Subtract 1 for the header row
$processedRecords = 0;
// Create a temporary directory to store the PDF files
$tempDir = '/var/www/html/insuromatic/temp/';
if (!file_exists($tempDir)) {
mkdir($tempDir, 0777, true);
}
// Create a ZipArchive instance
$zip = new ZipArchive();
$zipFileName = 'pdf_archive.zip';
if ($zip->open($zipFileName, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true) {
// Open and read the CSV file
if (($handle = fopen($csvFile, "r")) !== FALSE) {
// Skip the first row (header)
fgetcsv($handle);
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
// Assuming your CSV columns are in order (column1, column2, column3)
$column1 = $data[0];
$column2 = $data[1];
$column3 = $data[2];
// Insert data into the MySQL database
$sql = "INSERT INTO import_csv_data (id, name, email) VALUES ('$column1', '$column2', '$column3')";
mysqli_query($conn, $sql);
// Generate a PDF for this record
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
$pdf->AddPage();
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, "ID: $column1", 0, 1);
$pdf->Cell(0, 10, "Naam: $column2", 0, 1);
$pdf->Cell(0, 10, "Email: $column3", 0, 1);
// Customize the PDF content as needed
// Save the PDF in the temporary directory
$pdfFileName = $tempDir . "record_$column1.pdf";
$pdf->Output($pdfFileName, 'F');
// Add the PDF to the ZIP archive
$zip->addFile($pdfFileName, "record_$column1.pdf");
// Delete the record from the database
$deleteSql = "DELETE FROM import_csv_data WHERE id = '$column1'";
mysqli_query($conn, $deleteSql);
// Update progress
$processedRecords++;
// Send progress to the client
// echo "Processed $processedRecords out of $totalRecords records.<br />n"; // LINE 65
// Flush the output buffer to send data immediately to the client
ob_flush();
flush();
// Close the PDF document
$pdf->Close();
}
fclose($handle);
}
// Close the ZIP archive
$zip->close();
// Remove temporary PDF files
array_map('unlink', glob($tempDir . '*.pdf'));
rmdir($tempDir);
// Provide the ZIP archive for download
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename="$zipFileName"");
ob_end_clean();
flush();
readfile($zipFileName); // LINE 89
unlink($zipFileName); // Delete the ZIP file after download
}
// Close the MySQL connection
mysqli_close($conn);
}
?>
Server config:
Apache/2.4.57 (Debian)
PHP 8.0.30 FPM/FastCGI
Problem:
- The echo() statement on line 65 works fine when the readfile() statement on line 89 is commented out, I see the progress echoed on the screen
- The readfile() statement on line 89 works fine when the echo() statement on line 65 is commented out, I get a ZIP download containing the created PDF files
However, when both lines are enabled, I see a lot of garbage on the screen (the raw PDF content I think) after the progress is echoed to the screen. The ZIP is not offered for download.
Unfortunately, I have no clue about what i’m doing wrong. I tried several places of ob_end_clean(), ob_end_flush() and so on but with no luck, the garbage keeps being printed. Can someone point me in the right direction?
//Edit: reworked version:
<?php
// Include necessary libraries for database, PDF generation, and ZIP compression.
require_once('db_connection.php');
require_once('tcpdf/tcpdf.php');
if (isset($_POST['submit'])) {
// Get uploaded file data
$csvFile = $_FILES['csv_file']['tmp_name'];
// Initialize progress variables
$totalRecords = count(file($csvFile)) - 1; // Subtract 1 for the header row
$processedRecords = 0;
// Create a temporary directory to store the PDF files
$tempDir = '/var/www/html/insuromatic/temp/';
if (!file_exists($tempDir)) {
mkdir($tempDir, 0777, true);
}
// Open and read the CSV file
if (($handle = fopen($csvFile, "r")) !== FALSE) {
// Skip the first row (header)
fgetcsv($handle);
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
// Assuming your CSV columns are in order (column1, column2, column3)
$column1 = $data[0];
$column2 = $data[1];
$column3 = $data[2];
// Insert data into the MySQL database
$sql = "INSERT INTO import_csv_data (id, name, email) VALUES ('$column1', '$column2', '$column3')";
mysqli_query($conn, $sql);
// Generate a PDF for this record
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
$pdf->AddPage();
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, "ID: $column1", 0, 1);
$pdf->Cell(0, 10, "Naam: $column2", 0, 1);
$pdf->Cell(0, 10, "Email: $column3", 0, 1);
// Customize the PDF content as needed
// Save the PDF in the temporary directory
$pdfFileName = $tempDir . "record_$column1.pdf";
$pdf->Output($pdfFileName, 'F');
// Delete the record from the database
$deleteSql = "DELETE FROM import_csv_data WHERE id = '$column1'";
mysqli_query($conn, $deleteSql);
// Update progress
$processedRecords++;
// Send progress to the client
echo "Processed $processedRecords out of $totalRecords records.<br />n";
// Flush the output buffer to send data immediately to the client
ob_flush();
flush();
// Close the PDF document
$pdf->Close();
}
fclose($handle);
}
// Close the MySQL connection
mysqli_close($conn);
// Output a JavaScript script to perform the redirection
echo '<script>window.location.href = "download.php";</script>';
//Prevent any further execution
exit;
}
?>
download.php:
<?php
// Specify the directory containing your PDF files
$directory = '/var/www/html/insuromatic/temp';
// Define the name of the ZIP archive file
$zipFileName = 'pdf_archive.zip';
// Create a ZipArchive object
$zip = new ZipArchive();
// Open the ZIP archive for writing
if ($zip->open($zipFileName, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true) {
// Create a recursive directory iterator to scan the directory
$iterator = new RecursiveDirectoryIterator($directory);
$files = new RecursiveIteratorIterator($iterator);
// Loop through all files in the directory
foreach ($files as $file) {
// Check if the file is a PDF
if ($file->isFile() && strtolower(pathinfo($file, PATHINFO_EXTENSION)) === 'pdf') {
// Add the PDF file to the ZIP archive with its original name
$zip->addFile($file, $file->getBasename());
}
}
// Close the ZIP archive
$zip->close();
// Remove temporary PDF files
$tempDir = '/var/www/html/insuromatic/temp/';
array_map('unlink', glob($tempDir . '*.pdf'));
rmdir($tempDir);
// Set the appropriate headers for a ZIP file download
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="' . $zipFileName . '"');
header('Content-Length: ' . filesize($zipFileName));
// Send the ZIP file to the client's browser
readfile($zipFileName);
// Delete the ZIP file from the server (optional)
unlink($zipFileName);
exit; // Terminate the script
} else {
echo "Failed to create ZIP archive.";
}
?>
2
Answers
The topic that @Progman referred to pointed me in the right direction. I reworked the code as follow:
index.html:
generatepdf.php:
The progress is displayed correctly and the download is offered. The issue is resolved.
In order for
to work you need to start output buffering first using
and must not use
in between.