Is it possible to get a file extension without knowing it? - php

I have a file called 94bf663a100e848fb599209af8cdc2b5.wmv. I know pathinfo will not give me the extension if I just use the name 94bf663a100e848fb599209af8cdc2b5. I believe glob is only for checking if a file exists. So is it possible to get a file extension just knowing the file name (94bf663a100e848fb599209af8cdc2b5)?

As the example on the php glob manual page suggests, glob does not simply check if the file exists, it returns every file that matches the expression.
Here's a modification of the example on that page for your needs:
$name = "94bf663a100e848fb599209af8cdc2b5";
$matching = glob($name . ".*");
$info = pathinfo($matching[0]);
$ext = $info['extension'];
This assumes there is one (and only one) file with that name (with any extension), but you should be able to modify it if the file might not exist, or there might be multiple files with the same name, and different extensions.

The finfo_file() function will inspect the byte signature of a file to return its mimetype. From there, you can mostly deduce the correct file extension.
// Adapted from the PHP docs
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
echo finfo_file($finfo, $filename);
finfo_close($finfo);

The first few characters of the file (binary) will usually give you some kind of hint about what the file type is.
Try it out by opening some binary files (rar, zip, mp3 etc.) in Notepad.

Try filetype() or mime_content_type() function in php...
pass the file path it returns the file type.

Related

How to find file without specific file extension in laravel storage?

How to find file by name without specific extension in laravel Storage?
like this "filename.*"
Storage::get("filename.*")
I tried this but seems not to work. It searches for specific file with specific extension.
Storage::get() takes a file path as a parameter and returns the content of a single file identified by this path or throws FileNotFoundException if file can't be found.
Wildcards are not supported in the path - one reason for that could be that there might be multiple files that match the path with wildcards which would break the rule that content of a single file is returned from Storage::get(). Scanning the whole folder would also be much slower, especially with remote storages.
However, you could get what you want using other functionality that Storage facade offers. First, list the content of your storage - that will give you the list of all available files. Then filter the list yourself to get the list of matching files.
// list all filenames in given path
$allFiles = Storage::files('');
// filter the ones that match the filename.*
$matchingFiles = preg_grep('/^filename\./', $allFiles);
// iterate through files and echo their content
foreach ($matchingFiles as $path) {
echo Storage::get($path);
}
Accepted solution works. However I've found this other and I like it more:
$matchingFiles = \Illuminate\Support\Facades\File::glob("{$path}/*.log");
See reference here:
http://laravel-recipes.com/recipes/143/finding-files-matching-a-pattern
Minor change to jedrzej.kurylo's answer and combining wogsland's answer using laravel 8:
'/^filename\./' or '/filename\./' pattern does not work in my case.
// From:
$matchingFiles = preg_grep('/^filename./', $allFiles);
// To:
$allFiles = Storage::disk('yourStorageDisk')->files('folder/path');
$allowedMimeTypes = ['image/jpeg', 'image/png', 'image/webp'];
$matchingFiles = preg_grep('{'.$image.'}', $allFiles);
foreach ($matchingFiles as $path) {
// get real mime type
$contentType = image_type_to_mime_type(exif_imagetype(asset($path)));
// compare it with our allowed mime types
if (in_array($contentType, $allowedMimeTypes)) {
// do something here...
}
}
This way we can fetch files or images safely.
Dont trust what you see. Get inside and get the ext for your file
$pic = 'url/your.file';
$ext = image_type_to_mime_type(exif_imagetype($pic));
$ext = explode('/',$ext);
echo $ext[1];

PHP fileupload type check

