search for in the  
<flockfopen>
Last updated: Thu, 19 May 2005

fnmatch

(PHP 4 >= 4.3.0, PHP 5)

fnmatch -- Match filename against a pattern

Description

bool fnmatch ( string pattern, string string [, int flags] )

fnmatch() checks if the passed string would match the given shell wildcard pattern.

This is especially useful for filenames, but may also be used on regular strings. The average user may be used to shell patterns or at least in their simplest form to '?' and '*' wildcards so using fnmatch() instead of ereg() or preg_match() for frontend search expression input may be way more convenient for non-programming users.

Example 1. Checking a color name against a shell wildcard pattern.

<?php
if (fnmatch("*gr[ae]y", $color)) {
  echo
"some form of gray ...";
}
?>

Warning

For now this function is not available on Windows or other non-POSIX compliant systems.

See also glob(), ereg(), preg_match() and the Unix manpage on fnmatch(3) for flag names (as long as they are not documented here ).



User Contributed Notes
fnmatch
jcannonb at gmail dot com
06-May-2005 02:50
I wrote a better SQL match.  The other one had bugs in it:

function sql_match($pattern,$data)
{
  $lpattern=strtolower($pattern);
   $ldata=strtolower($data);
  
  $lp=strlen($lpattern);
   $ld=strlen($ldata);
  
   $ip=0;
   $id=0;
  
   for ($ip=0; $ip<$lp; $ip++)
   {
     if ($lpattern[$ip]=='%')
       {
         $ip++;
           if ($ip >= $lp)
           {
             return true;
           }
           for (;;)
           {
             if ($lpattern[$ip] == $ldata[$id])
               {
                 break;
               }
               else
               {
                 $id++;
                   if ($id > $ld)
                   {
                     return false;
                   }
               }
           }
       }
       if ($lpattern[$ip] <> $ldata[$id])
       {
         return false;
       }
       $id++;
   }
       if ($ld >= $lp)
       {
         if ($lpattern[$lp-1] != '%')
           {
             return false;
           }
       }
   return true;
}
jcannonb at gmail dot com
27-Apr-2005 11:04
/******************************************************************\
* sql_match Written by Joshua C. Butcher                          *
* Works like the like() functionality in SQL                      *
* %zealbot% matches zealbot 1234zealbot and zealbodt1234          *
* zealbot% matches zealbot1234                                    *
* %zealbot matches 1234zealbot                                    *
* zealbot matches only zealbot                                    *
/******************************************************************/

function sql_match($pattern,$data)
{
  $lp=strlen($pattern);
   $ld=strlen($data);
  
   $ip=0;
   $id=0;
  
   for ($ip=0; $ip<$lp; $ip++)
   {
     if ($pattern[$ip]=='%')
       {
         $ip++;
           if ($ip >= $lp)
           {
             return true;
           }
           for (;;)
           {
             if ($pattern[$ip] == $data[$id])
               {
                 break;
               }
               else
               {
                 $id++;
                   if ($id > $ld)
                   {
                     return true;
                   }
               }
           }
       }
       if ($pattern[$ip] <> $data[$id])
       {
         return false;
       }
       $id++;
   }
   if ($ld <> $lp)
   {
     return false;
   }
   return true;
}
jcl [atNOSPAM] jcl [dot] name
22-Nov-2004 09:49
Oooops, sorry, I did a mistake... Here is the right version :

function my_fnmatch ($pattern, $file)
{
  $lenpattern = strlen($pattern);
  $lenfile    = strlen($file);

  for($i=0 ; $i<$lenpattern ; $i++)
  {
   if($pattern[$i] == "*")
   {
     for($c=$i ; $c<max($lenpattern, $lenfile) ; $c++)
     {
       if(my_fnmatch(substr($pattern, $i+1), substr($file, $c)))
           return true;
     }
     return false;
   }

   if($pattern[$i] == "[")
   {
     $letter_set = array();
     for($c=$i+1 ; $c<$lenpattern ; $c++)
     {
       if($pattern[$c] != "]")
         array_push($letter_set, $pattern[$c]);
       else
         break;
     }
     foreach($letter_set as $letter)
     {
       if(my_fnmatch($letter.substr($pattern, $c+1), substr($file, $i)))
         return true;
     }
     return false;
   }

   if($pattern[$i] == "?") continue;
   if($pattern[$i] != $file[$i]) return false;
  }

  if(($lenpattern != $lenfile) && ($pattern[$i - 1] == "?")) return false;
  return true;
}

Cheers
Jean-Charles Lefebvre
jcl [atNOSPAM] jcl [dot] name
22-Nov-2004 09:41
I've found a bug in the my_fnmatch() function of 'michael at zend dot com'.
If you call :
my_fnmatch('c:/tem?', 'c:/tempo');

