A Python application is saying the zip files I am streaming via a PHP streamer aren't zip files. However, winrar opens them with no issues.
This is the headers it is sending:
Content-disposition: filename=example.zip
Content-type: application/zip; charset=binary
Do I need more/different headers?
Below is the code:
<?php
session_start();
if(!$_SESSION['directory']){
print "Sorry, only logged in users can view downloads";
exit;
};
?>
<?php
$hidden_file_directory = "download/".$_SESSION['directory']; //Name of the directory where all the sub directories and files exists
$file_path = $_GET['file']; //Get the file from URL variable
$real_file_path = realpath("$hidden_file_directory/$file_path"); //Set the file path w.r.t the download.php... It may be different for u
$filename = basename($real_file_path);
if(dirname($real_file_path) != getcwd() ."/". $hidden_file_directory)
die("File does not exist.");
if(file_exists($real_file_path)) {
$content_type = get_mime($real_file_path);
header("Content-disposition: filename=$filename"); //Tell the filename to the browser
header("Content-type: $content_type"); //Stream as a binary file! So it would force browser to download
readfile($real_file_path); //Read and stream the file
}
else {
echo "File does not exist.";
}
function get_mime($filename) {
$mime_types = array(
'txt' => 'text/plain',
'htm' => 'text/html',
'html' => 'text/html',
'php' => 'text/html',
'css' => 'text/css',
'js' => 'application/javascript',
'json' => 'application/json',
'xml' => 'application/xml',
'swf' => 'application/x-shockwave-flash',
'flv' => 'video/x-flv',
// images
'png' => 'image/png',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'gif' => 'image/gif',
'bmp' => 'image/bmp',
'ico' => 'image/vnd.microsoft.icon',
'tiff' => 'image/tiff',
'tif' => 'image/tiff',
'svg' => 'image/svg+xml',
'svgz' => 'image/svg+xml',
// archives
'zip' => 'application/zip',
'rar' => 'application/x-rar-compressed',
'exe' => 'application/x-msdownload',
'msi' => 'application/x-msdownload',
'cab' => 'application/vnd.ms-cab-compressed',
// audio/video
'mp3' => 'audio/mpeg',
'qt' => 'video/quicktime',
'mov' => 'video/quicktime',
// adobe
'pdf' => 'application/pdf',
'psd' => 'image/vnd.adobe.photoshop',
'ai' => 'application/postscript',
'eps' => 'application/postscript',
'ps' => 'application/postscript',
// ms office
'doc' => 'application/msword',
'rtf' => 'application/rtf',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
// open office
'odt' => 'application/vnd.oasis.opendocument.text',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
);
$ext = strtolower(array_pop(explode('.',$filename)));
if (array_key_exists($ext, $mime_types)) {
return $mime_types[$ext];
}
elseif (function_exists('finfo_open')) {
$finfo = finfo_open(FILEINFO_MIME);
$mimetype = finfo_file($finfo, $filename);
finfo_close($finfo);
return $mimetype;
}
else {
return 'application/octet-stream';
}
}
?>
Edit - I added:
if(dirname($real_file_path) != getcwd() ."/". $hidden_file_directory)
die("File does not exist.");
When those who pointed out the insecurity. Hopefully this will be secure enough.
I've noticed that some browsers need the filename to be double quoted or they dont know what it is, perhaps python does the same. Try sending
header("Content-disposition: filename=\"$filename\"");
Also are you sure it is infact application/zip
and not application/x-zip-compressed
?
On a side note: You are using the filename directly from the querystring. What if I send my filename as file=..\..\..\..\..\..\systemdir\config.xml
? Perhaps you should add some checking. basename() like you use the next step might be a good idea.