Check if file exists without extension

Hi,
I was just wondering how I could check if a file exists without the extension, and then get the extension? Basically “filename” could be .jpg .png or .gif but I won’t know which. Any help would be appreciated.

Cheers,
Rhys

I’ll give you 2 hints as to how i’d do it, and lets see if you can figure it out :wink:

[FPHP]scandir[/FPHP]
[FPHP]preg_grep[/FPHP]

cough glob /cough

Which is fine if you want to scan the entirity of your structure. If you want a specific directory scanned, you’ll need a bit more refinement than glob :wink:

scandir and create an array of files, then check for the filename using preg_grep?

Something along the lines of:


$dir    = '/images/montage';
$files = scandir($dir);
$matches = preg_grep($filename.??EXT??, $files);
echo $matches[0];

Is that right? And how would I know what I have, ie .jpg?

Thanks for the replies.

preg_grep for “~”.$filename.“~” (need the delimiters on the pattern)

foreach ($matches AS $match) {
echo end(explode(‘.’,$match));
}

Can you elaborate on “scan the entirity of your structure”?

I was wondering the same thing. Surely glob, a system function acting on the CWD, is faster than grabbing all files in a directory and separately applying a regular expression?

Why not just:

$dir = 'images/montage';
$filename = 'test';
$files = glob("{$dir}/{$filename}.*");
var_dump($files);

In addition to all the functions mentioned above, you can use [fphp]pathinfo[/fphp] to break the path up into sections, including getting the extension of the file or getting its base name.

Wait, ok - glob allows you to use a pattern, so you just need the pattern for your search. I think this will work - let me know if it works…


$imageFilesInDirectory = glob('*.{jpg}{png}{gif}{jpeg}');

Do NOT use double quotes on that pattern, as the braces would be interpretted by PHP as a variable delimit. In that string the braces delimit the pattern of the extension being sought.

If that works as I think it will return the image files of the current working directory. If you know the directory you need to search, prepend it by absolute path like so…


$imageFilesInDirectory = glob($dir.'/*.{jpg}{png}{gif}{jpeg}');  // Shouldn't there need to be some | operator between extensions sought?

I have 20,000 files/images in a subdirectory of my site (I’m running a Wiki.)
In another subdirectory, I have 2 files.

You’re telling me glob’ing across 20002 files is going to be faster than scandir’ing 2 and running a preg across them?

Touche good sir. Dare I challenge you to a duel with some chdir or shall I just accept defeat?

I’d be interested to see what’s quicker:

chdir,glob,chdir (because you gotta get back to the original dir)
or
scandir,preg_grep

Honestly, I dont know which would be faster.

[ot]I’m completely lost, could you answer my earlier question, StarLion? What’s with the chdir()-ing? Also, how is glob()-ing a folder (or several) and different to scandir()-ing a folder (or several)? glob is essentially scandir+regex*. I don’t understand how you think one would do something 20,002 times and the other only 2.

  • wildcard pattern matching, not regex.[/ot]

As the others have noted, one way would be to use [glob()](http://php.net/glob) to look for files matching a pattern.

$files = glob('path/to/files/filename.{jpg,png,gif}', GLOB_BRACE);

Another option is just to loop over the extensions until you find one, or not.


$extensions = array('jpg', 'png', 'gif');
foreach ($extensions as $ext) {
    if (file_exists('path/to/files/filename.' . $ext)) {
        echo 'Found filename.' . $ext;
        break;
    }
}

Unless I’m very confused about the method of glob, running glob() pulls an entry for every file of every directory at-or-below the CWD, checks it against the wildcard, and then either returns it or doesnt, and moves on.

In the example above, if you stayed in the root directory and glob’d, glob would have to work over 20002 files (plus however many were in the root directory itself).

Jake’s statement about chdir moves the CWD to the subdirectory first, so glob() only has to run over 2 files. chdir would be needed to move back to the inital directory at the end to prevent issues with other file operations in the page execution.

Scandir takes the directory to scan as a parameter, and so will only scan the 2 files without needing to change the CWD. (Well, 4 files on a *NIX system, as . and … will be returned as well, but the point remains.)

I’m not sure where the apparent need for calling chdir() came from, that’s not the case at all. With glob() you can provide any path you like (including absolute paths) as part of the pattern, as in my example above.

As for glob() looking recursively into all files/folders from the specified path, that’s not the case at all. Glob can be told to look in multiple folders, given the right pattern, e.g. path/to/folders/*/*.txt. The most usual case (again see my example) is to look at the contents of a single folder (by specifying a path with no wildcards, path/to/files/) for file/folder names matching a wildcard pattern (filename.*).

So glob walks to a directory first? Handy to know. Thanks Salathe!

(should probably say “it sub patterns through the directories first”, but it’s 9am and I’m on an iPhone. Editing is hard)

Wow a lot of responses. Thanks. I wasn’t in work Friday so only just seen them. I think I will give glob a try:


$files = glob('path/to/files/filename.{jpg,png,gif}', GLOB_BRACE);  

So thanks for that and for all help.

I will give it a try first thing when I’m back in and post results. Should be much cleaner than the old system of grabbing the filenames from the DB.

Cheers,
Rhys

Slight problem. Just trying to debug and make sure some files are being returned. I have:

$files = glob(URL_IMG.'montage/montage-'.$categoryID.'.{jpg,png,gif,jpeg}', GLOB_BRACE);
foreach ($files as $filename){
echo $filename."\
";
}

Which returns Warning: Invalid argument supplied for foreach() in …

I thought $files would be an array and that code would be OK?

OK it turns out glob() simply isn’t finding anything. Even with a wildcard extension. Nothing is retuned. Any ideas why glob() wouldn’t work?

What is the value of URL_IMG.'montage/montage-'.$categoryID.'.{jpg,png,gif,jpeg}'?