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

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

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