LTP GCOV extension - code coverage report
Current view: directory - ext/standard - browscap.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 158
Code covered: 5.1 % Executed lines: 8
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 5                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2007 The PHP Group                                |
       6                 :    +----------------------------------------------------------------------+
       7                 :    | This source file is subject to version 3.01 of the PHP license,      |
       8                 :    | that is bundled with this package in the file LICENSE, and is        |
       9                 :    | available through the world-wide-web at the following url:           |
      10                 :    | http://www.php.net/license/3_01.txt                                  |
      11                 :    | If you did not receive a copy of the PHP license and are unable to   |
      12                 :    | obtain it through the world-wide-web, please send a note to          |
      13                 :    | license@php.net so we can mail you a copy immediately.               |
      14                 :    +----------------------------------------------------------------------+
      15                 :    | Author: Zeev Suraski <zeev@zend.com>                                 |
      16                 :    +----------------------------------------------------------------------+
      17                 :  */
      18                 : 
      19                 : /* $Id: browscap.c,v 1.85.2.2.2.3 2007/03/07 00:52:40 iliaa Exp $ */
      20                 : 
      21                 : #include "php.h"
      22                 : #include "php_regex.h"
      23                 : #include "php_browscap.h"
      24                 : #include "php_ini.h"
      25                 : #include "php_string.h"
      26                 : 
      27                 : #include "zend_globals.h"
      28                 : 
      29                 : static HashTable browser_hash;
      30                 : static zval *current_section;
      31                 : 
      32                 : #define DEFAULT_SECTION_NAME "Default Browser Capability Settings"
      33                 : 
      34                 : /* OBJECTS_FIXME: This whole extension needs going through. The use of objects looks pretty broken here */
      35                 : 
      36                 : static void browscap_entry_dtor(zval **zvalue)
      37               0 : {
      38               0 :         if (Z_TYPE_PP(zvalue) == IS_ARRAY) {
      39               0 :                 zend_hash_destroy(Z_ARRVAL_PP(zvalue));
      40               0 :                 free(Z_ARRVAL_PP(zvalue));
      41               0 :         } else if (Z_TYPE_PP(zvalue) == IS_STRING) {
      42               0 :                 if (Z_STRVAL_PP(zvalue)) {
      43               0 :                         free(Z_STRVAL_PP(zvalue));
      44                 :                 }
      45                 :         }
      46               0 :         free(*zvalue);
      47               0 : }
      48                 : 
      49                 : /* {{{ convert_browscap_pattern
      50                 :  */
      51                 : static void convert_browscap_pattern(zval *pattern)
      52               0 : {
      53                 :         register int i, j;
      54                 :         char *t;
      55                 : 
      56               0 :         php_strtolower(Z_STRVAL_P(pattern), Z_STRLEN_P(pattern));
      57                 : 
      58               0 :         t = (char *) safe_pemalloc(Z_STRLEN_P(pattern), 2, 3, 1);
      59                 : 
      60               0 :         t[0] = '^';
      61                 : 
      62               0 :         for (i=0, j=1; i<Z_STRLEN_P(pattern); i++, j++) {
      63               0 :                 switch (Z_STRVAL_P(pattern)[i]) {
      64                 :                         case '?':
      65               0 :                                 t[j] = '.';
      66               0 :                                 break;
      67                 :                         case '*':
      68               0 :                                 t[j++] = '.';
      69               0 :                                 t[j] = '*';
      70               0 :                                 break;
      71                 :                         case '.':
      72               0 :                                 t[j++] = '\\';
      73               0 :                                 t[j] = '.';
      74               0 :                                 break;
      75                 :                         default:
      76               0 :                                 t[j] = Z_STRVAL_P(pattern)[i];
      77                 :                                 break;
      78                 :                 }
      79                 :         }
      80                 : 
      81               0 :         t[j++] = '$';
      82                 : 
      83               0 :         t[j]=0;
      84               0 :         Z_STRVAL_P(pattern) = t;
      85               0 :         Z_STRLEN_P(pattern) = j;
      86               0 : }
      87                 : /* }}} */
      88                 : 
      89                 : /* {{{ php_browscap_parser_cb
      90                 :  */
      91                 : static void php_browscap_parser_cb(zval *arg1, zval *arg2, int callback_type, void *arg)
      92               0 : {
      93               0 :         if (!arg1) {
      94               0 :                 return;
      95                 :         }
      96                 : 
      97               0 :         switch (callback_type) {
      98                 :                 case ZEND_INI_PARSER_ENTRY:
      99               0 :                         if (current_section && arg2) {
     100                 :                                 zval *new_property;
     101                 :                                 char *new_key;
     102                 : 
     103               0 :                                 new_property = (zval *) pemalloc(sizeof(zval), 1);
     104               0 :                                 INIT_PZVAL(new_property);
     105               0 :                                 Z_STRVAL_P(new_property) = zend_strndup(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2));
     106               0 :                                 Z_STRLEN_P(new_property) = Z_STRLEN_P(arg2);
     107               0 :                                 Z_TYPE_P(new_property) = IS_STRING;
     108                 : 
     109               0 :                                 new_key = zend_strndup(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1));
     110               0 :                                 zend_str_tolower(new_key, Z_STRLEN_P(arg1));
     111               0 :                                 zend_hash_update(Z_ARRVAL_P(current_section), new_key, Z_STRLEN_P(arg1)+1, &new_property, sizeof(zval *), NULL);
     112               0 :                                 free(new_key);
     113                 :                         }
     114               0 :                         break;
     115                 :                 case ZEND_INI_PARSER_SECTION: {
     116                 :                                 zval *processed;
     117                 :                                 zval *unprocessed;
     118                 :                                 HashTable *section_properties;
     119                 : 
     120                 :                                 /*printf("'%s' (%d)\n",$1.value.str.val,$1.value.str.len+1);*/
     121               0 :                                 current_section = (zval *) pemalloc(sizeof(zval), 1);
     122               0 :                                 INIT_PZVAL(current_section);
     123               0 :                                 processed = (zval *) pemalloc(sizeof(zval), 1);
     124               0 :                                 INIT_PZVAL(processed);
     125               0 :                                 unprocessed = (zval *) pemalloc(sizeof(zval), 1);
     126               0 :                                 INIT_PZVAL(unprocessed);
     127                 : 
     128               0 :                                 section_properties = (HashTable *) pemalloc(sizeof(HashTable), 1);
     129               0 :                                 zend_hash_init(section_properties, 0, NULL, (dtor_func_t) browscap_entry_dtor, 1);
     130               0 :                                 current_section->value.ht = section_properties;
     131               0 :                                 current_section->type = IS_ARRAY;
     132               0 :                                 zend_hash_update(&browser_hash, Z_STRVAL_P(arg1), Z_STRLEN_P(arg1)+1, (void *) &current_section, sizeof(zval *), NULL);
     133                 : 
     134               0 :                                 Z_STRVAL_P(processed) = Z_STRVAL_P(arg1);
     135               0 :                                 Z_STRLEN_P(processed) = Z_STRLEN_P(arg1);
     136               0 :                                 Z_TYPE_P(processed) = IS_STRING;
     137               0 :                                 Z_STRVAL_P(unprocessed) = Z_STRVAL_P(arg1);
     138               0 :                                 Z_STRLEN_P(unprocessed) = Z_STRLEN_P(arg1);
     139               0 :                                 Z_TYPE_P(unprocessed) = IS_STRING;
     140               0 :                                 Z_STRVAL_P(unprocessed) = zend_strndup(Z_STRVAL_P(unprocessed), Z_STRLEN_P(unprocessed));
     141                 : 
     142               0 :                                 convert_browscap_pattern(processed);
     143               0 :                                 zend_hash_update(section_properties, "browser_name_regex", sizeof("browser_name_regex"), (void *) &processed, sizeof(zval *), NULL);
     144               0 :                                 zend_hash_update(section_properties, "browser_name_pattern", sizeof("browser_name_pattern"), (void *) &unprocessed, sizeof(zval *), NULL);
     145                 :                         }
     146                 :                         break;
     147                 :         }
     148                 : }
     149                 : /* }}} */
     150                 : 
     151                 : /* {{{ PHP_MINIT_FUNCTION
     152                 :  */
     153                 : PHP_MINIT_FUNCTION(browscap)
     154             220 : {
     155             220 :         char *browscap = INI_STR("browscap");
     156                 : 
     157             220 :         if (browscap && browscap[0]) {
     158                 :                 zend_file_handle fh;
     159               0 :                 memset(&fh, 0, sizeof(fh));
     160                 : 
     161               0 :                 if (zend_hash_init_ex(&browser_hash, 0, NULL, (dtor_func_t) browscap_entry_dtor, 1, 0)==FAILURE) {
     162               0 :                         return FAILURE;
     163                 :                 }
     164                 : 
     165               0 :                 fh.handle.fp = VCWD_FOPEN(browscap, "r");
     166               0 :                 fh.opened_path = NULL;
     167               0 :                 fh.free_filename = 0;
     168               0 :                 if (!fh.handle.fp) {
     169               0 :                         zend_error(E_CORE_WARNING, "Cannot open '%s' for reading", browscap);
     170               0 :                         return FAILURE;
     171                 :                 }
     172               0 :                 fh.filename = browscap;
     173               0 :                 Z_TYPE(fh) = ZEND_HANDLE_FP;
     174               0 :                 zend_parse_ini_file(&fh, 1, (zend_ini_parser_cb_t) php_browscap_parser_cb, &browser_hash);
     175                 :         }
     176                 : 
     177             220 :         return SUCCESS;
     178                 : }
     179                 : /* }}} */
     180                 : 
     181                 : /* {{{ PHP_MSHUTDOWN_FUNCTION
     182                 :  */
     183                 : PHP_MSHUTDOWN_FUNCTION(browscap)
     184             219 : {
     185             219 :         char *browscap = INI_STR("browscap");
     186             219 :         if (browscap && browscap[0]) {
     187               0 :                 zend_hash_destroy(&browser_hash);
     188                 :         }
     189             219 :         return SUCCESS;
     190                 : }
     191                 : /* }}} */
     192                 : 
     193                 : 
     194                 : /* {{{ browser_reg_compare
     195                 :  */
     196                 : static int browser_reg_compare(zval **browser, int num_args, va_list args, zend_hash_key *key)
     197               0 : {
     198                 :         zval **browser_regex, **previous_match;
     199                 :         regex_t r;
     200               0 :         char *lookup_browser_name = va_arg(args, char *);
     201               0 :         zval **found_browser_entry = va_arg(args, zval **);
     202                 : 
     203                 :         /* See if we have an exact match, if so, we're done... */
     204               0 :         if (*found_browser_entry) {
     205               0 :                 if (zend_hash_find(Z_ARRVAL_PP(found_browser_entry), "browser_name_pattern", sizeof("browser_name_pattern"), (void**) &previous_match) == FAILURE) {
     206               0 :                         return 0;
     207                 :                 }
     208               0 :                 else if (!strcasecmp(Z_STRVAL_PP(previous_match), lookup_browser_name)) {
     209               0 :                         return 0;
     210                 :                 }
     211                 :         }
     212                 : 
     213                 : 
     214               0 :         if (zend_hash_find(Z_ARRVAL_PP(browser), "browser_name_regex", sizeof("browser_name_regex"), (void **) &browser_regex) == FAILURE) {
     215               0 :                 return 0;
     216                 :         }
     217                 : 
     218               0 :         if (regcomp(&r, Z_STRVAL_PP(browser_regex), REG_NOSUB)!=0) {
     219               0 :                 return 0;
     220                 :         }
     221               0 :         if (regexec(&r, lookup_browser_name, 0, NULL, 0)==0) {
     222                 :                 /* If we've found a possible browser, we need to do a comparison of the
     223                 :                    number of characters changed in the user agent being checked versus
     224                 :                    the previous match found and the current match. */
     225               0 :                 if (*found_browser_entry) {
     226               0 :                         int i, prev_len = 0, curr_len = 0, ua_len;
     227                 :                         zval **current_match;
     228                 : 
     229               0 :                         if (zend_hash_find(Z_ARRVAL_PP(browser), "browser_name_pattern", sizeof("browser_name_pattern"), (void**) &current_match) == FAILURE) {
     230               0 :                                 regfree(&r);
     231               0 :                                 return 0;
     232                 :                         }
     233                 : 
     234               0 :                         ua_len = strlen(lookup_browser_name);
     235                 : 
     236               0 :                         for (i = 0; i < Z_STRLEN_PP(previous_match); i++) {
     237               0 :                                 switch (Z_STRVAL_PP(previous_match)[i]) {
     238                 :                                         case '?':
     239                 :                                         case '*':
     240                 :                                                 /* do nothing, ignore these characters in the count */
     241               0 :                                         break;
     242                 : 
     243                 :                                         default:
     244               0 :                                                 ++prev_len;
     245                 :                                 }
     246                 :                         }
     247                 : 
     248               0 :                         for (i = 0; i < Z_STRLEN_PP(current_match); i++) {
     249               0 :                                 switch (Z_STRVAL_PP(current_match)[i]) {
     250                 :                                         case '?':
     251                 :                                         case '*':
     252                 :                                                 /* do nothing, ignore these characters in the count */
     253               0 :                                         break;
     254                 : 
     255                 :                                         default:
     256               0 :                                                 ++curr_len;
     257                 :                                 }
     258                 :                         }
     259                 : 
     260                 : 
     261                 :                         /* Pick which browser pattern replaces the least amount of
     262                 :                            characters when compared to the original user agent string... */
     263               0 :                         if (ua_len - prev_len > ua_len - curr_len) {
     264               0 :                                 *found_browser_entry = *browser;
     265                 :                         }
     266                 :                 }
     267                 :                 else {
     268               0 :                         *found_browser_entry = *browser;
     269                 :                 }
     270                 :         }
     271                 : 
     272                 :         if (&r) {
     273               0 :                 regfree(&r);
     274                 :         }
     275                 : 
     276               0 :         return 0;
     277                 : }
     278                 : /* }}} */
     279                 : 
     280                 : /* {{{ proto mixed get_browser([string browser_name [, bool return_array]])
     281                 :    Get information about the capabilities of a browser. If browser_name is omitted
     282                 :    or null, HTTP_USER_AGENT is used. Returns an object by default; if return_array
     283                 :    is true, returns an array. */
     284                 : PHP_FUNCTION(get_browser)
     285               0 : {
     286               0 :         zval **agent_name = NULL, **agent, **retarr;
     287                 :         zval *found_browser_entry, *tmp_copy;
     288                 :         char *lookup_browser_name;
     289               0 :         zend_bool return_array = 0;
     290               0 :         char *browscap = INI_STR("browscap");
     291                 : 
     292               0 :         if (!browscap || !browscap[0]) {
     293               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "browscap ini directive not set.");
     294               0 :                 RETURN_FALSE;
     295                 :         }
     296                 : 
     297               0 :         if (ZEND_NUM_ARGS() > 2 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &agent_name, &retarr) == FAILURE) {
     298               0 :                 ZEND_WRONG_PARAM_COUNT();
     299                 :         }
     300                 : 
     301               0 :         if (agent_name == NULL || Z_TYPE_PP(agent_name) == IS_NULL) {
     302               0 :                 zend_is_auto_global("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC);
     303               0 :                 if (!PG(http_globals)[TRACK_VARS_SERVER]
     304                 :                         || zend_hash_find(PG(http_globals)[TRACK_VARS_SERVER]->value.ht, "HTTP_USER_AGENT", sizeof("HTTP_USER_AGENT"), (void **) &agent_name)==FAILURE) {
     305               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "HTTP_USER_AGENT variable is not set, cannot determine user agent name");
     306               0 :                         RETURN_FALSE;
     307                 :                 }
     308                 :         }
     309                 : 
     310               0 :         convert_to_string_ex(agent_name);
     311               0 :         lookup_browser_name = estrndup(Z_STRVAL_PP(agent_name), Z_STRLEN_PP(agent_name));
     312               0 :         php_strtolower(lookup_browser_name, strlen(lookup_browser_name));
     313                 : 
     314               0 :         if (ZEND_NUM_ARGS() == 2) {
     315               0 :                 convert_to_boolean_ex(retarr);
     316               0 :                 return_array = Z_BVAL_PP(retarr);
     317                 :         }
     318                 : 
     319               0 :         if (zend_hash_find(&browser_hash, lookup_browser_name, strlen(lookup_browser_name)+1, (void **) &agent)==FAILURE) {
     320               0 :                 found_browser_entry = NULL;
     321               0 :                 zend_hash_apply_with_arguments(&browser_hash, (apply_func_args_t) browser_reg_compare, 2, lookup_browser_name, &found_browser_entry);
     322                 : 
     323               0 :                 if (found_browser_entry) {
     324               0 :                         agent = &found_browser_entry;
     325               0 :                 } else if (zend_hash_find(&browser_hash, DEFAULT_SECTION_NAME, sizeof(DEFAULT_SECTION_NAME), (void **) &agent)==FAILURE) {
     326               0 :                         efree(lookup_browser_name);
     327               0 :                         RETURN_FALSE;
     328                 :                 }
     329                 :         }
     330                 : 
     331               0 :         if (return_array) {
     332               0 :                 array_init(return_value);
     333               0 :                 zend_hash_copy(Z_ARRVAL_P(return_value), Z_ARRVAL_PP(agent), (copy_ctor_func_t) zval_add_ref, (void *) &tmp_copy, sizeof(zval *));
     334                 :         }
     335                 :         else {
     336               0 :                 object_init(return_value);
     337               0 :                 zend_hash_copy(Z_OBJPROP_P(return_value), Z_ARRVAL_PP(agent), (copy_ctor_func_t) zval_add_ref, (void *) &tmp_copy, sizeof(zval *));
     338                 :         }
     339                 : 
     340               0 :         while (zend_hash_find(Z_ARRVAL_PP(agent), "parent", sizeof("parent"), (void **) &agent_name)==SUCCESS) {
     341               0 :                 if (zend_hash_find(&browser_hash, Z_STRVAL_PP(agent_name), Z_STRLEN_PP(agent_name)+1, (void **)&agent)==FAILURE) {
     342               0 :                         break;
     343                 :                 }
     344                 : 
     345               0 :                 if (return_array) {
     346               0 :                         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);
     347                 :                 }
     348                 :                 else {
     349               0 :                         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);
     350                 :                 }
     351                 :         }
     352                 : 
     353               0 :         efree(lookup_browser_name);
     354                 : }
     355                 : /* }}} */
     356                 : 
     357                 : /*
     358                 :  * Local variables:
     359                 :  * tab-width: 4
     360                 :  * c-basic-offset: 4
     361                 :  * End:
     362                 :  * vim600: sw=4 ts=4 fdm=marker
     363                 :  * vim<600: sw=4 ts=4
     364                 :  */

Generated by: LTP GCOV extension version 1.5