1999-04-17 08:37:12 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2004-01-08 16:18:22 +08:00
| PHP Version 5 |
1999-04-17 08:37:12 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2011-01-01 10:17:06 +08:00
| Copyright ( c ) 1997 - 2011 The PHP Group |
1999-04-17 08:37:12 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2006-01-01 20:51:34 +08:00
| This source file is subject to version 3.01 of the PHP license , |
1999-07-16 21:13:16 +08:00
| that is bundled with this package in the file LICENSE , and is |
2003-06-11 04:04:29 +08:00
| available through the world - wide - web at the following url : |
2006-01-01 20:51:34 +08:00
| http : //www.php.net/license/3_01.txt |
1999-07-16 21:13:16 +08:00
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world - wide - web , please send a note to |
| license @ php . net so we can mail you a copy immediately . |
1999-04-17 08:37:12 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2002-02-28 16:29:35 +08:00
| Author : Zeev Suraski < zeev @ zend . com > |
1999-04-17 08:37:12 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
2000-07-24 09:40:02 +08:00
/* $Id$ */
1999-04-17 08:37:12 +08:00
# include "php.h"
1999-12-05 03:19:57 +08:00
# include "php_browscap.h"
1999-04-17 08:37:12 +08:00
# include "php_ini.h"
2004-03-16 05:26:39 +08:00
# include "php_string.h"
2008-08-07 20:50:17 +08:00
# include "ext/pcre/php_pcre.h"
2007-11-05 20:27:42 +08:00
2007-09-28 10:05:10 +08:00
# include "zend_ini_scanner.h"
1999-04-17 08:37:12 +08:00
# include "zend_globals.h"
2000-10-30 07:10:22 +08:00
static HashTable browser_hash ;
static zval * current_section ;
2007-09-28 10:05:10 +08:00
static char * current_section_name ;
1999-04-17 08:37:12 +08:00
2000-07-25 16:09:00 +08:00
# define DEFAULT_SECTION_NAME "Default Browser Capability Settings"
2000-07-23 19:11:35 +08:00
2001-07-29 16:40:41 +08:00
/* OBJECTS_FIXME: This whole extension needs going through. The use of objects looks pretty broken here */
2000-10-30 07:10:22 +08:00
2007-11-05 20:27:42 +08:00
static void browscap_entry_dtor ( zval * * zvalue ) /* { { { */
2000-10-30 07:10:22 +08:00
{
2005-12-06 06:54:01 +08:00
if ( Z_TYPE_PP ( zvalue ) = = IS_ARRAY ) {
zend_hash_destroy ( Z_ARRVAL_PP ( zvalue ) ) ;
free ( Z_ARRVAL_PP ( zvalue ) ) ;
} else if ( Z_TYPE_PP ( zvalue ) = = IS_STRING ) {
if ( Z_STRVAL_PP ( zvalue ) ) {
free ( Z_STRVAL_PP ( zvalue ) ) ;
2005-01-26 05:33:58 +08:00
}
2000-10-30 07:10:22 +08:00
}
2005-12-06 06:54:01 +08:00
free ( * zvalue ) ;
2000-10-30 07:10:22 +08:00
}
2007-11-05 20:27:42 +08:00
/* }}} */
2000-10-30 07:10:22 +08:00
2007-11-05 20:27:42 +08:00
static void convert_browscap_pattern ( zval * pattern ) /* { { { */
2000-10-30 07:10:22 +08:00
{
2008-08-07 20:50:17 +08:00
int i , j = 0 ;
2000-10-30 07:10:22 +08:00
char * t ;
2004-03-16 05:26:39 +08:00
php_strtolower ( Z_STRVAL_P ( pattern ) , Z_STRLEN_P ( pattern ) ) ;
2003-03-15 01:54:38 +08:00
2008-08-07 20:50:17 +08:00
t = ( char * ) safe_pemalloc ( Z_STRLEN_P ( pattern ) , 2 , 5 , 1 ) ;
2004-03-16 05:26:39 +08:00
2008-08-07 20:50:17 +08:00
t [ j + + ] = ' <EFBFBD> ' ;
t [ j + + ] = ' ^ ' ;
2004-03-16 05:26:39 +08:00
2008-08-07 20:50:17 +08:00
for ( i = 0 ; i < Z_STRLEN_P ( pattern ) ; i + + , j + + ) {
2001-09-26 05:58:48 +08:00
switch ( Z_STRVAL_P ( pattern ) [ i ] ) {
2000-10-30 07:10:22 +08:00
case ' ? ' :
t [ j ] = ' . ' ;
break ;
case ' * ' :
t [ j + + ] = ' . ' ;
t [ j ] = ' * ' ;
break ;
case ' . ' :
t [ j + + ] = ' \\ ' ;
t [ j ] = ' . ' ;
break ;
2008-08-07 20:50:17 +08:00
case ' \\ ' :
t [ j + + ] = ' \\ ' ;
t [ j ] = ' \\ ' ;
break ;
case ' ( ' :
t [ j + + ] = ' \\ ' ;
t [ j ] = ' ( ' ;
break ;
case ' ) ' :
t [ j + + ] = ' \\ ' ;
t [ j ] = ' ) ' ;
break ;
case ' <EFBFBD> ' :
t [ j + + ] = ' \\ ' ;
t [ j ] = ' <EFBFBD> ' ;
break ;
2000-10-30 07:10:22 +08:00
default :
2001-09-26 05:58:48 +08:00
t [ j ] = Z_STRVAL_P ( pattern ) [ i ] ;
2000-10-30 07:10:22 +08:00
break ;
}
}
2003-04-29 05:49:47 +08:00
2004-03-16 05:26:39 +08:00
t [ j + + ] = ' $ ' ;
2008-08-07 20:50:17 +08:00
t [ j + + ] = ' <EFBFBD> ' ;
2003-04-29 05:49:47 +08:00
2000-10-30 07:10:22 +08:00
t [ j ] = 0 ;
2001-09-26 05:58:48 +08:00
Z_STRVAL_P ( pattern ) = t ;
Z_STRLEN_P ( pattern ) = j ;
2000-10-30 07:10:22 +08:00
}
2001-06-06 21:06:12 +08:00
/* }}} */
2000-10-30 07:10:22 +08:00
2007-11-05 20:27:42 +08:00
static void php_browscap_parser_cb ( zval * arg1 , zval * arg2 , zval * arg3 , int callback_type , void * arg TSRMLS_DC ) /* { { { */
2000-10-30 07:10:22 +08:00
{
2002-10-15 02:13:18 +08:00
if ( ! arg1 ) {
return ;
}
2000-10-30 07:10:22 +08:00
switch ( callback_type ) {
case ZEND_INI_PARSER_ENTRY :
2002-10-15 02:13:18 +08:00
if ( current_section & & arg2 ) {
2000-10-30 07:10:22 +08:00
zval * new_property ;
char * new_key ;
2007-09-28 10:05:10 +08:00
/* parent entry can not be same as current section -> causes infinite loop! */
2008-08-19 23:16:33 +08:00
if ( ! strcasecmp ( Z_STRVAL_P ( arg1 ) , " parent " ) & &
current_section_name ! = NULL & &
2007-09-28 10:05:10 +08:00
! strcasecmp ( current_section_name , Z_STRVAL_P ( arg2 ) )
) {
2009-06-06 10:40:49 +08:00
zend_error ( E_CORE_ERROR , " Invalid browscap ini file: 'Parent' value cannot be same as the section name: %s (in file %s) " , current_section_name , INI_STR ( " browscap " ) ) ;
2007-09-28 10:05:10 +08:00
return ;
}
2007-03-07 08:52:40 +08:00
new_property = ( zval * ) pemalloc ( sizeof ( zval ) , 1 ) ;
2000-10-30 07:10:22 +08:00
INIT_PZVAL ( new_property ) ;
2001-09-26 05:58:48 +08:00
Z_TYPE_P ( new_property ) = IS_STRING ;
2003-04-29 05:49:47 +08:00
2007-09-28 10:05:10 +08:00
/* Set proper value for true/false settings */
if ( ( Z_STRLEN_P ( arg2 ) = = 2 & & ! strncasecmp ( Z_STRVAL_P ( arg2 ) , " on " , sizeof ( " on " ) - 1 ) ) | |
( Z_STRLEN_P ( arg2 ) = = 3 & & ! strncasecmp ( Z_STRVAL_P ( arg2 ) , " yes " , sizeof ( " yes " ) - 1 ) ) | |
( Z_STRLEN_P ( arg2 ) = = 4 & & ! strncasecmp ( Z_STRVAL_P ( arg2 ) , " true " , sizeof ( " true " ) - 1 ) )
) {
Z_STRVAL_P ( new_property ) = zend_strndup ( " 1 " , 1 ) ;
Z_STRLEN_P ( new_property ) = 1 ;
} else if (
( Z_STRLEN_P ( arg2 ) = = 2 & & ! strncasecmp ( Z_STRVAL_P ( arg2 ) , " no " , sizeof ( " no " ) - 1 ) ) | |
( Z_STRLEN_P ( arg2 ) = = 3 & & ! strncasecmp ( Z_STRVAL_P ( arg2 ) , " off " , sizeof ( " off " ) - 1 ) ) | |
( Z_STRLEN_P ( arg2 ) = = 4 & & ! strncasecmp ( Z_STRVAL_P ( arg2 ) , " none " , sizeof ( " none " ) - 1 ) ) | |
( Z_STRLEN_P ( arg2 ) = = 5 & & ! strncasecmp ( Z_STRVAL_P ( arg2 ) , " false " , sizeof ( " false " ) - 1 ) )
) {
Z_STRVAL_P ( new_property ) = zend_strndup ( " " , 0 ) ;
Z_STRLEN_P ( new_property ) = 0 ;
} else { /* Other than true/false setting */
Z_STRVAL_P ( new_property ) = zend_strndup ( Z_STRVAL_P ( arg2 ) , Z_STRLEN_P ( arg2 ) ) ;
Z_STRLEN_P ( new_property ) = Z_STRLEN_P ( arg2 ) ;
}
2000-10-30 07:10:22 +08:00
new_key = zend_strndup ( Z_STRVAL_P ( arg1 ) , Z_STRLEN_P ( arg1 ) ) ;
zend_str_tolower ( new_key , Z_STRLEN_P ( arg1 ) ) ;
2007-11-05 20:27:42 +08:00
zend_hash_update ( Z_ARRVAL_P ( current_section ) , new_key , Z_STRLEN_P ( arg1 ) + 1 , & new_property , sizeof ( zval * ) , NULL ) ;
2000-10-30 07:10:22 +08:00
free ( new_key ) ;
}
break ;
case ZEND_INI_PARSER_SECTION : {
zval * processed ;
2003-03-15 01:54:38 +08:00
zval * unprocessed ;
2002-04-30 19:30:07 +08:00
HashTable * section_properties ;
2000-10-30 07:10:22 +08:00
2007-11-05 20:27:42 +08:00
/*printf("'%s' (%d)\n",$1.value.str.val,$1.value.str.len + 1);*/
2007-03-07 08:52:40 +08:00
current_section = ( zval * ) pemalloc ( sizeof ( zval ) , 1 ) ;
2000-10-30 07:10:22 +08:00
INIT_PZVAL ( current_section ) ;
2007-03-07 08:52:40 +08:00
processed = ( zval * ) pemalloc ( sizeof ( zval ) , 1 ) ;
2000-10-30 07:10:22 +08:00
INIT_PZVAL ( processed ) ;
2007-03-07 08:52:40 +08:00
unprocessed = ( zval * ) pemalloc ( sizeof ( zval ) , 1 ) ;
2003-03-15 01:54:38 +08:00
INIT_PZVAL ( unprocessed ) ;
2000-10-30 07:10:22 +08:00
2007-03-07 08:52:40 +08:00
section_properties = ( HashTable * ) pemalloc ( sizeof ( HashTable ) , 1 ) ;
2002-04-30 19:30:07 +08:00
zend_hash_init ( section_properties , 0 , NULL , ( dtor_func_t ) browscap_entry_dtor , 1 ) ;
2007-09-28 10:05:10 +08:00
Z_ARRVAL_P ( current_section ) = section_properties ;
Z_TYPE_P ( current_section ) = IS_ARRAY ;
2008-08-19 23:16:33 +08:00
if ( current_section_name ) {
free ( current_section_name ) ;
}
2007-09-28 10:05:10 +08:00
current_section_name = zend_strndup ( Z_STRVAL_P ( arg1 ) , Z_STRLEN_P ( arg1 ) ) ;
2007-11-05 20:27:42 +08:00
zend_hash_update ( & browser_hash , Z_STRVAL_P ( arg1 ) , Z_STRLEN_P ( arg1 ) + 1 , ( void * ) & current_section , sizeof ( zval * ) , NULL ) ;
2000-10-30 07:10:22 +08:00
2001-09-26 05:58:48 +08:00
Z_STRVAL_P ( processed ) = Z_STRVAL_P ( arg1 ) ;
Z_STRLEN_P ( processed ) = Z_STRLEN_P ( arg1 ) ;
Z_TYPE_P ( processed ) = IS_STRING ;
2003-03-15 01:54:38 +08:00
Z_STRVAL_P ( unprocessed ) = Z_STRVAL_P ( arg1 ) ;
Z_STRLEN_P ( unprocessed ) = Z_STRLEN_P ( arg1 ) ;
Z_TYPE_P ( unprocessed ) = IS_STRING ;
Z_STRVAL_P ( unprocessed ) = zend_strndup ( Z_STRVAL_P ( unprocessed ) , Z_STRLEN_P ( unprocessed ) ) ;
2000-10-30 07:10:22 +08:00
convert_browscap_pattern ( processed ) ;
2003-03-15 01:54:38 +08:00
zend_hash_update ( section_properties , " browser_name_regex " , sizeof ( " browser_name_regex " ) , ( void * ) & processed , sizeof ( zval * ) , NULL ) ;
zend_hash_update ( section_properties , " browser_name_pattern " , sizeof ( " browser_name_pattern " ) , ( void * ) & unprocessed , sizeof ( zval * ) , NULL ) ;
2000-10-30 07:10:22 +08:00
}
break ;
}
}
2001-06-06 21:06:12 +08:00
/* }}} */
2000-10-30 07:10:22 +08:00
2007-11-05 20:27:42 +08:00
PHP_MINIT_FUNCTION ( browscap ) /* {{{ */
2000-10-30 07:10:22 +08:00
{
char * browscap = INI_STR ( " browscap " ) ;
2003-07-01 04:31:57 +08:00
if ( browscap & & browscap [ 0 ] ) {
2000-10-30 07:10:22 +08:00
zend_file_handle fh ;
2003-03-15 01:54:38 +08:00
memset ( & fh , 0 , sizeof ( fh ) ) ;
2000-10-30 07:10:22 +08:00
2007-11-05 20:27:42 +08:00
if ( zend_hash_init_ex ( & browser_hash , 0 , NULL , ( dtor_func_t ) browscap_entry_dtor , 1 , 0 ) = = FAILURE ) {
2000-10-30 07:10:22 +08:00
return FAILURE ;
}
2001-04-30 20:45:02 +08:00
fh . handle . fp = VCWD_FOPEN ( browscap , " r " ) ;
2003-05-16 23:13:47 +08:00
fh . opened_path = NULL ;
fh . free_filename = 0 ;
2000-10-30 07:10:22 +08:00
if ( ! fh . handle . fp ) {
2003-05-28 01:24:59 +08:00
zend_error ( E_CORE_WARNING , " Cannot open '%s' for reading " , browscap ) ;
2000-10-30 07:10:22 +08:00
return FAILURE ;
}
2000-10-31 07:39:14 +08:00
fh . filename = browscap ;
2001-09-26 05:58:48 +08:00
Z_TYPE ( fh ) = ZEND_HANDLE_FP ;
2008-08-19 23:16:33 +08:00
current_section_name = NULL ;
2007-09-28 10:05:10 +08:00
zend_parse_ini_file ( & fh , 1 , ZEND_INI_SCANNER_RAW , ( zend_ini_parser_cb_t ) php_browscap_parser_cb , & browser_hash TSRMLS_CC ) ;
2008-08-19 23:16:33 +08:00
if ( current_section_name ) {
free ( current_section_name ) ;
current_section_name = NULL ;
}
2000-10-30 07:10:22 +08:00
}
return SUCCESS ;
}
2001-06-06 21:06:12 +08:00
/* }}} */
2000-10-30 07:10:22 +08:00
2007-11-05 20:27:42 +08:00
PHP_MSHUTDOWN_FUNCTION ( browscap ) /* {{{ */
2000-10-30 07:10:22 +08:00
{
2003-07-01 04:31:57 +08:00
char * browscap = INI_STR ( " browscap " ) ;
if ( browscap & & browscap [ 0 ] ) {
2000-10-30 07:10:22 +08:00
zend_hash_destroy ( & browser_hash ) ;
}
return SUCCESS ;
}
2001-06-06 21:06:12 +08:00
/* }}} */
2000-10-30 07:10:22 +08:00
2008-07-25 03:52:24 +08:00
static int browser_reg_compare ( zval * * browser TSRMLS_DC , int num_args , va_list args , zend_hash_key * key ) /* { { { */
1999-04-17 08:37:12 +08:00
{
2004-03-16 05:26:39 +08:00
zval * * browser_regex , * * previous_match ;
2008-08-07 20:50:17 +08:00
pcre * re ;
int re_options ;
pcre_extra * re_extra ;
2001-08-12 01:03:37 +08:00
char * lookup_browser_name = va_arg ( args , char * ) ;
2008-08-07 20:50:17 +08:00
int lookup_browser_length = va_arg ( args , int ) ;
2001-08-12 01:03:37 +08:00
zval * * found_browser_entry = va_arg ( args , zval * * ) ;
1999-04-17 08:37:12 +08:00
2004-03-16 05:26:39 +08:00
/* See if we have an exact match, if so, we're done... */
2003-05-21 01:59:16 +08:00
if ( * found_browser_entry ) {
2004-03-16 05:26:39 +08:00
if ( zend_hash_find ( Z_ARRVAL_PP ( found_browser_entry ) , " browser_name_pattern " , sizeof ( " browser_name_pattern " ) , ( void * * ) & previous_match ) = = FAILURE ) {
2003-05-21 01:59:16 +08:00
return 0 ;
}
2004-03-16 05:26:39 +08:00
else if ( ! strcasecmp ( Z_STRVAL_PP ( previous_match ) , lookup_browser_name ) ) {
2003-05-21 01:59:16 +08:00
return 0 ;
}
2000-07-23 19:32:18 +08:00
}
2004-03-16 05:26:39 +08:00
if ( zend_hash_find ( Z_ARRVAL_PP ( browser ) , " browser_name_regex " , sizeof ( " browser_name_regex " ) , ( void * * ) & browser_regex ) = = FAILURE ) {
return 0 ;
}
2008-08-07 20:50:17 +08:00
re = pcre_get_compiled_regex ( Z_STRVAL_PP ( browser_regex ) , & re_extra , & re_options TSRMLS_CC ) ;
if ( re = = NULL ) {
1999-04-17 08:37:12 +08:00
return 0 ;
}
2008-08-07 20:50:17 +08:00
if ( pcre_exec ( re , re_extra , lookup_browser_name , lookup_browser_length , 0 , re_options , NULL , 0 ) = = 0 ) {
2004-03-16 05:26:39 +08:00
/* If we've found a possible browser, we need to do a comparison of the
number of characters changed in the user agent being checked versus
the previous match found and the current match . */
if ( * found_browser_entry ) {
int i , prev_len = 0 , curr_len = 0 , ua_len ;
zval * * current_match ;
if ( zend_hash_find ( Z_ARRVAL_PP ( browser ) , " browser_name_pattern " , sizeof ( " browser_name_pattern " ) , ( void * * ) & current_match ) = = FAILURE ) {
return 0 ;
}
2008-08-07 20:50:17 +08:00
ua_len = lookup_browser_length ;
2004-03-16 05:26:39 +08:00
for ( i = 0 ; i < Z_STRLEN_PP ( previous_match ) ; i + + ) {
switch ( Z_STRVAL_PP ( previous_match ) [ i ] ) {
case ' ? ' :
case ' * ' :
/* do nothing, ignore these characters in the count */
break ;
default :
+ + prev_len ;
}
}
for ( i = 0 ; i < Z_STRLEN_PP ( current_match ) ; i + + ) {
switch ( Z_STRVAL_PP ( current_match ) [ i ] ) {
case ' ? ' :
case ' * ' :
/* do nothing, ignore these characters in the count */
break ;
default :
+ + curr_len ;
}
}
/* Pick which browser pattern replaces the least amount of
characters when compared to the original user agent string . . . */
if ( ua_len - prev_len > ua_len - curr_len ) {
* found_browser_entry = * browser ;
}
}
else {
* found_browser_entry = * browser ;
}
}
1999-04-17 08:37:12 +08:00
return 0 ;
}
2001-06-06 21:06:12 +08:00
/* }}} */
1999-04-17 08:37:12 +08:00
2003-04-29 05:49:47 +08:00
/* {{{ proto mixed get_browser([string browser_name [, bool return_array]])
2007-11-05 20:27:42 +08:00
Get information about the capabilities of a browser . If browser_name is omitted or null , HTTP_USER_AGENT is used . Returns an object by default ; if return_array is true , returns an array . */
1999-05-16 19:19:26 +08:00
PHP_FUNCTION ( get_browser )
1999-04-17 08:37:12 +08:00
{
2007-11-05 20:27:42 +08:00
char * agent_name = NULL ;
2008-10-22 06:08:38 +08:00
int agent_name_len = 0 ;
2007-11-05 20:27:42 +08:00
zend_bool return_array = 0 ;
2009-11-24 08:18:16 +08:00
zval * * agent , * * z_agent_name , * * http_user_agent ;
2001-08-12 01:03:37 +08:00
zval * found_browser_entry , * tmp_copy ;
2000-07-23 19:11:35 +08:00
char * lookup_browser_name ;
2003-07-01 04:31:57 +08:00
char * browscap = INI_STR ( " browscap " ) ;
1999-04-17 08:37:12 +08:00
2003-07-01 04:31:57 +08:00
if ( ! browscap | | ! browscap [ 0 ] ) {
2007-09-30 13:49:45 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " browscap ini directive not set " ) ;
1999-04-17 08:37:12 +08:00
RETURN_FALSE ;
}
2003-03-15 01:54:38 +08:00
2007-11-05 20:27:42 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " |s!b " , & agent_name , & agent_name_len , & return_array ) = = FAILURE ) {
return ;
1999-04-17 08:37:12 +08:00
}
2004-03-16 05:26:39 +08:00
2007-11-05 20:27:42 +08:00
if ( agent_name = = NULL ) {
zend_is_auto_global ( " _SERVER " , sizeof ( " _SERVER " ) - 1 TSRMLS_CC ) ;
2009-11-24 08:18:16 +08:00
if ( ! PG ( http_globals ) [ TRACK_VARS_SERVER ] | |
zend_hash_find ( HASH_OF ( PG ( http_globals ) [ TRACK_VARS_SERVER ] ) , " HTTP_USER_AGENT " , sizeof ( " HTTP_USER_AGENT " ) , ( void * * ) & http_user_agent ) = = FAILURE
) {
2003-03-15 01:54:38 +08:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " HTTP_USER_AGENT variable is not set, cannot determine user agent name " ) ;
RETURN_FALSE ;
}
2009-11-24 08:18:16 +08:00
agent_name = Z_STRVAL_PP ( http_user_agent ) ;
agent_name_len = Z_STRLEN_PP ( http_user_agent ) ;
2003-03-15 01:54:38 +08:00
}
2007-11-05 20:27:42 +08:00
lookup_browser_name = estrndup ( agent_name , agent_name_len ) ;
php_strtolower ( lookup_browser_name , agent_name_len ) ;
2003-03-15 01:54:38 +08:00
2007-11-05 20:27:42 +08:00
if ( zend_hash_find ( & browser_hash , lookup_browser_name , agent_name_len + 1 , ( void * * ) & agent ) = = FAILURE ) {
1999-04-24 08:12:00 +08:00
found_browser_entry = NULL ;
2008-08-07 20:50:17 +08:00
zend_hash_apply_with_arguments ( & browser_hash TSRMLS_CC , ( apply_func_args_t ) browser_reg_compare , 3 , lookup_browser_name , agent_name_len , & found_browser_entry ) ;
2003-04-29 05:49:47 +08:00
1999-04-24 08:12:00 +08:00
if ( found_browser_entry ) {
2000-07-26 02:50:02 +08:00
agent = & found_browser_entry ;
2007-11-05 20:27:42 +08:00
} else if ( zend_hash_find ( & browser_hash , DEFAULT_SECTION_NAME , sizeof ( DEFAULT_SECTION_NAME ) , ( void * * ) & agent ) = = FAILURE ) {
2004-03-16 05:26:39 +08:00
efree ( lookup_browser_name ) ;
1999-04-17 08:37:12 +08:00
RETURN_FALSE ;
}
}
2003-03-15 01:54:38 +08:00
if ( return_array ) {
array_init ( return_value ) ;
zend_hash_copy ( Z_ARRVAL_P ( return_value ) , Z_ARRVAL_PP ( agent ) , ( copy_ctor_func_t ) zval_add_ref , ( void * ) & tmp_copy , sizeof ( zval * ) ) ;
}
else {
object_init ( return_value ) ;
zend_hash_copy ( Z_OBJPROP_P ( return_value ) , Z_ARRVAL_PP ( agent ) , ( copy_ctor_func_t ) zval_add_ref , ( void * ) & tmp_copy , sizeof ( zval * ) ) ;
}
2003-04-29 05:49:47 +08:00
2008-08-29 22:14:09 +08:00
while ( zend_hash_find ( Z_ARRVAL_PP ( agent ) , " parent " , sizeof ( " parent " ) , ( void * * ) & z_agent_name ) = = SUCCESS ) {
if ( zend_hash_find ( & browser_hash , Z_STRVAL_PP ( z_agent_name ) , Z_STRLEN_PP ( z_agent_name ) + 1 , ( void * * ) & agent ) = = FAILURE ) {
1999-04-17 08:37:12 +08:00
break ;
}
2003-03-15 01:54:38 +08:00
if ( return_array ) {
zend_hash_merge ( Z_ARRVAL_P ( return_value ) , Z_ARRVAL_PP ( agent ) , ( copy_ctor_func_t ) zval_add_ref , ( void * ) & tmp_copy , sizeof ( zval * ) , 0 ) ;
}
else {
zend_hash_merge ( Z_OBJPROP_P ( return_value ) , Z_ARRVAL_PP ( agent ) , ( copy_ctor_func_t ) zval_add_ref , ( void * ) & tmp_copy , sizeof ( zval * ) , 0 ) ;
}
1999-04-17 08:37:12 +08:00
}
2004-03-16 05:26:39 +08:00
2006-12-22 05:37:45 +08:00
efree ( lookup_browser_name ) ;
1999-04-17 08:37:12 +08:00
}
2000-03-29 19:38:47 +08:00
/* }}} */
1999-04-17 08:37:12 +08:00
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* End :
2001-09-09 21:29:31 +08:00
* vim600 : sw = 4 ts = 4 fdm = marker
* vim < 600 : sw = 4 ts = 4
1999-04-17 08:37:12 +08:00
*/