Forum Moderators: coopster

Message Too Old, No Replies

Detecting browser user-agent in php

Is there a very simple way?

         

trillianjedi

4:46 pm on Dec 1, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Hi guys,

A few searches revealed a couple of basic browser user-agent detection functions, although nothing under 20 lines of code or so.

All I want to do is:-

If Not(FireFox) display GetFirefox adsense button

Is there a gloriously simple way of doing that, or do I need to use one of these GPL script functions out there?

Thanks,

TJ

coopster

4:54 pm on Dec 1, 2005 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



I am by no means an expert on user agents but if you are looking for something quite simple you could just look for the term 'Firefox' in the HTTP_USER_AGENT $_SERVER variable.
if (!stripos [php.net]($_SERVER['HTTP_USER_AGENT'], 'Firefox')) {  
// display GetFirefox adsense button
}

Note: stripos() is PHP5 only.

trillianjedi

5:35 pm on Dec 1, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



That's certainly gloriously simple coop, thanks.

I'm not sure if we're on php5 - I think we're on 4?

Is there an alternative to the StrPos function in 4?

TJ

DanA

6:44 pm on Dec 1, 2005 (gmt 0)

10+ Year Member



$UA=getenv("HTTP_USER_AGENT");
if(!eregi("Firefox",$UA)){
// display GetFirefox adsense button
}

jatar_k

7:27 pm on Dec 1, 2005 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



you could use strpos which is php4

coopster

7:53 pm on Dec 1, 2005 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



To get a case-insensitive search I used stripos(). strpos() will be case-sensitive. A regex would probably be your next best bet as DanA has demonstrated. stripos() is just faster, that's all.

trillianjedi

8:18 pm on Dec 1, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Thanks guys - very helpful.

stripos() is just faster

How about strtolower(strpos($UA))?

jatar_k

8:34 pm on Dec 1, 2005 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



yep, that should be fine

whoisgregg

11:42 pm on Dec 1, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



How about strtolower(strpos($UA))?

yep, that should be fine

Isn't that just going to lowercase the result of strpos?

I think it'd look like this if you don't have stripos:

if (!strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'firefox')) { 
// display GetFirefox adsense button
}

coopster

2:37 am on Dec 2, 2005 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



Right on, whoisgregg. And I did a little time study in PHP5 to show some differences when I tested ...

assigning a variable using getenv()
versus
assigning a variable using the $_SERVER superglobal

and

discovering the user agent with each of the following:
eregi
stripos
strpos(strtolower())
preg_match

Conclusions on my PHP5 box at the end of the code (note: the snippet won't work unless you are on PHP5 because of the microtime function, you'll have to modify it to work in PHP4) ...

<?php 
$time_start = microtime(true);
for ($i=1; $i<=1000; $i++) {
$UA=getenv("HTTP_USER_AGENT");
}
$time_end = microtime(true);
$time = $time_end - $time_start;
printf("getenv Time: %0.15f\n", $time);
$time_start = microtime(true);
for ($i=1; $i<=1000; $i++) {
$UA=$_SERVER['HTTP_USER_AGENT'];
}
$time_end = microtime(true);
$time = $time_end - $time_start;
printf("SERVER Time: %0.15f\n", $time);
$time_start = microtime(true);
for ($i=1; $i<=1000; $i++) {
if(!eregi("Firefox",$_SERVER['HTTP_USER_AGENT'])){
// display GetFirefox adsense button
}
}
$time_end = microtime(true);
$time = $time_end - $time_start;
printf("eregi Time: %0.15f\n", $time);
$time_start = microtime(true);
for ($i=1; $i<=1000; $i++) {
if (!stripos($_SERVER['HTTP_USER_AGENT'], 'Firefox')) {
// display GetFirefox adsense button
}
}
$time_end = microtime(true);
$time = $time_end - $time_start;
printf(">PHP5 Time: %0.15f\n", $time);
$time_start = microtime(true);
for ($i=1; $i<=1000; $i++) {
if (!strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'firefox')) {
// display GetFirefox adsense button
}
}
$time_end = microtime(true);
$time = $time_end - $time_start;
printf(">PHP4 Time: %0.15f\n", $time);
$time_start = microtime(true);
for ($i=1; $i<=1000; $i++) {
if(!preg_match("/Firefox/i",$_SERVER['HTTP_USER_AGENT'])){
// display GetFirefox adsense button
}
}
$time_end = microtime(true);
$time = $time_end - $time_start;
printf(">pcre Time: %0.15f\n", $time);
exit;

//
// Output was as follows:
//

getenv Time: 0.013556957244873
SERVER Time: 0.000906944274902
eregi Time: 0.015411138534546
>PHP5 Time: 0.009479045867920
>PHP4 Time: 0.008875131607056
>pcre Time: 0.003269910812378
//
// After applying a static var:
//
eregi Time: 0.017683029174805
>PHP5 Time: 0.008775949478149
>PHP4 Time: 0.009084939956665
>pcre Time: 0.003593921661377

Conclusions:

I had never tested getenv() vs $_SERVER before so I thought I would see what showed up ... using the $_SERVER superglobal was much faster than using getenv(). Every time.

But this surprised me ...
preg_match() came in much faster than the other comparisons. I wondered if it had something to do with the "lookup" of the $_SERVER superglobal in each of the for loops so I assigned the $_SERVER['HTTP_USER_AGENT'] to a static variable in another test and it made no difference. What was also odd was that the "PHP5 stripos()" versus "PHP4 strpos(strtolower())" comparison bounced back and forth. They were so close in comparison that it made little or no difference. I haven't looked into the source code for the new PHP5 function stripos() but I am guessing that it is doing much the same behind the scenes as what we are doing here with the existing functions available in PHP4.
Too much time on my hands tonight I guess ;-)

coopster

2:43 am on Dec 2, 2005 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



Oh yeah, I almost forgot. I know that there were PCRE updates added in PHP5. Perhaps the documentation* [php.net] is off now regarding strpos() being faster than the PCRE? I'd love to hear the developers' perspective on this ...

*Tip: Do not use preg_match() if you only want to check if one string is contained in another string. Use strpos() or strstr() instead as they will be faster.

trillianjedi

10:17 am on Dec 2, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Isn't that just going to lowercase the result of strpos?

Hehe - good spot Whoisgregg - thanks. That's one of those bugs that could have been hard to spot and work out what was going wrong ;-)

Coop thanks, this is fascinating. Based on this do I take it that pregmatch under php4 is probably going to serve me just as well as anything else?

TJ

coopster

4:15 pm on Dec 5, 2005 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



Certainly should, TJ. We are talking milliseconds comparisons here and if it is a simple expression you will be using your end user isn't going to notice any difference, that's for sure!

I posted all the details here only because other PHP'ers may want to have a look and do some more conclusive studies themselves. We often discuss how certain functions out-perform others, particularly when the recommendations come from the PHP developers and the accompanying documentation. In this particular case I am noticing a turn in the trend so I thought I would post my findings.