browscap.ini module error + fix

php.internals

Uwe Schindler

23 years ago
There is a small error in the browscap.ini in PHP4.3.2 RC and PHP 5 which makes thedetection of for example Internet Explorer wrong: This is a example from browscap.ini:
>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; IE 5.5 >[IE 5.5] >browser=IE >version=5.5 >majorver=5 >minorver=5 >css=2 >frames=True >iframes=True >tables=True >cookies=True >backgroundsounds=True >vbscript=True >javascript=True >javaapplets=True >activexcontrols=True >ak=False >sk=False >cdf=True >aol=False >beta=False >win16=False >crawler=False >stripper=False >wap=False >netclr=False > >[Mozilla/4.0 (compatible; MSIE 5.5*;*AOL *Win 9x 4.90*)*] >parent=IE 5.5 >platform=WinME >aol=True
The problem is now: If the client sends as User agent: "Mozilla/4.0 (compatible; MSIE 5.5; AOL Win 9x 4.90)" the browscap.c scans the ini file until it finds the first match. In the above example the regex created from [IE 5.5] is "IE 5\.5", the second one "Mozilla/4\.0 (compatible; MSIE 5.5.*;*AOL .*Win 9x 4\.90.*).*", but the first one matches first to the user agent, which does not give the platform back to the php script. The error is that the pattern must match the WHOLE string! So I modified the browscap.c file that it adds a ^ at the beginning of regex and a $ at the end of regex. After that all browsers are detected exactly like in ASP. Browsers with errors are: IE, Konqueror, some spiders... The modification looks like that:
>/* {{{ convert_browscap_pattern > */ >static void convert_browscap_pattern(zval *pattern) >{ > register int i, j; > char *t; > > for (i=0; i<Z_STRLEN_P(pattern); i++) { > if (Z_STRVAL_P(pattern)[i]=='*' || > Z_STRVAL_P(pattern)[i]=='?' || Z_STRVAL_P(pattern)[i]=='.') { > break; > } > } > > if (i==Z_STRLEN_P(pattern)) { /* no wildcards */ > Z_STRVAL_P(pattern) = zend_strndup(Z_STRVAL_P(pattern), > Z_STRLEN_P(pattern)); > return; > } > > t = (char *) malloc(Z_STRLEN_P(pattern)*2 + 3); > t[0]='^'; > > for (i=0, j=1; i<Z_STRLEN_P(pattern); i++, j++) { > switch (Z_STRVAL_P(pattern)[i]) { > case '?': > t[j] = '.'; > break; > case '*': > t[j++] = '.'; > t[j] = '*'; > break; > case '.': > t[j++] = '\\'; > t[j] = '.'; > break; > default: > t[j] = Z_STRVAL_P(pattern)[i]; > break; > } > } > > if (j && (t[j-1] == '.')) { > t[j++] = '*'; > } > > t[j++]='$'; > > t[j]=0; > Z_STRVAL_P(pattern) = t; > Z_STRLEN_P(pattern) = j; >} >/* }}} */
If you also think thats right can you give my thetaphi@php.net CVS account write access to ext/standard, i will then submit the modifications? Uwe

Wez Furlong

23 years ago
On Sun, 27 Apr 2003, Uwe Schindler wrote:
> So I modified the browscap.c file that it adds a ^ at the beginning of > regex and a $ at the end of regex. After that all browsers are detected > exactly like in ASP. Browsers with errors are: IE, Konqueror, some spiders... > > The modification looks like that: > >/* {{{ convert_browscap_pattern > > */
[snip]
> If you also think thats right can you give my thetaphi@php.net CVS account > write access to ext/standard, i will then submit the modifications?
Lets have a unified diff first? (see README.SUBMITTING_PATCH). --Wez.

Uwe Schindler

23 years ago
Was only to look through the code. But the patch is here (PHP4.3 version). Uwe At 12:12 27.04.2003 +0100, Wez Furlong wrote:

J Smith

23 years ago
Before committing this, could you look at the browscap.c version in HEAD? I made similar changes a month or so ago but I didn't MFH because it affected BC a bit. The fix was for a segfault, but I added the '^' thing, too. See browscap.c version 1.69 for the change (1.70 just has the superglobal JIT thing.) I can MFH the changes to 4.3 if there's no objections. I just left it in HEAD because of the minor BC divergance. (Very minor -- I ran a stock 4.3 and a modified browscap.c against 200 MB worth of Apache logs and the difference in reported browsers was negligible.) J Uwe Schindler wrote:

