The whole problem is that you are downloading along with the contents of index.php:
<?php
require 'config/Config.php';
require 'config/tratarUrl.php';
?>
<html lang="pt-br">
<link rel="stylesheet" href="<?=DIR_CSS?>Style.css">
<link rel="icon" href="<?= DIR_IMAGES?>icon.png"
<meta charset="UTF-8">
<title>Site</title>
<head>
<meta charset="UTF-8">
</head>
<body>
<?php
include $pag;
?>
</body>
</html>
Meaning when you download the file, it’s coming along:
<html lang="pt-br">
<link rel="stylesheet" href="Style.css">
<link rel="icon" href="icon.png">
<meta charset="UTF-8">
<title>Site</title>
<head>
<meta charset="UTF-8">
</head>
<body>
CONTEUDO DO ARQUIVO AQUI
</body>
</html>
I recommend separating the download.php or simply creating an if.
Using if:
<?php
require 'config/Config.php';
require 'config/tratarUrl.php';
if (preg_match('#pages/download\.php$#', $pag) > 0) {
include $pag;
exit;
}
?>
<html lang="pt-br">
<link rel="stylesheet" href="<?=DIR_CSS?>Style.css">
<link rel="icon" href="<?= DIR_IMAGES?>icon.png"
<meta charset="UTF-8">
<title>Site</title>
<head>
<meta charset="UTF-8">
</head>
<body>
<?php
include $pag;
?>
</body>
</html>
Or else you can rewrite . htaccess like this:
RewriteEngine On
RewriteBase /
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
#se a url vier com prefix download
RewriteRule ^download/ /pages/download.php [QSA,L]
#outras urls
RewriteRule (.*) /index.php [QSA,L]
Then your pages/download.php
should leave something more or less thus:
<?php
require 'config/Config.php';
//... Conteudo do seu download.php ...
$file_path = DIR_ARQUIVOS.$key.'.zip';
$file_name = $key.'.zip';
$new_name = $sql->getKeyName($key);
set_time_limit(0);
// Verifica se o arquivo não existe
if (!file_exists($file_path)) {
// Exiba uma mensagem de erro caso ele não exista
exit;
}
// Configuramos os headers que serão enviados para o browser
header('Content-Type: "application/zip"');
header('Content-Disposition: attachment; filename="'.basename($file_path).'"');
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: no-cache');
// Envia o arquivo para o cliente
readfile($file_name);
Problems with filesize
The filesize
was not the problem of your script, but rather the mixed content as I mentioned, an interesting thing to send the Content-Length
is that the browsers progress bar usually give an estimate in percentage of the download more accurate, so it would be interesting to define this. However it is good to note that filesize
uses int
and depending on the processor architecture you will have limits, which can cause problems such as the one I mentioned in filesize for files larger than 2GB on x86 platforms
An alternative solution would be using the CURL
(that returns in string
and not in int
), thus:
function filesizecurl($arquivo)
{
if (is_file($arquivo) === false) {
return false;
}
$arquivo = realpath(preg_replace('#^file:#', '', $arquivo));
$ch = curl_init('file://' . ltrim($arquivo, '/'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //Faz o retorno ser salvo na variável
curl_setopt($ch, CURLOPT_HEADER, 1); //Faz retornar os headers
curl_setopt($ch, CURLOPT_NOBODY, 1); //Evita retornar o corpo
$headers = curl_exec($ch);
curl_close($ch);
$ch = null;
//Com preg_match extraímos o tamanho retornado de Content-Length
if (preg_match('#(^c|\sc)ontent\-length:(\s|)(\d+)#i', $headers, $matches) > 0) {
return $matches[3];
}
return false;
}
// Configuramos os headers que serão enviados para o browser
header('Content-Length: ' . filesizecurl($file_name));
header('Content-Type: "application/zip"');
header('Content-Disposition: attachment; filename="'.basename($file_path).'"');
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: no-cache');
// Envia o arquivo para o cliente
readfile($file_name);
Let’s go continue this discussion in chat.
– Guilherme Nascimento