Download a file from a folder with php

Hello to All,

I arrived at the end of the book and I’m trying to change a code of the chapter 12 of “Sviluppare applicazioni con PHP e MySQL”. I would like to use the script to copy a file on the server disk, not on the mysql database. I can manage uploads but I can’t manage downloads.

The code that I’m using permits to me to download a file with the url of the file instead of the file. I don’t understand well the meaning of “echo $url;” and I think that it is the problem.

How can I change this code? Where is the mistake?

if (isset($_GET['action']) and ( $_GET['action'] == 'view' or $_GET['action'] == 'download') and
        isset($_GET['id'])) {
    include 'db.inc.php';

    try {
        $sql = 'SELECT filename, mimetype, url
        FROM filestore
        WHERE id = :id';
        $s = $pdo->prepare($sql);
        $s->bindValue(':id', $_GET['id']);
        $s->execute();
    } catch (PDOException $e) {
        $error = 'Database error fetching requested file.';
        include $_SERVER['DOCUMENT_ROOT'] . '/includes/error.html.php';
        exit();
    }

    $file = $s->fetch();
    if (!$file) {
        $error = 'File with specified ID not found in the database!';
        include $_SERVER['DOCUMENT_ROOT'] . '/includes/error.html.php';
        exit();
    }

    $filename = $file['filename'];
    $mimetype = $file['mimetype'];
    $url = $file['url'];
    $disposition = 'inline';

    if ($_GET['action'] == 'download') {
        $mimetype = 'application/octet-stream';
        $disposition = 'attachment';
    }

    // Content-type must come before Content-disposition
    header('Content-length: ' . strlen($url));
    header("Content-type: $mimetype");
    header("Content-disposition: $disposition; filename=$filename");
    header("Location: $url");
    echo $url;
    exit();
}

I send to you full code. I tryed this other solution but it doesn’t work:

db.inc.html.php

<?php
try
{
  $pdo = new PDO('mysql:host=localhost;dbname=filestore', 'filestoreuser', 'mypassword');
  $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  $pdo->exec('SET NAMES "utf8"');
}
catch (PDOException $e)
{
  $error = 'Unable to connect to the database server.';
  include 'error.html.php';
  exit();
}

error.html.php

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset=utf-8"/>
		<title>PHP Error</title>
	</head>
	<body>
		<p>
			<?php echo $error; ?>
		</p>
	</body>
</html>

files.html.php

<?php include_once $_SERVER['DOCUMENT_ROOT'] .
    '/includes/helpers.inc.php'; ?>
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>PHP/MySQL File Repository</title>
  </head>
  <body>
    <h1>PHP/MySQL File Repository</h1>

    <form action="" method="post" enctype="multipart/form-data">
      <div>
        <label for="upload">Upload File:
            <input type="file" id="upload" name="upload"></label>
      </div>
      <div>
        <label for="desc">File Description:
        <input type="text" id="desc" name="desc"
            maxlength="255"></label>
      </div>
      <div>
        <input type="hidden" name="action" value="upload">
        <input type="submit" value="Upload">
      </div>
    </form>

    <?php if (count($files) > 0): ?>

    <p>The following files are stored in the database:</p>

    <table>
      <thead>
        <tr>
          <th>Filename</th>
          <th>Type</th>
          <th>Description</th>
        </tr>
      </thead>
      <tbody>
        <?php foreach($files as $f): ?>
        <tr>
          <td>
            <a href="?action=view&amp;id=<?php htmlout($f['id']); ?>"
                ><?php htmlout($f['filename']); ?></a>
          </td>
          <td><?php htmlout($f['mimetype']); ?></td>
          <td><?php htmlout($f['description']); ?></td>
          <td>
            <form action="" method="get">
              <div>
                <input type="hidden" name="action" value="download"/>
                <input type="hidden" name="id" value="<?php htmlout($f['id']); ?>"/>
                <input type="submit" value="Download"/>
              </div>
            </form>
          </td>
          <td>
            <form action="" method="post">
              <div>
                <input type="hidden" name="action" value="delete"/>
                <input type="hidden" name="id" value="<?php htmlout($f['id']); ?>"/>
                <input type="submit" value="Delete"/>
              </div>
            </form>
          </td>
        </tr>
        <?php endforeach; ?>
      </tbody>
    </table>

    <?php endif; ?>
  </body>
</html>

index.php

<?php

include_once $_SERVER['DOCUMENT_ROOT'] .
        '/includes/magicquotes.inc.php';

