0

I have a php page to retrieve uploaded (attached) files. The inputs of this file is the file name and its extension (for example jpg). Then I convert the extension to content type using function below:

function ConvertToMimeType($extension) {
    $MimeTypes = array('audio/aac', 'application/x-abiword', 'application/octet-stream', 'video/x-msvideo', 'application/vnd.amazon.ebook', 'application/octet-stream', 'application/x-bzip', 'application/x-bzip2', 'application/x-csh', 'text/css', 'text/csv', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-fontobject', 'application/epub+zip', 'application/ecmascript', 'image/gif', 'text/html', 'image/x-icon', 'text/calendar', 'application/java-archive', 'image/jpeg', 'image/jpg', 'application/javascript', 'application/json', 'audio/midi', 'video/mpeg', 'application/vnd.apple.installer+xml', 'application/vnd.oasis.opendocument.presentation', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.text', 'audio/ogg', 'video/ogg', 'application/ogg', 'font/otf', 'image/png', 'application/pdf', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/x-rar-compressed', 'application/rtf', 'application/x-sh', 'image/svg+xml', 'application/x-shockwave-flash', 'application/x-tar', 'image/tiff', 'application/typescript', 'font/ttf', 'application/vnd.visio', 'audio/wav', 'audio/webm', 'video/webm', 'image/webp', 'font/woff', 'font/woff2', 'application/xhtml+xml', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/xml', 'application/vnd.mozilla.xul+xml', 'application/zip', 'video/3gpp', 'audio/3gpp', 'video/3gpp2', 'audio/3gpp2', 'application/x-7z-compressed');
    $fmime = 'application/octet-stream';
    foreach ($MimeTypes as $mime) {
        if (substr($mime, strpos($mime, "/") + 1) == $extension) {
            $fmime = $mime;
            break;
        }
    }
    return $fmime;
}

Then the code lines below, return the file to client:

header('Content-disposition: filename="' . $fname . '"');
header('Pragma: no-cache');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header("Content-type: " . ConvertToMimeType($AttachFileType));
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($ffullname));
echo file_get_contents($ffullname);

but the retrieved file has a content type text/html and is plain text instead of file. The response header is as below:

Status Code: 200 OK
Remote Address: 127.0.0.2:80
Referrer Policy: no-referrer-when-downgrade
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection: Keep-Alive
Content-Encoding: gzip
Content-Length: 19924
Content-Type: text/html; charset=UTF-8
Date: Mon, 24 Sep 2018 11:23:43 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive: timeout=5, max=100
Pragma: no-cache
Server: Apache/2.4.29 (Ubuntu)
Vary: Accept-Encoding

And output is like this:

sample image

Update

I have already tested to print out $AttachFileType and ConvertToMimeType($AttachFileType) and the output is 'jpg' and 'image/jpg', so the problem is not with logic.

halfer
  • 19,824
  • 17
  • 99
  • 186
ConductedClever
  • 4,175
  • 2
  • 35
  • 69
  • do you want ur file downloadble?? – Er. Amit Joshi Sep 25 '18 at 05:35
  • Yes @Er.AmitJoshi . – ConductedClever Sep 25 '18 at 05:59
  • `Content-Encoding: gzip` isn’t set by your script, so that is likely configured on the web server level. And if it is configured based on the file extension `.php`, it might also overwrite the Content-Type header maybe? Check where/how this is configured, and try turning it off. – misorude Sep 25 '18 at 06:42
  • 1
    the `header` can't change headers when the output has started earlier. `file_get_contents` can gobble memory with big file. – Deadooshka Sep 25 '18 at 07:24
  • You are absolutely right @Deadooshka . The problem was that, an included php file was writing some js lines to output and in the result of client side, they was not visible, so I couldn't recognize the problem. The problem is now solved removing that js lines. – ConductedClever Sep 26 '18 at 08:32
  • and the comment of @misorude was very probable to occur and I was suspicious to it, but my problem was not that. – ConductedClever Sep 26 '18 at 08:33

1 Answers1

0

By the way you have not assigned anything in $AttachFileType variable, what exactly you are populating $AttachFileType variable with? Are you passing only extension to your function? If yes you are mistaken. If you are passing file mimetype then out put your $AttachFileType and check what you are passing.

If you are passing extension only you have to set predefined array of extension as a key with relevant mime type as a value and match which mime type you have to return. But you can not trust file extension to find exact file mime type and it can leads to security issue.

You can try following solution though I've not tested with your requirement but we use similar workaround in our projects.

function ConvertToMimeType($fileLocation) {
    $MimeTypes = array('audio/aac', 'application/x-abiword', 'application/octet-stream', 'video/x-msvideo', 'application/vnd.amazon.ebook', 'application/octet-stream', 'application/x-bzip', 'application/x-bzip2', 'application/x-csh', 'text/css', 'text/csv', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-fontobject', 'application/epub+zip', 'application/ecmascript', 'image/gif', 'text/html', 'image/x-icon', 'text/calendar', 'application/java-archive', 'image/jpeg', 'image/jpg', 'application/javascript', 'application/json', 'audio/midi', 'video/mpeg', 'application/vnd.apple.installer+xml', 'application/vnd.oasis.opendocument.presentation', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.text', 'audio/ogg', 'video/ogg', 'application/ogg', 'font/otf', 'image/png', 'application/pdf', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/x-rar-compressed', 'application/rtf', 'application/x-sh', 'image/svg+xml', 'application/x-shockwave-flash', 'application/x-tar', 'image/tiff', 'application/typescript', 'font/ttf', 'application/vnd.visio', 'audio/wav', 'audio/webm', 'video/webm', 'image/webp', 'font/woff', 'font/woff2', 'application/xhtml+xml', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/xml', 'application/vnd.mozilla.xul+xml', 'application/zip', 'video/3gpp', 'audio/3gpp', 'video/3gpp2', 'audio/3gpp2', 'application/x-7z-compressed');

    $fileInfo = new finfo(FILEINFO_MIME);
    $fileMimeType = $fileInfo->file($fileLocation);

    $fileMime = 'application/octet-stream';
    if(in_array($fileMimeType, $MimeTypes))
    {
        $fileMime = $fileMimeType;
    }
    return $fileMime;
}

$fname = 'file.xxx';
$fileToDownload = 'path/to/'.$fname;

header('Content-disposition: filename="' . $fname . '"');
header('Pragma: no-cache');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header("Content-type: " . ConvertToMimeType($fileToDownload));
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($fileToDownload));

// if you want to download file use
    $fp=fopen($fileToDownload,"r");
    fpassthru($fp);
    exit();
// or 
echo file_get_contents($fileToDownload);
  • 1
    @ConductedClever if you are facing any issue with given code you can try header part as `header("Content-Description: What ever you want");` `header("Content-Type: " . ConvertToMimeType($fileToDownload));` `header("Content-Disposition:attachment; filename=\"$fname\"");` `header("Content-Transfer-Encoding: binary");` ` header("Expires: 0");` `header("Cache-Control: must-revalidate");` `header("Pragma: public");` `header("Content-Length: " . filesize($fileToDownload));` `ob_clean();` ` flush();` `readfile($fileToDownload);` `exit;` – adaptable.services Sep 25 '18 at 06:56
  • In some tests I have faced problems solved by `if (ob_get_contents() && ob_get_length()) ob_clean();` and `flush();`. so answer was very useful but not about the current problem. – ConductedClever Sep 26 '18 at 08:36
  • @ConductedClever It works for me on many websites without any problem. But if not works for you then there must be any other issue, if you can provide me you final code I can help you. – adaptable.services Sep 26 '18 at 09:12