Annotation of embedaddon/php/ext/standard/browscap.c, revision 1.1.1.3

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.3 ! misho       5:    | Copyright (c) 1997-2013 The PHP Group                                |
1.1       misho       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: 
1.1.1.2   misho      19: /* $Id$ */
1.1       misho      20: 
                     21: #include "php.h"
                     22: #include "php_browscap.h"
                     23: #include "php_ini.h"
                     24: #include "php_string.h"
                     25: #include "ext/pcre/php_pcre.h"
                     26: 
                     27: #include "zend_ini_scanner.h"
                     28: #include "zend_globals.h"
                     29: 
                     30: typedef struct {
                     31:        HashTable *htab;
                     32:        zval *current_section;
                     33:        char *current_section_name;
                     34:        char filename[MAXPATHLEN];
                     35: } browser_data;
                     36: 
                     37: /* browser data defined in startup phase, eagerly loaded in MINIT */
                     38: static browser_data global_bdata = {0};
                     39: 
                     40: /* browser data defined in activation phase, lazily loaded in get_browser.
                     41:  * Per request and per thread, if applicable */
                     42: ZEND_BEGIN_MODULE_GLOBALS(browscap)
                     43:        browser_data activation_bdata;
                     44: ZEND_END_MODULE_GLOBALS(browscap)
                     45: 