if (isset($_POST['action']) and $_POST['action'] == 'upload') {
    // Bail out if the file isn't really an upload
    if (!is_uploaded_file($_FILES['upload']['tmp_name'])) {
        $error = 'There was no file uploaded!';
        include $_SERVER['DOCUMENT_ROOT'] . '/includes/error.html.php';
        exit();
    }
    $uploadfile = $_FILES['upload']['tmp_name'];
    $uploadname = $_FILES['upload']['name'];
    $uploadtype = $_FILES['upload']['type'];
    $uploaddesc = $_POST['desc'];
    $uploaddata = file_get_contents($uploadfile);
    // Creazione dell'url per caricare il file nel database
    $url = $_SERVER['DOCUMENT_ROOT'] . '/file_download/' . $uploadname;

    try {
        copy($_FILES['upload']['tmp_name'], $url);
    } catch (Exception $e) {
        $error = 'Copia del file sul server non riuscita!';
        include $_SERVER['DOCUMENT_ROOT'] . '/includes/error.html.php';
        exit();
    }
    include 'db.inc.php';

    try {
        $sql = 'INSERT INTO filestore SET
        filename = :filename,
        mimetype = :mimetype,
        description = :description,
        url = :url';
        $s = $pdo->prepare($sql);
        $s->bindValue(':filename', $uploadname);
        $s->bindValue(':mimetype', $uploadtype);
        $s->bindValue(':description', $uploaddesc);
        $s->bindValue(':url', $url);
        $s->execute();
    } catch (PDOException $e) {
        $error = 'Database error storing file!';
        include $_SERVER['DOCUMENT_ROOT'] . '/includes/error.html.php';
        exit();
    }

    header('Location: .');
    exit();
}

if (isset($_GET['action']) and ( $_GET['action'] == 'view' or $_GET['action'] == 'download') and
        isset($_GET['id'])) {
    include 'db.inc.php';

    try {
        $sql = 'SELECT filename, mimetype, url
        FROM filestore
        WHERE id = :id';
        $s = $pdo->prepare($sql);
        $s->bindValue(':id', $_GET['id']);
        $s->execute();
    } catch (PDOException $e) {
        $error = 'Database error fetching requested file.';
        include $_SERVER['DOCUMENT_ROOT'] . '/includes/error.html.php';
        exit();
    }

    $file = $s->fetch();
    if (!$file) {
        $error = 'File with specified ID not found in the database!';
        include $_SERVER['DOCUMENT_ROOT'] . '/includes/error.html.php';
        exit();
    }

    $filename = $file['filename'];
    $mimetype = $file['mimetype'];
    $url = $file['url'];
    $disposition = 'inline';

    if ($_GET['action'] == 'download') {
        $mimetype = 'application/octet-stream';
        $disposition = 'attachment';
    }
    $url_pubblico = 'http://' . $_SERVER['SERVER_NAME'] . '/file_download/' . $filename;
    // Content-type must come before Content-disposition
    header('Content-length: ' . strlen($url_pubblico));
    header("Content-type: $mimetype");
    header("Content-disposition: $disposition; filename=$filename");
    //echo $url_pubblico;
    $readfile = readfile($url_pubblico);
    echo $readfile;
    exit();
}

if (isset($_POST['action']) and $_POST['action'] == 'delete' and
        isset($_POST['id'])) {
    include 'db.inc.php';
    try {
        $sql = 'SELECT url FROM filestore
        WHERE id = :id';
        $s = $pdo->prepare($sql);
        $s->bindValue(':id', $_POST['id']);
        $s->execute();
    } catch (PDOException $e) {
        $error = 'La url del file salvata nel database non è leggibile.';
        include $_SERVER['DOCUMENT_ROOT'] . '/includes/error.html.php';
        exit();
    }
    try {
        $row = $s->fetch();
        $unlink = unlink($row['url']);
    } catch (PDOException $e) {
        $error = 'Impossibile cancellare il file dal server.';
        include $_SERVER['DOCUMENT_ROOT'] . '/includes/error.html.php';
        exit();
    }
    try {
        $sql = 'DELETE FROM filestore
        WHERE id = :id';
        $s = $pdo->prepare($sql);
        $s->bindValue(':id', $_POST['id']);
        $s->execute();
    } catch (PDOException $e) {
        $error = 'Database error deleting requested file.';
        include $_SERVER['DOCUMENT_ROOT'] . '/includes/error.html.php';
        exit();
    }

    header('Location: .');
    exit();
}

include 'db.inc.php';

try {
    $result = $pdo->query(
            'SELECT id, filename, mimetype, description
      FROM filestore');
} catch (PDOException $e) {
    $error = 'Database error fetching stored files.';
    include $_SERVER['DOCUMENT_ROOT'] . '/includes/error.html.php';
    exit();
}

$files = array();
foreach ($result as $row) {
    $files[] = array(
        'id' => $row['id'],
        'filename' => $row['filename'],
        'mimetype' => $row['mimetype'],
        'description' => $row['description']);
}

include 'files.html.php';

filestore.sql

# Code to create a simple file storage table

CREATE TABLE filestore (
  id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
  filename VARCHAR(255) NOT NULL,
  mimetype VARCHAR(50) NOT NULL,
  description VARCHAR(255) NOT NULL,
  url VARCHAR(255) NOT NULL
) DEFAULT CHARACTER SET utf8 ENGINE=InnoDB;

everything works except the download…

The script works fine. The problems that I encountered were due to the spaces included in the file name.