Ok here is my code for uploading files
$ext_whitelist = array('pdf','doc','doc','mkv','mp4','mpg','mpeg','avi','flv','wma','ogg');
if(in_array($ext, $ext_whitelist))
{
$uniqid_file = uniqid('', true)."_".$file['name'];
$lokacija = $folder . "/" . $uniqid_file;
$encoded_uniqid_file = base64_encode($uniqid_file);
move_uploaded_file($file['tmp_name'], $lokacija);
$base_url= base_url("forms/fdownload/$encoded_uniqid_file/$path");
$form_data[$key] = "$uniqid_file ";
}
This checks file extension, so easy some could rename file, can someone help me to check file type proper?
Insted of a comment, I'll write a bit more as an answer.
Mimetype checking is a good thing if you want to know the type of the file, but it's not secure if you want to allow/deny the files at upload, because it's very easy to fake the mimetype.
Just try it, you can change it with a proxy or you can create a simple image, then add some php code at the end and rename it to .php. If you only check the mimetype, you can upload this .php file and run it on the server.
If you upload .jpg with php code in it, it's okay, the server won't push it through the php parser. (Except when you change the default configuration. (Apache: AddType, nginx: AddHandler )
There are some "secure" ways to check the uploaded files:
1. Check the extension and compare it to a whitelist.
This is the example in the question, but I'd like to write a complete solution. (A common mistake to check only the first think after the ., because there could be file names like: something.txt.php so always check the last postfix.)
$ext = array_pop(explode(".", $fileName));
$whitelist = array('pdf','doc','doc','mkv','mp4','mpg','mpeg','avi','flv','wma','ogg');
if (in_array($ext, $whitelist) {
//OK the extension is good, handle the upload.
} else {
//Wrong type, add error message.
}
If you use something like this, be careful and never allow extensions like .php and anything wich is in the server config.
2. Rename the file and drop the extension.
This is an another good way, but maybe you want to keep the original file name, the extension and the mimetype. You can store them in a database!
For this solution just take the original filename, add some random data (because if you upload into a single folder and you trie to upload something.jpg 2 time that would be a bad idea), then store this.
For example:
$newName = sha1($fileName.time());
move_uploaded_file($file['tmp_name'], $uploadPath . $newName);
Because the file doesn't have an extension, the server wont try to run it. (But if it's for example an image it'll work in the browsers, because they use the mimetype to determine the type and we didn't changed that.)
You can use
perl-file-mimeinfo
Ex:-
$file_path = '/tmp/temp.jpg';
$mimetype = trim(shell_exec("/usr/bin/mimetype -bi ".escapeshellarg($file_path)));
$info = null;
if(strpos($mimetype, "video/")===0 || strpos($mimetype, 'x-flash-video') > 0){
$info = 'video';
}elseif(strpos($mimetype, "audio/")===0){
$info = 'audio';
}elseif(strpos($mimetype, "image/")===0){
$info = 'image';
}

Check for file with same filename, but different extension

I have a directory contain jpeg and raw image files. Some jpeg files have a raw file version of them, some don't. Luckily, if a jpeg has a raw file they are named the same (excluding the extension). So, I need a way to check this directory for a matching raw file of the same filename, exclusing file extesion. the raw file, file extension could be pretty much anything.
Any ideas how I can do this? I have the filename (excluding extesion) stored of $filename at the moment.
To explain further. I have a directory with the following files in it:
cat.jpg
dog.jpg
bird.jpg
cat.raf
dog.foo
I need to match cat.jpg to cat.rag and dog.jpg to dog.foo. These have just been extracted from a uploaded zip file.
Try searching for files starting with the same name:
$fileWithoutExtension = basename($filename, '.jpg');
$allFilesWithThisName = glob($fileWithoutExtension . '.*');
if (count($allFilesWithThisName)) {
echo 'There is another file with this name';
}
As you already have the filename w/o the extension, you can just check if the raw file exists (file_exists()):
if (file_exists($filename.'.raw')) {
echo 'RAW file exists:', $filename , "\n";
}
But this seems so trivial to me, that I might did not understood your question completely.

finfo path not found

I'm on 5.3.1 and after reading the docs, I see that fileinfo is included and that pecl is no longer required. I an however getting:
finfo_file(): File or path not found
I'm not sure what it's looking for. I've enabled the extension in the ini file and attempted to run the example from the PHP site:
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
foreach (glob("*") as $filename) {
echo finfo_file($finfo, $filename) . "\n";
}
finfo_close($finfo);
Can someone tell me what file I need?
I've just discovered from my hosting company that the path to the elusive magic.mime file is to be found when running phpinfo(): look for the entry "mime_magic.magicfile". If it's not listed, contact your hosting company and explain you need this file and path for PHP finfo(). Worked for me.
You need to either configure your environment so PHP knows where the "magic database file" is, or, as another possibility, when calling fileinfo_open, you need to specify the path to the magic database file (quoting) :
Name of a magic database file, usually
something like /path/to/magic.mime. If
not specified, the MAGIC environment
variable is used. If this variable is
not set either, /usr/share/misc/magic
is used by default. A .mime and/or
.mgc suffix is added if needed.
See the example given on the manual page of fileinfo_open, for instance (quoting) :
$finfo = finfo_open(FILEINFO_MIME, "/usr/share/misc/magic"); // return mime type ala mimetype extension
if (!$finfo) {
echo "Opening fileinfo database failed";
exit();
}
/* get mime-type for a specific file */
$filename = "/usr/local/something.txt";
echo finfo_file($finfo, $filename);
/* close connection */
finfo_close($finfo);
Of course, up to you to find where that file is on your system...

How to get the file type in PHP

I have a .doc file and I renamed named it to give it a .jpg extension. When I process the renamed file with my function it accepts the file as having a .jpg although the file is not really a JPEG. What's the best way to find the actual file type? Here is my current code:
function getExtension($str) {
$i = strrpos($str,".");
if (!$i) { return ""; }
$l = strlen($str) - $i;
$ext = substr($str,$i+1,$l);
return $ext;
}
What's the best way to check the file's type without depending on the extension?
You can use PHP's Fileinfo to detect file types based on their contents; however, it is only available in PHP 5.3.0 or if you have access to install PECL extensions.
It returns a file's mime-type, such as text/html, image/gif, or application/vnd.ms-excel which should be more accurate (accounts for contents possibly having multiple common extensions, such as: jpg, jpe, jpeg).
This is the one I use and it has never failed me.
function getExtension($str)
{
$i = explode('.', $str);
return strtolower(end($i));
}
I don't know if you can check the actual original file extension if someone has renamed it, you would have to have the spec of every file type you were checking for I'm not sure how easy it is to tell. But you could verify something was an image like this:
function isImage($file)
{
if(#getimagesize($file) == false)
return false;
else
return true;
}
Summing up
if(isImage($file) && getExtention($file) == "jpg")
{
//Process, it's a valid image
}
Firstly, with respect to file extension, on't reinvent the wheel. Use PHP's pathinfo() function:
$extension = pathinfo($filename, PATHINFO_EXTENSION);
Secondly, you're quite right: the file extension tells you nothing about it's contents.
Third, you should where possible determine the contents of the file yourself rather than relying on either the file extension or the MIME type (from file uploads). Both are arbitrary and simply specified by the client.
Images are fairly easy because you can load the file with the GD library. It'll fail if its not an image and you can interrogate it for size, etc.
Word documents are harder. If you're running on Windows, you can make a call to the system to load the file and see if it does load. I'm not aware of any native PHP library that can do this.
If you just want to get the file extension, you could use pathinfo:
function getExtension($str)
{
$info = pathinfo($str)
return $info['extension'];
}
However, it sounds like you want to check if the file you're given is a valid image. To do that, you can do something similar with the getimagesize() function:
function getMimeType($str)
{
$info = #getimagesize($str)
if (!$info)
{
// Uh oh, this wasn't a valid image -- do some error handling
return NULL;
}
return $info['mime'];
}
Using this, you can check the MIME type of the image ("image/jpeg", etc.), and validate if the given file is really the type of image you think it is.
You can use explode(".", $sFileName) and take the last item of the array to do this, but that one fails when you have something like filename.tar.gz, when you want the last two array items, or filename.class.php, when, after you have implemented the last-two-array-items-thing, you just want the last one.
The best way of doing this is, in my opinion, pathinfo($sFileName). This returns an array with the keys dirname, basename, extension (if any), and filename.
If you want the file type, though, you'll have to use something like PHP 5.3's built-in Fileinfo to get the file's MIME-type. (getimagesize() returns the MIME-type too, but this only works on images!)
function file_extension($filename) {
$path_info = pathinfo($filename);
return $path_info['extension'];
}

Categories