18

I'm reading all the files in a single directory and I want to filter on JPG,JPEG,GIF and PNG.

Both capital and small letters. Those are the only files to be accepted.

I am currently using this:

$testPics = takeFiles($picsDir, "([^\s]+(?=\.(jpg|JPG|jpeg|JPEG|png|PNG|gif|GIF))\.\2)");

and the function takeFiles looks like this:

function takerFiles($dir, $rex="") {
    $dir .= "/";
    $files = array();
    $dp = opendir($dir);
    while ($file = readdir($dp)) {
      if ($file == '.')  continue;
      if ($file == '..') continue;
      if (is_dir($file)) continue;
      if ($rex!="" && !preg_match($rex, $file)) continue;
      $files[] = $file;
    }
    closedir($dp);
    return $files;
  }

And it always returns nothing. So something must be wrong with my regex code.

Vordreller
  • 2,524
  • 10
  • 34
  • 51

7 Answers7

38

I think something is wrong with your regex. Try testing regexes here first: https://www.regexpal.com/

I think this one might work for you:

/^.*\.(jpg|jpeg|png|gif)$/i

Note the /i at the end - this is the "case insensitive" flag, saves you having to type out all permutations :)

elliottregan
  • 1,301
  • 1
  • 13
  • 33
11

How about using glob() instead?

$files = glob($dir . '*.{jpg,gif,png,jpeg}',GLOB_BRACE);
Eran Galperin
  • 86,251
  • 24
  • 115
  • 132
3

Is there any reason you don't want to use scandir and pathinfo?

public function scanForFiles($path, array $exts)
{
    $files = scanDir($path);

    $return = array();

    foreach($files as $file)
    {
        if($file != '.' && $file != '..')
        {
            if(in_array(pathinfo($file, PATHINFO_EXTENSION), $exts))) {
                $return[] = $file;   
            }
        }
    }

    return $return;
}

So you could also check if the file is a directory and do a recursive call to scan that directory. I wrote the code in haste so might not be 100% correct.

Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47
smack0007
  • 11,016
  • 7
  • 41
  • 48
  • This answser should be at the top. Regexp are often overkill. I love them but you must stick to KISS when possible. – Bite code Nov 26 '08 at 16:15
2

This works out for me

$string = "your-file-name.jpg";
preg_match("/\b(\.jpg|\.JPG|\.png|\.PNG|\.gif|\.GIF)\b/", $string, $output_array);

Best.

Rodrigo
  • 1,638
  • 1
  • 15
  • 27
1

You should put slashes around your regexp. -> "/(...)/"

angus
  • 2,305
  • 1
  • 15
  • 22
0

There are a few ways of doing this.

Have you tried glob()?:

$files = glob("{$picsDir}/*.{gif,jpeg,jpg,png}", GLOB_BRACE);

Have you considered pathinfo()?:

$info = pathinfo($file);
switch(strtolower($info['extension'])) {
    case 'jpeg':
    case 'jpg':
    case 'gif':
    case 'png':
        $files[] = $file;
        break;
}

If you're insistant upon using the regular expression, there's no need to match the whole filename, just the extension. Use the $ token to match the end of the string, and use the i flag to denote case-insensitivity. Also, don't forget to use a delimiter in your expression, in my case "%":

$rex = '%\.(gif|jpe?g|png)$%i';
ringmaster
  • 2,879
  • 3
  • 28
  • 31
0

Here are two different ways to compile an array of files by type (conf for demo) from a target directory. I'm not sure which is better performance wise.

    $path    = '/etc/apache2/';
    $conf_files = []; 

    // Remove . and .. from the returned array from scandir
    $files = array_diff(scandir($path), array('.', '..'));
    foreach($files as $file) {
        if(in_array(pathinfo($file, PATHINFO_EXTENSION), ['conf'])) {
            $conf_files[] = $file;   
        }   
    }
    return $conf_files;

This will return the full file path not just the file name

return $files = glob($path . '*.{conf}',GLOB_BRACE);
zeros-and-ones
  • 4,227
  • 6
  • 35
  • 54