-2

I have a list of file extensions that must be check it's existence to any file (name + extension).

I want to use preg_match function, so I need an appropriate regex pattern with fastest logic and could produce shortest matches array (array length = 1).

File extensions = jpg|jpeg|png|gif|pdf

Example:

$pattern = ????;
$matches = '';
$result = preg_match($pattern, $filename, $matches);

Correct file (name + extension) Input:

1) $filename = 'trial.gen.OO7.jpg';

2) $filename = 'http://localhost/index.php/profile/stackoverflow/0000000123.911.png?_id=900d';

3) $filename = 'fast-n-furious.pdf';

Output:

=> $result: true
=> $matches:
    1) array( [0] => trial.gen.OO7.jpg )
    2) array( [0] => http://localhost/index.php/profile/stackoverflow/0000000123.911.png )
    3) array( [0] => fast-n-furious.pdf )

Incorrect file (name + extension) Input:

1) $filename = 'trial.gen.OO7.jpg.php';

2) $filename = 'http://localhost/index.php/profile/stackoverflow/0000000123.911.?_id=84d';

3) $filename = 'fast-n-furious';

Output:

=> $result: false
=> $matches: array( [] )

SecretAgentMan
  • 2,856
  • 7
  • 21
  • 41
OO7
  • 660
  • 4
  • 10
  • 1
    Using `preg_match` is overengineering. – u_mulder Apr 04 '20 at 18:19
  • 1
    See https://stackoverflow.com/questions/619610/whats-the-most-efficient-test-of-whether-a-php-string-ends-with-another-string and https://stackoverflow.com/questions/834303/startswith-and-endswith-functions-in-php – Wiktor Stribiżew Apr 04 '20 at 18:24
  • Thank you. But I need a cool fastest pattern. – OO7 Apr 04 '20 at 18:29
  • 1
    Look at `pathinfo`. When writing a regex `cool fastest pattern` isn't a description I hear often. – user3783243 Apr 04 '20 at 18:34
  • Thank you. I means the pattern will produce one dimension array with length 1, and have fastest logic. You can see about it on my question. – OO7 Apr 04 '20 at 18:41
  • @OO7 If you worry about execution time, a plain string function or file system check - whatever is appropriate - will probably be faster; in any case, you should describe what it is you actually want to do, and what your output should be. Do you want to validate a file name and receive a truth value, or match the whole file name, or match the extension? The phrase `shortest matches array (array length = 1)` does not give any insight into the kind of information you want to get. – oriberu Apr 04 '20 at 19:12
  • Verry sorry, I have edit my question for that inconvenient. However thank you for ur attn. – OO7 Apr 04 '20 at 19:59
  • @OO7 Using `$pattern = '/.*\.(?:jpe?g|png|gif|pdf)$/i';` should pretty much give you the results you want. The expression matches a whole line if it ends in one of the given file extensions preceded by a period. If you want to filter a list of file names down to those matching the expression, you could use [preg_grep()](https://www.php.net/manual/en/function.preg-grep.php). `.*` is not needed to validate the file name, but makes php return the whole string. You wouldn't actually need that in your scenario, since you have `$filename` to begin with. – oriberu Apr 04 '20 at 20:24
  • @oriberu: Excellent. Very comprehensive. Thank you. However, how if the file is on url and end with query string. Eg: $filename = 'http://localhost/index.php/profile/stackoverflow/0000000123.911.png?_id=900d'; I hope you give best answer nor a comment pls. – OO7 Apr 04 '20 at 21:04

2 Answers2

2

The following regular expression matches a whole line .* if it ends in a period \. followed by one of the given file extensions (?:jpe?g|png|gif|pdf), while accounting for an optional group of query parameters (?:\?\S+)? preceding the end of the line $:

/.*\.(?:jpe?g|png|gif|pdf)(?:\?\S+)?$/i

See regex demo. The i flag enables case-insensitive matching.

In PHP:

$filename = 'http://localhost/index.php/profile/stackoverflow/0000000123.911.png?_id=900d';
$pattern = '/.*\.(?:jpe?g|png|gif|pdf)(?:\?\S+)?$/i';
$result = preg_match($pattern, $filename, $matches);

Which leads to 1 (meaning success) as $result and an array containing the matched line as $matches.

In case you want to deal with a list of texts and only grab the ones matching the pattern, you could also use preg_grep():

$texts = [
    'trial.gen.OO7.jpg', 
    'http://localhost/index.php/profile/stackoverflow/0000000123.911.png?_id=900d', 
    'fast-n-furious.pdf', 
    'trial.gen.OO7.jpg.php', 
    'http://localhost/index.php/profile/stackoverflow/0000000123.911.?_id=84d', 
    'fast-n-furious'
];
$results = preg_grep($pattern, $texts);

$results then contains:

Array
(
    [0] => trial.gen.OO7.jpg
    [1] => http://localhost/index.php/profile/stackoverflow/0000000123.911.png?_id=900d
    [2] => fast-n-furious.pdf
)
oriberu
  • 1,186
  • 9
  • 6
0

After doing some trial, finally I have solve the problem.

To: @oriberu, @WiktorStribizew, @u_mulder, etc. : thank you for the comments and helps.

Here is the function for anybody that wants it. Feel free to copy and paste this code for your software development.

/* set isFullPath argument to true for full path match result
    otherwise set to false for file name + extension result (no full path)
 */
function isMatchExtension($extList, $filePath, &$matches, $isFullPath = false) {

    $prefix = $isFullPath ? '.*' : '[^\/|\\\]*';

    /* make sure to check for "?" mark to handle file extension redundancy possibility inside the file path
        eg:
          extension files: 001|002|003|004|005|006|007

          for filePath: '/trial/profile.001/files/anyfile.007';

          then match should be: (for full path)
          => Array( [0] => /trial/profile.001/files/anyfile.007 )

          or: (for file name + extension only)
          => Array( [0] => anyfile.007 )
     */
    $pattern = "/$prefix\.(?:$extList)(?=\?)/i";

    /* we add $filePath with "?" mark to make sure the path has it.
    return preg_match($pattern, $filePath.'?', $matches);
}

// Usage Example:

$extList = 'jpg|jpeg|png|gif|pdf|html';

$filePath = 'http://localhost/index.php/profile/stackoverflow/0000000123.911.png?_id=900d';

$isFullPath = false;

$matches = [];

$isMatch = isMatchExtension($extList, $filePath, $matches, $isFullPath);

 // display result
 echo 'result: ' . ($isMatch ? 'true' : 'false') . '</br>';
 echo 'matches: </br>';
 print_r($matches);

 // the output:
 result: true
 matches:
 Array( [0] => 0000000123.911.png )
SecretAgentMan
  • 2,856
  • 7
  • 21
  • 41
OO7
  • 660
  • 4
  • 10