Uwe Schindler

23 years ago
OK. I think we should apply your patch to 4.3, too. At 12:12 28.04.2003 -0400, Jay Smith wrote:
>Before committing this, could you look at the browscap.c version in HEAD? I >made similar changes a month or so ago but I didn't MFH because it affected >BC a bit. The fix was for a segfault, but I added the '^' thing, too. See >browscap.c version 1.69 for the change (1.70 just has the superglobal JIT >thing.) > >I can MFH the changes to 4.3 if there's no objections. I just left it in >HEAD because of the minor BC divergance. (Very minor -- I ran a stock 4.3 >and a modified browscap.c against 200 MB worth of Apache logs and the >difference in reported browsers was negligible.) > >J
The reported browsers are correct, but not complete reported. For example Internet Explorer (as I told in my post) is correctly detected (because of the [IE x.x] which is in the user agent), but the exact version and platform not. And because of this a lot of scripts fail because get_browser()->platform is for example undefined. And IE is one of the most used browsers... ----- Uwe Schindler Addr 1: Bamberger Str. 24a, D-96049 Bamberg Addr 2: Drausnickstr. 153, D-91052 Erlangen http://www.thetaphi.de - http:///www.schindlers-software.de eMails: uwe@thetaphi.de (private); info@schindlers-software.de (company) Tel./Fax: +49 700 PCLATEIN (+49 700 72528346) Schindlers Software - Home of Schindlers PC-LATEIN 3.10 DIE Software zum Lateinlernen!

J Smith

23 years ago
Here's the output I'm getting from PHP 4 (without patch) for the user agent "Mozilla/4.0 (compatible; MSIE 5.5*;*AOL *Win 9x 4.90*)*": stdClass Object ( [browser_name_pattern] => Mozilla/4\.0 (compatible; MSIE 5\.5.*;.*AOL .*Win 9x 4\.90.*).* [parent] => IE 5.5 [platform] => WinME [aol] => 1 [browser] => IE [version] => 5.5 [majorver] => 5 [minorver] => 5 [css] => 2 [frames] => 1 [iframes] => 1 [tables] => 1 [cookies] => 1 [backgroundsounds] => 1 [vbscript] => 1 [javascript] => 1 [javaapplets] => 1 [activexcontrols] => 1 [ak] => [sk] => [cdf] => 1 [beta] => [win16] => [crawler] => [stripper] => [wap] => [netclr] => ) And current HEAD with the patch: stdClass Object ( [browser_name_regex] => ^Mozilla/4\.0 (compatible; MSIE 5\.5.*;.*AOL .*Win 9x 4\.90.*).* [browser_name_pattern] => Mozilla/4.0 (compatible; MSIE 5.5*;*AOL *Win 9x 4.90*)* [parent] => IE 5.5 [platform] => WinME [aol] => 1 [browser] => IE [version] => 5.5 [majorver] => 5 [minorver] => 5 [css] => 2 [frames] => 1 [iframes] => 1 [tables] => 1 [cookies] => 1 [backgroundsounds] => 1 [vbscript] => 1 [javascript] => 1 [javaapplets] => 1 [activexcontrols] => 1 [ak] => [sk] => [cdf] => 1 [beta] => [win16] => [crawler] => [stripper] => [wap] => [netclr] => ) The browser_name_regex is what is actually checked in the function (which is really just browser_name_pattern from the older version with the extra '^') and browser_name_pattern is the browscap.ini entry as it actually appears in the file. That's why I didn't MFH, there was that little change. I don't know how often browser_name_pattern is actually used in PHP code, probably not much, but a little change like that might be important to some people. But if there's no objections, I can MFH and it can go into 4.3.2RC2, I suppose, and if there's major problems with it, revert it before the final. Also, note that the prototype has changed slightly. It's now proto mixed get_browser([string browser_name [, bool return_array]]) If browser_name is called without a string or browser_name is null, HTTP_USER_AGENT is used as before. The return value is an object by default, but setting return_array to true returns an array instead. J Uwe Schindler wrote: