-1

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.";
}
?>
8
  • 2
    You can't mix zip data with plain text. Everything output by the script will be included in the download. Commented Oct 2, 2023 at 19:17
  • Does this answer your question? PHP-How to solve that Html Page Source is appending to the download file Commented Oct 2, 2023 at 19:21
  • A "download" is simply the content of the file "echod" by the server. If you echo anything else, you no longer have the content of your file, but the content plus something else Commented Oct 2, 2023 at 19:58
  • I try to understand...I expected that the ob_end_clean(); just before the readfile() would solve this issue but it isn't? Commented Oct 2, 2023 at 20:18
  • Which line is line 65? Or 89? Commented Oct 2, 2023 at 21:26

2 Answers 2

0

In order for

ob_end_clean();

to work you need to start output buffering first using

ob_start();

and must not use

ob_flush();

in between.

Sign up to request clarification or add additional context in comments.

Comments

0

The topic that @Progman referred to pointed me in the right direction. I reworked the code as follow:

index.html:

<!DOCTYPE html>
<html>
<head>
    <title>CSV to PDF</title>
</head>
<body>

    <div id="downloadlink">
        <a href="insuromatic.csv">Download demo CSV bestand</a>
    </div>


    <div id="generatePDFS"></div>

    <input type="file" id="csvFileInput" name="csvFileInput"><br />
    <button id="generatePDFSbutton">Genereer en download PDF bestanden</button><br />

<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script>
    $(document).ready(function() {
        $("#generatePDFSbutton").click(function() {
            // Get the selected CSV file
            var csvFile = $("#csvFileInput")[0].files[0];

            if (csvFile) {
                // Create a FormData object to send the file data
                var formData = new FormData();
                formData.append('action', 'generatePDFS');
                formData.append('csvFile', csvFile);

                $.ajax({
                    url: 'generatepdf.php',
                    type: 'POST',
                    data: formData,
                    processData: false,
                    contentType: false,
                    success: function(response) {
                        $("#generatePDFS").html(response);
                            fetch('download.php', {
                                method: 'GET',
                                responseType: 'blob',
                            })

                        .then(response => response.blob())

                        .then(blob => {
                            const url = window.URL.createObjectURL(blob);
                            const a = document.createElement('a');
                            a.style.display = 'none';
                            a.href = url;
                            a.download = 'pdf.zip';

                            document.body.appendChild(a);
                            a.click();

                            window.URL.revokeObjectURL(url);
                        })

                        .catch(error => {
                            console.error('Error downloading file:', error);
                        });
                    }
                });

            } else {
                alert('Please select a CSV file');
            }
        });
    });
</script>
</body>
</html>

generatepdf.php:

<?php
if (isset($_POST['action'])) {
    $action = $_POST['action'];
    if ($action === 'generatePDFS') {
        // Call PHP function generatePDFS
        $result = generatePDFS();
        echo $result;
    }
}

    function generatePDFS() {

    // Include necessary libraries for database, PDF generation, and ZIP compression.
    require_once('db_connection.php');
    require_once('tcpdf/tcpdf.php');

    if (isset($_POST['action'])) {

        // Get uploaded file data
        $csvFile = $_FILES['csvFile']['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/testomatic/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 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 "$processedRecords van de $totalRecords records verwerkt.<br />\n";

                // Close the PDF document
                $pdf->Close();
            }
            fclose($handle);
        }

    // Close the MySQL connection
    mysqli_close($conn);

    //Prevent any further execution
    exit;
    }
}
?>

The progress is displayed correctly and the download is offered. The issue is resolved.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.