Annotation of embedaddon/php/ext/session/session.c, revision 1.1

1.1     ! misho       1: /*
        !             2:    +----------------------------------------------------------------------+
        !             3:    | PHP Version 5                                                        |
        !             4:    +----------------------------------------------------------------------+
        !             5:    | Copyright (c) 1997-2012 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:    | Authors: Sascha Schumann <sascha@schumann.cx>                        |
        !            16:    |          Andrei Zmievski <andrei@php.net>                            |
        !            17:    +----------------------------------------------------------------------+
        !            18:  */
        !            19: 
        !            20: /* $Id: session.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            21: 
        !            22: #ifdef HAVE_CONFIG_H
        !            23: #include "config.h"
        !            24: #endif
        !            25: 
        !            26: #include "php.h"
        !            27: 
        !            28: #ifdef PHP_WIN32
        !            29: # include "win32/winutil.h"
        !            30: # include "win32/time.h"
        !            31: #else
        !            32: #include <sys/time.h>
        !            33: #endif
        !            34: 
        !            35: #include <sys/stat.h>
        !            36: #include <fcntl.h>
        !            37: 
        !            38: #include "php_ini.h"
        !            39: #include "SAPI.h"
        !            40: #include "php_session.h"
        !            41: #include "ext/standard/md5.h"
        !            42: #include "ext/standard/sha1.h"
        !            43: #include "ext/standard/php_var.h"
        !            44: #include "ext/date/php_date.h"
        !            45: #include "ext/standard/php_lcg.h"
        !            46: #include "ext/standard/url_scanner_ex.h"
        !            47: #include "ext/standard/php_rand.h" /* for RAND_MAX */
        !            48: #include "ext/standard/info.h"
        !            49: #include "ext/standard/php_smart_str.h"
        !            50: #include "ext/standard/url.h"
        !            51: 
        !            52: #include "mod_files.h"
        !            53: #include "mod_user.h"
        !            54: 
        !            55: #ifdef HAVE_LIBMM
        !            56: #include "mod_mm.h"
        !            57: #endif
        !            58: 
        !            59: PHPAPI ZEND_DECLARE_MODULE_GLOBALS(ps);
        !            60: 
        !            61: /* ***********
        !            62:    * Helpers *
        !            63:    *********** */
        !            64: 
        !            65: #define IF_SESSION_VARS() \
        !            66:        if (PS(http_session_vars) && PS(http_session_vars)->type == IS_ARRAY)
        !            67: 
        !            68: #define SESSION_CHECK_ACTIVE_STATE     \
        !            69:        if (PS(session_status) == php_session_active) { \
        !            70:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "A session is active. You cannot change the session module's ini settings at this time");   \
        !            71:                return FAILURE; \
        !            72:        }
        !            73: 
        !            74: /* Dispatched by RINIT and by php_session_destroy */
        !            75: static inline void php_rinit_session_globals(TSRMLS_D) /* {{{ */
        !            76: {
        !            77:        PS(id) = NULL;
        !            78:        PS(session_status) = php_session_none;
        !            79:        PS(mod_data) = NULL;
        !            80:        /* Do NOT init PS(mod_user_names) here! */
        !            81:        PS(http_session_vars) = NULL;
        !            82: }
        !            83: /* }}} */
        !            84: 
        !            85: /* Dispatched by RSHUTDOWN and by php_session_destroy */
        !            86: static inline void php_rshutdown_session_globals(TSRMLS_D) /* {{{ */
        !            87: {
        !            88:        if (PS(http_session_vars)) {
        !            89:                zval_ptr_dtor(&PS(http_session_vars));
        !            90:                PS(http_session_vars) = NULL;
        !            91:        }
        !            92:        /* Do NOT destroy PS(mod_user_names) here! */
        !            93:        if (PS(mod_data)) {
        !            94:                zend_try {
        !            95:                        PS(mod)->s_close(&PS(mod_data) TSRMLS_CC);
        !            96:                } zend_end_try();
        !            97:        }
        !            98:        if (PS(id)) {
        !            99:                efree(PS(id));
        !           100:        }
        !           101: }
        !           102: /* }}} */
        !           103: 
        !           104: static int php_session_destroy(TSRMLS_D) /* {{{ */
        !           105: {
        !           106:        int retval = SUCCESS;
        !           107: 
        !           108:        if (PS(session_status) != php_session_active) {
        !           109:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Trying to destroy uninitialized session");
        !           110:                return FAILURE;
        !           111:        }
        !           112: 
        !           113:        if (PS(mod)->s_destroy(&PS(mod_data), PS(id) TSRMLS_CC) == FAILURE) {
        !           114:                retval = FAILURE;
        !           115:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session object destruction failed");
        !           116:        }
        !           117: 
        !           118:        php_rshutdown_session_globals(TSRMLS_C);
        !           119:        php_rinit_session_globals(TSRMLS_C);
        !           120: 
        !           121:        return retval;
        !           122: }
        !           123: /* }}} */
        !           124: 
        !           125: PHPAPI void php_add_session_var(char *name, size_t namelen TSRMLS_DC) /* {{{ */
        !           126: {
        !           127:        zval **sym_track = NULL;
        !           128: 
        !           129:        IF_SESSION_VARS() {
        !           130:                zend_hash_find(Z_ARRVAL_P(PS(http_session_vars)), name, namelen + 1, (void *) &sym_track);
        !           131:        } else {
        !           132:                return;
        !           133:        }
        !           134: 
        !           135:        /* Set up a proper reference between $_SESSION["x"] and $x. */
        !           136: 
        !           137:        if (PG(register_globals)) {
        !           138:                zval **sym_global = NULL;
        !           139: 
        !           140:                if (zend_hash_find(&EG(symbol_table), name, namelen + 1, (void *) &sym_global) == SUCCESS) {
        !           141:                        if ((Z_TYPE_PP(sym_global) == IS_ARRAY && Z_ARRVAL_PP(sym_global) == &EG(symbol_table)) || *sym_global == PS(http_session_vars)) {
        !           142:                                return;
        !           143:                        }
        !           144:                }
        !           145: 
        !           146:                if (sym_global == NULL && sym_track == NULL) {
        !           147:                        zval *empty_var;
        !           148: 
        !           149:                        ALLOC_INIT_ZVAL(empty_var); /* this sets refcount to 1 */
        !           150:                        Z_SET_REFCOUNT_P(empty_var, 0); /* our module does not maintain a ref */
        !           151:                        /* The next call will increase refcount by NR_OF_SYM_TABLES==2 */
        !           152:                        zend_set_hash_symbol(empty_var, name, namelen, 1, 2, Z_ARRVAL_P(PS(http_session_vars)), &EG(symbol_table));
        !           153:                } else if (sym_global == NULL) {
        !           154:                        SEPARATE_ZVAL_IF_NOT_REF(sym_track);
        !           155:                        zend_set_hash_symbol(*sym_track, name, namelen, 1, 1, &EG(symbol_table));
        !           156:                } else if (sym_track == NULL) {
        !           157:                        SEPARATE_ZVAL_IF_NOT_REF(sym_global);
        !           158:                        zend_set_hash_symbol(*sym_global, name, namelen, 1, 1, Z_ARRVAL_P(PS(http_session_vars)));
        !           159:                }
        !           160:        } else {
        !           161:                if (sym_track == NULL) {
        !           162:                        zval *empty_var;
        !           163: 
        !           164:                        ALLOC_INIT_ZVAL(empty_var);
        !           165:                        ZEND_SET_SYMBOL_WITH_LENGTH(Z_ARRVAL_P(PS(http_session_vars)), name, namelen+1, empty_var, 1, 0);
        !           166:                }
        !           167:        }
        !           168: }
        !           169: /* }}} */
        !           170: 
        !           171: PHPAPI void php_set_session_var(char *name, size_t namelen, zval *state_val, php_unserialize_data_t *var_hash TSRMLS_DC) /* {{{ */
        !           172: {
        !           173:        if (PG(register_globals)) {
        !           174:                zval **old_symbol;
        !           175:                if (zend_hash_find(&EG(symbol_table),name,namelen+1,(void *)&old_symbol) == SUCCESS) {
        !           176:                        if ((Z_TYPE_PP(old_symbol) == IS_ARRAY && Z_ARRVAL_PP(old_symbol) == &EG(symbol_table)) || *old_symbol == PS(http_session_vars)) {
        !           177:                                return;
        !           178:                        }
        !           179: 
        !           180:                        /* A global symbol with the same name exists already. That
        !           181:                         * symbol might have been created by other means (e.g. $_GET).
        !           182:                         *
        !           183:                         * hash_update in zend_set_hash_symbol is not good, because
        !           184:                         * it will leave referenced variables (such as local instances
        !           185:                         * of a global variable) dangling.
        !           186:                         *
        !           187:                         * BTW: if you use register_globals references between
        !           188:                         * session-vars won't work because of this very reason! */
        !           189: 
        !           190:                        REPLACE_ZVAL_VALUE(old_symbol,state_val,1);
        !           191: 
        !           192:                        /* The following line will update the reference table used for
        !           193:                         * unserialization.  It is optional, because some storage
        !           194:                         * formats may not be able to represent references. */
        !           195: 
        !           196:                        if (var_hash) {
        !           197:                                PHP_VAR_UNSERIALIZE_ZVAL_CHANGED(var_hash,state_val,*old_symbol);
        !           198:                        }
        !           199: 
        !           200:                        zend_set_hash_symbol(*old_symbol, name, namelen, 1, 1, Z_ARRVAL_P(PS(http_session_vars)));
        !           201:                } else {
        !           202:                        zend_set_hash_symbol(state_val, name, namelen, 1, 2, Z_ARRVAL_P(PS(http_session_vars)), &EG(symbol_table));
        !           203:                }
        !           204:        } else IF_SESSION_VARS() {
        !           205:                zend_set_hash_symbol(state_val, name, namelen, PZVAL_IS_REF(state_val), 1, Z_ARRVAL_P(PS(http_session_vars)));
        !           206:        }
        !           207: }
        !           208: /* }}} */
        !           209: 
        !           210: PHPAPI int php_get_session_var(char *name, size_t namelen, zval ***state_var TSRMLS_DC) /* {{{ */
        !           211: {
        !           212:        int ret = FAILURE;
        !           213: 
        !           214:        IF_SESSION_VARS() {
        !           215:                ret = zend_hash_find(Z_ARRVAL_P(PS(http_session_vars)), name, namelen + 1, (void **) state_var);
        !           216: 
        !           217:                /* If register_globals is enabled, and
        !           218:                 * if there is an entry for the slot in $_SESSION, and
        !           219:                 * if that entry is still set to NULL, and
        !           220:                 * if the global var exists, then
        !           221:                 * we prefer the same key in the global sym table. */
        !           222: 
        !           223:                if (PG(register_globals) && ret == SUCCESS && Z_TYPE_PP(*state_var) == IS_NULL) {
        !           224:                        zval **tmp;
        !           225: 
        !           226:                        if (zend_hash_find(&EG(symbol_table), name, namelen + 1, (void **) &tmp) == SUCCESS) {
        !           227:                                *state_var = tmp;
        !           228:                        }
        !           229:                }
        !           230:        }
        !           231:        return ret;
        !           232: }
        !           233: /* }}} */
        !           234: 
        !           235: static void php_session_track_init(TSRMLS_D) /* {{{ */
        !           236: {
        !           237:        zval *session_vars = NULL;
        !           238: 
        !           239:        /* Unconditionally destroy existing arrays -- possible dirty data */
        !           240:        zend_delete_global_variable("HTTP_SESSION_VARS", sizeof("HTTP_SESSION_VARS")-1 TSRMLS_CC);
        !           241:        zend_delete_global_variable("_SESSION", sizeof("_SESSION")-1 TSRMLS_CC);
        !           242: 
        !           243:        if (PS(http_session_vars)) {
        !           244:                zval_ptr_dtor(&PS(http_session_vars));
        !           245:        }
        !           246: 
        !           247:        MAKE_STD_ZVAL(session_vars);
        !           248:        array_init(session_vars);
        !           249:        PS(http_session_vars) = session_vars;
        !           250: 
        !           251:        if (PG(register_long_arrays)) {
        !           252:                ZEND_SET_GLOBAL_VAR_WITH_LENGTH("HTTP_SESSION_VARS", sizeof("HTTP_SESSION_VARS"), PS(http_session_vars), 3, 1);
        !           253:                ZEND_SET_GLOBAL_VAR_WITH_LENGTH("_SESSION", sizeof("_SESSION"), PS(http_session_vars), 3, 1);
        !           254:        }
        !           255:        else {
        !           256:                ZEND_SET_GLOBAL_VAR_WITH_LENGTH("_SESSION", sizeof("_SESSION"), PS(http_session_vars), 2, 1);
        !           257:        }
        !           258: }
        !           259: /* }}} */
        !           260: 
        !           261: static char *php_session_encode(int *newlen TSRMLS_DC) /* {{{ */
        !           262: {
        !           263:        char *ret = NULL;
        !           264: 
        !           265:        IF_SESSION_VARS() {
        !           266:                if (!PS(serializer)) {
        !           267:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown session.serialize_handler. Failed to encode session object");
        !           268:                        ret = NULL;
        !           269:                } else if (PS(serializer)->encode(&ret, newlen TSRMLS_CC) == FAILURE) {
        !           270:                        ret = NULL;
        !           271:                }
        !           272:        } else {
        !           273:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot encode non-existent session");
        !           274:        }
        !           275:        return ret;
        !           276: }
        !           277: /* }}} */
        !           278: 
        !           279: static void php_session_decode(const char *val, int vallen TSRMLS_DC) /* {{{ */
        !           280: {
        !           281:        if (!PS(serializer)) {
        !           282:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown session.serialize_handler. Failed to decode session object");
        !           283:                return;
        !           284:        }
        !           285:        if (PS(serializer)->decode(val, vallen TSRMLS_CC) == FAILURE) {
        !           286:                php_session_destroy(TSRMLS_C);
        !           287:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to decode session object. Session has been destroyed");
        !           288:        }
        !           289: }
        !           290: /* }}} */
        !           291: 
        !           292: /*
        !           293:  * Note that we cannot use the BASE64 alphabet here, because
        !           294:  * it contains "/" and "+": both are unacceptable for simple inclusion
        !           295:  * into URLs.
        !           296:  */
        !           297: 
        !           298: static char hexconvtab[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,-";
        !           299: 
        !           300: enum {
        !           301:        PS_HASH_FUNC_MD5,
        !           302:        PS_HASH_FUNC_SHA1,
        !           303:        PS_HASH_FUNC_OTHER
        !           304: };
        !           305: 
        !           306: /* returns a pointer to the byte after the last valid character in out */
        !           307: static char *bin_to_readable(char *in, size_t inlen, char *out, char nbits) /* {{{ */
        !           308: {
        !           309:        unsigned char *p, *q;
        !           310:        unsigned short w;
        !           311:        int mask;
        !           312:        int have;
        !           313: 
        !           314:        p = (unsigned char *) in;
        !           315:        q = (unsigned char *)in + inlen;
        !           316: 
        !           317:        w = 0;
        !           318:        have = 0;
        !           319:        mask = (1 << nbits) - 1;
        !           320: 
        !           321:        while (1) {
        !           322:                if (have < nbits) {
        !           323:                        if (p < q) {
        !           324:                                w |= *p++ << have;
        !           325:                                have += 8;
        !           326:                        } else {
        !           327:                                /* consumed everything? */
        !           328:                                if (have == 0) break;
        !           329:                                /* No? We need a final round */
        !           330:                                have = nbits;
        !           331:                        }
        !           332:                }
        !           333: 
        !           334:                /* consume nbits */
        !           335:                *out++ = hexconvtab[w & mask];
        !           336:                w >>= nbits;
        !           337:                have -= nbits;
        !           338:        }
        !           339: 
        !           340:        *out = '\0';
        !           341:        return out;
        !           342: }
        !           343: /* }}} */
        !           344: 
        !           345: PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS) /* {{{ */
        !           346: {
        !           347:        PHP_MD5_CTX md5_context;
        !           348:        PHP_SHA1_CTX sha1_context;
        !           349: #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
        !           350:        void *hash_context;
        !           351: #endif
        !           352:        unsigned char *digest;
        !           353:        int digest_len;
        !           354:        int j;
        !           355:        char *buf, *outid;
        !           356:        struct timeval tv;
        !           357:        zval **array;
        !           358:        zval **token;
        !           359:        char *remote_addr = NULL;
        !           360: 
        !           361:        gettimeofday(&tv, NULL);
        !           362: 
        !           363:        if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &array) == SUCCESS &&
        !           364:                Z_TYPE_PP(array) == IS_ARRAY &&
        !           365:                zend_hash_find(Z_ARRVAL_PP(array), "REMOTE_ADDR", sizeof("REMOTE_ADDR"), (void **) &token) == SUCCESS
        !           366:        ) {
        !           367:                remote_addr = Z_STRVAL_PP(token);
        !           368:        }
        !           369: 
        !           370:        /* maximum 15+19+19+10 bytes */
        !           371:        spprintf(&buf, 0, "%.15s%ld%ld%0.8F", remote_addr ? remote_addr : "", tv.tv_sec, (long int)tv.tv_usec, php_combined_lcg(TSRMLS_C) * 10);
        !           372: 
        !           373:        switch (PS(hash_func)) {
        !           374:                case PS_HASH_FUNC_MD5:
        !           375:                        PHP_MD5Init(&md5_context);
        !           376:                        PHP_MD5Update(&md5_context, (unsigned char *) buf, strlen(buf));
        !           377:                        digest_len = 16;
        !           378:                        break;
        !           379:                case PS_HASH_FUNC_SHA1:
        !           380:                        PHP_SHA1Init(&sha1_context);
        !           381:                        PHP_SHA1Update(&sha1_context, (unsigned char *) buf, strlen(buf));
        !           382:                        digest_len = 20;
        !           383:                        break;
        !           384: #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
        !           385:                case PS_HASH_FUNC_OTHER:
        !           386:                        if (!PS(hash_ops)) {
        !           387:                                php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid session hash function");
        !           388:                                efree(buf);
        !           389:                                return NULL;
        !           390:                        }
        !           391: 
        !           392:                        hash_context = emalloc(PS(hash_ops)->context_size);
        !           393:                        PS(hash_ops)->hash_init(hash_context);
        !           394:                        PS(hash_ops)->hash_update(hash_context, (unsigned char *) buf, strlen(buf));
        !           395:                        digest_len = PS(hash_ops)->digest_size;
        !           396:                        break;
        !           397: #endif /* HAVE_HASH_EXT */
        !           398:                default:
        !           399:                        php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid session hash function");
        !           400:                        efree(buf);
        !           401:                        return NULL;
        !           402:        }
        !           403:        efree(buf);
        !           404: 
        !           405:        if (PS(entropy_length) > 0) {
        !           406: #ifdef PHP_WIN32
        !           407:                unsigned char rbuf[2048];
        !           408:                size_t toread = PS(entropy_length);
        !           409: 
        !           410:                if (php_win32_get_random_bytes(rbuf, (size_t) toread) == SUCCESS){
        !           411: 
        !           412:                        switch (PS(hash_func)) {
        !           413:                                case PS_HASH_FUNC_MD5:
        !           414:                                        PHP_MD5Update(&md5_context, rbuf, toread);
        !           415:                                        break;
        !           416:                                case PS_HASH_FUNC_SHA1:
        !           417:                                        PHP_SHA1Update(&sha1_context, rbuf, toread);
        !           418:                                        break;
        !           419: # if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
        !           420:                                case PS_HASH_FUNC_OTHER:
        !           421:                                        PS(hash_ops)->hash_update(hash_context, rbuf, toread);
        !           422:                                        break;
        !           423: # endif /* HAVE_HASH_EXT */
        !           424:                        }
        !           425:                }
        !           426: #else
        !           427:                int fd;
        !           428: 
        !           429:                fd = VCWD_OPEN(PS(entropy_file), O_RDONLY);
        !           430:                if (fd >= 0) {
        !           431:                        unsigned char rbuf[2048];
        !           432:                        int n;
        !           433:                        int to_read = PS(entropy_length);
        !           434: 
        !           435:                        while (to_read > 0) {
        !           436:                                n = read(fd, rbuf, MIN(to_read, sizeof(rbuf)));
        !           437:                                if (n <= 0) break;
        !           438: 
        !           439:                                switch (PS(hash_func)) {
        !           440:                                        case PS_HASH_FUNC_MD5:
        !           441:                                                PHP_MD5Update(&md5_context, rbuf, n);
        !           442:                                                break;
        !           443:                                        case PS_HASH_FUNC_SHA1:
        !           444:                                                PHP_SHA1Update(&sha1_context, rbuf, n);
        !           445:                                                break;
        !           446: #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
        !           447:                                        case PS_HASH_FUNC_OTHER:
        !           448:                                                PS(hash_ops)->hash_update(hash_context, rbuf, n);
        !           449:                                                break;
        !           450: #endif /* HAVE_HASH_EXT */
        !           451:                                }
        !           452:                                to_read -= n;
        !           453:                        }
        !           454:                        close(fd);
        !           455:                }
        !           456: #endif
        !           457:        }
        !           458: 
        !           459:        digest = emalloc(digest_len + 1);
        !           460:        switch (PS(hash_func)) {
        !           461:                case PS_HASH_FUNC_MD5:
        !           462:                        PHP_MD5Final(digest, &md5_context);
        !           463:                        break;
        !           464:                case PS_HASH_FUNC_SHA1:
        !           465:                        PHP_SHA1Final(digest, &sha1_context);
        !           466:                        break;
        !           467: #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
        !           468:                case PS_HASH_FUNC_OTHER:
        !           469:                        PS(hash_ops)->hash_final(digest, hash_context);
        !           470:                        efree(hash_context);
        !           471:                        break;
        !           472: #endif /* HAVE_HASH_EXT */
        !           473:        }
        !           474: 
        !           475:        if (PS(hash_bits_per_character) < 4
        !           476:                        || PS(hash_bits_per_character) > 6) {
        !           477:                PS(hash_bits_per_character) = 4;
        !           478: 
        !           479:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ini setting hash_bits_per_character is out of range (should be 4, 5, or 6) - using 4 for now");
        !           480:        }
        !           481:        
        !           482:        outid = emalloc((size_t)((digest_len + 2) * ((8.0f / PS(hash_bits_per_character)) + 0.5)));
        !           483:        j = (int) (bin_to_readable((char *)digest, digest_len, outid, (char)PS(hash_bits_per_character)) - outid);
        !           484:        efree(digest);
        !           485: 
        !           486:        if (newlen) {
        !           487:                *newlen = j;
        !           488:        }
        !           489: 
        !           490:        return outid;
        !           491: }
        !           492: /* }}} */
        !           493: 
        !           494: static void php_session_initialize(TSRMLS_D) /* {{{ */
        !           495: {
        !           496:        char *val;
        !           497:        int vallen;
        !           498: 
        !           499:        /* check session name for invalid characters */
        !           500:        if (PS(id) && strpbrk(PS(id), "\r\n\t <>'\"\\")) {
        !           501:                efree(PS(id));
        !           502:                PS(id) = NULL;
        !           503:        }
        !           504: 
        !           505:        if (!PS(mod)) {
        !           506:                php_error_docref(NULL TSRMLS_CC, E_ERROR, "No storage module chosen - failed to initialize session");
        !           507:                return;
        !           508:        }
        !           509: 
        !           510:        /* Open session handler first */
        !           511:        if (PS(mod)->s_open(&PS(mod_data), PS(save_path), PS(session_name) TSRMLS_CC) == FAILURE) {
        !           512:                php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to initialize storage module: %s (path: %s)", PS(mod)->s_name, PS(save_path));
        !           513:                return;
        !           514:        }
        !           515: 
        !           516:        /* If there is no ID, use session module to create one */
        !           517:        if (!PS(id)) {
        !           518: new_session:
        !           519:                PS(id) = PS(mod)->s_create_sid(&PS(mod_data), NULL TSRMLS_CC);
        !           520:                if (PS(use_cookies)) {
        !           521:                        PS(send_cookie) = 1;
        !           522:                }
        !           523:        }
        !           524: 
        !           525:        /* Read data */
        !           526:        /* Question: if you create a SID here, should you also try to read data?
        !           527:         * I'm not sure, but while not doing so will remove one session operation
        !           528:         * it could prove usefull for those sites which wish to have "default"
        !           529:         * session information. */
        !           530:        php_session_track_init(TSRMLS_C);
        !           531:        PS(invalid_session_id) = 0;
        !           532:        if (PS(mod)->s_read(&PS(mod_data), PS(id), &val, &vallen TSRMLS_CC) == SUCCESS) {
        !           533:                php_session_decode(val, vallen TSRMLS_CC);
        !           534:                efree(val);
        !           535:        } else if (PS(invalid_session_id)) { /* address instances where the session read fails due to an invalid id */
        !           536:                PS(invalid_session_id) = 0;
        !           537:                efree(PS(id));
        !           538:                PS(id) = NULL;
        !           539:                goto new_session;
        !           540:        }
        !           541: }
        !           542: /* }}} */
        !           543: 
        !           544: static int migrate_global(HashTable *ht, HashPosition *pos TSRMLS_DC) /* {{{ */
        !           545: {
        !           546:        char *str;
        !           547:        uint str_len;
        !           548:        ulong num_key;
        !           549:        int n;
        !           550:        zval **val;
        !           551:        int ret = 0;
        !           552: 
        !           553:        n = zend_hash_get_current_key_ex(ht, &str, &str_len, &num_key, 0, pos);
        !           554: 
        !           555:        switch (n) {
        !           556:                case HASH_KEY_IS_STRING:
        !           557:                        if (zend_hash_find(&EG(symbol_table), str, str_len, (void **) &val) == SUCCESS &&
        !           558:                                val && Z_TYPE_PP(val) != IS_NULL
        !           559:                        ) {
        !           560:                                ZEND_SET_SYMBOL_WITH_LENGTH(ht, str, str_len, *val, Z_REFCOUNT_PP(val) + 1, 1);
        !           561:                                ret = 1;
        !           562:                        }
        !           563:                        break;
        !           564:                case HASH_KEY_IS_LONG:
        !           565:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "The session bug compatibility code will not "
        !           566:                                        "try to locate the global variable $%lu due to its "
        !           567:                                        "numeric nature", num_key);
        !           568:                        break;
        !           569:        }
        !           570:        return ret;
        !           571: }
        !           572: /* }}} */
        !           573: 
        !           574: static void php_session_save_current_state(TSRMLS_D) /* {{{ */
        !           575: {
        !           576:        int ret = FAILURE;
        !           577: 
        !           578:        IF_SESSION_VARS() {
        !           579:                if (PS(bug_compat) && !PG(register_globals)) {
        !           580:                        HashTable *ht = Z_ARRVAL_P(PS(http_session_vars));
        !           581:                        HashPosition pos;
        !           582:                        zval **val;
        !           583:                        int do_warn = 0;
        !           584: 
        !           585:                        zend_hash_internal_pointer_reset_ex(ht, &pos);
        !           586: 
        !           587:                        while (zend_hash_get_current_data_ex(ht, (void **) &val, &pos) != FAILURE) {
        !           588:                                if (Z_TYPE_PP(val) == IS_NULL) {
        !           589:                                        if (migrate_global(ht, &pos TSRMLS_CC)) {
        !           590:                                                do_warn = 1;
        !           591:                                        }
        !           592:                                }
        !           593:                                zend_hash_move_forward_ex(ht, &pos);
        !           594:                        }
        !           595: 
        !           596:                        if (do_warn && PS(bug_compat_warn)) {
        !           597:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Your script possibly relies on a session side-effect which existed until PHP 4.2.3. Please be advised that the session extension does not consider global variables as a source of data, unless register_globals is enabled. You can disable this functionality and this warning by setting session.bug_compat_42 or session.bug_compat_warn to off, respectively");
        !           598:                        }
        !           599:                }
        !           600: 
        !           601:                if (PS(mod_data)) {
        !           602:                        char *val;
        !           603:                        int vallen;
        !           604: 
        !           605:                        val = php_session_encode(&vallen TSRMLS_CC);
        !           606:                        if (val) {
        !           607:                                ret = PS(mod)->s_write(&PS(mod_data), PS(id), val, vallen TSRMLS_CC);
        !           608:                                efree(val);
        !           609:                        } else {
        !           610:                                ret = PS(mod)->s_write(&PS(mod_data), PS(id), "", 0 TSRMLS_CC);
        !           611:                        }
        !           612:                }
        !           613: 
        !           614:                if (ret == FAILURE) {
        !           615:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write session data (%s). Please "
        !           616:                                        "verify that the current setting of session.save_path "
        !           617:                                        "is correct (%s)",
        !           618:                                        PS(mod)->s_name,
        !           619:                                        PS(save_path));
        !           620:                }
        !           621:        }
        !           622: 
        !           623:        if (PS(mod_data)) {
        !           624:                PS(mod)->s_close(&PS(mod_data) TSRMLS_CC);
        !           625:        }
        !           626: }
        !           627: /* }}} */
        !           628: 
        !           629: /* *************************
        !           630:    * INI Settings/Handlers *
        !           631:    ************************* */
        !           632: 
        !           633: static PHP_INI_MH(OnUpdateSaveHandler) /* {{{ */
        !           634: {
        !           635:        ps_module *tmp;
        !           636:        SESSION_CHECK_ACTIVE_STATE;
        !           637: 
        !           638:        tmp = _php_find_ps_module(new_value TSRMLS_CC);
        !           639: 
        !           640:        if (PG(modules_activated) && !tmp) {
        !           641:                int err_type;
        !           642: 
        !           643:                if (stage == ZEND_INI_STAGE_RUNTIME) {
        !           644:                        err_type = E_WARNING;
        !           645:                } else {
        !           646:                        err_type = E_ERROR;
        !           647:                }
        !           648: 
        !           649:                /* Do not output error when restoring ini options. */
        !           650:                if (stage != ZEND_INI_STAGE_DEACTIVATE) {
        !           651:                        php_error_docref(NULL TSRMLS_CC, err_type, "Cannot find save handler '%s'", new_value);
        !           652:                }
        !           653:                return FAILURE;
        !           654:        }
        !           655:        PS(mod) = tmp;
        !           656: 
        !           657:        return SUCCESS;
        !           658: }
        !           659: /* }}} */
        !           660: 
        !           661: static PHP_INI_MH(OnUpdateSerializer) /* {{{ */
        !           662: {
        !           663:        const ps_serializer *tmp;
        !           664:        SESSION_CHECK_ACTIVE_STATE;
        !           665: 
        !           666:        tmp = _php_find_ps_serializer(new_value TSRMLS_CC);
        !           667: 
        !           668:        if (PG(modules_activated) && !tmp) {
        !           669:                int err_type;
        !           670: 
        !           671:                if (stage == ZEND_INI_STAGE_RUNTIME) {
        !           672:                        err_type = E_WARNING;
        !           673:                } else {
        !           674:                        err_type = E_ERROR;
        !           675:                }
        !           676: 
        !           677:                /* Do not output error when restoring ini options. */
        !           678:                if (stage != ZEND_INI_STAGE_DEACTIVATE) {
        !           679:                        php_error_docref(NULL TSRMLS_CC, err_type, "Cannot find serialization handler '%s'", new_value);
        !           680:                }
        !           681:                return FAILURE;
        !           682:        }
        !           683:        PS(serializer) = tmp;
        !           684: 
        !           685:        return SUCCESS;
        !           686: }
        !           687: /* }}} */
        !           688: 
        !           689: static PHP_INI_MH(OnUpdateTransSid) /* {{{ */
        !           690: {
        !           691:        SESSION_CHECK_ACTIVE_STATE;
        !           692: 
        !           693:        if (!strncasecmp(new_value, "on", sizeof("on"))) {
        !           694:                PS(use_trans_sid) = (zend_bool) 1;
        !           695:        } else {
        !           696:                PS(use_trans_sid) = (zend_bool) atoi(new_value);
        !           697:        }
        !           698: 
        !           699:        return SUCCESS;
        !           700: }
        !           701: /* }}} */
        !           702: 
        !           703: static PHP_INI_MH(OnUpdateSaveDir) /* {{{ */
        !           704: {
        !           705:        /* Only do the safemode/open_basedir check at runtime */
        !           706:        if (stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) {
        !           707:                char *p;
        !           708: 
        !           709:                if (memchr(new_value, '\0', new_value_length) != NULL) {
        !           710:                        return FAILURE;
        !           711:                }
        !           712: 
        !           713:                /* we do not use zend_memrchr() since path can contain ; itself */
        !           714:                if ((p = strchr(new_value, ';'))) {
        !           715:                        char *p2;
        !           716:                        p++;
        !           717:                        if ((p2 = strchr(p, ';'))) {
        !           718:                                p = p2 + 1;
        !           719:                        }
        !           720:                } else {
        !           721:                        p = new_value;
        !           722:                }
        !           723: 
        !           724:                if (PG(safe_mode) && *p && (!php_checkuid(p, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
        !           725:                        return FAILURE;
        !           726:                }
        !           727: 
        !           728:                if (PG(open_basedir) && *p && php_check_open_basedir(p TSRMLS_CC)) {
        !           729:                        return FAILURE;
        !           730:                }
        !           731:        }
        !           732: 
        !           733:        OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
        !           734:        return SUCCESS;
        !           735: }
        !           736: /* }}} */
        !           737: 
        !           738: static PHP_INI_MH(OnUpdateHashFunc) /* {{{ */
        !           739: {
        !           740:        long val;
        !           741:        char *endptr = NULL;
        !           742: 
        !           743: #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
        !           744:        PS(hash_ops) = NULL;
        !           745: #endif
        !           746: 
        !           747:        val = strtol(new_value, &endptr, 10);
        !           748:        if (endptr && (*endptr == '\0')) {
        !           749:                /* Numeric value */
        !           750:                PS(hash_func) = val ? 1 : 0;
        !           751: 
        !           752:                return SUCCESS;
        !           753:        }
        !           754: 
        !           755:        if (new_value_length == (sizeof("md5") - 1) &&
        !           756:                strncasecmp(new_value, "md5", sizeof("md5") - 1) == 0) {
        !           757:                PS(hash_func) = PS_HASH_FUNC_MD5;
        !           758: 
        !           759:                return SUCCESS;
        !           760:        }
        !           761: 
        !           762:        if (new_value_length == (sizeof("sha1") - 1) &&
        !           763:                strncasecmp(new_value, "sha1", sizeof("sha1") - 1) == 0) {
        !           764:                PS(hash_func) = PS_HASH_FUNC_SHA1;
        !           765: 
        !           766:                return SUCCESS;
        !           767:        }
        !           768: 
        !           769: #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH) /* {{{ */
        !           770: {
        !           771:        php_hash_ops *ops = (php_hash_ops*)php_hash_fetch_ops(new_value, new_value_length);
        !           772: 
        !           773:        if (ops) {
        !           774:                PS(hash_func) = PS_HASH_FUNC_OTHER;
        !           775:                PS(hash_ops) = ops;
        !           776: 
        !           777:                return SUCCESS;
        !           778:        }
        !           779: }
        !           780: #endif /* HAVE_HASH_EXT }}} */
        !           781: 
        !           782:        return FAILURE;
        !           783: }
        !           784: /* }}} */
        !           785: 
        !           786: /* {{{ PHP_INI
        !           787:  */
        !           788: PHP_INI_BEGIN()
        !           789:        STD_PHP_INI_BOOLEAN("session.bug_compat_42",    "1",         PHP_INI_ALL, OnUpdateBool,   bug_compat,         php_ps_globals,    ps_globals)
        !           790:        STD_PHP_INI_BOOLEAN("session.bug_compat_warn",  "1",         PHP_INI_ALL, OnUpdateBool,   bug_compat_warn,    php_ps_globals,    ps_globals)
        !           791:        STD_PHP_INI_ENTRY("session.save_path",          "",          PHP_INI_ALL, OnUpdateSaveDir,save_path,          php_ps_globals,    ps_globals)
        !           792:        STD_PHP_INI_ENTRY("session.name",               "PHPSESSID", PHP_INI_ALL, OnUpdateString, session_name,       php_ps_globals,    ps_globals)
        !           793:        PHP_INI_ENTRY("session.save_handler",           "files",     PHP_INI_ALL, OnUpdateSaveHandler)
        !           794:        STD_PHP_INI_BOOLEAN("session.auto_start",       "0",         PHP_INI_ALL, OnUpdateBool,   auto_start,         php_ps_globals,    ps_globals)
        !           795:        STD_PHP_INI_ENTRY("session.gc_probability",     "1",         PHP_INI_ALL, OnUpdateLong,   gc_probability,     php_ps_globals,    ps_globals)
        !           796:        STD_PHP_INI_ENTRY("session.gc_divisor",         "100",       PHP_INI_ALL, OnUpdateLong,   gc_divisor,         php_ps_globals,    ps_globals)
        !           797:        STD_PHP_INI_ENTRY("session.gc_maxlifetime",     "1440",      PHP_INI_ALL, OnUpdateLong,   gc_maxlifetime,     php_ps_globals,    ps_globals)
        !           798:        PHP_INI_ENTRY("session.serialize_handler",      "php",       PHP_INI_ALL, OnUpdateSerializer)
        !           799:        STD_PHP_INI_ENTRY("session.cookie_lifetime",    "0",         PHP_INI_ALL, OnUpdateLong,   cookie_lifetime,    php_ps_globals,    ps_globals)
        !           800:        STD_PHP_INI_ENTRY("session.cookie_path",        "/",         PHP_INI_ALL, OnUpdateString, cookie_path,        php_ps_globals,    ps_globals)
        !           801:        STD_PHP_INI_ENTRY("session.cookie_domain",      "",          PHP_INI_ALL, OnUpdateString, cookie_domain,      php_ps_globals,    ps_globals)
        !           802:        STD_PHP_INI_BOOLEAN("session.cookie_secure",    "",          PHP_INI_ALL, OnUpdateBool,   cookie_secure,      php_ps_globals,    ps_globals)
        !           803:        STD_PHP_INI_BOOLEAN("session.cookie_httponly",  "",          PHP_INI_ALL, OnUpdateBool,   cookie_httponly,    php_ps_globals,    ps_globals)
        !           804:        STD_PHP_INI_BOOLEAN("session.use_cookies",      "1",         PHP_INI_ALL, OnUpdateBool,   use_cookies,        php_ps_globals,    ps_globals)
        !           805:        STD_PHP_INI_BOOLEAN("session.use_only_cookies", "1",         PHP_INI_ALL, OnUpdateBool,   use_only_cookies,   php_ps_globals,    ps_globals)
        !           806:        STD_PHP_INI_ENTRY("session.referer_check",      "",          PHP_INI_ALL, OnUpdateString, extern_referer_chk, php_ps_globals,    ps_globals)
        !           807:        STD_PHP_INI_ENTRY("session.entropy_file",       "",          PHP_INI_ALL, OnUpdateString, entropy_file,       php_ps_globals,    ps_globals)
        !           808:        STD_PHP_INI_ENTRY("session.entropy_length",     "0",         PHP_INI_ALL, OnUpdateLong,   entropy_length,     php_ps_globals,    ps_globals)
        !           809:        STD_PHP_INI_ENTRY("session.cache_limiter",      "nocache",   PHP_INI_ALL, OnUpdateString, cache_limiter,      php_ps_globals,    ps_globals)
        !           810:        STD_PHP_INI_ENTRY("session.cache_expire",       "180",       PHP_INI_ALL, OnUpdateLong,   cache_expire,       php_ps_globals,    ps_globals)
        !           811:        PHP_INI_ENTRY("session.use_trans_sid",          "0",         PHP_INI_ALL, OnUpdateTransSid)
        !           812:        PHP_INI_ENTRY("session.hash_function",          "0",         PHP_INI_ALL, OnUpdateHashFunc)
        !           813:        STD_PHP_INI_ENTRY("session.hash_bits_per_character", "4",    PHP_INI_ALL, OnUpdateLong,   hash_bits_per_character, php_ps_globals, ps_globals)
        !           814: 
        !           815:        /* Commented out until future discussion */
        !           816:        /* PHP_INI_ENTRY("session.encode_sources", "globals,track", PHP_INI_ALL, NULL) */
        !           817: PHP_INI_END()
        !           818: /* }}} */
        !           819: 
        !           820: /* ***************
        !           821:    * Serializers *
        !           822:    *************** */
        !           823: 
        !           824: #define PS_BIN_NR_OF_BITS 8
        !           825: #define PS_BIN_UNDEF (1<<(PS_BIN_NR_OF_BITS-1))
        !           826: #define PS_BIN_MAX (PS_BIN_UNDEF-1)
        !           827: 
        !           828: PS_SERIALIZER_ENCODE_FUNC(php_binary) /* {{{ */
        !           829: {
        !           830:        smart_str buf = {0};
        !           831:        php_serialize_data_t var_hash;
        !           832:        PS_ENCODE_VARS;
        !           833: 
        !           834:        PHP_VAR_SERIALIZE_INIT(var_hash);
        !           835: 
        !           836:        PS_ENCODE_LOOP(
        !           837:                        if (key_length > PS_BIN_MAX) continue;
        !           838:                        smart_str_appendc(&buf, (unsigned char) key_length);
        !           839:                        smart_str_appendl(&buf, key, key_length);
        !           840:                        php_var_serialize(&buf, struc, &var_hash TSRMLS_CC);
        !           841:                } else {
        !           842:                        if (key_length > PS_BIN_MAX) continue;
        !           843:                        smart_str_appendc(&buf, (unsigned char) (key_length & PS_BIN_UNDEF));
        !           844:                        smart_str_appendl(&buf, key, key_length);
        !           845:        );
        !           846: 
        !           847:        if (newlen) {
        !           848:                *newlen = buf.len;
        !           849:        }
        !           850:        smart_str_0(&buf);
        !           851:        *newstr = buf.c;
        !           852:        PHP_VAR_SERIALIZE_DESTROY(var_hash);
        !           853: 
        !           854:        return SUCCESS;
        !           855: }
        !           856: /* }}} */
        !           857: 
        !           858: PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */
        !           859: {
        !           860:        const char *p;
        !           861:        char *name;
        !           862:        const char *endptr = val + vallen;
        !           863:        zval *current;
        !           864:        int namelen;
        !           865:        int has_value;
        !           866:        php_unserialize_data_t var_hash;
        !           867: 
        !           868:        PHP_VAR_UNSERIALIZE_INIT(var_hash);
        !           869: 
        !           870:        for (p = val; p < endptr; ) {
        !           871:                zval **tmp;
        !           872:                namelen = ((unsigned char)(*p)) & (~PS_BIN_UNDEF);
        !           873: 
        !           874:                if (namelen < 0 || namelen > PS_BIN_MAX || (p + namelen) >= endptr) {
        !           875:                        return FAILURE;
        !           876:                }
        !           877: 
        !           878:                has_value = *p & PS_BIN_UNDEF ? 0 : 1;
        !           879: 
        !           880:                name = estrndup(p + 1, namelen);
        !           881: 
        !           882:                p += namelen + 1;
        !           883: 
        !           884:                if (zend_hash_find(&EG(symbol_table), name, namelen + 1, (void **) &tmp) == SUCCESS) {
        !           885:                        if ((Z_TYPE_PP(tmp) == IS_ARRAY && Z_ARRVAL_PP(tmp) == &EG(symbol_table)) || *tmp == PS(http_session_vars)) {
        !           886:                                efree(name);
        !           887:                                continue;
        !           888:                        }
        !           889:                }
        !           890: 
        !           891:                if (has_value) {
        !           892:                        ALLOC_INIT_ZVAL(current);
        !           893:                        if (php_var_unserialize(&current, (const unsigned char **) &p, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) {
        !           894:                                php_set_session_var(name, namelen, current, &var_hash  TSRMLS_CC);
        !           895:                        }
        !           896:                        zval_ptr_dtor(&current);
        !           897:                }
        !           898:                PS_ADD_VARL(name, namelen);
        !           899:                efree(name);
        !           900:        }
        !           901: 
        !           902:        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
        !           903: 
        !           904:        return SUCCESS;
        !           905: }
        !           906: /* }}} */
        !           907: 
        !           908: #define PS_DELIMITER '|'
        !           909: #define PS_UNDEF_MARKER '!'
        !           910: 
        !           911: PS_SERIALIZER_ENCODE_FUNC(php) /* {{{ */
        !           912: {
        !           913:        smart_str buf = {0};
        !           914:        php_serialize_data_t var_hash;
        !           915:        PS_ENCODE_VARS;
        !           916: 
        !           917:        PHP_VAR_SERIALIZE_INIT(var_hash);
        !           918: 
        !           919:        PS_ENCODE_LOOP(
        !           920:                        smart_str_appendl(&buf, key, key_length);
        !           921:                        if (memchr(key, PS_DELIMITER, key_length) || memchr(key, PS_UNDEF_MARKER, key_length)) {
        !           922:                                PHP_VAR_SERIALIZE_DESTROY(var_hash);
        !           923:                                smart_str_free(&buf);
        !           924:                                return FAILURE;
        !           925:                        }
        !           926:                        smart_str_appendc(&buf, PS_DELIMITER);
        !           927: 
        !           928:                        php_var_serialize(&buf, struc, &var_hash TSRMLS_CC);
        !           929:                } else {
        !           930:                        smart_str_appendc(&buf, PS_UNDEF_MARKER);
        !           931:                        smart_str_appendl(&buf, key, key_length);
        !           932:                        smart_str_appendc(&buf, PS_DELIMITER);
        !           933:        );
        !           934: 
        !           935:        if (newlen) {
        !           936:                *newlen = buf.len;
        !           937:        }
        !           938:        smart_str_0(&buf);
        !           939:        *newstr = buf.c;
        !           940: 
        !           941:        PHP_VAR_SERIALIZE_DESTROY(var_hash);
        !           942:        return SUCCESS;
        !           943: }
        !           944: /* }}} */
        !           945: 
        !           946: PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */
        !           947: {
        !           948:        const char *p, *q;
        !           949:        char *name;
        !           950:        const char *endptr = val + vallen;
        !           951:        zval *current;
        !           952:        int namelen;
        !           953:        int has_value;
        !           954:        php_unserialize_data_t var_hash;
        !           955: 
        !           956:        PHP_VAR_UNSERIALIZE_INIT(var_hash);
        !           957: 
        !           958:        p = val;
        !           959: 
        !           960:        while (p < endptr) {
        !           961:                zval **tmp;
        !           962:                q = p;
        !           963:                while (*q != PS_DELIMITER) {
        !           964:                        if (++q >= endptr) goto break_outer_loop;
        !           965:                }
        !           966:                if (p[0] == PS_UNDEF_MARKER) {
        !           967:                        p++;
        !           968:                        has_value = 0;
        !           969:                } else {
        !           970:                        has_value = 1;
        !           971:                }
        !           972: 
        !           973:                namelen = q - p;
        !           974:                name = estrndup(p, namelen);
        !           975:                q++;
        !           976: 
        !           977:                if (zend_hash_find(&EG(symbol_table), name, namelen + 1, (void **) &tmp) == SUCCESS) {
        !           978:                        if ((Z_TYPE_PP(tmp) == IS_ARRAY && Z_ARRVAL_PP(tmp) == &EG(symbol_table)) || *tmp == PS(http_session_vars)) {
        !           979:                                goto skip;
        !           980:                        }
        !           981:                }
        !           982: 
        !           983:                if (has_value) {
        !           984:                        ALLOC_INIT_ZVAL(current);
        !           985:                        if (php_var_unserialize(&current, (const unsigned char **) &q, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) {
        !           986:                                php_set_session_var(name, namelen, current, &var_hash  TSRMLS_CC);
        !           987:                        }
        !           988:                        zval_ptr_dtor(&current);
        !           989:                }
        !           990:                PS_ADD_VARL(name, namelen);
        !           991: skip:
        !           992:                efree(name);
        !           993: 
        !           994:                p = q;
        !           995:        }
        !           996: break_outer_loop:
        !           997: 
        !           998:        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
        !           999: 
        !          1000:        return SUCCESS;
        !          1001: }
        !          1002: /* }}} */
        !          1003: 
        !          1004: #define MAX_SERIALIZERS 10
        !          1005: #define PREDEFINED_SERIALIZERS 2
        !          1006: 
        !          1007: static ps_serializer ps_serializers[MAX_SERIALIZERS + 1] = {
        !          1008:        PS_SERIALIZER_ENTRY(php),
        !          1009:        PS_SERIALIZER_ENTRY(php_binary)
        !          1010: };
        !          1011: 
        !          1012: PHPAPI int php_session_register_serializer(const char *name, int (*encode)(PS_SERIALIZER_ENCODE_ARGS), int (*decode)(PS_SERIALIZER_DECODE_ARGS)) /* {{{ */
        !          1013: {
        !          1014:        int ret = -1;
        !          1015:        int i;
        !          1016: 
        !          1017:        for (i = 0; i < MAX_SERIALIZERS; i++) {
        !          1018:                if (ps_serializers[i].name == NULL) {
        !          1019:                        ps_serializers[i].name = name;
        !          1020:                        ps_serializers[i].encode = encode;
        !          1021:                        ps_serializers[i].decode = decode;
        !          1022:                        ps_serializers[i + 1].name = NULL;
        !          1023:                        ret = 0;
        !          1024:                        break;
        !          1025:                }
        !          1026:        }
        !          1027:        return ret;
        !          1028: }
        !          1029: /* }}} */
        !          1030: 
        !          1031: /* *******************
        !          1032:    * Storage Modules *
        !          1033:    ******************* */
        !          1034: 
        !          1035: #define MAX_MODULES 10
        !          1036: #define PREDEFINED_MODULES 2
        !          1037: 
        !          1038: static ps_module *ps_modules[MAX_MODULES + 1] = {
        !          1039:        ps_files_ptr,
        !          1040:        ps_user_ptr
        !          1041: };
        !          1042: 
        !          1043: PHPAPI int php_session_register_module(ps_module *ptr) /* {{{ */
        !          1044: {
        !          1045:        int ret = -1;
        !          1046:        int i;
        !          1047: 
        !          1048:        for (i = 0; i < MAX_MODULES; i++) {
        !          1049:                if (!ps_modules[i]) {
        !          1050:                        ps_modules[i] = ptr;
        !          1051:                        ret = 0;
        !          1052:                        break;
        !          1053:                }
        !          1054:        }
        !          1055:        return ret;
        !          1056: }
        !          1057: /* }}} */
        !          1058: 
        !          1059: /* ******************
        !          1060:    * Cache Limiters *
        !          1061:    ****************** */
        !          1062: 
        !          1063: typedef struct {
        !          1064:        char *name;
        !          1065:        void (*func)(TSRMLS_D);
        !          1066: } php_session_cache_limiter_t;
        !          1067: 
        !          1068: #define CACHE_LIMITER(name) _php_cache_limiter_##name
        !          1069: #define CACHE_LIMITER_FUNC(name) static void CACHE_LIMITER(name)(TSRMLS_D)
        !          1070: #define CACHE_LIMITER_ENTRY(name) { #name, CACHE_LIMITER(name) },
        !          1071: #define ADD_HEADER(a) sapi_add_header(a, strlen(a), 1);
        !          1072: #define MAX_STR 512
        !          1073: 
        !          1074: static char *month_names[] = {
        !          1075:        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        !          1076:        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
        !          1077: };
        !          1078: 
        !          1079: static char *week_days[] = {
        !          1080:        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
        !          1081: };
        !          1082: 
        !          1083: static inline void strcpy_gmt(char *ubuf, time_t *when) /* {{{ */
        !          1084: {
        !          1085:        char buf[MAX_STR];
        !          1086:        struct tm tm, *res;
        !          1087:        int n;
        !          1088: 
        !          1089:        res = php_gmtime_r(when, &tm);
        !          1090: 
        !          1091:        if (!res) {
        !          1092:                buf[0] = '\0';
        !          1093:                return;
        !          1094:        }
        !          1095: 
        !          1096:        n = slprintf(buf, sizeof(buf), "%s, %02d %s %d %02d:%02d:%02d GMT", /* SAFE */
        !          1097:                                week_days[tm.tm_wday], tm.tm_mday,
        !          1098:                                month_names[tm.tm_mon], tm.tm_year + 1900,
        !          1099:                                tm.tm_hour, tm.tm_min,
        !          1100:                                tm.tm_sec);
        !          1101:        memcpy(ubuf, buf, n);
        !          1102:        ubuf[n] = '\0';
        !          1103: }
        !          1104: /* }}} */
        !          1105: 
        !          1106: static inline void last_modified(TSRMLS_D) /* {{{ */
        !          1107: {
        !          1108:        const char *path;
        !          1109:        struct stat sb;
        !          1110:        char buf[MAX_STR + 1];
        !          1111: 
        !          1112:        path = SG(request_info).path_translated;
        !          1113:        if (path) {
        !          1114:                if (VCWD_STAT(path, &sb) == -1) {
        !          1115:                        return;
        !          1116:                }
        !          1117: 
        !          1118: #define LAST_MODIFIED "Last-Modified: "
        !          1119:                memcpy(buf, LAST_MODIFIED, sizeof(LAST_MODIFIED) - 1);
        !          1120:                strcpy_gmt(buf + sizeof(LAST_MODIFIED) - 1, &sb.st_mtime);
        !          1121:                ADD_HEADER(buf);
        !          1122:        }
        !          1123: }
        !          1124: /* }}} */
        !          1125: 
        !          1126: #define EXPIRES "Expires: "
        !          1127: CACHE_LIMITER_FUNC(public) /* {{{ */
        !          1128: {
        !          1129:        char buf[MAX_STR + 1];
        !          1130:        struct timeval tv;
        !          1131:        time_t now;
        !          1132: 
        !          1133:        gettimeofday(&tv, NULL);
        !          1134:        now = tv.tv_sec + PS(cache_expire) * 60;
        !          1135:        memcpy(buf, EXPIRES, sizeof(EXPIRES) - 1);
        !          1136:        strcpy_gmt(buf + sizeof(EXPIRES) - 1, &now);
        !          1137:        ADD_HEADER(buf);
        !          1138: 
        !          1139:        snprintf(buf, sizeof(buf) , "Cache-Control: public, max-age=%ld", PS(cache_expire) * 60); /* SAFE */
        !          1140:        ADD_HEADER(buf);
        !          1141: 
        !          1142:        last_modified(TSRMLS_C);
        !          1143: }
        !          1144: /* }}} */
        !          1145: 
        !          1146: CACHE_LIMITER_FUNC(private_no_expire) /* {{{ */
        !          1147: {
        !          1148:        char buf[MAX_STR + 1];
        !          1149: 
        !          1150:        snprintf(buf, sizeof(buf), "Cache-Control: private, max-age=%ld, pre-check=%ld", PS(cache_expire) * 60, PS(cache_expire) * 60); /* SAFE */
        !          1151:        ADD_HEADER(buf);
        !          1152: 
        !          1153:        last_modified(TSRMLS_C);
        !          1154: }
        !          1155: /* }}} */
        !          1156: 
        !          1157: CACHE_LIMITER_FUNC(private) /* {{{ */
        !          1158: {
        !          1159:        ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT");
        !          1160:        CACHE_LIMITER(private_no_expire)(TSRMLS_C);
        !          1161: }
        !          1162: /* }}} */
        !          1163: 
        !          1164: CACHE_LIMITER_FUNC(nocache) /* {{{ */
        !          1165: {
        !          1166:        ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT");
        !          1167: 
        !          1168:        /* For HTTP/1.1 conforming clients and the rest (MSIE 5) */
        !          1169:        ADD_HEADER("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
        !          1170: 
        !          1171:        /* For HTTP/1.0 conforming clients */
        !          1172:        ADD_HEADER("Pragma: no-cache");
        !          1173: }
        !          1174: /* }}} */
        !          1175: 
        !          1176: static php_session_cache_limiter_t php_session_cache_limiters[] = {
        !          1177:        CACHE_LIMITER_ENTRY(public)
        !          1178:        CACHE_LIMITER_ENTRY(private)
        !          1179:        CACHE_LIMITER_ENTRY(private_no_expire)
        !          1180:        CACHE_LIMITER_ENTRY(nocache)
        !          1181:        {0}
        !          1182: };
        !          1183: 
        !          1184: static int php_session_cache_limiter(TSRMLS_D) /* {{{ */
        !          1185: {
        !          1186:        php_session_cache_limiter_t *lim;
        !          1187: 
        !          1188:        if (PS(cache_limiter)[0] == '\0') return 0;
        !          1189: 
        !          1190:        if (SG(headers_sent)) {
        !          1191:                char *output_start_filename = php_get_output_start_filename(TSRMLS_C);
        !          1192:                int output_start_lineno = php_get_output_start_lineno(TSRMLS_C);
        !          1193: 
        !          1194:                if (output_start_filename) {
        !          1195:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot send session cache limiter - headers already sent (output started at %s:%d)", output_start_filename, output_start_lineno);
        !          1196:                } else {
        !          1197:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot send session cache limiter - headers already sent");
        !          1198:                }
        !          1199:                return -2;
        !          1200:        }
        !          1201: 
        !          1202:        for (lim = php_session_cache_limiters; lim->name; lim++) {
        !          1203:                if (!strcasecmp(lim->name, PS(cache_limiter))) {
        !          1204:                        lim->func(TSRMLS_C);
        !          1205:                        return 0;
        !          1206:                }
        !          1207:        }
        !          1208: 
        !          1209:        return -1;
        !          1210: }
        !          1211: /* }}} */
        !          1212: 
        !          1213: /* *********************
        !          1214:    * Cookie Management *
        !          1215:    ********************* */
        !          1216: 
        !          1217: #define COOKIE_SET_COOKIE "Set-Cookie: "
        !          1218: #define COOKIE_EXPIRES "; expires="
        !          1219: #define COOKIE_PATH            "; path="
        !          1220: #define COOKIE_DOMAIN  "; domain="
        !          1221: #define COOKIE_SECURE  "; secure"
        !          1222: #define COOKIE_HTTPONLY        "; HttpOnly"
        !          1223: 
        !          1224: static void php_session_send_cookie(TSRMLS_D) /* {{{ */
        !          1225: {
        !          1226:        smart_str ncookie = {0};
        !          1227:        char *date_fmt = NULL;
        !          1228:        char *e_session_name, *e_id;
        !          1229: 
        !          1230:        if (SG(headers_sent)) {
        !          1231:                char *output_start_filename = php_get_output_start_filename(TSRMLS_C);
        !          1232:                int output_start_lineno = php_get_output_start_lineno(TSRMLS_C);
        !          1233: 
        !          1234:                if (output_start_filename) {
        !          1235:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot send session cookie - headers already sent by (output started at %s:%d)", output_start_filename, output_start_lineno);
        !          1236:                } else {
        !          1237:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot send session cookie - headers already sent");
        !          1238:                }
        !          1239:                return;
        !          1240:        }
        !          1241: 
        !          1242:        /* URL encode session_name and id because they might be user supplied */
        !          1243:        e_session_name = php_url_encode(PS(session_name), strlen(PS(session_name)), NULL);
        !          1244:        e_id = php_url_encode(PS(id), strlen(PS(id)), NULL);
        !          1245: 
        !          1246:        smart_str_appends(&ncookie, COOKIE_SET_COOKIE);
        !          1247:        smart_str_appends(&ncookie, e_session_name);
        !          1248:        smart_str_appendc(&ncookie, '=');
        !          1249:        smart_str_appends(&ncookie, e_id);
        !          1250: 
        !          1251:        efree(e_session_name);
        !          1252:        efree(e_id);
        !          1253: 
        !          1254:        if (PS(cookie_lifetime) > 0) {
        !          1255:                struct timeval tv;
        !          1256:                time_t t;
        !          1257: 
        !          1258:                gettimeofday(&tv, NULL);
        !          1259:                t = tv.tv_sec + PS(cookie_lifetime);
        !          1260: 
        !          1261:                if (t > 0) {
        !          1262:                        date_fmt = php_format_date("D, d-M-Y H:i:s T", sizeof("D, d-M-Y H:i:s T")-1, t, 0 TSRMLS_CC);
        !          1263:                        smart_str_appends(&ncookie, COOKIE_EXPIRES);
        !          1264:                        smart_str_appends(&ncookie, date_fmt);
        !          1265:                        efree(date_fmt);
        !          1266:                }
        !          1267:        }
        !          1268: 
        !          1269:        if (PS(cookie_path)[0]) {
        !          1270:                smart_str_appends(&ncookie, COOKIE_PATH);
        !          1271:                smart_str_appends(&ncookie, PS(cookie_path));
        !          1272:        }
        !          1273: 
        !          1274:        if (PS(cookie_domain)[0]) {
        !          1275:                smart_str_appends(&ncookie, COOKIE_DOMAIN);
        !          1276:                smart_str_appends(&ncookie, PS(cookie_domain));
        !          1277:        }
        !          1278: 
        !          1279:        if (PS(cookie_secure)) {
        !          1280:                smart_str_appends(&ncookie, COOKIE_SECURE);
        !          1281:        }
        !          1282: 
        !          1283:        if (PS(cookie_httponly)) {
        !          1284:                smart_str_appends(&ncookie, COOKIE_HTTPONLY);
        !          1285:        }
        !          1286: 
        !          1287:        smart_str_0(&ncookie);
        !          1288: 
        !          1289:        /*      'replace' must be 0 here, else a previous Set-Cookie
        !          1290:                header, probably sent with setcookie() will be replaced! */
        !          1291:        sapi_add_header_ex(ncookie.c, ncookie.len, 0, 0 TSRMLS_CC);
        !          1292: }
        !          1293: /* }}} */
        !          1294: 
        !          1295: PHPAPI ps_module *_php_find_ps_module(char *name TSRMLS_DC) /* {{{ */
        !          1296: {
        !          1297:        ps_module *ret = NULL;
        !          1298:        ps_module **mod;
        !          1299:        int i;
        !          1300: 
        !          1301:        for (i = 0, mod = ps_modules; i < MAX_MODULES; i++, mod++) {
        !          1302:                if (*mod && !strcasecmp(name, (*mod)->s_name)) {
        !          1303:                        ret = *mod;
        !          1304:                        break;
        !          1305:                }
        !          1306:        }
        !          1307:        return ret;
        !          1308: }
        !          1309: /* }}} */
        !          1310: 
        !          1311: PHPAPI const ps_serializer *_php_find_ps_serializer(char *name TSRMLS_DC) /* {{{ */
        !          1312: {
        !          1313:        const ps_serializer *ret = NULL;
        !          1314:        const ps_serializer *mod;
        !          1315: 
        !          1316:        for (mod = ps_serializers; mod->name; mod++) {
        !          1317:                if (!strcasecmp(name, mod->name)) {
        !          1318:                        ret = mod;
        !          1319:                        break;
        !          1320:                }
        !          1321:        }
        !          1322:        return ret;
        !          1323: }
        !          1324: /* }}} */
        !          1325: 
        !          1326: #define PPID2SID \
        !          1327:                convert_to_string((*ppid)); \
        !          1328:                PS(id) = estrndup(Z_STRVAL_PP(ppid), Z_STRLEN_PP(ppid))
        !          1329: 
        !          1330: static void php_session_reset_id(TSRMLS_D) /* {{{ */
        !          1331: {
        !          1332:        int module_number = PS(module_number);
        !          1333: 
        !          1334:        if (PS(use_cookies) && PS(send_cookie)) {
        !          1335:                php_session_send_cookie(TSRMLS_C);
        !          1336:                PS(send_cookie) = 0;
        !          1337:        }
        !          1338: 
        !          1339:        /* if the SID constant exists, destroy it. */
        !          1340:        zend_hash_del(EG(zend_constants), "sid", sizeof("sid"));
        !          1341: 
        !          1342:        if (PS(define_sid)) {
        !          1343:                smart_str var = {0};
        !          1344: 
        !          1345:                smart_str_appends(&var, PS(session_name));
        !          1346:                smart_str_appendc(&var, '=');
        !          1347:                smart_str_appends(&var, PS(id));
        !          1348:                smart_str_0(&var);
        !          1349:                REGISTER_STRINGL_CONSTANT("SID", var.c, var.len, 0);
        !          1350:        } else {
        !          1351:                REGISTER_STRINGL_CONSTANT("SID", STR_EMPTY_ALLOC(), 0, 0);
        !          1352:        }
        !          1353: 
        !          1354:        if (PS(apply_trans_sid)) {
        !          1355:                php_url_scanner_reset_vars(TSRMLS_C);
        !          1356:                php_url_scanner_add_var(PS(session_name), strlen(PS(session_name)), PS(id), strlen(PS(id)), 1 TSRMLS_CC);
        !          1357:        }
        !          1358: }
        !          1359: /* }}} */
        !          1360: 
        !          1361: PHPAPI void php_session_start(TSRMLS_D) /* {{{ */
        !          1362: {
        !          1363:        zval **ppid;
        !          1364:        zval **data;
        !          1365:        char *p, *value;
        !          1366:        int nrand;
        !          1367:        int lensess;
        !          1368: 
        !          1369:        if (PS(use_only_cookies)) {
        !          1370:                PS(apply_trans_sid) = 0;
        !          1371:        } else {
        !          1372:                PS(apply_trans_sid) = PS(use_trans_sid);
        !          1373:        }
        !          1374: 
        !          1375:        switch (PS(session_status)) {
        !          1376:                case php_session_active:
        !          1377:                        php_error(E_NOTICE, "A session had already been started - ignoring session_start()");
        !          1378:                        return;
        !          1379:                        break;
        !          1380: 
        !          1381:                case php_session_disabled:
        !          1382:                        value = zend_ini_string("session.save_handler", sizeof("session.save_handler"), 0);
        !          1383:                        if (!PS(mod) && value) {
        !          1384:                                PS(mod) = _php_find_ps_module(value TSRMLS_CC);
        !          1385:                                if (!PS(mod)) {
        !          1386:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot find save handler '%s' - session startup failed", value);
        !          1387:                                        return;
        !          1388:                                }
        !          1389:                        }
        !          1390:                        value = zend_ini_string("session.serialize_handler", sizeof("session.serialize_handler"), 0);
        !          1391:                        if (!PS(serializer) && value) {
        !          1392:                                PS(serializer) = _php_find_ps_serializer(value TSRMLS_CC);
        !          1393:                                if (!PS(serializer)) {
        !          1394:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot find serialization handler '%s' - session startup failed", value);
        !          1395:                                        return;
        !          1396:                                }
        !          1397:                        }
        !          1398:                        PS(session_status) = php_session_none;
        !          1399:                        /* fallthrough */
        !          1400: 
        !          1401:                default:
        !          1402:                case php_session_none:
        !          1403:                        PS(define_sid) = 1;
        !          1404:                        PS(send_cookie) = 1;
        !          1405:        }
        !          1406: 
        !          1407:        lensess = strlen(PS(session_name));
        !          1408: 
        !          1409:        /* Cookies are preferred, because initially
        !          1410:         * cookie and get variables will be available. */
        !          1411: 
        !          1412:        if (!PS(id)) {
        !          1413:                if (PS(use_cookies) && zend_hash_find(&EG(symbol_table), "_COOKIE", sizeof("_COOKIE"), (void **) &data) == SUCCESS &&
        !          1414:                                Z_TYPE_PP(data) == IS_ARRAY &&
        !          1415:                                zend_hash_find(Z_ARRVAL_PP(data), PS(session_name), lensess + 1, (void **) &ppid) == SUCCESS
        !          1416:                ) {
        !          1417:                        PPID2SID;
        !          1418:                        PS(apply_trans_sid) = 0;
        !          1419:                        PS(send_cookie) = 0;
        !          1420:                        PS(define_sid) = 0;
        !          1421:                }
        !          1422: 
        !          1423:                if (!PS(use_only_cookies) && !PS(id) &&
        !          1424:                                zend_hash_find(&EG(symbol_table), "_GET", sizeof("_GET"), (void **) &data) == SUCCESS &&
        !          1425:                                Z_TYPE_PP(data) == IS_ARRAY &&
        !          1426:                                zend_hash_find(Z_ARRVAL_PP(data), PS(session_name), lensess + 1, (void **) &ppid) == SUCCESS
        !          1427:                ) {
        !          1428:                        PPID2SID;
        !          1429:                        PS(send_cookie) = 0;
        !          1430:                }
        !          1431: 
        !          1432:                if (!PS(use_only_cookies) && !PS(id) &&
        !          1433:                                zend_hash_find(&EG(symbol_table), "_POST", sizeof("_POST"), (void **) &data) == SUCCESS &&
        !          1434:                                Z_TYPE_PP(data) == IS_ARRAY &&
        !          1435:                                zend_hash_find(Z_ARRVAL_PP(data), PS(session_name), lensess + 1, (void **) &ppid) == SUCCESS
        !          1436:                ) {
        !          1437:                        PPID2SID;
        !          1438:                        PS(send_cookie) = 0;
        !          1439:                }
        !          1440:        }
        !          1441: 
        !          1442:        /* Check the REQUEST_URI symbol for a string of the form
        !          1443:         * '<session-name>=<session-id>' to allow URLs of the form
        !          1444:         * http://yoursite/<session-name>=<session-id>/script.php */
        !          1445: 
        !          1446:        if (!PS(use_only_cookies) && !PS(id) && PG(http_globals)[TRACK_VARS_SERVER] &&
        !          1447:                        zend_hash_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), "REQUEST_URI", sizeof("REQUEST_URI"), (void **) &data) == SUCCESS &&
        !          1448:                        Z_TYPE_PP(data) == IS_STRING &&
        !          1449:                        (p = strstr(Z_STRVAL_PP(data), PS(session_name))) &&
        !          1450:                        p[lensess] == '='
        !          1451:        ) {
        !          1452:                char *q;
        !          1453: 
        !          1454:                p += lensess + 1;
        !          1455:                if ((q = strpbrk(p, "/?\\"))) {
        !          1456:                        PS(id) = estrndup(p, q - p);
        !          1457:                        PS(send_cookie) = 0;
        !          1458:                }
        !          1459:        }
        !          1460: 
        !          1461:        /* Check whether the current request was referred to by
        !          1462:         * an external site which invalidates the previously found id. */
        !          1463: 
        !          1464:        if (PS(id) &&
        !          1465:                        PS(extern_referer_chk)[0] != '\0' &&
        !          1466:                        PG(http_globals)[TRACK_VARS_SERVER] &&
        !          1467:                        zend_hash_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_REFERER", sizeof("HTTP_REFERER"), (void **) &data) == SUCCESS &&
        !          1468:                        Z_TYPE_PP(data) == IS_STRING &&
        !          1469:                        Z_STRLEN_PP(data) != 0 &&
        !          1470:                        strstr(Z_STRVAL_PP(data), PS(extern_referer_chk)) == NULL
        !          1471:        ) {
        !          1472:                efree(PS(id));
        !          1473:                PS(id) = NULL;
        !          1474:                PS(send_cookie) = 1;
        !          1475:                if (PS(use_trans_sid) && !PS(use_only_cookies)) {
        !          1476:                        PS(apply_trans_sid) = 1;
        !          1477:                }
        !          1478:        }
        !          1479: 
        !          1480:        php_session_initialize(TSRMLS_C);
        !          1481: 
        !          1482:        if (!PS(use_cookies) && PS(send_cookie)) {
        !          1483:                if (PS(use_trans_sid) && !PS(use_only_cookies)) {
        !          1484:                        PS(apply_trans_sid) = 1;
        !          1485:                }
        !          1486:                PS(send_cookie) = 0;
        !          1487:        }
        !          1488: 
        !          1489:        php_session_reset_id(TSRMLS_C);
        !          1490: 
        !          1491:        PS(session_status) = php_session_active;
        !          1492: 
        !          1493:        php_session_cache_limiter(TSRMLS_C);
        !          1494: 
        !          1495:        if (PS(mod_data) && PS(gc_probability) > 0) {
        !          1496:                int nrdels = -1;
        !          1497: 
        !          1498:                nrand = (int) ((float) PS(gc_divisor) * php_combined_lcg(TSRMLS_C));
        !          1499:                if (nrand < PS(gc_probability)) {
        !          1500:                        PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &nrdels TSRMLS_CC);
        !          1501: #ifdef SESSION_DEBUG
        !          1502:                        if (nrdels != -1) {
        !          1503:                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "purged %d expired session objects", nrdels);
        !          1504:                        }
        !          1505: #endif
        !          1506:                }
        !          1507:        }
        !          1508: }
        !          1509: /* }}} */
        !          1510: 
        !          1511: static void php_session_flush(TSRMLS_D) /* {{{ */
        !          1512: {
        !          1513:        if (PS(session_status) == php_session_active) {
        !          1514:                PS(session_status) = php_session_none;
        !          1515:                zend_try {
        !          1516:                        php_session_save_current_state(TSRMLS_C);
        !          1517:                } zend_end_try();
        !          1518:        }
        !          1519: }
        !          1520: /* }}} */
        !          1521: 
        !          1522: PHPAPI void session_adapt_url(const char *url, size_t urllen, char **new, size_t *newlen TSRMLS_DC) /* {{{ */
        !          1523: {
        !          1524:        if (PS(apply_trans_sid) && (PS(session_status) == php_session_active)) {
        !          1525:                *new = php_url_scanner_adapt_single_url(url, urllen, PS(session_name), PS(id), newlen TSRMLS_CC);
        !          1526:        }
        !          1527: }
        !          1528: /* }}} */
        !          1529: 
        !          1530: /* ********************************
        !          1531:    * Userspace exported functions *
        !          1532:    ******************************** */
        !          1533: 
        !          1534: /* {{{ proto void session_set_cookie_params(int lifetime [, string path [, string domain [, bool secure[, bool httponly]]]])
        !          1535:    Set session cookie parameters */
        !          1536: static PHP_FUNCTION(session_set_cookie_params)
        !          1537: {
        !          1538:        zval **lifetime = NULL;
        !          1539:        char *path = NULL, *domain = NULL;
        !          1540:        int path_len, domain_len, argc = ZEND_NUM_ARGS();
        !          1541:        zend_bool secure = 0, httponly = 0;
        !          1542: 
        !          1543:        if (!PS(use_cookies) ||
        !          1544:                zend_parse_parameters(argc TSRMLS_CC, "Z|ssbb", &lifetime, &path, &path_len, &domain, &domain_len, &secure, &httponly) == FAILURE) {
        !          1545:                return;
        !          1546:        }
        !          1547: 
        !          1548:        convert_to_string_ex(lifetime);
        !          1549: 
        !          1550:        zend_alter_ini_entry("session.cookie_lifetime", sizeof("session.cookie_lifetime"), Z_STRVAL_PP(lifetime), Z_STRLEN_PP(lifetime), PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        !          1551: 
        !          1552:        if (path) {
        !          1553:                zend_alter_ini_entry("session.cookie_path", sizeof("session.cookie_path"), path, path_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        !          1554:        }
        !          1555:        if (domain) {
        !          1556:                zend_alter_ini_entry("session.cookie_domain", sizeof("session.cookie_domain"), domain, domain_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        !          1557:        }
        !          1558: 
        !          1559:        if (argc > 3) {
        !          1560:                zend_alter_ini_entry("session.cookie_secure", sizeof("session.cookie_secure"), secure ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        !          1561:        }
        !          1562:        if (argc > 4) {
        !          1563:                zend_alter_ini_entry("session.cookie_httponly", sizeof("session.cookie_httponly"), httponly ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        !          1564:        }
        !          1565: }
        !          1566: /* }}} */
        !          1567: 
        !          1568: /* {{{ proto array session_get_cookie_params(void)
        !          1569:    Return the session cookie parameters */
        !          1570: static PHP_FUNCTION(session_get_cookie_params)
        !          1571: {
        !          1572:        if (zend_parse_parameters_none() == FAILURE) {
        !          1573:                return;
        !          1574:        }
        !          1575: 
        !          1576:        array_init(return_value);
        !          1577: 
        !          1578:        add_assoc_long(return_value, "lifetime", PS(cookie_lifetime));
        !          1579:        add_assoc_string(return_value, "path", PS(cookie_path), 1);
        !          1580:        add_assoc_string(return_value, "domain", PS(cookie_domain), 1);
        !          1581:        add_assoc_bool(return_value, "secure", PS(cookie_secure));
        !          1582:        add_assoc_bool(return_value, "httponly", PS(cookie_httponly));
        !          1583: }
        !          1584: /* }}} */
        !          1585: 
        !          1586: /* {{{ proto string session_name([string newname])
        !          1587:    Return the current session name. If newname is given, the session name is replaced with newname */
        !          1588: static PHP_FUNCTION(session_name)
        !          1589: {
        !          1590:        char *name = NULL;
        !          1591:        int name_len;
        !          1592: 
        !          1593:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {
        !          1594:                return;
        !          1595:        }
        !          1596: 
        !          1597:        RETVAL_STRING(PS(session_name), 1);
        !          1598: 
        !          1599:        if (name) {
        !          1600:                zend_alter_ini_entry("session.name", sizeof("session.name"), name, name_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        !          1601:        }
        !          1602: }
        !          1603: /* }}} */
        !          1604: 
        !          1605: /* {{{ proto string session_module_name([string newname])
        !          1606:    Return the current module name used for accessing session data. If newname is given, the module name is replaced with newname */
        !          1607: static PHP_FUNCTION(session_module_name)
        !          1608: {
        !          1609:        char *name = NULL;
        !          1610:        int name_len;
        !          1611: 
        !          1612:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {
        !          1613:                return;
        !          1614:        }
        !          1615: 
        !          1616:        /* Set return_value to current module name */
        !          1617:        if (PS(mod) && PS(mod)->s_name) {
        !          1618:                RETVAL_STRING(safe_estrdup(PS(mod)->s_name), 0);
        !          1619:        } else {
        !          1620:                RETVAL_EMPTY_STRING();
        !          1621:        }
        !          1622: 
        !          1623:        if (name) {
        !          1624:                if (!_php_find_ps_module(name TSRMLS_CC)) {
        !          1625:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot find named PHP session module (%s)", name);
        !          1626: 
        !          1627:                        zval_dtor(return_value);
        !          1628:                        RETURN_FALSE;
        !          1629:                }
        !          1630:                if (PS(mod_data)) {
        !          1631:                        PS(mod)->s_close(&PS(mod_data) TSRMLS_CC);
        !          1632:                }
        !          1633:                PS(mod_data) = NULL;
        !          1634: 
        !          1635:                zend_alter_ini_entry("session.save_handler", sizeof("session.save_handler"), name, name_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        !          1636:        }
        !          1637: }
        !          1638: /* }}} */
        !          1639: 
        !          1640: /* {{{ proto void session_set_save_handler(string open, string close, string read, string write, string destroy, string gc)
        !          1641:    Sets user-level functions */
        !          1642: static PHP_FUNCTION(session_set_save_handler)
        !          1643: {
        !          1644:        zval ***args = NULL;
        !          1645:        int i, num_args, argc = ZEND_NUM_ARGS();
        !          1646:        char *name;
        !          1647: 
        !          1648:        if (PS(session_status) != php_session_none) {
        !          1649:                RETURN_FALSE;
        !          1650:        }
        !          1651: 
        !          1652:        if (argc != 6) {
        !          1653:                WRONG_PARAM_COUNT;
        !          1654:        }
        !          1655: 
        !          1656:        if (zend_parse_parameters(argc TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
        !          1657:                return;
        !          1658:        }
        !          1659: 
        !          1660:        for (i = 0; i < 6; i++) {
        !          1661:                if (!zend_is_callable(*args[i], 0, &name TSRMLS_CC)) {
        !          1662:                        efree(args);
        !          1663:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument %d is not a valid callback", i+1);
        !          1664:                        efree(name);
        !          1665:                        RETURN_FALSE;
        !          1666:                }
        !          1667:                efree(name);
        !          1668:        }
        !          1669: 
        !          1670:        zend_alter_ini_entry("session.save_handler", sizeof("session.save_handler"), "user", sizeof("user")-1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        !          1671: 
        !          1672:        for (i = 0; i < 6; i++) {
        !          1673:                if (PS(mod_user_names).names[i] != NULL) {
        !          1674:                        zval_ptr_dtor(&PS(mod_user_names).names[i]);
        !          1675:                }
        !          1676:                Z_ADDREF_PP(args[i]);
        !          1677:                PS(mod_user_names).names[i] = *args[i];
        !          1678:        }
        !          1679: 
        !          1680:        efree(args);
        !          1681:        RETURN_TRUE;
        !          1682: }
        !          1683: /* }}} */
        !          1684: 
        !          1685: /* {{{ proto string session_save_path([string newname])
        !          1686:    Return the current save path passed to module_name. If newname is given, the save path is replaced with newname */
        !          1687: static PHP_FUNCTION(session_save_path)
        !          1688: {
        !          1689:        char *name = NULL;
        !          1690:        int name_len;
        !          1691: 
        !          1692:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {
        !          1693:                return;
        !          1694:        }
        !          1695: 
        !          1696:        RETVAL_STRING(PS(save_path), 1);
        !          1697: 
        !          1698:        if (name) {
        !          1699:                if (memchr(name, '\0', name_len) != NULL) {
        !          1700:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "The save_path cannot contain NULL characters");
        !          1701:                        zval_dtor(return_value);
        !          1702:                        RETURN_FALSE;
        !          1703:                }
        !          1704:                zend_alter_ini_entry("session.save_path", sizeof("session.save_path"), name, name_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        !          1705:        }
        !          1706: }
        !          1707: /* }}} */
        !          1708: 
        !          1709: /* {{{ proto string session_id([string newid])
        !          1710:    Return the current session id. If newid is given, the session id is replaced with newid */
        !          1711: static PHP_FUNCTION(session_id)
        !          1712: {
        !          1713:        char *name = NULL;
        !          1714:        int name_len;
        !          1715: 
        !          1716:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {
        !          1717:                return;
        !          1718:        }
        !          1719: 
        !          1720:        if (PS(id)) {
        !          1721:                RETVAL_STRING(PS(id), 1);
        !          1722:        } else {
        !          1723:                RETVAL_EMPTY_STRING();
        !          1724:        }
        !          1725: 
        !          1726:        if (name) {
        !          1727:                if (PS(id)) {
        !          1728:                        efree(PS(id));
        !          1729:                }
        !          1730:                PS(id) = estrndup(name, name_len);
        !          1731:        }
        !          1732: }
        !          1733: /* }}} */
        !          1734: 
        !          1735: /* {{{ proto bool session_regenerate_id([bool delete_old_session])
        !          1736:    Update the current session id with a newly generated one. If delete_old_session is set to true, remove the old session. */
        !          1737: static PHP_FUNCTION(session_regenerate_id)
        !          1738: {
        !          1739:        zend_bool del_ses = 0;
        !          1740: 
        !          1741:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &del_ses) == FAILURE) {
        !          1742:                return;
        !          1743:        }
        !          1744: 
        !          1745:        if (SG(headers_sent) && PS(use_cookies)) {
        !          1746:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot regenerate session id - headers already sent");
        !          1747:                RETURN_FALSE;
        !          1748:        }
        !          1749: 
        !          1750:        if (PS(session_status) == php_session_active) {
        !          1751:                if (PS(id)) {
        !          1752:                        if (del_ses && PS(mod)->s_destroy(&PS(mod_data), PS(id) TSRMLS_CC) == FAILURE) {
        !          1753:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session object destruction failed");
        !          1754:                                RETURN_FALSE;
        !          1755:                        }
        !          1756:                        efree(PS(id));
        !          1757:                        PS(id) = NULL;
        !          1758:                }
        !          1759: 
        !          1760:                PS(id) = PS(mod)->s_create_sid(&PS(mod_data), NULL TSRMLS_CC);
        !          1761: 
        !          1762:                PS(send_cookie) = 1;
        !          1763:                php_session_reset_id(TSRMLS_C);
        !          1764: 
        !          1765:                RETURN_TRUE;
        !          1766:        }
        !          1767:        RETURN_FALSE;
        !          1768: }
        !          1769: /* }}} */
        !          1770: 
        !          1771: /* {{{ proto string session_cache_limiter([string new_cache_limiter])
        !          1772:    Return the current cache limiter. If new_cache_limited is given, the current cache_limiter is replaced with new_cache_limiter */
        !          1773: static PHP_FUNCTION(session_cache_limiter)
        !          1774: {
        !          1775:        char *limiter = NULL;
        !          1776:        int limiter_len;
        !          1777: 
        !          1778:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &limiter, &limiter_len) == FAILURE) {
        !          1779:                return;
        !          1780:        }
        !          1781: 
        !          1782:        RETVAL_STRING(PS(cache_limiter), 1);
        !          1783: 
        !          1784:        if (limiter) {
        !          1785:                zend_alter_ini_entry("session.cache_limiter", sizeof("session.cache_limiter"), limiter, limiter_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
        !          1786:        }
        !          1787: }
        !          1788: /* }}} */
        !          1789: 
        !          1790: /* {{{ proto int session_cache_expire([int new_cache_expire])
        !          1791:    Return the current cache expire. If new_cache_expire is given, the current cache_expire is replaced with new_cache_expire */
        !          1792: static PHP_FUNCTION(session_cache_expire)
        !          1793: {
        !          1794:        zval **expires = NULL;
        !          1795:        int argc = ZEND_NUM_ARGS();
        !          1796: 
        !          1797:        if (zend_parse_parameters(argc TSRMLS_CC, "|Z", &expires) == FAILURE) {
        !          1798:                return;
        !          1799:        }
        !          1800: 
        !          1801:        RETVAL_LONG(PS(cache_expire));
        !          1802: 
        !          1803:        if (argc == 1) {
        !          1804:                convert_to_string_ex(expires);
        !          1805:                zend_alter_ini_entry("session.cache_expire", sizeof("session.cache_expire"), Z_STRVAL_PP(expires), Z_STRLEN_PP(expires), ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME);
        !          1806:        }
        !          1807: }
        !          1808: /* }}} */
        !          1809: 
        !          1810: /* {{{ static void php_register_var(zval** entry TSRMLS_DC) */
        !          1811: static void php_register_var(zval** entry TSRMLS_DC)
        !          1812: {
        !          1813:        zval **value;
        !          1814: 
        !          1815:        if (Z_TYPE_PP(entry) == IS_ARRAY) {
        !          1816:                if (Z_ARRVAL_PP(entry)->nApplyCount > 1) {
        !          1817:                        return;
        !          1818:                }
        !          1819: 
        !          1820:                zend_hash_internal_pointer_reset(Z_ARRVAL_PP(entry));
        !          1821:                Z_ARRVAL_PP(entry)->nApplyCount++;
        !          1822: 
        !          1823:                while (zend_hash_get_current_data(Z_ARRVAL_PP(entry), (void**)&value) == SUCCESS) {
        !          1824:                        php_register_var(value TSRMLS_CC);
        !          1825:                        zend_hash_move_forward(Z_ARRVAL_PP(entry));
        !          1826:                }
        !          1827: 
        !          1828:                Z_ARRVAL_PP(entry)->nApplyCount--;
        !          1829:        } else {
        !          1830:                convert_to_string_ex(entry);
        !          1831: 
        !          1832:                if ((strcmp(Z_STRVAL_PP(entry), "HTTP_SESSION_VARS") != 0) &&
        !          1833:                        (strcmp(Z_STRVAL_PP(entry), "_SESSION") != 0)
        !          1834:                ) {
        !          1835:                        PS_ADD_VARL(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry));
        !          1836:                }
        !          1837:        }
        !          1838: }
        !          1839: /* }}} */
        !          1840: 
        !          1841: /* {{{ proto string session_encode(void)
        !          1842:    Serializes the current setup and returns the serialized representation */
        !          1843: static PHP_FUNCTION(session_encode)
        !          1844: {
        !          1845:        int len;
        !          1846:        char *enc;
        !          1847: 
        !          1848:        if (zend_parse_parameters_none() == FAILURE) {
        !          1849:                return;
        !          1850:        }
        !          1851: 
        !          1852:        enc = php_session_encode(&len TSRMLS_CC);
        !          1853:        if (enc == NULL) {
        !          1854:                RETURN_FALSE;
        !          1855:        }
        !          1856: 
        !          1857:        RETVAL_STRINGL(enc, len, 0);
        !          1858: }
        !          1859: /* }}} */
        !          1860: 
        !          1861: /* {{{ proto bool session_decode(string data)
        !          1862:    Deserializes data and reinitializes the variables */
        !          1863: static PHP_FUNCTION(session_decode)
        !          1864: {
        !          1865:        char *str;
        !          1866:        int str_len;
        !          1867: 
        !          1868:        if (PS(session_status) == php_session_none) {
        !          1869:                RETURN_FALSE;
        !          1870:        }
        !          1871: 
        !          1872:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
        !          1873:                return;
        !          1874:        }
        !          1875: 
        !          1876:        php_session_decode(str, str_len TSRMLS_CC);
        !          1877: 
        !          1878:        RETURN_TRUE;
        !          1879: }
        !          1880: /* }}} */
        !          1881: 
        !          1882: /* {{{ proto bool session_start(void)
        !          1883:    Begin session - reinitializes freezed variables, registers browsers etc */
        !          1884: static PHP_FUNCTION(session_start)
        !          1885: {
        !          1886:        /* skipping check for non-zero args for performance reasons here ?*/
        !          1887:        php_session_start(TSRMLS_C);
        !          1888: 
        !          1889:        if (PS(session_status) != php_session_active) {
        !          1890:                RETURN_FALSE;
        !          1891:        }
        !          1892:        RETURN_TRUE;
        !          1893: }
        !          1894: /* }}} */
        !          1895: 
        !          1896: /* {{{ proto bool session_destroy(void)
        !          1897:    Destroy the current session and all data associated with it */
        !          1898: static PHP_FUNCTION(session_destroy)
        !          1899: {
        !          1900:        if (zend_parse_parameters_none() == FAILURE) {
        !          1901:                return;
        !          1902:        }
        !          1903: 
        !          1904:        RETURN_BOOL(php_session_destroy(TSRMLS_C) == SUCCESS);
        !          1905: }
        !          1906: /* }}} */
        !          1907: 
        !          1908: /* {{{ proto void session_unset(void)
        !          1909:    Unset all registered variables */
        !          1910: static PHP_FUNCTION(session_unset)
        !          1911: {
        !          1912:        if (PS(session_status) == php_session_none) {
        !          1913:                RETURN_FALSE;
        !          1914:        }
        !          1915: 
        !          1916:        IF_SESSION_VARS() {
        !          1917:                HashTable *ht_sess_var;
        !          1918: 
        !          1919:                SEPARATE_ZVAL_IF_NOT_REF(&PS(http_session_vars));
        !          1920:                ht_sess_var = Z_ARRVAL_P(PS(http_session_vars));
        !          1921: 
        !          1922:                if (PG(register_globals)) {
        !          1923:                        uint str_len;
        !          1924:                        char *str;
        !          1925:                        ulong num_key;
        !          1926:                        HashPosition pos;
        !          1927: 
        !          1928:                        zend_hash_internal_pointer_reset_ex(ht_sess_var, &pos);
        !          1929: 
        !          1930:                        while (zend_hash_get_current_key_ex(ht_sess_var, &str, &str_len, &num_key, 0, &pos) == HASH_KEY_IS_STRING) {
        !          1931:                                zend_delete_global_variable(str, str_len - 1 TSRMLS_CC);
        !          1932:                                zend_hash_move_forward_ex(ht_sess_var, &pos);
        !          1933:                        }
        !          1934:                }
        !          1935: 
        !          1936:                /* Clean $_SESSION. */
        !          1937:                zend_hash_clean(ht_sess_var);
        !          1938:        }
        !          1939: }
        !          1940: /* }}} */
        !          1941: 
        !          1942: /* {{{ proto void session_write_close(void)
        !          1943:    Write session data and end session */
        !          1944: static PHP_FUNCTION(session_write_close)
        !          1945: {
        !          1946:        php_session_flush(TSRMLS_C);
        !          1947: }
        !          1948: /* }}} */
        !          1949: 
        !          1950: /* {{{ proto bool session_register(mixed var_names [, mixed ...])
        !          1951:    Adds varname(s) to the list of variables which are freezed at the session end */
        !          1952: static PHP_FUNCTION(session_register)
        !          1953: {
        !          1954:        zval ***args = NULL;
        !          1955:        int num_args, i;
        !          1956: 
        !          1957:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
        !          1958:                return;
        !          1959:        }
        !          1960: 
        !          1961:        if (PS(session_status) == php_session_none || PS(session_status) == php_session_disabled) {
        !          1962:                php_session_start(TSRMLS_C);
        !          1963:        }
        !          1964: 
        !          1965:        if (PS(session_status) == php_session_disabled) {
        !          1966:                if (args) {
        !          1967:                        efree(args);
        !          1968:                }
        !          1969:                RETURN_FALSE;
        !          1970:        }
        !          1971: 
        !          1972:        for (i = 0; i < num_args; i++) {
        !          1973:                if (Z_TYPE_PP(args[i]) == IS_ARRAY) {
        !          1974:                        SEPARATE_ZVAL(args[i]);
        !          1975:                }
        !          1976:                php_register_var(args[i] TSRMLS_CC);
        !          1977:        }
        !          1978: 
        !          1979:        if (args) {
        !          1980:                efree(args);
        !          1981:        }
        !          1982: 
        !          1983:        RETURN_TRUE;
        !          1984: }
        !          1985: /* }}} */
        !          1986: 
        !          1987: /* {{{ proto bool session_unregister(string varname)
        !          1988:    Removes varname from the list of variables which are freezed at the session end */
        !          1989: static PHP_FUNCTION(session_unregister)
        !          1990: {
        !          1991:        char *p_name;
        !          1992:        int p_name_len;
        !          1993: 
        !          1994:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &p_name, &p_name_len) == FAILURE) {
        !          1995:                return;
        !          1996:        }
        !          1997: 
        !          1998:        IF_SESSION_VARS() {
        !          1999:                SEPARATE_ZVAL_IF_NOT_REF(&PS(http_session_vars));
        !          2000:                PS_DEL_VARL(p_name, p_name_len);
        !          2001:        }
        !          2002: 
        !          2003:        RETURN_TRUE;
        !          2004: }
        !          2005: /* }}} */
        !          2006: 
        !          2007: /* {{{ proto bool session_is_registered(string varname)
        !          2008:    Checks if a variable is registered in session */
        !          2009: static PHP_FUNCTION(session_is_registered)
        !          2010: {
        !          2011:        zval *p_var;
        !          2012:        char *p_name;
        !          2013:        int p_name_len;
        !          2014: 
        !          2015:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &p_name, &p_name_len) == FAILURE) {
        !          2016:                return;
        !          2017:        }
        !          2018: 
        !          2019:        if (PS(session_status) == php_session_none) {
        !          2020:                RETURN_FALSE;
        !          2021:        }
        !          2022: 
        !          2023:        IF_SESSION_VARS() {
        !          2024:                if (zend_hash_find(Z_ARRVAL_P(PS(http_session_vars)), p_name, p_name_len+1, (void **)&p_var) == SUCCESS) {
        !          2025:                        RETURN_TRUE;
        !          2026:                }
        !          2027:        }
        !          2028:        RETURN_FALSE;
        !          2029: }
        !          2030: /* }}} */
        !          2031: 
        !          2032: /* {{{ arginfo */
        !          2033: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_name, 0, 0, 0)
        !          2034:        ZEND_ARG_INFO(0, name)
        !          2035: ZEND_END_ARG_INFO()
        !          2036: 
        !          2037: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_module_name, 0, 0, 0)
        !          2038:        ZEND_ARG_INFO(0, module)
        !          2039: ZEND_END_ARG_INFO()
        !          2040: 
        !          2041: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_save_path, 0, 0, 0)
        !          2042:        ZEND_ARG_INFO(0, path)
        !          2043: ZEND_END_ARG_INFO()
        !          2044: 
        !          2045: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_id, 0, 0, 0)
        !          2046:        ZEND_ARG_INFO(0, id)
        !          2047: ZEND_END_ARG_INFO()
        !          2048: 
        !          2049: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_regenerate_id, 0, 0, 0)
        !          2050:        ZEND_ARG_INFO(0, delete_old_session)
        !          2051: ZEND_END_ARG_INFO()
        !          2052: 
        !          2053: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_decode, 0, 0, 1)
        !          2054:        ZEND_ARG_INFO(0, data)
        !          2055: ZEND_END_ARG_INFO()
        !          2056: 
        !          2057: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_register, 0, 0, 1)
        !          2058:        ZEND_ARG_INFO(0, name)
        !          2059:        ZEND_ARG_INFO(0, ...)
        !          2060: ZEND_END_ARG_INFO()
        !          2061: 
        !          2062: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_unregister, 0, 0, 1)
        !          2063:        ZEND_ARG_INFO(0, name)
        !          2064: ZEND_END_ARG_INFO()
        !          2065: 
        !          2066: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_is_registered, 0, 0, 1)
        !          2067:        ZEND_ARG_INFO(0, name)
        !          2068: ZEND_END_ARG_INFO()
        !          2069: 
        !          2070: ZEND_BEGIN_ARG_INFO(arginfo_session_void, 0)
        !          2071: ZEND_END_ARG_INFO()
        !          2072: 
        !          2073: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_set_save_handler, 0, 0, 6)
        !          2074:        ZEND_ARG_INFO(0, open)
        !          2075:        ZEND_ARG_INFO(0, close)
        !          2076:        ZEND_ARG_INFO(0, read)
        !          2077:        ZEND_ARG_INFO(0, write)
        !          2078:        ZEND_ARG_INFO(0, destroy)
        !          2079:        ZEND_ARG_INFO(0, gc)
        !          2080: ZEND_END_ARG_INFO()
        !          2081: 
        !          2082: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_cache_limiter, 0, 0, 0)
        !          2083:        ZEND_ARG_INFO(0, cache_limiter)
        !          2084: ZEND_END_ARG_INFO()
        !          2085: 
        !          2086: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_cache_expire, 0, 0, 0)
        !          2087:        ZEND_ARG_INFO(0, new_cache_expire)
        !          2088: ZEND_END_ARG_INFO()
        !          2089: 
        !          2090: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_set_cookie_params, 0, 0, 1)
        !          2091:        ZEND_ARG_INFO(0, lifetime)
        !          2092:        ZEND_ARG_INFO(0, path)
        !          2093:        ZEND_ARG_INFO(0, domain)
        !          2094:        ZEND_ARG_INFO(0, secure)
        !          2095:        ZEND_ARG_INFO(0, httponly)
        !          2096: ZEND_END_ARG_INFO()
        !          2097: /* }}} */
        !          2098: 
        !          2099: /* {{{ session_functions[]
        !          2100:  */
        !          2101: static const zend_function_entry session_functions[] = {
        !          2102:        PHP_FE(session_name,              arginfo_session_name)
        !          2103:        PHP_FE(session_module_name,       arginfo_session_module_name)
        !          2104:        PHP_FE(session_save_path,         arginfo_session_save_path)
        !          2105:        PHP_FE(session_id,                arginfo_session_id)
        !          2106:        PHP_FE(session_regenerate_id,     arginfo_session_regenerate_id)
        !          2107:        PHP_FE(session_decode,            arginfo_session_decode)
        !          2108:        PHP_DEP_FE(session_register,      arginfo_session_register)
        !          2109:        PHP_DEP_FE(session_unregister,    arginfo_session_unregister)
        !          2110:        PHP_DEP_FE(session_is_registered, arginfo_session_is_registered)
        !          2111:        PHP_FE(session_encode,            arginfo_session_void)
        !          2112:        PHP_FE(session_start,             arginfo_session_void)
        !          2113:        PHP_FE(session_destroy,           arginfo_session_void)
        !          2114:        PHP_FE(session_unset,             arginfo_session_void)
        !          2115:        PHP_FE(session_set_save_handler,  arginfo_session_set_save_handler)
        !          2116:        PHP_FE(session_cache_limiter,     arginfo_session_cache_limiter)
        !          2117:        PHP_FE(session_cache_expire,      arginfo_session_cache_expire)
        !          2118:        PHP_FE(session_set_cookie_params, arginfo_session_set_cookie_params)
        !          2119:        PHP_FE(session_get_cookie_params, arginfo_session_void)
        !          2120:        PHP_FE(session_write_close,       arginfo_session_void)
        !          2121:        PHP_FALIAS(session_commit, session_write_close, arginfo_session_void)
        !          2122:        PHP_FE_END
        !          2123: };
        !          2124: /* }}} */
        !          2125: 
        !          2126: /* ********************************
        !          2127:    * Module Setup and Destruction *
        !          2128:    ******************************** */
        !          2129: 
        !          2130: static PHP_RINIT_FUNCTION(session) /* {{{ */
        !          2131: {
        !          2132:        php_rinit_session_globals(TSRMLS_C);
        !          2133: 
        !          2134:        if (PS(mod) == NULL) {
        !          2135:                char *value;
        !          2136: 
        !          2137:                value = zend_ini_string("session.save_handler", sizeof("session.save_handler"), 0);
        !          2138:                if (value) {
        !          2139:                        PS(mod) = _php_find_ps_module(value TSRMLS_CC);
        !          2140:                }
        !          2141:        }
        !          2142: 
        !          2143:        if (PS(serializer) == NULL) {
        !          2144:                char *value;
        !          2145: 
        !          2146:                value = zend_ini_string("session.serialize_handler", sizeof("session.serialize_handler"), 0);
        !          2147:                if (value) {
        !          2148:                        PS(serializer) = _php_find_ps_serializer(value TSRMLS_CC);
        !          2149:                }
        !          2150:        }
        !          2151: 
        !          2152:        if (PS(mod) == NULL || PS(serializer) == NULL) {
        !          2153:                /* current status is unusable */
        !          2154:                PS(session_status) = php_session_disabled;
        !          2155:                return SUCCESS;
        !          2156:        }
        !          2157: 
        !          2158:        if (PS(auto_start)) {
        !          2159:                php_session_start(TSRMLS_C);
        !          2160:        }
        !          2161: 
        !          2162:        return SUCCESS;
        !          2163: }
        !          2164: /* }}} */
        !          2165: 
        !          2166: static PHP_RSHUTDOWN_FUNCTION(session) /* {{{ */
        !          2167: {
        !          2168:        int i;
        !          2169: 
        !          2170:        php_session_flush(TSRMLS_C);
        !          2171:        php_rshutdown_session_globals(TSRMLS_C);
        !          2172: 
        !          2173:        /* this should NOT be done in php_rshutdown_session_globals() */
        !          2174:        for (i = 0; i < 6; i++) {
        !          2175:                if (PS(mod_user_names).names[i] != NULL) {
        !          2176:                        zval_ptr_dtor(&PS(mod_user_names).names[i]);
        !          2177:                        PS(mod_user_names).names[i] = NULL;
        !          2178:                }
        !          2179:        }
        !          2180: 
        !          2181:        return SUCCESS;
        !          2182: }
        !          2183: /* }}} */
        !          2184: 
        !          2185: static PHP_GINIT_FUNCTION(ps) /* {{{ */
        !          2186: {
        !          2187:        int i;
        !          2188: 
        !          2189:        ps_globals->save_path = NULL;
        !          2190:        ps_globals->session_name = NULL;
        !          2191:        ps_globals->id = NULL;
        !          2192:        ps_globals->mod = NULL;
        !          2193:        ps_globals->serializer = NULL;
        !          2194:        ps_globals->mod_data = NULL;
        !          2195:        ps_globals->session_status = php_session_none;
        !          2196:        for (i = 0; i < 6; i++) {
        !          2197:                ps_globals->mod_user_names.names[i] = NULL;
        !          2198:        }
        !          2199:        ps_globals->http_session_vars = NULL;
        !          2200: }
        !          2201: /* }}} */
        !          2202: 
        !          2203: static PHP_MINIT_FUNCTION(session) /* {{{ */
        !          2204: {
        !          2205:        zend_register_auto_global("_SESSION", sizeof("_SESSION")-1, NULL TSRMLS_CC);
        !          2206: 
        !          2207:        PS(module_number) = module_number; /* if we really need this var we need to init it in zts mode as well! */
        !          2208: 
        !          2209:        PS(session_status) = php_session_none;
        !          2210:        REGISTER_INI_ENTRIES();
        !          2211: 
        !          2212: #ifdef HAVE_LIBMM
        !          2213:        PHP_MINIT(ps_mm) (INIT_FUNC_ARGS_PASSTHRU);
        !          2214: #endif
        !          2215:        return SUCCESS;
        !          2216: }
        !          2217: /* }}} */
        !          2218: 
        !          2219: static PHP_MSHUTDOWN_FUNCTION(session) /* {{{ */
        !          2220: {
        !          2221:        UNREGISTER_INI_ENTRIES();
        !          2222: 
        !          2223: #ifdef HAVE_LIBMM
        !          2224:        PHP_MSHUTDOWN(ps_mm) (SHUTDOWN_FUNC_ARGS_PASSTHRU);
        !          2225: #endif
        !          2226: 
        !          2227:        ps_serializers[PREDEFINED_SERIALIZERS].name = NULL;
        !          2228:        memset(&ps_modules[PREDEFINED_MODULES], 0, (MAX_MODULES-PREDEFINED_MODULES)*sizeof(ps_module *));
        !          2229: 
        !          2230:        return SUCCESS;
        !          2231: }
        !          2232: /* }}} */
        !          2233: 
        !          2234: static PHP_MINFO_FUNCTION(session) /* {{{ */
        !          2235: {
        !          2236:        ps_module **mod;
        !          2237:        ps_serializer *ser;
        !          2238:        smart_str save_handlers = {0};
        !          2239:        smart_str ser_handlers = {0};
        !          2240:        int i;
        !          2241: 
        !          2242:        /* Get save handlers */
        !          2243:        for (i = 0, mod = ps_modules; i < MAX_MODULES; i++, mod++) {
        !          2244:                if (*mod && (*mod)->s_name) {
        !          2245:                        smart_str_appends(&save_handlers, (*mod)->s_name);
        !          2246:                        smart_str_appendc(&save_handlers, ' ');
        !          2247:                }
        !          2248:        }
        !          2249: 
        !          2250:        /* Get serializer handlers */
        !          2251:        for (i = 0, ser = ps_serializers; i < MAX_SERIALIZERS; i++, ser++) {
        !          2252:                if (ser && ser->name) {
        !          2253:                        smart_str_appends(&ser_handlers, ser->name);
        !          2254:                        smart_str_appendc(&ser_handlers, ' ');
        !          2255:                }
        !          2256:        }
        !          2257: 
        !          2258:        php_info_print_table_start();
        !          2259:        php_info_print_table_row(2, "Session Support", "enabled" );
        !          2260: 
        !          2261:        if (save_handlers.c) {
        !          2262:                smart_str_0(&save_handlers);
        !          2263:                php_info_print_table_row(2, "Registered save handlers", save_handlers.c);
        !          2264:                smart_str_free(&save_handlers);
        !          2265:        } else {
        !          2266:                php_info_print_table_row(2, "Registered save handlers", "none");
        !          2267:        }
        !          2268: 
        !          2269:        if (ser_handlers.c) {
        !          2270:                smart_str_0(&ser_handlers);
        !          2271:                php_info_print_table_row(2, "Registered serializer handlers", ser_handlers.c);
        !          2272:                smart_str_free(&ser_handlers);
        !          2273:        } else {
        !          2274:                php_info_print_table_row(2, "Registered serializer handlers", "none");
        !          2275:        }
        !          2276: 
        !          2277:        php_info_print_table_end();
        !          2278: 
        !          2279:        DISPLAY_INI_ENTRIES();
        !          2280: }
        !          2281: /* }}} */
        !          2282: 
        !          2283: static const zend_module_dep session_deps[] = { /* {{{ */
        !          2284:        ZEND_MOD_OPTIONAL("hash")
        !          2285:        ZEND_MOD_REQUIRED("spl")
        !          2286:        ZEND_MOD_END
        !          2287: };
        !          2288: /* }}} */
        !          2289: 
        !          2290: zend_module_entry session_module_entry = {
        !          2291:        STANDARD_MODULE_HEADER_EX,
        !          2292:        NULL,
        !          2293:        session_deps,
        !          2294:        "session",
        !          2295:        session_functions,
        !          2296:        PHP_MINIT(session), PHP_MSHUTDOWN(session),
        !          2297:        PHP_RINIT(session), PHP_RSHUTDOWN(session),
        !          2298:        PHP_MINFO(session),
        !          2299:        NO_VERSION_YET,
        !          2300:        PHP_MODULE_GLOBALS(ps),
        !          2301:        PHP_GINIT(ps),
        !          2302:        NULL,
        !          2303:        NULL,
        !          2304:        STANDARD_MODULE_PROPERTIES_EX
        !          2305: };
        !          2306: 
        !          2307: #ifdef COMPILE_DL_SESSION
        !          2308: ZEND_GET_MODULE(session)
        !          2309: #endif
        !          2310: 
        !          2311: /*
        !          2312:  * Local variables:
        !          2313:  * tab-width: 4
        !          2314:  * c-basic-offset: 4
        !          2315:  * End:
        !          2316:  * vim600: noet sw=4 ts=4 fdm=marker
        !          2317:  * vim<600: sw=4 ts=4
        !          2318:  */

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