The whole problem is that you're downloading content from index.php together:
<?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>
That is when you download the file, this is coming together:
<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 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 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 get something more or less like this:
<?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
filesize
was not the problem of your script, but the mixed content as I mentioned, an interesting thing to send Content-Length
is that the browsers progress bar usually give an estimate of the percentage of the most accurate download , then it would be interesting to define this. However it is worth noting that filesize
uses int
and depending on the processor architecture you will have limits, which can cause problems like what I mentioned in filesize for files larger than 2GB on x86 platforms
A workaround would be to use CURL
(which returns string
and not int
), like this:
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);