3

I came here searching for an answer to sniffing for iOS 6 via the useragent and found a wonderful answer here: How to detect iOS 6 and all minor versions by user agent?

All regular expressions I've worked with previously have been pretty simple and I'm banging my head against a wall trying to get this one working properly. Unfortunately the PHP parser isn't giving me any errors!

I know for a fact I'm doing something wrong, since I'm getting a match for the code below while running firefox on my laptop.

I would appreciate if anyone could point me in the right direction here, I can't figure out what I'm doing wrong.

$subject = $_SERVER['HTTP_USER_AGENT'];
$pattern = '~^(?:(?:(?:Mozilla/\d.\d\s*()+|Mobile\s*Safari\s*\d+.\d+(.\d+)?\s*)(?:iPhone(?:\s+Simulator)?|iPad|iPod);\s*(?:U;\s*)?(?:[a-z]+(?:-[a-z]+)?;\s*)?CPU\s* (?:iPhone\s*)?(?:OS\s*\d+\d+(?:\d+)?\s*)?(?:like|comme)\s*Mac\s*O?S?\s*X(?:;\s*[a-z]+(?:-[a-z]+)?)?)\s*)?(?:AppleWebKit/\d+(?:.\d+(?:.\d+)?|\s*+)?\s*)?(?:(KHTML,\s*(?:like|comme)\s*Gecko\s*)\s*)?(?:Version/\d+.\d+(?:.\d+)?\s*)?(?:Mobile/\w+\s*)?(?:Safari/\d+.\d+(.\d+)?)?.*$~';

if (preg_match($pattern,$subject))
{
    echo "match";
}
Community
  • 1
  • 1
nmford
  • 151
  • 2
  • 12
  • What does `var_dump( $_SERVER['HTTP_USER_AGENT']);` output? – nickb Oct 12 '12 at 14:41
  • @nickb Obviously depends on what device/browser I'm using, but in Firefox on my laptop: string(83) "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1" It's not supposed to match that! – nmford Oct 12 '12 at 14:42
  • 2
    Obviously. The point is the regex is faulty - It does indeed match that user agent, when clearly it is not the correct behavior. – nickb Oct 12 '12 at 14:44
  • @nickb Ack, I figured with the detail and instructions the guy put into his reply that it worked properly! – nmford Oct 12 '12 at 14:46
  • @nickb especially as that user had checked it as a correct answer – nmford Oct 12 '12 at 14:48

2 Answers2

3

Try this instead :

^(?:(?:(?:Mozilla/\d\.\d\s*\()+|Mobile\s*Safari\s*\d+\.\d+(\.\d+)?\s*)(?:iPhone(?:\s+Simulator)?|iPad|iPod);\s*(?:U;\s*)?(?:[a-z]+(?:-[a-z]+)?;\s*)?CPU\s*(?:iPhone\s*)?(?:OS\s*\d+_\d+(?:_\d+)?\s*)?(?:like|comme)\s*Mac\s*O?S?\s*X(?:;\s*[a-z]+(?:-[a-z]+)?)?\)\s*)?(?:AppleWebKit/\d+(?:\.\d+(?:\.\d+)?|\s*\+)?\s*)?(?:\(KHTML,\s*(?:like|comme)\s*Gecko\s*\)\s*)?(?:Version/\d+\.\d+(?:\.\d+)?\s*)?(?:Mobile/\w+\s*)?(?:Safari/\d+\.\d+(\.\d+)?.*)?$

Demo : http://gskinner.com/RegExr/?32eou

A even more generic solution : http://code.google.com/p/php-mobile-detect/

Stephan
  • 41,764
  • 65
  • 238
  • 329
Alix Axel
  • 151,645
  • 95
  • 393
  • 500
  • Warning: preg_match() [function.preg-match]: Compilation failed: range out of order in character class at offset 243 – nmford Oct 12 '12 at 14:49
  • @nmford: Did you add the delimiters? – Alix Axel Oct 12 '12 at 14:51
  • @nmford: I guess I double pasted or something, try again. – Alix Axel Oct 12 '12 at 14:57
  • 1
    The script parses now, but it still matches for firefox on my laptop which it shouldn't. Starting to think that perhaps I should just put something simpler together myself! – nmford Oct 12 '12 at 15:02
  • 1
    @nmford: Matches Firefox because of the `Mozilla` and since everything else is optional... You should use atomic groups. Or better yet, don't reinvent the wheel: http://code.google.com/p/php-mobile-detect/. – Alix Axel Oct 12 '12 at 15:04
  • Hah, thanks Alix. Probably the best way to go. I voted this answer up for that comment, perhaps edit your answer to reflect it? – nmford Oct 12 '12 at 15:06
  • @nmford: No problem. Just out of curiosity, may I ask where you picked up `~` for the PCRE delimiters? I've been using them for years, and lately I've been seeing them used everywhere! – Alix Axel Oct 12 '12 at 15:07
  • Saw it mentioned on here once and have been using them since! – nmford Oct 12 '12 at 15:10
  • @Stephan: Still, doesn't seem to match anything. – Alix Axel Oct 12 '12 at 19:31
  • 2
    @AlixAxel I have updated the demo. It runs fine now. I noticed that the original cut/paste regex in your answer had some meta characters left out. – Stephan Oct 12 '12 at 20:06
3

The regex had some error. Some metachars has gone because of SO character escaping system.

Here is the PHP code of your question updated :

$subject = $_SERVER['HTTP_USER_AGENT'];
$pattern = '~^(?:(?:(?:Mozilla/\d\.\d\s*\()+|Mobile\s*Safari\s*\d+\.\d+(\.\d+)?\s*)(?:iPhone(?:\s+Simulator)?|iPad|iPod);\s*(?:U;\s*)?(?:[a-z]+(?:-[a-z]+)?;\s*)?CPU\s*(?:iPhone\s*)?(?:OS\s*\d+_\d+(?:_\d+)?\s*)?(?:like|comme)\s*Mac\s*O?S?\s*X(?:;\s*[a-z]+(?:-[a-z]+)?)?\)\s*)?(?:AppleWebKit/\d+(?:\.\d+(?:\.\d+)?|\s*\+)?\s*)?(?:\(KHTML,\s*(?:like|comme)\s*Gecko\s*\)\s*)?(?:Version/\d+\.\d+(?:\.\d+)?\s*)?(?:Mobile/\w+\s*)?(?:Safari/\d+\.\d+(?:\.\d+)?.*)?$~';

if (preg_match($pattern,$subject))
{
    echo "match";
}
Stephan
  • 41,764
  • 65
  • 238
  • 329