1.1.1.3 ! misho      46: ZEND_DECLARE_MODULE_GLOBALS(browscap)
1.1       misho      47: 
                     48: #ifdef ZTS
                     49: #define BROWSCAP_G(v)  TSRMG(browscap_globals_id, zend_browscap_globals *, v)
                     50: #else
                     51: #define BROWSCAP_G(v)  (browscap_globals.v)
                     52: #endif
                     53: 
                     54: #define DEFAULT_SECTION_NAME "Default Browser Capability Settings"
                     55: 
                     56: /* OBJECTS_FIXME: This whole extension needs going through. The use of objects looks pretty broken here */
                     57: 
                     58: static void browscap_entry_dtor_request(zval **zvalue) /* {{{ */
                     59: {
                     60:        if (Z_TYPE_PP(zvalue) == IS_ARRAY) {
                     61:                zend_hash_destroy(Z_ARRVAL_PP(zvalue));
                     62:                efree(Z_ARRVAL_PP(zvalue));
                     63:        } else if (Z_TYPE_PP(zvalue) == IS_STRING) {
                     64:                if (Z_STRVAL_PP(zvalue)) {
                     65:                        efree(Z_STRVAL_PP(zvalue));
                     66:                }
                     67:        }
                     68:        efree(*zvalue);
                     69: }
                     70: /* }}} */
                     71: 
                     72: static void browscap_entry_dtor_persistent(zval **zvalue) /* {{{ */ {
                     73:        if (Z_TYPE_PP(zvalue) == IS_ARRAY) {
                     74:                zend_hash_destroy(Z_ARRVAL_PP(zvalue));
                     75:                free(Z_ARRVAL_PP(zvalue));
                     76:        } else if (Z_TYPE_PP(zvalue) == IS_STRING) {
                     77:                if (Z_STRVAL_PP(zvalue)) {
                     78:                        free(Z_STRVAL_PP(zvalue));
                     79:                }
                     80:        }
                     81:        free(*zvalue);
                     82: }
                     83: /* }}} */
                     84: 
                     85: static void convert_browscap_pattern(zval *pattern, int persistent) /* {{{ */
                     86: {
                     87:        int i, j=0;
                     88:        char *t;
                     89: 
                     90:        php_strtolower(Z_STRVAL_P(pattern), Z_STRLEN_P(pattern));
                     91: 
                     92:        t = (char *) safe_pemalloc(Z_STRLEN_P(pattern), 2, 5, persistent);
                     93: 
                     94:        t[j++] = '\xA7'; /* section sign */
                     95:        t[j++] = '^';
                     96: 
                     97:        for (i=0; i<Z_STRLEN_P(pattern); i++, j++) {
                     98:                switch (Z_STRVAL_P(pattern)[i]) {
                     99:                        case '?':
                    100:                                t[j] = '.';
                    101:                                break;
                    102:                        case '*':
                    103:                                t[j++] = '.';
                    104:                                t[j] = '*';
                    105:                                break;
                    106:                        case '.':
                    107:                                t[j++] = '\\';
                    108:                                t[j] = '.';
                    109:                                break;
                    110:                        case '\\':
                    111:                                t[j++] = '\\';
                    112:                                t[j] = '\\';
                    113:                                break;
                    114:                        case '(':
                    115:                                t[j++] = '\\';
                    116:                                t[j] = '(';
                    117:                                break;
                    118:                        case ')':
                    119:                                t[j++] = '\\';
                    120:                                t[j] = ')';
                    121:                                break;
                    122:                        case '\xA7':
                    123:                                t[j++] = '\\';
                    124:                                t[j] = '\xA7';
                    125:                                break;
                    126:                        default:
                    127:                                t[j] = Z_STRVAL_P(pattern)[i];
                    128:                                break;
                    129:                }
                    130:        }
                    131: 
                    132:        t[j++] = '$';
                    133:        t[j++] = '\xA7';
                    134: 
                    135:        t[j]=0;
                    136:        Z_STRVAL_P(pattern) = t;
                    137:        Z_STRLEN_P(pattern) = j;
                    138: }
                    139: /* }}} */
                    140: 
                    141: static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callback_type, void *arg TSRMLS_DC) /* {{{ */
                    142: {
                    143:        browser_data *bdata = arg;
                    144:        int persistent = bdata->htab->persistent;
                    145:        
                    146:        if (!arg1) {
                    147:                return;
                    148:        }
                    149: 
                    150:        switch (callback_type) {
                    151:                case ZEND_INI_PARSER_ENTRY:
                    152:                        if (bdata->current_section && arg2) {
                    153:                                zval *new_property;
                    154:                                char *new_key;
                    155: 
                    156:                                /* parent entry can not be same as current section -> causes infinite loop! */
                    157:                                if (!strcasecmp(Z_STRVAL_P(arg1), "parent") && 
                    158:                                        bdata->current_section_name != NULL &&
                    159:                                        !strcasecmp(bdata->current_section_name, Z_STRVAL_P(arg2))
                    160:                                ) {
                    161:                                        zend_error(E_CORE_ERROR, "Invalid browscap ini file: "
                    162:                                                "'Parent' value cannot be same as the section name: %s "
                    163:                                                "(in file %s)", bdata->current_section_name, INI_STR("browscap"));
                    164:                                        return;
                    165:                                }
                    166: 
                    167:                                new_property = (zval *) pemalloc(sizeof(zval), persistent);
                    168:                                INIT_PZVAL(new_property);
                    169:                                Z_TYPE_P(new_property) = IS_STRING;
                    170: 
                    171:                                /* Set proper value for true/false settings */
                    172:                                if ((Z_STRLEN_P(arg2) == 2 && !strncasecmp(Z_STRVAL_P(arg2), "on", sizeof("on") - 1)) ||
                    173:                                        (Z_STRLEN_P(arg2) == 3 && !strncasecmp(Z_STRVAL_P(arg2), "yes", sizeof("yes") - 1)) ||
                    174:                                        (Z_STRLEN_P(arg2) == 4 && !strncasecmp(Z_STRVAL_P(arg2), "true", sizeof("true") - 1))
                    175:                                ) {
                    176:                                        Z_STRVAL_P(new_property) = pestrndup("1", 1, persistent);
                    177:                                        Z_STRLEN_P(new_property) = 1;
                    178:                                } else if (
                    179:                                        (Z_STRLEN_P(arg2) == 2 && !strncasecmp(Z_STRVAL_P(arg2), "no", sizeof("no") - 1)) ||
                    180:                                        (Z_STRLEN_P(arg2) == 3 && !strncasecmp(Z_STRVAL_P(arg2), "off", sizeof("off") - 1)) ||
                    181:                                        (Z_STRLEN_P(arg2) == 4 && !strncasecmp(Z_STRVAL_P(arg2), "none", sizeof("none") - 1)) ||
                    182:                                        (Z_STRLEN_P(arg2) == 5 && !strncasecmp(Z_STRVAL_P(arg2), "false", sizeof("false") - 1))
                    183:                                ) {
                    184:                                        Z_STRVAL_P(new_property) = pestrndup("", 0, persistent);
                    185:                                        Z_STRLEN_P(new_property) = 0;
                    186:                                } else { /* Other than true/false setting */
                    187:                                        Z_STRVAL_P(new_property) = pestrndup(Z_STRVAL_P(arg2),
                    188:                                                        Z_STRLEN_P(arg2), persistent);
                    189:                                        Z_STRLEN_P(new_property) = Z_STRLEN_P(arg2);
                    190:                                }
                    191:                                new_key = pestrndup(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1), persistent);
                    192:                                zend_str_tolower(new_key, Z_STRLEN_P(arg1));
                    193:                                zend_hash_update(Z_ARRVAL_P(bdata->current_section), new_key, Z_STRLEN_P(arg1) + 1, &new_property, sizeof(zval *), NULL);
                    194:                                pefree(new_key, persistent);
                    195:                        }
                    196:                        break;
                    197:                case ZEND_INI_PARSER_SECTION: {
                    198:                                zval *processed;
                    199:                                zval *unprocessed;
                    200:                                HashTable *section_properties;
                    201: 
                    202:                                /*printf("'%s' (%d)\n",$1.value.str.val,$1.value.str.len + 1);*/
                    203:                                bdata->current_section = (zval *) pemalloc(sizeof(zval), persistent);
                    204:                                INIT_PZVAL(bdata->current_section);
                    205:                                processed = (zval *) pemalloc(sizeof(zval), persistent);
                    206:                                INIT_PZVAL(processed);
                    207:                                unprocessed = (zval *) pemalloc(sizeof(zval), persistent);
                    208:                                INIT_PZVAL(unprocessed);
                    209: 
                    210:                                section_properties = (HashTable *) pemalloc(sizeof(HashTable), persistent);
                    211:                                zend_hash_init(section_properties, 0, NULL,
                    212:                                                (dtor_func_t) (persistent?browscap_entry_dtor_persistent
                    213:                                                                                                 :browscap_entry_dtor_request),
                    214:                                                persistent);
                    215:                                Z_ARRVAL_P(bdata->current_section) = section_properties;
                    216:                                Z_TYPE_P(bdata->current_section) = IS_ARRAY;
                    217:                                if (bdata->current_section_name) {
                    218:                                        pefree(bdata->current_section_name, persistent);
                    219:                                }
                    220:                                bdata->current_section_name = pestrndup(Z_STRVAL_P(arg1),
                    221:                                                Z_STRLEN_P(arg1), persistent);
                    222: 
                    223:                                zend_hash_update(bdata->htab, Z_STRVAL_P(arg1), Z_STRLEN_P(arg1) + 1, (void *) &bdata->current_section, sizeof(zval *), NULL);
                    224: 
                    225:                                Z_STRVAL_P(processed) = Z_STRVAL_P(arg1);
                    226:                                Z_STRLEN_P(processed) = Z_STRLEN_P(arg1);
                    227:                                Z_TYPE_P(processed) = IS_STRING;
                    228:                                Z_STRVAL_P(unprocessed) = Z_STRVAL_P(arg1);
                    229:                                Z_STRLEN_P(unprocessed) = Z_STRLEN_P(arg1);
                    230:                                Z_TYPE_P(unprocessed) = IS_STRING;
                    231:                                Z_STRVAL_P(unprocessed) = pestrndup(Z_STRVAL_P(unprocessed), Z_STRLEN_P(unprocessed), persistent);
                    232: 
                    233:                                convert_browscap_pattern(processed, persistent);
                    234:                                zend_hash_update(section_properties, "browser_name_regex", sizeof("browser_name_regex"), (void *) &processed, sizeof(zval *), NULL);
                    235:                                zend_hash_update(section_properties, "browser_name_pattern", sizeof("browser_name_pattern"), (void *) &unprocessed, sizeof(zval *), NULL);
                    236:                        }
                    237:                        break;
                    238:        }
                    239: }
                    240: /* }}} */
                    241: 
                    242: static int browscap_read_file(char *filename, browser_data *browdata, int persistent TSRMLS_DC) /* {{{ */
                    243: {
                    244:        zend_file_handle fh = {0};
                    245:        
                    246:        if (filename == NULL || filename[0] == '\0') {
                    247:                return FAILURE;
                    248:        }
                    249:        
                    250:        browdata->htab = pemalloc(sizeof *browdata->htab, persistent);
                    251:        if (browdata->htab == NULL) {
                    252:                return FAILURE;
                    253:        }
                    254: 
                    255:        if (zend_hash_init_ex(browdata->htab, 0, NULL,
                    256:                        (dtor_func_t) (persistent?browscap_entry_dtor_persistent
                    257:                                                                         :browscap_entry_dtor_request),
                    258:                        persistent, 0) == FAILURE) {
                    259:                pefree(browdata->htab, persistent);
                    260:                browdata->htab = NULL;
                    261:                return FAILURE;
                    262:        }
                    263: 
                    264:        fh.handle.fp = VCWD_FOPEN(filename, "r");
                    265:        fh.opened_path = NULL;
                    266:        fh.free_filename = 0;
                    267:        if (!fh.handle.fp) {
                    268:                zend_hash_destroy(browdata->htab);
                    269:                pefree(browdata->htab, persistent);
                    270:                browdata->htab = NULL;
                    271:                zend_error(E_CORE_WARNING, "Cannot open '%s' for reading", filename);
                    272:                return FAILURE;
                    273:        }
                    274:        fh.filename = filename;
                    275:        Z_TYPE(fh) = ZEND_HANDLE_FP;
                    276:        browdata->current_section_name = NULL;
                    277:        zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_RAW,
                    278:                        (zend_ini_parser_cb_t) php_browscap_parser_cb, browdata TSRMLS_CC);
                    279:        if (browdata->current_section_name != NULL) {
                    280:                pefree(browdata->current_section_name, persistent);
                    281:                browdata->current_section_name = NULL;
                    282:        }
                    283:        
                    284:        return SUCCESS;
                    285: }
                    286: /* }}} */
                    287: 
                    288: #ifdef ZTS
                    289: static void browscap_globals_ctor(zend_browscap_globals *browscap_globals TSRMLS_DC) /* {{{ */
                    290: {
                    291:        browscap_globals->activation_bdata.htab = NULL;
                    292:        browscap_globals->activation_bdata.current_section = NULL;
                    293:        browscap_globals->activation_bdata.current_section_name = NULL;
                    294:        browscap_globals->activation_bdata.filename[0] = '\0';
                    295: }
                    296: /* }}} */
                    297: #endif
                    298: 
                    299: static void browscap_bdata_dtor(browser_data *bdata, int persistent TSRMLS_DC) /* {{{ */
                    300: {
                    301:        if (bdata->htab != NULL) {
                    302:                zend_hash_destroy(bdata->htab);
                    303:                pefree(bdata->htab, persistent);
                    304:                bdata->htab = NULL;
                    305:        }
                    306:        bdata->filename[0] = '\0';
                    307:        /* current_section_* are only used during parsing */
                    308: }
                    309: /* }}} */
                    310: 
                    311: /* {{{ PHP_INI_MH
                    312:  */
                    313: PHP_INI_MH(OnChangeBrowscap)
                    314: {
                    315:        if (stage == PHP_INI_STAGE_STARTUP) {
                    316:                /* value handled in browscap.c's MINIT */
                    317:                return SUCCESS;
                    318:        } else if (stage == PHP_INI_STAGE_ACTIVATE) {
                    319:                browser_data *bdata = &BROWSCAP_G(activation_bdata);
                    320:                if (bdata->filename[0] != '\0') {
                    321:                        browscap_bdata_dtor(bdata, 0 TSRMLS_CC);
                    322:                }
                    323:                if (VCWD_REALPATH(new_value, bdata->filename) == NULL) {
                    324:                        return FAILURE;
                    325:                }
                    326:                return SUCCESS;
                    327:        }
                    328:        
                    329:        return FAILURE;
                    330: }
                    331: /* }}} */
                    332: 
                    333: PHP_MINIT_FUNCTION(browscap) /* {{{ */
                    334: {
                    335:        char *browscap = INI_STR("browscap");
1.1.1.2   misho     336: 
1.1       misho     337: #ifdef ZTS
                    338:        ts_allocate_id(&browscap_globals_id, sizeof(browser_data),
1.1.1.2   misho     339:                browscap_globals_ctor, NULL);
1.1       misho     340: #endif
                    341:        /* ctor call not really needed for non-ZTS */
                    342: 
                    343:        if (browscap && browscap[0]) {
                    344:                if (browscap_read_file(browscap, &global_bdata, 1 TSRMLS_CC) == FAILURE) {
                    345:                        return FAILURE;
                    346:                }
                    347:        }
                    348: 
                    349:        return SUCCESS;
                    350: }
                    351: /* }}} */
                    352: 
                    353: PHP_RSHUTDOWN_FUNCTION(browscap) /* {{{ */
                    354: {
                    355:        browser_data *bdata = &BROWSCAP_G(activation_bdata);
                    356:        if (bdata->filename[0] != '\0') {
                    357:                browscap_bdata_dtor(bdata, 0 TSRMLS_CC);
                    358:        }
                    359:        
                    360:        return SUCCESS;
                    361: }
                    362: /* }}} */
                    363: 
                    364: PHP_MSHUTDOWN_FUNCTION(browscap) /* {{{ */
                    365: {
                    366:        browscap_bdata_dtor(&global_bdata, 1 TSRMLS_CC);
                    367:        
                    368:        return SUCCESS;
                    369: }
                    370: /* }}} */
                    371: 
                    372: static int browser_reg_compare(zval **browser TSRMLS_DC, int num_args, va_list args, zend_hash_key *key) /* {{{ */
                    373: {
                    374:        zval **browser_regex, **previous_match;
                    375:        pcre *re;
                    376:        int re_options;
                    377:        pcre_extra *re_extra;
                    378:        char *lookup_browser_name = va_arg(args, char *);
                    379:        int lookup_browser_length = va_arg(args, int);
                    380:        zval **found_browser_entry = va_arg(args, zval **);
                    381: 
                    382:        /* See if we have an exact match, if so, we're done... */
                    383:        if (*found_browser_entry) {
                    384:                if (zend_hash_find(Z_ARRVAL_PP(found_browser_entry), "browser_name_pattern", sizeof("browser_name_pattern"), (void**) &previous_match) == FAILURE) {
                    385:                        return 0;
                    386:                }
                    387:                else if (!strcasecmp(Z_STRVAL_PP(previous_match), lookup_browser_name)) {
                    388:                        return 0;
                    389:                }
                    390:        }
                    391: 
                    392:        if (zend_hash_find(Z_ARRVAL_PP(browser), "browser_name_regex", sizeof("browser_name_regex"), (void **) &browser_regex) == FAILURE) {
                    393:                return 0;
                    394:        }
                    395: 
                    396:        re = pcre_get_compiled_regex(Z_STRVAL_PP(browser_regex), &re_extra, &re_options TSRMLS_CC);
                    397:        if (re == NULL) {
                    398:                return 0;
                    399:        }
                    400: 
                    401:        if (pcre_exec(re, re_extra, lookup_browser_name, lookup_browser_length, 0, re_options, NULL, 0) == 0) {
                    402:                /* If we've found a possible browser, we need to do a comparison of the
                    403:                   number of characters changed in the user agent being checked versus
                    404:                   the previous match found and the current match. */
                    405:                if (*found_browser_entry) {
                    406:                        int i, prev_len = 0, curr_len = 0, ua_len;
                    407:                        zval **current_match;
                    408: 
                    409:                        if (zend_hash_find(Z_ARRVAL_PP(browser), "browser_name_pattern", sizeof("browser_name_pattern"), (void**) &current_match) == FAILURE) {
                    410:                                return 0;
                    411:                        }
                    412: 
                    413:                        ua_len = lookup_browser_length;
                    414: 
                    415:                        for (i = 0; i < Z_STRLEN_PP(previous_match); i++) {
                    416:                                switch (Z_STRVAL_PP(previous_match)[i]) {
                    417:                                        case '?':
                    418:                                        case '*':
                    419:                                                /* do nothing, ignore these characters in the count */
                    420:                                        break;
                    421: 
                    422:                                        default:
                    423:                                                ++prev_len;
                    424:                                }
                    425:                        }
                    426: 
                    427:                        for (i = 0; i < Z_STRLEN_PP(current_match); i++) {
                    428:                                switch (Z_STRVAL_PP(current_match)[i]) {
                    429:                                        case '?':
                    430:                                        case '*':
                    431:                                                /* do nothing, ignore these characters in the count */
                    432:                                        break;
                    433: 
                    434:                                        default:
                    435:                                                ++curr_len;
                    436:                                }
                    437:                        }
                    438: 
                    439:                        /* Pick which browser pattern replaces the least amount of
                    440:                           characters when compared to the original user agent string... */
                    441:                        if (ua_len - prev_len > ua_len - curr_len) {
                    442:                                *found_browser_entry = *browser;
                    443:                        }
                    444:                }
                    445:                else {
                    446:                        *found_browser_entry = *browser;
                    447:                }
                    448:        }
                    449: 
                    450:        return 0;
                    451: }
                    452: /* }}} */
                    453: 