It will match, this is an error since the '?' generic character is supposed to match only one character.
The bug was hard to find since this is really an exception...
Here is my corrected version, I think it's bug-free now :)

function my_fnmatch ($pattern, $file)
{
  $lenpattern = strlen($pattern);
  $lenfile    = strlen($file);

  for($i=0 ; $i<$lenpattern ; $i++)
  {
   if($pattern[$i] == "*")
   {
     for($c=$i ; $c<max($lenpattern, $lenfile) ; $c++)
     {
       if(my_fnmatch(substr($pattern, $i+1), substr($file, $c)))
           return true;
     }
     return false;
   }

   if($pattern[$i] == "[")
   {
     $letter_set = array();
     for($c=$i+1 ; $c<$lenpattern ; $c++)
     {
       if($pattern[$c] != "]")
         array_push($letter_set, $pattern[$c]);
       else
         break;
     }
     foreach($letter_set as $letter)
     {
       if(my_fnmatch($letter.substr($pattern, $c+1), substr($file, $i)))
         return true;
     }
     return false;
   }

   if($pattern[$i] == "?") continue;
   if($pattern[$i] != $file[$i]) return false;
  }

  if($pattern[$i - 1] == "?") return false;
  return true;
}

The bug correction is at the end of the function (the 'if' test).

Cheers,
Jean-Charles Lefebvre
phlipping at yahoo dot com
06-Aug-2003 05:59
you couls also try this function that I wrote before I found fnmatch:

function WildToReg($str)
{
  $s = ""; 
  for ($i = 0; $i < strlen($str); $i++)
  {
   $c = $str{$i};
   if ($c =='?')
   $s .= '.'; // any character
   else if ($c == '*')   
   $s .= '.*'; // 0 or more any characters   
   else if ($c == '[' || $c == ']')
   $s .= $c;  // one of characters within []
   else
   $s .= '\\' . $c;
  }
  $s = '^' . $s . '$';

  //trim redundant ^ or $
  //eg ^.*\.txt$ matches exactly the same as \.txt$
  if (substr($s,0,3) == "^.*")
   $s = substr($s,3);
  if (substr($s,-3,3) == ".*$")
   $s = substr($s,0,-3);
  return $s;
}

if (ereg(WildToReg("*.txt"), $fn))
  print "$fn is a text file";
else
  print "$fn is not a text file";
michael at zend dot com
18-Apr-2003 06:18
Try this one, supporting all filename matching facilities:

  // MY_FNMATCH
  function my_fnmatch($pattern, $file)
  {
   for($i=0; $i<strlen($pattern); $i++) {
     if($pattern[$i] == "*") {
       for($c=$i; $c<max(strlen($pattern), strlen($file)); $c++) {
         if(my_fnmatch(substr($pattern, $i+1), substr($file, $c))) {
           return true;
         }
       }
       return false;
     }
     if($pattern[$i] == "[") {
       $letter_set = array();
       for($c=$i+1; $c<strlen($pattern); $c++) {
         if($pattern[$c] != "]") {
           array_push($letter_set, $pattern[$c]);
         }
         else break;
       }
       foreach ($letter_set as $letter) {
         if(my_fnmatch($letter.substr($pattern, $c+1), substr($file, $i))) {
           return true;
         }
       }
       return false;
     }
     if($pattern[$i] == "?") {
       continue;
     } 
     if($pattern[$i] != $file[$i]) {
       return false;
     }
   }

   return true;
  }
me at lejfdiecks dot de
15-Apr-2003 09:46
I had the same problem ("Call to undefined function: fnmatch()") using PHP 4.2.3 on a hosted webserver; so I wrote "my own" fnmatch(). Hope it helps someone:

function fnmatch($strPattern, $strString)
// My fnmatch()
// Supports '?' and '*' as wildcards
{

  $intPos = 0;
  do
  {
   $strPatternChar = substr($strPattern, $intPos, 1);
   $strStringChar  = substr($strString, $intPos, 1);

   if ($strPatternChar == '*')
   {
     $bolMatch = TRUE;
     break;
   }
   $bolMatch = ($strPatternChar == $strStringChar) || ($strPatternChar == '?' && $strStringChar != '');
   $intPos++;
  } while (($bolMatch == TRUE) && ($intPos < max(strlen($strPattern), strlen($strString))));

  return($bolMatch);
}

// Main program - test fnmatch() function
if (fnmatch('te?t', 'test'))
  echo "Pattern <b>matches</b> string.";
else
  echo "Pattern <b>does not</b> match string.";

<flockfopen>
 Last updated: Thu, 19 May 2005
Copyright © 2001-2005 The PHP Group
All rights reserved.
This unofficial mirror is operated at: The Server Pages
Last updated: Thu May 19 17:35:34 2005 CDT