@ -27,16 +27,49 @@
# include "zend_ini_scanner.h"
# include "zend_globals.h"
static HashTable browser_hash ;
static zval * current_section ;
static char * current_section_name ;
typedef struct {
HashTable * htab ;
zval * current_section ;
char * current_section_name ;
char filename [ MAXPATHLEN ] ;
} browser_data ;
/* browser data defined in startup phase, eagerly loaded in MINIT */
static browser_data global_bdata = { 0 } ;
/* browser data defined in activation phase, lazily loaded in get_browser.
* Per request and per thread , if applicable */
ZEND_BEGIN_MODULE_GLOBALS ( browscap )
browser_data activation_bdata ;
ZEND_END_MODULE_GLOBALS ( browscap )
ZEND_DECLARE_MODULE_GLOBALS ( browscap ) ;
# ifdef ZTS
# define BROWSCAP_G(v) TSRMG(browscap_globals_id, zend_browscap_globals *, v)
# else
# define BROWSCAP_G(v) (browscap_globals.v)
# endif
# define DEFAULT_SECTION_NAME "Default Browser Capability Settings"
/* OBJECTS_FIXME: This whole extension needs going through. The use of objects looks pretty broken here */
static void browscap_entry_dtor ( zval * * zvalue ) /* { { { */
static void browscap_entry_dtor_request ( zval * * zvalue ) /* { { { */
{
if ( Z_TYPE_PP ( zvalue ) = = IS_ARRAY ) {
zend_hash_destroy ( Z_ARRVAL_PP ( zvalue ) ) ;
efree ( Z_ARRVAL_PP ( zvalue ) ) ;
} else if ( Z_TYPE_PP ( zvalue ) = = IS_STRING ) {
if ( Z_STRVAL_PP ( zvalue ) ) {
efree ( Z_STRVAL_PP ( zvalue ) ) ;
}
}
efree ( * zvalue ) ;
}
/* }}} */
static void browscap_entry_dtor_persistent ( zval * * zvalue ) /* { { { */ {
if ( Z_TYPE_PP ( zvalue ) = = IS_ARRAY ) {
zend_hash_destroy ( Z_ARRVAL_PP ( zvalue ) ) ;
free ( Z_ARRVAL_PP ( zvalue ) ) ;
@ -49,16 +82,16 @@ static void browscap_entry_dtor(zval **zvalue) /* {{{ */
}
/* }}} */
static void convert_browscap_pattern ( zval * pattern ) /* { { { */
static void convert_browscap_pattern ( zval * pattern , int persistent ) /* { { { */
{
int i , j = 0 ;
char * t ;
php_strtolower ( Z_STRVAL_P ( pattern ) , Z_STRLEN_P ( pattern ) ) ;
t = ( char * ) safe_pemalloc ( Z_STRLEN_P ( pattern ) , 2 , 5 , 1 ) ;
t = ( char * ) safe_pemalloc ( Z_STRLEN_P ( pattern ) , 2 , 5 , persistent ) ;
t [ j + + ] = ' § ' ;
t [ j + + ] = ' \xA7 ' ; /* section sign */
t [ j + + ] = ' ^ ' ;
for ( i = 0 ; i < Z_STRLEN_P ( pattern ) ; i + + , j + + ) {
@ -86,9 +119,9 @@ static void convert_browscap_pattern(zval *pattern) /* {{{ */
t [ j + + ] = ' \\ ' ;
t [ j ] = ' ) ' ;
break ;
case ' § ' :
case ' \xA7 ' :
t [ j + + ] = ' \\ ' ;
t [ j ] = ' § ' ;
t [ j ] = ' \xA7 ' ;
break ;
default :
t [ j ] = Z_STRVAL_P ( pattern ) [ i ] ;
@ -97,7 +130,7 @@ static void convert_browscap_pattern(zval *pattern) /* {{{ */
}
t [ j + + ] = ' $ ' ;
t [ j + + ] = ' § ' ;
t [ j + + ] = ' \xA7 ' ;
t [ j ] = 0 ;
Z_STRVAL_P ( pattern ) = t ;
@ -107,26 +140,31 @@ static void convert_browscap_pattern(zval *pattern) /* {{{ */
static void php_browscap_parser_cb ( zval * arg1 , zval * arg2 , zval * arg3 , int callback_type , void * arg TSRMLS_DC ) /* { { { */
{
browser_data * bdata = arg ;
int persistent = bdata - > htab - > persistent ;
if ( ! arg1 ) {
return ;
}
switch ( callback_type ) {
case ZEND_INI_PARSER_ENTRY :
if ( current_section & & arg2 ) {
if ( bdata - > current_section & & arg2 ) {
zval * new_property ;
char * new_key ;
/* parent entry can not be same as current section -> causes infinite loop! */
if ( ! strcasecmp ( Z_STRVAL_P ( arg1 ) , " parent " ) & &
current_section_name ! = NULL & &
! strcasecmp ( current_section_name , Z_STRVAL_P ( arg2 ) )
bdata - > current_section_name ! = NULL & &
! strcasecmp ( bdata - > current_section_name , Z_STRVAL_P ( arg2 ) )
) {
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 " ) ) ;
zend_error ( E_CORE_ERROR , " Invalid browscap ini file: "
" 'Parent' value cannot be same as the section name: %s "
" (in file %s) " , bdata - > current_section_name , INI_STR ( " browscap " ) ) ;
return ;
}
new_property = ( zval * ) pemalloc ( sizeof ( zval ) , 1 ) ;
new_property = ( zval * ) pemalloc ( sizeof ( zval ) , persistent ) ;
INIT_PZVAL ( new_property ) ;
Z_TYPE_P ( new_property ) = IS_STRING ;
@ -135,7 +173,7 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callb
( 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_STRVAL_P ( new_property ) = pe strndup( " 1 " , 1 , persistent ) ;
Z_STRLEN_P ( new_property ) = 1 ;
} else if (
( Z_STRLEN_P ( arg2 ) = = 2 & & ! strncasecmp ( Z_STRVAL_P ( arg2 ) , " no " , sizeof ( " no " ) - 1 ) ) | |
@ -143,16 +181,17 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callb
( 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_STRVAL_P ( new_property ) = pe strndup( " " , 0 , persistent ) ;
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_STRVAL_P ( new_property ) = pestrndup ( Z_STRVAL_P ( arg2 ) ,
Z_STRLEN_P ( arg2 ) , persistent ) ;
Z_STRLEN_P ( new_property ) = Z_STRLEN_P ( arg2 ) ;
}
new_key = zend_ strndup( Z_STRVAL_P ( arg1 ) , Z_STRLEN_P ( arg1 ) ) ;
new_key = pe strndup( Z_STRVAL_P ( arg1 ) , Z_STRLEN_P ( arg1 ) , persistent ) ;
zend_str_tolower ( new_key , Z_STRLEN_P ( arg1 ) ) ;
zend_hash_update ( Z_ARRVAL_P ( current_section ) , new_key , Z_STRLEN_P ( arg1 ) + 1 , & new_property , sizeof ( zval * ) , NULL ) ;
free ( new_key ) ;
zend_hash_update ( Z_ARRVAL_P ( bdata - > current_section ) , new_key , Z_STRLEN_P ( arg1 ) + 1 , & new_property , sizeof ( zval * ) , NULL ) ;
pe free( new_key , persistent ) ;
}
break ;
case ZEND_INI_PARSER_SECTION : {
@ -161,23 +200,27 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callb
HashTable * section_properties ;
/*printf("'%s' (%d)\n",$1.value.str.val,$1.value.str.len + 1);*/
current_section = ( zval * ) pemalloc ( sizeof ( zval ) , 1 ) ;
INIT_PZVAL ( current_section ) ;
processed = ( zval * ) pemalloc ( sizeof ( zval ) , 1 ) ;
bdata - > current_section = ( zval * ) pemalloc ( sizeof ( zval ) , persistent ) ;
INIT_PZVAL ( bdata - > current_section ) ;
processed = ( zval * ) pemalloc ( sizeof ( zval ) , persistent ) ;
INIT_PZVAL ( processed ) ;
unprocessed = ( zval * ) pemalloc ( sizeof ( zval ) , 1 ) ;
unprocessed = ( zval * ) pemalloc ( sizeof ( zval ) , persistent ) ;
INIT_PZVAL ( unprocessed ) ;
section_properties = ( HashTable * ) pemalloc ( sizeof ( HashTable ) , 1 ) ;
zend_hash_init ( section_properties , 0 , NULL , ( dtor_func_t ) browscap_entry_dtor , 1 ) ;
Z_ARRVAL_P ( current_section ) = section_properties ;
Z_TYPE_P ( current_section ) = IS_ARRAY ;
if ( current_section_name ) {
free ( current_section_name ) ;
section_properties = ( HashTable * ) pemalloc ( sizeof ( HashTable ) , persistent ) ;
zend_hash_init ( section_properties , 0 , NULL ,
( dtor_func_t ) ( persistent ? browscap_entry_dtor_persistent
: browscap_entry_dtor_request ) ,
persistent ) ;
Z_ARRVAL_P ( bdata - > current_section ) = section_properties ;
Z_TYPE_P ( bdata - > current_section ) = IS_ARRAY ;
if ( bdata - > current_section_name ) {
pefree ( bdata - > current_section_name , persistent ) ;
}
current_section_name = zend_strndup ( Z_STRVAL_P ( arg1 ) , Z_STRLEN_P ( arg1 ) ) ;
bdata - > current_section_name = pestrndup ( Z_STRVAL_P ( arg1 ) ,
Z_STRLEN_P ( arg1 ) , persistent ) ;
zend_hash_update ( & browser_hash , Z_STRVAL_P ( arg1 ) , Z_STRLEN_P ( arg1 ) + 1 , ( void * ) & current_section , sizeof ( zval * ) , NULL ) ;
zend_hash_update ( bdata - > htab , Z_STRVAL_P ( arg1 ) , Z_STRLEN_P ( arg1 ) + 1 , ( void * ) & bdata - > current_section , sizeof ( zval * ) , NULL ) ;
Z_STRVAL_P ( processed ) = Z_STRVAL_P ( arg1 ) ;
Z_STRLEN_P ( processed ) = Z_STRLEN_P ( arg1 ) ;
@ -185,9 +228,9 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callb
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 ) ) ;
Z_STRVAL_P ( unprocessed ) = pe strndup( Z_STRVAL_P ( unprocessed ) , Z_STRLEN_P ( unprocessed ) , persistent ) ;
convert_browscap_pattern ( processed ) ;
convert_browscap_pattern ( processed , persistent ) ;
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 ) ;
}
@ -196,45 +239,138 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callb
}
/* }}} */
PHP_MINIT_FUNCTION ( browscap ) /* {{{ */
static int browscap_read_file ( char * filename , browser_data * browdata , int persistent TSRMLS_DC ) /* { { { */
{
char * browscap = INI_STR ( " browscap " ) ;
zend_file_handle fh = { 0 } ;
if ( filename = = NULL | | filename [ 0 ] = = ' \0 ' ) {
return FAILURE ;
}
browdata - > htab = pemalloc ( sizeof * browdata - > htab , persistent ) ;
if ( browdata - > htab = = NULL ) {
return FAILURE ;
}
if ( browscap & & browscap [ 0 ] ) {
zend_file_handle fh ;
memset ( & fh , 0 , sizeof ( fh ) ) ;
if ( zend_hash_init_ex ( browdata - > htab , 0 , NULL ,
( dtor_func_t ) ( persistent ? browscap_entry_dtor_persistent
: browscap_entry_dtor_request ) ,
persistent , 0 ) = = FAILURE ) {
pefree ( browdata - > htab , persistent ) ;
browdata - > htab = NULL ;
return FAILURE ;
}
if ( zend_hash_init_ex ( & browser_hash , 0 , NULL , ( dtor_func_t ) browscap_entry_dtor , 1 , 0 ) = = FAILURE ) {
fh . handle . fp = VCWD_FOPEN ( filename , " r " ) ;
fh . opened_path = NULL ;
fh . free_filename = 0 ;
if ( ! fh . handle . fp ) {
zend_hash_destroy ( browdata - > htab ) ;
pefree ( browdata - > htab , persistent ) ;
browdata - > htab = NULL ;
zend_error ( E_CORE_WARNING , " Cannot open '%s' for reading " , filename ) ;
return FAILURE ;
}
fh . filename = filename ;
Z_TYPE ( fh ) = ZEND_HANDLE_FP ;
browdata - > current_section_name = NULL ;
zend_parse_ini_file ( & fh , 1 , ZEND_INI_SCANNER_RAW ,
( zend_ini_parser_cb_t ) php_browscap_parser_cb , browdata TSRMLS_CC ) ;
if ( browdata - > current_section_name ! = NULL ) {
pefree ( browdata - > current_section_name , persistent ) ;
browdata - > current_section_name = NULL ;
}
return SUCCESS ;
}
/* }}} */
# ifdef ZTS
static void browscap_globals_ctor ( zend_browscap_globals * browscap_globals TSRMLS_DC ) /* { { { */
{
browscap_globals - > activation_bdata . htab = NULL ;
browscap_globals - > activation_bdata . current_section = NULL ;
browscap_globals - > activation_bdata . current_section_name = NULL ;
browscap_globals - > activation_bdata . filename [ 0 ] = ' \0 ' ;
}
/* }}} */
# endif
static void browscap_bdata_dtor ( browser_data * bdata , int persistent TSRMLS_DC ) /* { { { */
{
if ( bdata - > htab ! = NULL ) {
zend_hash_destroy ( bdata - > htab ) ;
pefree ( bdata - > htab , persistent ) ;
bdata - > htab = NULL ;
}
bdata - > filename [ 0 ] = ' \0 ' ;
/* current_section_* are only used during parsing */
}
/* }}} */
/* {{{ PHP_INI_MH
*/
PHP_INI_MH ( OnChangeBrowscap )
{
if ( stage = = PHP_INI_STAGE_STARTUP ) {
/* value handled in browscap.c's MINIT */
return SUCCESS ;
} else if ( stage = = PHP_INI_STAGE_ACTIVATE ) {
browser_data * bdata = & BROWSCAP_G ( activation_bdata ) ;
if ( bdata - > filename [ 0 ] ! = ' \0 ' ) {
browscap_bdata_dtor ( bdata , 0 TSRMLS_CC ) ;
}
if ( VCWD_REALPATH ( new_value , bdata - > filename ) = = NULL ) {
return FAILURE ;
}
return SUCCESS ;
}
return FAILURE ;
}
/* }}} */
fh . handle . fp = VCWD_FOPEN ( browscap , " r " ) ;
fh . opened_path = NULL ;
fh . free_filename = 0 ;
if ( ! fh . handle . fp ) {
zend_error ( E_CORE_WARNING , " Cannot open '%s' for reading " , browscap ) ;
PHP_INI_BEGIN ( )
PHP_INI_ENTRY ( " browscap " , NULL , PHP_INI_SYSTEM , OnChangeBrowscap )
PHP_INI_END ( )
PHP_MINIT_FUNCTION ( browscap ) /* {{{ */
{
char * browscap = INI_STR ( " browscap " ) ;
REGISTER_INI_ENTRIES ( ) ;
if ( browscap & & browscap [ 0 ] ) {
if ( browscap_read_file ( browscap , & global_bdata , 1 TSRMLS_CC ) = = FAILURE ) {
return FAILURE ;
}
fh . filename = browscap ;
Z_TYPE ( fh ) = ZEND_HANDLE_FP ;
current_section_name = NULL ;
zend_parse_ini_file ( & fh , 1 , ZEND_INI_SCANNER_RAW , ( zend_ini_parser_cb_t ) php_browscap_parser_cb , & browser_hash TSRMLS_CC ) ;
if ( current_section_name ) {
free ( current_section_name ) ;
current_section_name = NULL ;
}
}
# ifdef ZTS
ts_allocate_id ( & browscap_globals_id , sizeof ( browser_data ) ,
browscap_globals_ctor , NULL ) ;
# endif
/* ctor call not really needed for non-ZTS */
return SUCCESS ;
}
/* }}} */
PHP_MSHUTDOWN_FUNCTION ( browscap ) /* {{{ */
PHP_R SHUTDOWN_FUNCTION ( browscap ) /* {{{ */
{
char * browscap = INI_STR ( " browscap " ) ;
if ( browscap & & browscap [ 0 ] ) {
zend_hash_destroy ( & browser_hash ) ;
browser_data * bdata = & BROWSCAP_G ( activation_bdata ) ;
if ( bdata - > filename [ 0 ] ! = ' \0 ' ) {
browscap_bdata_dtor ( bdata , 0 ) ;
}
return SUCCESS ;
}
/* }}} */
PHP_MSHUTDOWN_FUNCTION ( browscap ) /* {{{ */
{
browscap_bdata_dtor ( & global_bdata , 1 ) ;
return SUCCESS ;
}
/* }}} */
@ -331,11 +467,21 @@ PHP_FUNCTION(get_browser)
zval * * agent , * * z_agent_name , * * http_user_agent ;
zval * found_browser_entry , * tmp_copy ;
char * lookup_browser_name ;
char * browscap = INI_STR ( " browscap " ) ;
browser_data * bdata ;
if ( ! browscap | | ! browscap [ 0 ] ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " browscap ini directive not set " ) ;
RETURN_FALSE ;
if ( BROWSCAP_G ( activation_bdata ) . filename [ 0 ] ! = ' \0 ' ) {
bdata = & BROWSCAP_G ( activation_bdata ) ;
if ( bdata - > htab = = NULL ) { /* not initialized yet */
if ( browscap_read_file ( bdata - > filename , bdata , 0 TSRMLS_CC ) = = FAILURE ) {
RETURN_FALSE ;
}
}
} else {
if ( ! global_bdata . htab ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " browscap ini directive not set " ) ;
RETURN_FALSE ;
}
bdata = & global_bdata ;
}
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " |s!b " , & agent_name , & agent_name_len , & return_array ) = = FAILURE ) {
@ -357,13 +503,13 @@ PHP_FUNCTION(get_browser)
lookup_browser_name = estrndup ( agent_name , agent_name_len ) ;
php_strtolower ( lookup_browser_name , agent_name_len ) ;
if ( zend_hash_find ( & browser_hash , lookup_browser_name , agent_name_len + 1 , ( void * * ) & agent ) = = FAILURE ) {
if ( zend_hash_find ( bdata - > htab , lookup_browser_name , agent_name_len + 1 , ( void * * ) & agent ) = = FAILURE ) {
found_browser_entry = NULL ;
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 ) ;
zend_hash_apply_with_arguments ( bdata - > htab TSRMLS_CC , ( apply_func_args_t ) browser_reg_compare , 3 , lookup_browser_name , agent_name_len , & found_browser_entry ) ;
if ( found_browser_entry ) {
agent = & found_browser_entry ;
} else if ( zend_hash_find ( & browser_hash , DEFAULT_SECTION_NAME , sizeof ( DEFAULT_SECTION_NAME ) , ( void * * ) & agent ) = = FAILURE ) {
} else if ( zend_hash_find ( bdata - > htab , DEFAULT_SECTION_NAME , sizeof ( DEFAULT_SECTION_NAME ) , ( void * * ) & agent ) = = FAILURE ) {
efree ( lookup_browser_name ) ;
RETURN_FALSE ;
}
@ -379,7 +525,7 @@ PHP_FUNCTION(get_browser)
}
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 ) {
if ( zend_hash_find ( bdata - > htab , Z_STRVAL_PP ( z_agent_name ) , Z_STRLEN_PP ( z_agent_name ) + 1 , ( void * * ) & agent ) = = FAILURE ) {
break ;
}