1.1.1.3 ! misho     454: static void browscap_zval_copy_ctor(zval **p) /* {{{ */
        !           455: {
        !           456:        zval *new;
        !           457: 
        !           458:        ALLOC_ZVAL(new);
        !           459:        *new = **p;
        !           460: 
        !           461:        zval_copy_ctor(new);
        !           462: 
        !           463:        INIT_PZVAL(new);
        !           464:        *p = new;
        !           465: } /* }}} */
        !           466: 
1.1       misho     467: /* {{{ proto mixed get_browser([string browser_name [, bool return_array]])
                    468:    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. */
                    469: PHP_FUNCTION(get_browser)
                    470: {
                    471:        char *agent_name = NULL;
                    472:        int agent_name_len = 0;
                    473:        zend_bool return_array = 0;
                    474:        zval **agent, **z_agent_name, **http_user_agent;
                    475:        zval *found_browser_entry, *tmp_copy;
                    476:        char *lookup_browser_name;
                    477:        browser_data *bdata;
                    478: 
                    479:        if (BROWSCAP_G(activation_bdata).filename[0] != '\0') {
                    480:                bdata = &BROWSCAP_G(activation_bdata);
                    481:                if (bdata->htab == NULL) { /* not initialized yet */
                    482:                        if (browscap_read_file(bdata->filename, bdata, 0 TSRMLS_CC) == FAILURE) {
                    483:                                RETURN_FALSE;
                    484:                        }
                    485:                }
                    486:        } else {
                    487:                if (!global_bdata.htab) {
                    488:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "browscap ini directive not set");
                    489:                        RETURN_FALSE;
                    490:                }
                    491:                bdata = &global_bdata;
                    492:        }
                    493: 
                    494:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!b", &agent_name, &agent_name_len, &return_array) == FAILURE) {
                    495:                return;
                    496:        }
                    497: 
                    498:        if (agent_name == NULL) {
                    499:                zend_is_auto_global("_SERVER", sizeof("_SERVER") - 1 TSRMLS_CC);
                    500:                if (!PG(http_globals)[TRACK_VARS_SERVER] ||
                    501:                        zend_hash_find(HASH_OF(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_USER_AGENT", sizeof("HTTP_USER_AGENT"), (void **) &http_user_agent) == FAILURE
                    502:                ) {
                    503:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "HTTP_USER_AGENT variable is not set, cannot determine user agent name");
                    504:                        RETURN_FALSE;
                    505:                }
                    506:                agent_name = Z_STRVAL_PP(http_user_agent);
                    507:                agent_name_len = Z_STRLEN_PP(http_user_agent);
                    508:        }
                    509: 
                    510:        lookup_browser_name = estrndup(agent_name, agent_name_len);
                    511:        php_strtolower(lookup_browser_name, agent_name_len);
                    512: 
                    513:        if (zend_hash_find(bdata->htab, lookup_browser_name, agent_name_len + 1, (void **) &agent) == FAILURE) {
                    514:                found_browser_entry = NULL;
                    515:                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);
                    516: 
                    517:                if (found_browser_entry) {
                    518:                        agent = &found_browser_entry;
                    519:                } else if (zend_hash_find(bdata->htab, DEFAULT_SECTION_NAME, sizeof(DEFAULT_SECTION_NAME), (void **) &agent) == FAILURE) {
                    520:                        efree(lookup_browser_name);
                    521:                        RETURN_FALSE;
                    522:                }
                    523:        }
                    524: 
                    525:        if (return_array) {
                    526:                array_init(return_value);
1.1.1.3 ! misho     527:                zend_hash_copy(Z_ARRVAL_P(return_value), Z_ARRVAL_PP(agent), (copy_ctor_func_t) browscap_zval_copy_ctor, (void *) &tmp_copy, sizeof(zval *));
1.1       misho     528:        }
                    529:        else {
                    530:                object_init(return_value);
1.1.1.3 ! misho     531:                zend_hash_copy(Z_OBJPROP_P(return_value), Z_ARRVAL_PP(agent), (copy_ctor_func_t) browscap_zval_copy_ctor, (void *) &tmp_copy, sizeof(zval *));
1.1       misho     532:        }
                    533: 
                    534:        while (zend_hash_find(Z_ARRVAL_PP(agent), "parent", sizeof("parent"), (void **) &z_agent_name) == SUCCESS) {
                    535:                if (zend_hash_find(bdata->htab, Z_STRVAL_PP(z_agent_name), Z_STRLEN_PP(z_agent_name) + 1, (void **)&agent) == FAILURE) {
                    536:                        break;
                    537:                }
                    538: 
                    539:                if (return_array) {
1.1.1.3 ! misho     540:                        zend_hash_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_PP(agent), (copy_ctor_func_t) browscap_zval_copy_ctor, (void *) &tmp_copy, sizeof(zval *), 0);
1.1       misho     541:                }
                    542:                else {
1.1.1.3 ! misho     543:                        zend_hash_merge(Z_OBJPROP_P(return_value), Z_ARRVAL_PP(agent), (copy_ctor_func_t) browscap_zval_copy_ctor, (void *) &tmp_copy, sizeof(zval *), 0);
1.1       misho     544:                }
                    545:        }
                    546: 
                    547:        efree(lookup_browser_name);
                    548: }
                    549: /* }}} */
                    550: 
                    551: /*
                    552:  * Local variables:
                    553:  * tab-width: 4
                    554:  * c-basic-offset: 4
                    555:  * End:
                    556:  * vim600: sw=4 ts=4 fdm=marker
                    557:  * vim<600: sw=4 ts=4
                    558:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>