Skip to content

How to Download a File in PHP

This short tutorial will help you to learn how to download a file with PHP.

Just follow the examples below to easily meet that goal.

Using the readfile() Function

If you want to force the browser to save files or images locally when accessed via PHP, you can use the readfile() function.

Let’s see how to do it on the example of creating an image gallery, which will help the users to download image files using just one click.

In the example below, an image-gallery.php is generated and a code is placed inside it:

php generate image gallery with code

php
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Simple Image Gallery</title>
    <style>
      .img-box {
        display: inline-block;
        text-align: center;
        margin: 0 15px;
      }
    </style>
  </head>
  <body>
    <?php
    // Array encompassing sample image file names
    $images = ["kites.jpg", "balloons.jpg"];

    // Looping through the array to generate an image gallery
    foreach ($images as $image) {
        echo '<div class="img-box">';
        echo '<img src="images/' . $image . '" width="200" alt="' . pathinfo($image, PATHINFO_FILENAME) . '">';
        echo '<p><a href="download.php?file=' . urlencode($image) . '">Download</a></p>';
        echo '</div>';
    }
    ?>

  </body>
</html>

So, in the example above, the download link points to the download.php file. The URL contains the image filename as a query string. Note that the urlencode() function is used to safely pass filenames as URL parameters, as they may contain unsafe characters. The complete code for download.php, which forces the file download, looks as follows:

php automatic file download

php
<?php

if (isset($_GET["file"])) {
  // Get parameters
  $file = urldecode($_GET["file"]); // Decode URL-encoded string

  /* Check for path traversal attempts */
  if (strpos($file, '..') !== false) {
    die("Invalid file name!");
  }

  $filepath = "images/" . $file;

  // Process download
  if (file_exists($filepath)) {
    header('Content-Description: File Transfer');
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    header('Content-Type: ' . finfo_file($finfo, $filepath));
    finfo_close($finfo);
    header('Content-Disposition: attachment; filename="' . basename($filepath) . '"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($filepath));
    flush(); // Flush system output buffer
    readfile($filepath);
    die();
  } else {
    http_response_code(404);
    die();
  }
}

?>

Other file formats such as pdf, doc, and so on, can also be downloaded in the way, demonstrated above.

It is crucial to consider that in the example above, the code checks for path traversal attempts using strpos(). This prevents attackers from accessing files outside the intended directory by using sequences like ../ in the filename.

Dual-run preview — compare with live Symfony routes.