I have a tool which allows a user to upload a spreadsheet, and then I parse the spreadsheet with Laravel-Excel. My issue is, how can I check that the file is a valid excel file before attempting to parse it?
I looked in the PHPOffice/Laravel-Excel docs, and could not find a method for validating a file. So, my next guess was, if I attempt to Load() an invalid file, it will bomb out and give me a warning or error. However, rather than doing that, it will parse the file and try to somehow convert it to a spreadsheet. For example, I fed it a pdf and it did generate a collection containing whatever non-binary junk it could find in the pdf file. This is not desirable.
Currently, I am doing a mime-type check to validate the file.
//valid mime types
$mimeTypes = [
'application/csv', 'application/excel',
'application/vnd.ms-excel', 'application/vnd.msexcel',
'text/csv', 'text/anytext', 'text/plain', 'text/x-c',
'text/comma-separated-values',
'inode/x-empty',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
];
$file = request()->hasFile('file');
if ($file) {
if (in_array(request()->file('file')->getClientMimeType(), $mimeTypes)) {
//then parse the file
Config::set('excel.import.heading', 'original');
$data = Excel::load(request()->file('file')->path(), function ($reader) {
})->get();
//do some stuff with data...
} else {
//invalid file
}
} else {
//no file uploaded
}
This is not ideal, since there seems to be an exotic variety of possible mime types, so I would have to actively maintain the list, and certain csv files have a plaintext mime-type, so non-csv-plaintext files would pass muster here. Is there any standard way, provided by either Laravel, Laravel-Excel, or PHPOffice, to validate the file?
You are only checking the user-supplied file extension information here.
string
|null
getClientMimeType()
Returns the file mime type.
The client mime type is extracted from the request from which the file was uploaded, so it should not be considered as a safe value.
For a trusted mime type, use getMimeType() instead (which guesses the mime type based on the file content).
If you want to validate the magic MIME bytes in the uploaded file itself you can do this by relying on your operating system's magic MIME byte file like this in PHP.
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
// $mime will contain the correct mime type
$mime = finfo_file($finfo, $_FILES['your-form-upload-input-name-here']['tmp_name'];
finfo_close($finfo);
See finfo_file
for more details.
To do this specifically using the Symfony Component you're currently relying on call the getMimeType()
method instead. Note the difference is that getClientMimeType()
uses the client-supplied information which can't be trusted, whereas getMimeType()
does the same thing as demonstrated with finfo_file()
above.