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

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.3 ! misho       5:    | Copyright (c) 1997-2013 The PHP Group                                |
1.1       misho       6:    +----------------------------------------------------------------------+
                      7:    | This source file is subject to version 3.01 of the PHP license,      |
                      8:    | that is bundled with this package in the file LICENSE, and is        |
                      9:    | available through the world-wide-web at the following url:           |
                     10:    | http://www.php.net/license/3_01.txt                                  |
                     11:    | If you did not receive a copy of the PHP license and are unable to   |
                     12:    | obtain it through the world-wide-web, please send a note to          |
                     13:    | license@php.net so we can mail you a copy immediately.               |
                     14:    +----------------------------------------------------------------------+
                     15:    | 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)
                    284:        void *hash_context;
                    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: 
                    344:                if (php_win32_get_random_bytes(rbuf, (size_t) toread) == SUCCESS){
                    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: 
                    618: static PHP_INI_MH(OnUpdateHashFunc) /* {{{ */
                    619: {
                    620:        long val;
                    621:        char *endptr = NULL;
                    622: 
                    623: #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
                    624:        PS(hash_ops) = NULL;
                    625: #endif
                    626: 
                    627:        val = strtol(new_value, &endptr, 10);
                    628:        if (endptr && (*endptr == '\0')) {
                    629:                /* Numeric value */
                    630:                PS(hash_func) = val ? 1 : 0;
                    631: 
                    632:                return SUCCESS;
                    633:        }
                    634: 
                    635:        if (new_value_length == (sizeof("md5") - 1) &&
                    636:                strncasecmp(new_value, "md5", sizeof("md5") - 1) == 0) {
                    637:                PS(hash_func) = PS_HASH_FUNC_MD5;
                    638: 
                    639:                return SUCCESS;
                    640:        }
                    641: 
                    642:        if (new_value_length == (sizeof("sha1") - 1) &&
                    643:                strncasecmp(new_value, "sha1", sizeof("sha1") - 1) == 0) {
                    644:                PS(hash_func) = PS_HASH_FUNC_SHA1;
                    645: 
                    646:                return SUCCESS;
                    647:        }
                    648: 
                    649: #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH) /* {{{ */
                    650: {
                    651:        php_hash_ops *ops = (php_hash_ops*)php_hash_fetch_ops(new_value, new_value_length);
                    652: 
                    653:        if (ops) {
                    654:                PS(hash_func) = PS_HASH_FUNC_OTHER;
                    655:                PS(hash_ops) = ops;
                    656: 
                    657:                return SUCCESS;
                    658:        }
                    659: }
                    660: #endif /* HAVE_HASH_EXT }}} */
                    661: 
                    662:        return FAILURE;
                    663: }
                    664: /* }}} */
                    665: 
1.1.1.2   misho     666: static PHP_INI_MH(OnUpdateRfc1867Freq) /* {{{ */
                    667: {
                    668:        int tmp;
                    669:        tmp = zend_atoi(new_value, new_value_length);
                    670:        if(tmp < 0) {
                    671:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "session.upload_progress.freq must be greater than or equal to zero");
                    672:                return FAILURE;
                    673:        }
                    674:        if(new_value_length > 0 && new_value[new_value_length-1] == '%') {
                    675:                if(tmp > 100) {
                    676:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "session.upload_progress.freq cannot be over 100%%");
                    677:                        return FAILURE;
                    678:                }
                    679:                PS(rfc1867_freq) = -tmp;
                    680:        } else {
                    681:                PS(rfc1867_freq) = tmp;
                    682:        }
                    683:        return SUCCESS;
                    684: } /* }}} */
                    685: 
                    686: static ZEND_INI_MH(OnUpdateSmartStr) /* {{{ */
                    687: {
                    688:        smart_str *p;
                    689: #ifndef ZTS
                    690:        char *base = (char *) mh_arg2;
                    691: #else
                    692:        char *base;
                    693: 
                    694:        base = (char *) ts_resource(*((int *) mh_arg2));
                    695: #endif
                    696: 
                    697:        p = (smart_str *) (base+(size_t) mh_arg1);
                    698: 
                    699:        smart_str_sets(p, new_value);
                    700: 
                    701:        return SUCCESS;
                    702: }
                    703: /* }}} */
                    704: 
1.1       misho     705: /* {{{ PHP_INI
                    706:  */
                    707: PHP_INI_BEGIN()
                    708:        STD_PHP_INI_ENTRY("session.save_path",          "",          PHP_INI_ALL, OnUpdateSaveDir,save_path,          php_ps_globals,    ps_globals)
                    709:        STD_PHP_INI_ENTRY("session.name",               "PHPSESSID", PHP_INI_ALL, OnUpdateString, session_name,       php_ps_globals,    ps_globals)
                    710:        PHP_INI_ENTRY("session.save_handler",           "files",     PHP_INI_ALL, OnUpdateSaveHandler)
                    711:        STD_PHP_INI_BOOLEAN("session.auto_start",       "0",         PHP_INI_ALL, OnUpdateBool,   auto_start,         php_ps_globals,    ps_globals)
                    712:        STD_PHP_INI_ENTRY("session.gc_probability",     "1",         PHP_INI_ALL, OnUpdateLong,   gc_probability,     php_ps_globals,    ps_globals)
                    713:        STD_PHP_INI_ENTRY("session.gc_divisor",         "100",       PHP_INI_ALL, OnUpdateLong,   gc_divisor,         php_ps_globals,    ps_globals)
                    714:        STD_PHP_INI_ENTRY("session.gc_maxlifetime",     "1440",      PHP_INI_ALL, OnUpdateLong,   gc_maxlifetime,     php_ps_globals,    ps_globals)
                    715:        PHP_INI_ENTRY("session.serialize_handler",      "php",       PHP_INI_ALL, OnUpdateSerializer)
                    716:        STD_PHP_INI_ENTRY("session.cookie_lifetime",    "0",         PHP_INI_ALL, OnUpdateLong,   cookie_lifetime,    php_ps_globals,    ps_globals)
                    717:        STD_PHP_INI_ENTRY("session.cookie_path",        "/",         PHP_INI_ALL, OnUpdateString, cookie_path,        php_ps_globals,    ps_globals)
                    718:        STD_PHP_INI_ENTRY("session.cookie_domain",      "",          PHP_INI_ALL, OnUpdateString, cookie_domain,      php_ps_globals,    ps_globals)
                    719:        STD_PHP_INI_BOOLEAN("session.cookie_secure",    "",          PHP_INI_ALL, OnUpdateBool,   cookie_secure,      php_ps_globals,    ps_globals)
                    720:        STD_PHP_INI_BOOLEAN("session.cookie_httponly",  "",          PHP_INI_ALL, OnUpdateBool,   cookie_httponly,    php_ps_globals,    ps_globals)
                    721:        STD_PHP_INI_BOOLEAN("session.use_cookies",      "1",         PHP_INI_ALL, OnUpdateBool,   use_cookies,        php_ps_globals,    ps_globals)
                    722:        STD_PHP_INI_BOOLEAN("session.use_only_cookies", "1",         PHP_INI_ALL, OnUpdateBool,   use_only_cookies,   php_ps_globals,    ps_globals)
                    723:        STD_PHP_INI_ENTRY("session.referer_check",      "",          PHP_INI_ALL, OnUpdateString, extern_referer_chk, php_ps_globals,    ps_globals)
1.1.1.2   misho     724: #if HAVE_DEV_URANDOM
                    725:        STD_PHP_INI_ENTRY("session.entropy_file",       "/dev/urandom",          PHP_INI_ALL, OnUpdateString, entropy_file,       php_ps_globals,    ps_globals)
                    726:        STD_PHP_INI_ENTRY("session.entropy_length",     "32",         PHP_INI_ALL, OnUpdateLong,   entropy_length,     php_ps_globals,    ps_globals)
                    727: #elif HAVE_DEV_ARANDOM
                    728:        STD_PHP_INI_ENTRY("session.entropy_file",       "/dev/arandom",          PHP_INI_ALL, OnUpdateString, entropy_file,       php_ps_globals,    ps_globals)
                    729:        STD_PHP_INI_ENTRY("session.entropy_length",     "32",         PHP_INI_ALL, OnUpdateLong,   entropy_length,     php_ps_globals,    ps_globals)
                    730: #else
1.1       misho     731:        STD_PHP_INI_ENTRY("session.entropy_file",       "",          PHP_INI_ALL, OnUpdateString, entropy_file,       php_ps_globals,    ps_globals)
                    732:        STD_PHP_INI_ENTRY("session.entropy_length",     "0",         PHP_INI_ALL, OnUpdateLong,   entropy_length,     php_ps_globals,    ps_globals)
1.1.1.2   misho     733: #endif
1.1       misho     734:        STD_PHP_INI_ENTRY("session.cache_limiter",      "nocache",   PHP_INI_ALL, OnUpdateString, cache_limiter,      php_ps_globals,    ps_globals)
                    735:        STD_PHP_INI_ENTRY("session.cache_expire",       "180",       PHP_INI_ALL, OnUpdateLong,   cache_expire,       php_ps_globals,    ps_globals)
                    736:        PHP_INI_ENTRY("session.use_trans_sid",          "0",         PHP_INI_ALL, OnUpdateTransSid)
                    737:        PHP_INI_ENTRY("session.hash_function",          "0",         PHP_INI_ALL, OnUpdateHashFunc)
                    738:        STD_PHP_INI_ENTRY("session.hash_bits_per_character", "4",    PHP_INI_ALL, OnUpdateLong,   hash_bits_per_character, php_ps_globals, ps_globals)
                    739: 
1.1.1.2   misho     740:        /* Upload progress */
                    741:        STD_PHP_INI_BOOLEAN("session.upload_progress.enabled",
                    742:                                                        "1",     ZEND_INI_PERDIR, OnUpdateBool,        rfc1867_enabled, php_ps_globals, ps_globals)
                    743:        STD_PHP_INI_BOOLEAN("session.upload_progress.cleanup",
                    744:                                                        "1",     ZEND_INI_PERDIR, OnUpdateBool,        rfc1867_cleanup, php_ps_globals, ps_globals)
                    745:        STD_PHP_INI_ENTRY("session.upload_progress.prefix",
                    746:                                             "upload_progress_", ZEND_INI_PERDIR, OnUpdateSmartStr,      rfc1867_prefix,  php_ps_globals, ps_globals)
                    747:        STD_PHP_INI_ENTRY("session.upload_progress.name",
                    748:                                  "PHP_SESSION_UPLOAD_PROGRESS", ZEND_INI_PERDIR, OnUpdateSmartStr,      rfc1867_name,    php_ps_globals, ps_globals)
                    749:        STD_PHP_INI_ENTRY("session.upload_progress.freq",  "1%", ZEND_INI_PERDIR, OnUpdateRfc1867Freq, rfc1867_freq,    php_ps_globals, ps_globals)
                    750:        STD_PHP_INI_ENTRY("session.upload_progress.min_freq",
                    751:                                                           "1",  ZEND_INI_PERDIR, OnUpdateReal,        rfc1867_min_freq,php_ps_globals, ps_globals)
                    752: 
1.1       misho     753:        /* Commented out until future discussion */
                    754:        /* PHP_INI_ENTRY("session.encode_sources", "globals,track", PHP_INI_ALL, NULL) */
                    755: PHP_INI_END()
                    756: /* }}} */
                    757: 
                    758: /* ***************
                    759:    * Serializers *
                    760:    *************** */
                    761: 
                    762: #define PS_BIN_NR_OF_BITS 8
                    763: #define PS_BIN_UNDEF (1<<(PS_BIN_NR_OF_BITS-1))
                    764: #define PS_BIN_MAX (PS_BIN_UNDEF-1)
                    765: 
                    766: PS_SERIALIZER_ENCODE_FUNC(php_binary) /* {{{ */
                    767: {
                    768:        smart_str buf = {0};
                    769:        php_serialize_data_t var_hash;
                    770:        PS_ENCODE_VARS;
                    771: 
                    772:        PHP_VAR_SERIALIZE_INIT(var_hash);
                    773: 
                    774:        PS_ENCODE_LOOP(
                    775:                        if (key_length > PS_BIN_MAX) continue;
                    776:                        smart_str_appendc(&buf, (unsigned char) key_length);
                    777:                        smart_str_appendl(&buf, key, key_length);
                    778:                        php_var_serialize(&buf, struc, &var_hash TSRMLS_CC);
                    779:                } else {
                    780:                        if (key_length > PS_BIN_MAX) continue;
                    781:                        smart_str_appendc(&buf, (unsigned char) (key_length & PS_BIN_UNDEF));
                    782:                        smart_str_appendl(&buf, key, key_length);
                    783:        );
                    784: 
                    785:        if (newlen) {
                    786:                *newlen = buf.len;
                    787:        }
                    788:        smart_str_0(&buf);
                    789:        *newstr = buf.c;
                    790:        PHP_VAR_SERIALIZE_DESTROY(var_hash);
                    791: 
                    792:        return SUCCESS;
                    793: }
                    794: /* }}} */
                    795: 
                    796: PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */
                    797: {
                    798:        const char *p;
                    799:        char *name;
                    800:        const char *endptr = val + vallen;
                    801:        zval *current;
                    802:        int namelen;
                    803:        int has_value;
                    804:        php_unserialize_data_t var_hash;
                    805: 
                    806:        PHP_VAR_UNSERIALIZE_INIT(var_hash);
                    807: 
                    808:        for (p = val; p < endptr; ) {
                    809:                zval **tmp;
                    810:                namelen = ((unsigned char)(*p)) & (~PS_BIN_UNDEF);
                    811: 
                    812:                if (namelen < 0 || namelen > PS_BIN_MAX || (p + namelen) >= endptr) {
                    813:                        return FAILURE;
                    814:                }
                    815: 
                    816:                has_value = *p & PS_BIN_UNDEF ? 0 : 1;
                    817: 
                    818:                name = estrndup(p + 1, namelen);
                    819: 
                    820:                p += namelen + 1;
                    821: 
                    822:                if (zend_hash_find(&EG(symbol_table), name, namelen + 1, (void **) &tmp) == SUCCESS) {
                    823:                        if ((Z_TYPE_PP(tmp) == IS_ARRAY && Z_ARRVAL_PP(tmp) == &EG(symbol_table)) || *tmp == PS(http_session_vars)) {
                    824:                                efree(name);
                    825:                                continue;
                    826:                        }
                    827:                }
                    828: 
                    829:                if (has_value) {
                    830:                        ALLOC_INIT_ZVAL(current);
                    831:                        if (php_var_unserialize(&current, (const unsigned char **) &p, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) {
                    832:                                php_set_session_var(name, namelen, current, &var_hash  TSRMLS_CC);
                    833:                        }
                    834:                        zval_ptr_dtor(&current);
                    835:                }
                    836:                PS_ADD_VARL(name, namelen);
                    837:                efree(name);
                    838:        }
                    839: 
                    840:        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
                    841: 
                    842:        return SUCCESS;
                    843: }
                    844: /* }}} */
                    845: 
                    846: #define PS_DELIMITER '|'
                    847: #define PS_UNDEF_MARKER '!'
                    848: 
                    849: PS_SERIALIZER_ENCODE_FUNC(php) /* {{{ */
                    850: {
                    851:        smart_str buf = {0};
                    852:        php_serialize_data_t var_hash;
                    853:        PS_ENCODE_VARS;
                    854: 
                    855:        PHP_VAR_SERIALIZE_INIT(var_hash);
                    856: 
                    857:        PS_ENCODE_LOOP(
                    858:                        smart_str_appendl(&buf, key, key_length);
                    859:                        if (memchr(key, PS_DELIMITER, key_length) || memchr(key, PS_UNDEF_MARKER, key_length)) {
                    860:                                PHP_VAR_SERIALIZE_DESTROY(var_hash);
                    861:                                smart_str_free(&buf);
                    862:                                return FAILURE;
                    863:                        }
                    864:                        smart_str_appendc(&buf, PS_DELIMITER);
                    865: 
                    866:                        php_var_serialize(&buf, struc, &var_hash TSRMLS_CC);
                    867:                } else {
                    868:                        smart_str_appendc(&buf, PS_UNDEF_MARKER);
                    869:                        smart_str_appendl(&buf, key, key_length);
                    870:                        smart_str_appendc(&buf, PS_DELIMITER);
                    871:        );
                    872: 
                    873:        if (newlen) {
                    874:                *newlen = buf.len;
                    875:        }
                    876:        smart_str_0(&buf);
                    877:        *newstr = buf.c;
                    878: 
                    879:        PHP_VAR_SERIALIZE_DESTROY(var_hash);
                    880:        return SUCCESS;
                    881: }
                    882: /* }}} */
                    883: 
                    884: PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */
                    885: {
                    886:        const char *p, *q;
                    887:        char *name;
                    888:        const char *endptr = val + vallen;
                    889:        zval *current;
                    890:        int namelen;
                    891:        int has_value;
                    892:        php_unserialize_data_t var_hash;
                    893: 
                    894:        PHP_VAR_UNSERIALIZE_INIT(var_hash);
                    895: 
                    896:        p = val;
                    897: 
                    898:        while (p < endptr) {
                    899:                zval **tmp;
                    900:                q = p;
                    901:                while (*q != PS_DELIMITER) {
                    902:                        if (++q >= endptr) goto break_outer_loop;
                    903:                }
                    904:                if (p[0] == PS_UNDEF_MARKER) {
                    905:                        p++;
                    906:                        has_value = 0;
                    907:                } else {
                    908:                        has_value = 1;
                    909:                }
                    910: 
                    911:                namelen = q - p;
                    912:                name = estrndup(p, namelen);
                    913:                q++;
                    914: 
                    915:                if (zend_hash_find(&EG(symbol_table), name, namelen + 1, (void **) &tmp) == SUCCESS) {
                    916:                        if ((Z_TYPE_PP(tmp) == IS_ARRAY && Z_ARRVAL_PP(tmp) == &EG(symbol_table)) || *tmp == PS(http_session_vars)) {
                    917:                                goto skip;
                    918:                        }
                    919:                }
                    920: 
                    921:                if (has_value) {
                    922:                        ALLOC_INIT_ZVAL(current);
                    923:                        if (php_var_unserialize(&current, (const unsigned char **) &q, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) {
                    924:                                php_set_session_var(name, namelen, current, &var_hash  TSRMLS_CC);
                    925:                        }
                    926:                        zval_ptr_dtor(&current);
                    927:                }
                    928:                PS_ADD_VARL(name, namelen);
                    929: skip:
                    930:                efree(name);
                    931: 
                    932:                p = q;
                    933:        }
                    934: break_outer_loop:
                    935: 
                    936:        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
                    937: 
                    938:        return SUCCESS;
                    939: }
                    940: /* }}} */
                    941: 
                    942: #define MAX_SERIALIZERS 10
                    943: #define PREDEFINED_SERIALIZERS 2
                    944: 
                    945: static ps_serializer ps_serializers[MAX_SERIALIZERS + 1] = {
                    946:        PS_SERIALIZER_ENTRY(php),
                    947:        PS_SERIALIZER_ENTRY(php_binary)
                    948: };
                    949: 
                    950: PHPAPI int php_session_register_serializer(const char *name, int (*encode)(PS_SERIALIZER_ENCODE_ARGS), int (*decode)(PS_SERIALIZER_DECODE_ARGS)) /* {{{ */
                    951: {
                    952:        int ret = -1;
                    953:        int i;
                    954: 
                    955:        for (i = 0; i < MAX_SERIALIZERS; i++) {
                    956:                if (ps_serializers[i].name == NULL) {
                    957:                        ps_serializers[i].name = name;
                    958:                        ps_serializers[i].encode = encode;
                    959:                        ps_serializers[i].decode = decode;
                    960:                        ps_serializers[i + 1].name = NULL;
                    961:                        ret = 0;
                    962:                        break;
                    963:                }
                    964:        }
                    965:        return ret;
                    966: }
                    967: /* }}} */
                    968: 
                    969: /* *******************
                    970:    * Storage Modules *
                    971:    ******************* */
                    972: 
                    973: #define MAX_MODULES 10
                    974: #define PREDEFINED_MODULES 2
                    975: 
                    976: static ps_module *ps_modules[MAX_MODULES + 1] = {
                    977:        ps_files_ptr,
                    978:        ps_user_ptr
                    979: };
                    980: 
                    981: PHPAPI int php_session_register_module(ps_module *ptr) /* {{{ */
                    982: {
                    983:        int ret = -1;
                    984:        int i;
                    985: 
                    986:        for (i = 0; i < MAX_MODULES; i++) {
                    987:                if (!ps_modules[i]) {
                    988:                        ps_modules[i] = ptr;
                    989:                        ret = 0;
                    990:                        break;
                    991:                }
                    992:        }
                    993:        return ret;
                    994: }
                    995: /* }}} */
                    996: 
                    997: /* ******************
                    998:    * Cache Limiters *
                    999:    ****************** */
                   1000: 
                   1001: typedef struct {
                   1002:        char *name;
                   1003:        void (*func)(TSRMLS_D);
                   1004: } php_session_cache_limiter_t;
                   1005: 
                   1006: #define CACHE_LIMITER(name) _php_cache_limiter_##name
                   1007: #define CACHE_LIMITER_FUNC(name) static void CACHE_LIMITER(name)(TSRMLS_D)
                   1008: #define CACHE_LIMITER_ENTRY(name) { #name, CACHE_LIMITER(name) },
                   1009: #define ADD_HEADER(a) sapi_add_header(a, strlen(a), 1);
                   1010: #define MAX_STR 512
                   1011: 
                   1012: static char *month_names[] = {
                   1013:        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                   1014:        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
                   1015: };
                   1016: 
                   1017: static char *week_days[] = {
                   1018:        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
                   1019: };
                   1020: 
                   1021: static inline void strcpy_gmt(char *ubuf, time_t *when) /* {{{ */
                   1022: {
                   1023:        char buf[MAX_STR];
                   1024:        struct tm tm, *res;
                   1025:        int n;
                   1026: 
                   1027:        res = php_gmtime_r(when, &tm);
                   1028: 
                   1029:        if (!res) {
                   1030:                buf[0] = '\0';
                   1031:                return;
                   1032:        }
                   1033: 
                   1034:        n = slprintf(buf, sizeof(buf), "%s, %02d %s %d %02d:%02d:%02d GMT", /* SAFE */
                   1035:                                week_days[tm.tm_wday], tm.tm_mday,
                   1036:                                month_names[tm.tm_mon], tm.tm_year + 1900,
                   1037:                                tm.tm_hour, tm.tm_min,
                   1038:                                tm.tm_sec);
                   1039:        memcpy(ubuf, buf, n);
                   1040:        ubuf[n] = '\0';
                   1041: }
                   1042: /* }}} */
                   1043: 
                   1044: static inline void last_modified(TSRMLS_D) /* {{{ */
                   1045: {
                   1046:        const char *path;
                   1047:        struct stat sb;
                   1048:        char buf[MAX_STR + 1];
                   1049: 
                   1050:        path = SG(request_info).path_translated;
                   1051:        if (path) {
                   1052:                if (VCWD_STAT(path, &sb) == -1) {
                   1053:                        return;
                   1054:                }
                   1055: 
                   1056: #define LAST_MODIFIED "Last-Modified: "
                   1057:                memcpy(buf, LAST_MODIFIED, sizeof(LAST_MODIFIED) - 1);
                   1058:                strcpy_gmt(buf + sizeof(LAST_MODIFIED) - 1, &sb.st_mtime);
                   1059:                ADD_HEADER(buf);
                   1060:        }
                   1061: }
                   1062: /* }}} */
                   1063: 
                   1064: #define EXPIRES "Expires: "
                   1065: CACHE_LIMITER_FUNC(public) /* {{{ */
                   1066: {
                   1067:        char buf[MAX_STR + 1];
                   1068:        struct timeval tv;
                   1069:        time_t now;
                   1070: 
                   1071:        gettimeofday(&tv, NULL);
                   1072:        now = tv.tv_sec + PS(cache_expire) * 60;
                   1073:        memcpy(buf, EXPIRES, sizeof(EXPIRES) - 1);
                   1074:        strcpy_gmt(buf + sizeof(EXPIRES) - 1, &now);
                   1075:        ADD_HEADER(buf);
                   1076: 
                   1077:        snprintf(buf, sizeof(buf) , "Cache-Control: public, max-age=%ld", PS(cache_expire) * 60); /* SAFE */
                   1078:        ADD_HEADER(buf);
                   1079: 
                   1080:        last_modified(TSRMLS_C);
                   1081: }
                   1082: /* }}} */
                   1083: 
                   1084: CACHE_LIMITER_FUNC(private_no_expire) /* {{{ */
                   1085: {
                   1086:        char buf[MAX_STR + 1];
                   1087: 
                   1088:        snprintf(buf, sizeof(buf), "Cache-Control: private, max-age=%ld, pre-check=%ld", PS(cache_expire) * 60, PS(cache_expire) * 60); /* SAFE */
                   1089:        ADD_HEADER(buf);
                   1090: 
                   1091:        last_modified(TSRMLS_C);
                   1092: }
                   1093: /* }}} */
                   1094: 
                   1095: CACHE_LIMITER_FUNC(private) /* {{{ */
                   1096: {
                   1097:        ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT");
                   1098:        CACHE_LIMITER(private_no_expire)(TSRMLS_C);
                   1099: }
                   1100: /* }}} */
                   1101: 
                   1102: CACHE_LIMITER_FUNC(nocache) /* {{{ */
                   1103: {
                   1104:        ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT");
                   1105: 
                   1106:        /* For HTTP/1.1 conforming clients and the rest (MSIE 5) */
                   1107:        ADD_HEADER("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
                   1108: 
                   1109:        /* For HTTP/1.0 conforming clients */
                   1110:        ADD_HEADER("Pragma: no-cache");
                   1111: }
                   1112: /* }}} */
                   1113: 
                   1114: static php_session_cache_limiter_t php_session_cache_limiters[] = {
                   1115:        CACHE_LIMITER_ENTRY(public)
                   1116:        CACHE_LIMITER_ENTRY(private)
                   1117:        CACHE_LIMITER_ENTRY(private_no_expire)
                   1118:        CACHE_LIMITER_ENTRY(nocache)
                   1119:        {0}
                   1120: };
                   1121: 
                   1122: static int php_session_cache_limiter(TSRMLS_D) /* {{{ */
                   1123: {
                   1124:        php_session_cache_limiter_t *lim;
                   1125: 
                   1126:        if (PS(cache_limiter)[0] == '\0') return 0;
                   1127: 
                   1128:        if (SG(headers_sent)) {
1.1.1.2   misho    1129:                const char *output_start_filename = php_output_get_start_filename(TSRMLS_C);
                   1130:                int output_start_lineno = php_output_get_start_lineno(TSRMLS_C);
1.1       misho    1131: 
                   1132:                if (output_start_filename) {
                   1133:                        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);
                   1134:                } else {
                   1135:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot send session cache limiter - headers already sent");
                   1136:                }
                   1137:                return -2;
                   1138:        }
                   1139: 
                   1140:        for (lim = php_session_cache_limiters; lim->name; lim++) {
                   1141:                if (!strcasecmp(lim->name, PS(cache_limiter))) {
                   1142:                        lim->func(TSRMLS_C);
                   1143:                        return 0;
                   1144:                }
                   1145:        }
                   1146: 
                   1147:        return -1;
                   1148: }
                   1149: /* }}} */
                   1150: 
                   1151: /* *********************
                   1152:    * Cookie Management *
                   1153:    ********************* */
                   1154: 
                   1155: #define COOKIE_SET_COOKIE "Set-Cookie: "
                   1156: #define COOKIE_EXPIRES "; expires="
                   1157: #define COOKIE_PATH            "; path="
                   1158: #define COOKIE_DOMAIN  "; domain="
                   1159: #define COOKIE_SECURE  "; secure"
                   1160: #define COOKIE_HTTPONLY        "; HttpOnly"
                   1161: 
                   1162: static void php_session_send_cookie(TSRMLS_D) /* {{{ */
                   1163: {
                   1164:        smart_str ncookie = {0};
                   1165:        char *date_fmt = NULL;
                   1166:        char *e_session_name, *e_id;
                   1167: 
                   1168:        if (SG(headers_sent)) {
1.1.1.2   misho    1169:                const char *output_start_filename = php_output_get_start_filename(TSRMLS_C);
                   1170:                int output_start_lineno = php_output_get_start_lineno(TSRMLS_C);
1.1       misho    1171: 
                   1172:                if (output_start_filename) {
                   1173:                        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);
                   1174:                } else {
                   1175:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot send session cookie - headers already sent");
                   1176:                }
                   1177:                return;
                   1178:        }
                   1179: 
                   1180:        /* URL encode session_name and id because they might be user supplied */
                   1181:        e_session_name = php_url_encode(PS(session_name), strlen(PS(session_name)), NULL);
                   1182:        e_id = php_url_encode(PS(id), strlen(PS(id)), NULL);
                   1183: 
                   1184:        smart_str_appends(&ncookie, COOKIE_SET_COOKIE);
                   1185:        smart_str_appends(&ncookie, e_session_name);
                   1186:        smart_str_appendc(&ncookie, '=');
                   1187:        smart_str_appends(&ncookie, e_id);
                   1188: 
                   1189:        efree(e_session_name);
                   1190:        efree(e_id);
                   1191: 
                   1192:        if (PS(cookie_lifetime) > 0) {
                   1193:                struct timeval tv;
                   1194:                time_t t;
                   1195: 
                   1196:                gettimeofday(&tv, NULL);
                   1197:                t = tv.tv_sec + PS(cookie_lifetime);
                   1198: 
                   1199:                if (t > 0) {
                   1200:                        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);
                   1201:                        smart_str_appends(&ncookie, COOKIE_EXPIRES);
                   1202:                        smart_str_appends(&ncookie, date_fmt);
                   1203:                        efree(date_fmt);
                   1204:                }
                   1205:        }
                   1206: 
                   1207:        if (PS(cookie_path)[0]) {
                   1208:                smart_str_appends(&ncookie, COOKIE_PATH);
                   1209:                smart_str_appends(&ncookie, PS(cookie_path));
                   1210:        }
                   1211: 
                   1212:        if (PS(cookie_domain)[0]) {
                   1213:                smart_str_appends(&ncookie, COOKIE_DOMAIN);
                   1214:                smart_str_appends(&ncookie, PS(cookie_domain));
                   1215:        }
                   1216: 
                   1217:        if (PS(cookie_secure)) {
                   1218:                smart_str_appends(&ncookie, COOKIE_SECURE);
                   1219:        }
                   1220: 
                   1221:        if (PS(cookie_httponly)) {
                   1222:                smart_str_appends(&ncookie, COOKIE_HTTPONLY);
                   1223:        }
                   1224: 
                   1225:        smart_str_0(&ncookie);
                   1226: 
                   1227:        /*      'replace' must be 0 here, else a previous Set-Cookie
                   1228:                header, probably sent with setcookie() will be replaced! */
                   1229:        sapi_add_header_ex(ncookie.c, ncookie.len, 0, 0 TSRMLS_CC);
                   1230: }
                   1231: /* }}} */
                   1232: 
                   1233: PHPAPI ps_module *_php_find_ps_module(char *name TSRMLS_DC) /* {{{ */
                   1234: {
                   1235:        ps_module *ret = NULL;
                   1236:        ps_module **mod;
                   1237:        int i;
                   1238: 
                   1239:        for (i = 0, mod = ps_modules; i < MAX_MODULES; i++, mod++) {
                   1240:                if (*mod && !strcasecmp(name, (*mod)->s_name)) {
                   1241:                        ret = *mod;
                   1242:                        break;
                   1243:                }
                   1244:        }
                   1245:        return ret;
                   1246: }
                   1247: /* }}} */
                   1248: 
                   1249: PHPAPI const ps_serializer *_php_find_ps_serializer(char *name TSRMLS_DC) /* {{{ */
                   1250: {
                   1251:        const ps_serializer *ret = NULL;
                   1252:        const ps_serializer *mod;
                   1253: 
                   1254:        for (mod = ps_serializers; mod->name; mod++) {
                   1255:                if (!strcasecmp(name, mod->name)) {
                   1256:                        ret = mod;
                   1257:                        break;
                   1258:                }
                   1259:        }
                   1260:        return ret;
                   1261: }
                   1262: /* }}} */
                   1263: 
                   1264: #define PPID2SID \
                   1265:                convert_to_string((*ppid)); \
                   1266:                PS(id) = estrndup(Z_STRVAL_PP(ppid), Z_STRLEN_PP(ppid))
                   1267: 
                   1268: static void php_session_reset_id(TSRMLS_D) /* {{{ */
                   1269: {
                   1270:        int module_number = PS(module_number);
                   1271: 
                   1272:        if (PS(use_cookies) && PS(send_cookie)) {
                   1273:                php_session_send_cookie(TSRMLS_C);
                   1274:                PS(send_cookie) = 0;
                   1275:        }
                   1276: 
                   1277:        /* if the SID constant exists, destroy it. */
                   1278:        zend_hash_del(EG(zend_constants), "sid", sizeof("sid"));
                   1279: 
                   1280:        if (PS(define_sid)) {
                   1281:                smart_str var = {0};
                   1282: 
                   1283:                smart_str_appends(&var, PS(session_name));
                   1284:                smart_str_appendc(&var, '=');
                   1285:                smart_str_appends(&var, PS(id));
                   1286:                smart_str_0(&var);
                   1287:                REGISTER_STRINGL_CONSTANT("SID", var.c, var.len, 0);
                   1288:        } else {
                   1289:                REGISTER_STRINGL_CONSTANT("SID", STR_EMPTY_ALLOC(), 0, 0);
                   1290:        }
                   1291: 
                   1292:        if (PS(apply_trans_sid)) {
                   1293:                php_url_scanner_reset_vars(TSRMLS_C);
                   1294:                php_url_scanner_add_var(PS(session_name), strlen(PS(session_name)), PS(id), strlen(PS(id)), 1 TSRMLS_CC);
                   1295:        }
                   1296: }
                   1297: /* }}} */
                   1298: 
                   1299: PHPAPI void php_session_start(TSRMLS_D) /* {{{ */
                   1300: {
                   1301:        zval **ppid;
                   1302:        zval **data;
                   1303:        char *p, *value;
                   1304:        int nrand;
                   1305:        int lensess;
                   1306: 
                   1307:        if (PS(use_only_cookies)) {
                   1308:                PS(apply_trans_sid) = 0;
                   1309:        } else {
                   1310:                PS(apply_trans_sid) = PS(use_trans_sid);
                   1311:        }
                   1312: 
                   1313:        switch (PS(session_status)) {
                   1314:                case php_session_active:
                   1315:                        php_error(E_NOTICE, "A session had already been started - ignoring session_start()");
                   1316:                        return;
                   1317:                        break;
                   1318: 
                   1319:                case php_session_disabled:
                   1320:                        value = zend_ini_string("session.save_handler", sizeof("session.save_handler"), 0);
                   1321:                        if (!PS(mod) && value) {
                   1322:                                PS(mod) = _php_find_ps_module(value TSRMLS_CC);
                   1323:                                if (!PS(mod)) {
                   1324:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot find save handler '%s' - session startup failed", value);
                   1325:                                        return;
                   1326:                                }
                   1327:                        }
                   1328:                        value = zend_ini_string("session.serialize_handler", sizeof("session.serialize_handler"), 0);
                   1329:                        if (!PS(serializer) && value) {
                   1330:                                PS(serializer) = _php_find_ps_serializer(value TSRMLS_CC);
                   1331:                                if (!PS(serializer)) {
                   1332:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot find serialization handler '%s' - session startup failed", value);
                   1333:                                        return;
                   1334:                                }
                   1335:                        }
                   1336:                        PS(session_status) = php_session_none;
                   1337:                        /* fallthrough */
                   1338: 
                   1339:                default:
                   1340:                case php_session_none:
                   1341:                        PS(define_sid) = 1;
                   1342:                        PS(send_cookie) = 1;
                   1343:        }
                   1344: 
                   1345:        lensess = strlen(PS(session_name));
                   1346: 
                   1347:        /* Cookies are preferred, because initially
                   1348:         * cookie and get variables will be available. */
                   1349: 
                   1350:        if (!PS(id)) {
                   1351:                if (PS(use_cookies) && zend_hash_find(&EG(symbol_table), "_COOKIE", sizeof("_COOKIE"), (void **) &data) == SUCCESS &&
                   1352:                                Z_TYPE_PP(data) == IS_ARRAY &&
                   1353:                                zend_hash_find(Z_ARRVAL_PP(data), PS(session_name), lensess + 1, (void **) &ppid) == SUCCESS
                   1354:                ) {
                   1355:                        PPID2SID;
                   1356:                        PS(apply_trans_sid) = 0;
                   1357:                        PS(send_cookie) = 0;
                   1358:                        PS(define_sid) = 0;
                   1359:                }
                   1360: 
                   1361:                if (!PS(use_only_cookies) && !PS(id) &&
                   1362:                                zend_hash_find(&EG(symbol_table), "_GET", sizeof("_GET"), (void **) &data) == SUCCESS &&
                   1363:                                Z_TYPE_PP(data) == IS_ARRAY &&
                   1364:                                zend_hash_find(Z_ARRVAL_PP(data), PS(session_name), lensess + 1, (void **) &ppid) == SUCCESS
                   1365:                ) {
                   1366:                        PPID2SID;
                   1367:                        PS(send_cookie) = 0;
                   1368:                }
                   1369: 
                   1370:                if (!PS(use_only_cookies) && !PS(id) &&
                   1371:                                zend_hash_find(&EG(symbol_table), "_POST", sizeof("_POST"), (void **) &data) == SUCCESS &&
                   1372:                                Z_TYPE_PP(data) == IS_ARRAY &&
                   1373:                                zend_hash_find(Z_ARRVAL_PP(data), PS(session_name), lensess + 1, (void **) &ppid) == SUCCESS
                   1374:                ) {
                   1375:                        PPID2SID;
                   1376:                        PS(send_cookie) = 0;
                   1377:                }
                   1378:        }
                   1379: 
                   1380:        /* Check the REQUEST_URI symbol for a string of the form
                   1381:         * '<session-name>=<session-id>' to allow URLs of the form
                   1382:         * http://yoursite/<session-name>=<session-id>/script.php */
                   1383: 
                   1384:        if (!PS(use_only_cookies) && !PS(id) && PG(http_globals)[TRACK_VARS_SERVER] &&
                   1385:                        zend_hash_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), "REQUEST_URI", sizeof("REQUEST_URI"), (void **) &data) == SUCCESS &&
                   1386:                        Z_TYPE_PP(data) == IS_STRING &&
                   1387:                        (p = strstr(Z_STRVAL_PP(data), PS(session_name))) &&
                   1388:                        p[lensess] == '='
                   1389:        ) {
                   1390:                char *q;
                   1391: 
                   1392:                p += lensess + 1;
                   1393:                if ((q = strpbrk(p, "/?\\"))) {
                   1394:                        PS(id) = estrndup(p, q - p);
                   1395:                        PS(send_cookie) = 0;
                   1396:                }
                   1397:        }
                   1398: 
                   1399:        /* Check whether the current request was referred to by
                   1400:         * an external site which invalidates the previously found id. */
                   1401: 
                   1402:        if (PS(id) &&
                   1403:                        PS(extern_referer_chk)[0] != '\0' &&
                   1404:                        PG(http_globals)[TRACK_VARS_SERVER] &&
                   1405:                        zend_hash_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_REFERER", sizeof("HTTP_REFERER"), (void **) &data) == SUCCESS &&
                   1406:                        Z_TYPE_PP(data) == IS_STRING &&
                   1407:                        Z_STRLEN_PP(data) != 0 &&
                   1408:                        strstr(Z_STRVAL_PP(data), PS(extern_referer_chk)) == NULL
                   1409:        ) {
                   1410:                efree(PS(id));
                   1411:                PS(id) = NULL;
                   1412:                PS(send_cookie) = 1;
                   1413:                if (PS(use_trans_sid) && !PS(use_only_cookies)) {
                   1414:                        PS(apply_trans_sid) = 1;
                   1415:                }
                   1416:        }
                   1417: 
                   1418:        php_session_initialize(TSRMLS_C);
                   1419: 
                   1420:        if (!PS(use_cookies) && PS(send_cookie)) {
                   1421:                if (PS(use_trans_sid) && !PS(use_only_cookies)) {
                   1422:                        PS(apply_trans_sid) = 1;
                   1423:                }
                   1424:                PS(send_cookie) = 0;
                   1425:        }
                   1426: 
                   1427:        php_session_reset_id(TSRMLS_C);
                   1428: 
                   1429:        PS(session_status) = php_session_active;
                   1430: 
                   1431:        php_session_cache_limiter(TSRMLS_C);
                   1432: 
1.1.1.2   misho    1433:        if ((PS(mod_data) || PS(mod_user_implemented)) && PS(gc_probability) > 0) {
1.1       misho    1434:                int nrdels = -1;
                   1435: 
                   1436:                nrand = (int) ((float) PS(gc_divisor) * php_combined_lcg(TSRMLS_C));
                   1437:                if (nrand < PS(gc_probability)) {
                   1438:                        PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &nrdels TSRMLS_CC);
                   1439: #ifdef SESSION_DEBUG
                   1440:                        if (nrdels != -1) {
                   1441:                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "purged %d expired session objects", nrdels);
                   1442:                        }
                   1443: #endif
                   1444:                }
                   1445:        }
                   1446: }
                   1447: /* }}} */
                   1448: 
                   1449: static void php_session_flush(TSRMLS_D) /* {{{ */
                   1450: {
                   1451:        if (PS(session_status) == php_session_active) {
                   1452:                PS(session_status) = php_session_none;
1.1.1.2   misho    1453:                php_session_save_current_state(TSRMLS_C);
1.1       misho    1454:        }
                   1455: }
                   1456: /* }}} */
                   1457: 
                   1458: PHPAPI void session_adapt_url(const char *url, size_t urllen, char **new, size_t *newlen TSRMLS_DC) /* {{{ */
                   1459: {
                   1460:        if (PS(apply_trans_sid) && (PS(session_status) == php_session_active)) {
                   1461:                *new = php_url_scanner_adapt_single_url(url, urllen, PS(session_name), PS(id), newlen TSRMLS_CC);
                   1462:        }
                   1463: }
                   1464: /* }}} */
                   1465: 
                   1466: /* ********************************
                   1467:    * Userspace exported functions *
                   1468:    ******************************** */
                   1469: 
                   1470: /* {{{ proto void session_set_cookie_params(int lifetime [, string path [, string domain [, bool secure[, bool httponly]]]])
                   1471:    Set session cookie parameters */
                   1472: static PHP_FUNCTION(session_set_cookie_params)
                   1473: {
                   1474:        zval **lifetime = NULL;
                   1475:        char *path = NULL, *domain = NULL;
                   1476:        int path_len, domain_len, argc = ZEND_NUM_ARGS();
                   1477:        zend_bool secure = 0, httponly = 0;
                   1478: 
                   1479:        if (!PS(use_cookies) ||
                   1480:                zend_parse_parameters(argc TSRMLS_CC, "Z|ssbb", &lifetime, &path, &path_len, &domain, &domain_len, &secure, &httponly) == FAILURE) {
                   1481:                return;
                   1482:        }
                   1483: 
                   1484:        convert_to_string_ex(lifetime);
                   1485: 
                   1486:        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);
                   1487: 
                   1488:        if (path) {
                   1489:                zend_alter_ini_entry("session.cookie_path", sizeof("session.cookie_path"), path, path_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
                   1490:        }
                   1491:        if (domain) {
                   1492:                zend_alter_ini_entry("session.cookie_domain", sizeof("session.cookie_domain"), domain, domain_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
                   1493:        }
                   1494: 
                   1495:        if (argc > 3) {
                   1496:                zend_alter_ini_entry("session.cookie_secure", sizeof("session.cookie_secure"), secure ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
                   1497:        }
                   1498:        if (argc > 4) {
                   1499:                zend_alter_ini_entry("session.cookie_httponly", sizeof("session.cookie_httponly"), httponly ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
                   1500:        }
                   1501: }
                   1502: /* }}} */
                   1503: 
                   1504: /* {{{ proto array session_get_cookie_params(void)
                   1505:    Return the session cookie parameters */
                   1506: static PHP_FUNCTION(session_get_cookie_params)
                   1507: {
                   1508:        if (zend_parse_parameters_none() == FAILURE) {
                   1509:                return;
                   1510:        }
                   1511: 
                   1512:        array_init(return_value);
                   1513: 
                   1514:        add_assoc_long(return_value, "lifetime", PS(cookie_lifetime));
                   1515:        add_assoc_string(return_value, "path", PS(cookie_path), 1);
                   1516:        add_assoc_string(return_value, "domain", PS(cookie_domain), 1);
                   1517:        add_assoc_bool(return_value, "secure", PS(cookie_secure));
                   1518:        add_assoc_bool(return_value, "httponly", PS(cookie_httponly));
                   1519: }
                   1520: /* }}} */
                   1521: 
                   1522: /* {{{ proto string session_name([string newname])
                   1523:    Return the current session name. If newname is given, the session name is replaced with newname */
                   1524: static PHP_FUNCTION(session_name)
                   1525: {
                   1526:        char *name = NULL;
                   1527:        int name_len;
                   1528: 
                   1529:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {
                   1530:                return;
                   1531:        }
                   1532: 
                   1533:        RETVAL_STRING(PS(session_name), 1);
                   1534: 
                   1535:        if (name) {
                   1536:                zend_alter_ini_entry("session.name", sizeof("session.name"), name, name_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
                   1537:        }
                   1538: }
                   1539: /* }}} */
                   1540: 
                   1541: /* {{{ proto string session_module_name([string newname])
                   1542:    Return the current module name used for accessing session data. If newname is given, the module name is replaced with newname */
                   1543: static PHP_FUNCTION(session_module_name)
                   1544: {
                   1545:        char *name = NULL;
                   1546:        int name_len;
                   1547: 
                   1548:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {
                   1549:                return;
                   1550:        }
                   1551: 
                   1552:        /* Set return_value to current module name */
                   1553:        if (PS(mod) && PS(mod)->s_name) {
                   1554:                RETVAL_STRING(safe_estrdup(PS(mod)->s_name), 0);
                   1555:        } else {
                   1556:                RETVAL_EMPTY_STRING();
                   1557:        }
                   1558: 
                   1559:        if (name) {
                   1560:                if (!_php_find_ps_module(name TSRMLS_CC)) {
                   1561:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot find named PHP session module (%s)", name);
                   1562: 
                   1563:                        zval_dtor(return_value);
                   1564:                        RETURN_FALSE;
                   1565:                }
1.1.1.2   misho    1566:                if (PS(mod_data) || PS(mod_user_implemented)) {
1.1       misho    1567:                        PS(mod)->s_close(&PS(mod_data) TSRMLS_CC);
                   1568:                }
                   1569:                PS(mod_data) = NULL;
                   1570: 
                   1571:                zend_alter_ini_entry("session.save_handler", sizeof("session.save_handler"), name, name_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
                   1572:        }
                   1573: }
                   1574: /* }}} */
                   1575: 
                   1576: /* {{{ proto void session_set_save_handler(string open, string close, string read, string write, string destroy, string gc)
                   1577:    Sets user-level functions */
                   1578: static PHP_FUNCTION(session_set_save_handler)
                   1579: {
                   1580:        zval ***args = NULL;
                   1581:        int i, num_args, argc = ZEND_NUM_ARGS();
                   1582:        char *name;
                   1583: 
                   1584:        if (PS(session_status) != php_session_none) {
                   1585:                RETURN_FALSE;
                   1586:        }
                   1587: 
1.1.1.2   misho    1588:        if (argc != 1 && argc != 2 && argc != 6) {
1.1       misho    1589:                WRONG_PARAM_COUNT;
                   1590:        }
                   1591: 
1.1.1.2   misho    1592:        if (argc <= 2) {
                   1593:                zval *obj = NULL, *callback = NULL;
                   1594:                zend_uint func_name_len;
                   1595:                char *func_name;
                   1596:                HashPosition pos;
                   1597:                zend_function *default_mptr, *current_mptr;
                   1598:                ulong func_index;
                   1599:                php_shutdown_function_entry shutdown_function_entry;
                   1600:                zend_bool register_shutdown = 1;
                   1601: 
                   1602:                if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &obj, php_session_iface_entry, &register_shutdown) == FAILURE) {
                   1603:                        RETURN_FALSE;
                   1604:                }
                   1605: 
                   1606:                /* Find implemented methods */
                   1607:                zend_hash_internal_pointer_reset_ex(&php_session_class_entry->function_table, &pos);
                   1608:                i = 0;
                   1609:                while (zend_hash_get_current_data_ex(&php_session_class_entry->function_table, (void **) &default_mptr, &pos) == SUCCESS) {
                   1610:                        zend_hash_get_current_key_ex(&php_session_class_entry->function_table, &func_name, &func_name_len, &func_index, 0, &pos);
                   1611: 
                   1612:                        if (zend_hash_find(&Z_OBJCE_P(obj)->function_table, func_name, func_name_len, (void **)&current_mptr) == SUCCESS) {
                   1613:                                if (PS(mod_user_names).names[i] != NULL) {
                   1614:                                        zval_ptr_dtor(&PS(mod_user_names).names[i]);
                   1615:                                }
                   1616: 
                   1617:                                MAKE_STD_ZVAL(callback);
                   1618:                                array_init_size(callback, 2);
                   1619:                                Z_ADDREF_P(obj);
                   1620:                                add_next_index_zval(callback, obj);
                   1621:                                add_next_index_stringl(callback, func_name, func_name_len - 1, 1);
                   1622:                                PS(mod_user_names).names[i] = callback;
                   1623:                        } else {
                   1624:                                php_error_docref(NULL TSRMLS_CC, E_ERROR, "Session handler's function table is corrupt");
                   1625:                                RETURN_FALSE;
                   1626:                        }
                   1627: 
                   1628:                        zend_hash_move_forward_ex(&php_session_class_entry->function_table, &pos);
                   1629:                        ++i;
                   1630:                }
                   1631: 
                   1632:                if (register_shutdown) {
                   1633:                        /* create shutdown function */
                   1634:                        shutdown_function_entry.arg_count = 1;
                   1635:                        shutdown_function_entry.arguments = (zval **) safe_emalloc(sizeof(zval *), 1, 0);
                   1636: 
                   1637:                        MAKE_STD_ZVAL(callback);
                   1638:                        ZVAL_STRING(callback, "session_register_shutdown", 1);
                   1639:                        shutdown_function_entry.arguments[0] = callback;
                   1640: 
                   1641:                        /* add shutdown function, removing the old one if it exists */
                   1642:                        if (!register_user_shutdown_function("session_shutdown", sizeof("session_shutdown"), &shutdown_function_entry TSRMLS_CC)) {
                   1643:                                zval_ptr_dtor(&callback);
                   1644:                                efree(shutdown_function_entry.arguments);
                   1645:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to register session shutdown function");
                   1646:                                RETURN_FALSE;
                   1647:                        }
                   1648:                } else {
                   1649:                        /* remove shutdown function */
                   1650:                        remove_user_shutdown_function("session_shutdown", sizeof("session_shutdown") TSRMLS_CC);
                   1651:                }
                   1652: 
                   1653:                if (PS(mod) && PS(session_status) == php_session_none && PS(mod) != &ps_mod_user) {
                   1654:                        zend_alter_ini_entry("session.save_handler", sizeof("session.save_handler"), "user", sizeof("user")-1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
                   1655:                }
                   1656: 
                   1657:                RETURN_TRUE;
                   1658:        }
                   1659: 
1.1       misho    1660:        if (zend_parse_parameters(argc TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
                   1661:                return;
                   1662:        }
                   1663: 
1.1.1.2   misho    1664:        /* remove shutdown function */
                   1665:        remove_user_shutdown_function("session_shutdown", sizeof("session_shutdown") TSRMLS_CC);
                   1666: 
1.1       misho    1667:        for (i = 0; i < 6; i++) {
                   1668:                if (!zend_is_callable(*args[i], 0, &name TSRMLS_CC)) {
                   1669:                        efree(args);
                   1670:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument %d is not a valid callback", i+1);
                   1671:                        efree(name);
                   1672:                        RETURN_FALSE;
                   1673:                }
                   1674:                efree(name);
                   1675:        }
1.1.1.2   misho    1676:        
                   1677:        if (PS(mod) && PS(mod) != &ps_mod_user) {
                   1678:                zend_alter_ini_entry("session.save_handler", sizeof("session.save_handler"), "user", sizeof("user")-1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
                   1679:        }
1.1       misho    1680: 
                   1681:        for (i = 0; i < 6; i++) {
                   1682:                if (PS(mod_user_names).names[i] != NULL) {
                   1683:                        zval_ptr_dtor(&PS(mod_user_names).names[i]);
                   1684:                }
                   1685:                Z_ADDREF_PP(args[i]);
                   1686:                PS(mod_user_names).names[i] = *args[i];
                   1687:        }
                   1688: 
                   1689:        efree(args);
                   1690:        RETURN_TRUE;
                   1691: }
                   1692: /* }}} */
                   1693: 
                   1694: /* {{{ proto string session_save_path([string newname])
                   1695:    Return the current save path passed to module_name. If newname is given, the save path is replaced with newname */
                   1696: static PHP_FUNCTION(session_save_path)
                   1697: {
                   1698:        char *name = NULL;
                   1699:        int name_len;
                   1700: 
                   1701:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {
                   1702:                return;
                   1703:        }
                   1704: 
                   1705:        RETVAL_STRING(PS(save_path), 1);
                   1706: 
                   1707:        if (name) {
                   1708:                if (memchr(name, '\0', name_len) != NULL) {
                   1709:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "The save_path cannot contain NULL characters");
                   1710:                        zval_dtor(return_value);
                   1711:                        RETURN_FALSE;
                   1712:                }
                   1713:                zend_alter_ini_entry("session.save_path", sizeof("session.save_path"), name, name_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
                   1714:        }
                   1715: }
                   1716: /* }}} */
                   1717: 
                   1718: /* {{{ proto string session_id([string newid])
                   1719:    Return the current session id. If newid is given, the session id is replaced with newid */
                   1720: static PHP_FUNCTION(session_id)
                   1721: {
                   1722:        char *name = NULL;
                   1723:        int name_len;
                   1724: 
                   1725:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {
                   1726:                return;
                   1727:        }
                   1728: 
                   1729:        if (PS(id)) {
                   1730:                RETVAL_STRING(PS(id), 1);
                   1731:        } else {
                   1732:                RETVAL_EMPTY_STRING();
                   1733:        }
                   1734: 
                   1735:        if (name) {
                   1736:                if (PS(id)) {
                   1737:                        efree(PS(id));
                   1738:                }
                   1739:                PS(id) = estrndup(name, name_len);
                   1740:        }
                   1741: }
                   1742: /* }}} */
                   1743: 
                   1744: /* {{{ proto bool session_regenerate_id([bool delete_old_session])
                   1745:    Update the current session id with a newly generated one. If delete_old_session is set to true, remove the old session. */
                   1746: static PHP_FUNCTION(session_regenerate_id)
                   1747: {
                   1748:        zend_bool del_ses = 0;
                   1749: 
                   1750:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &del_ses) == FAILURE) {
                   1751:                return;
                   1752:        }
                   1753: 
                   1754:        if (SG(headers_sent) && PS(use_cookies)) {
                   1755:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot regenerate session id - headers already sent");
                   1756:                RETURN_FALSE;
                   1757:        }
                   1758: 
                   1759:        if (PS(session_status) == php_session_active) {
                   1760:                if (PS(id)) {
                   1761:                        if (del_ses && PS(mod)->s_destroy(&PS(mod_data), PS(id) TSRMLS_CC) == FAILURE) {
                   1762:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session object destruction failed");
                   1763:                                RETURN_FALSE;
                   1764:                        }
                   1765:                        efree(PS(id));
                   1766:                        PS(id) = NULL;
                   1767:                }
                   1768: 
                   1769:                PS(id) = PS(mod)->s_create_sid(&PS(mod_data), NULL TSRMLS_CC);
                   1770: 
                   1771:                PS(send_cookie) = 1;
                   1772:                php_session_reset_id(TSRMLS_C);
                   1773: 
                   1774:                RETURN_TRUE;
                   1775:        }
                   1776:        RETURN_FALSE;
                   1777: }
                   1778: /* }}} */
                   1779: 
                   1780: /* {{{ proto string session_cache_limiter([string new_cache_limiter])
                   1781:    Return the current cache limiter. If new_cache_limited is given, the current cache_limiter is replaced with new_cache_limiter */
                   1782: static PHP_FUNCTION(session_cache_limiter)
                   1783: {
                   1784:        char *limiter = NULL;
                   1785:        int limiter_len;
                   1786: 
                   1787:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &limiter, &limiter_len) == FAILURE) {
                   1788:                return;
                   1789:        }
                   1790: 
                   1791:        RETVAL_STRING(PS(cache_limiter), 1);
                   1792: 
                   1793:        if (limiter) {
                   1794:                zend_alter_ini_entry("session.cache_limiter", sizeof("session.cache_limiter"), limiter, limiter_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
                   1795:        }
                   1796: }
                   1797: /* }}} */
                   1798: 
                   1799: /* {{{ proto int session_cache_expire([int new_cache_expire])
                   1800:    Return the current cache expire. If new_cache_expire is given, the current cache_expire is replaced with new_cache_expire */
                   1801: static PHP_FUNCTION(session_cache_expire)
                   1802: {
                   1803:        zval **expires = NULL;
                   1804:        int argc = ZEND_NUM_ARGS();
                   1805: 
                   1806:        if (zend_parse_parameters(argc TSRMLS_CC, "|Z", &expires) == FAILURE) {
                   1807:                return;
                   1808:        }
                   1809: 
                   1810:        RETVAL_LONG(PS(cache_expire));
                   1811: 
                   1812:        if (argc == 1) {
                   1813:                convert_to_string_ex(expires);
                   1814:                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);
                   1815:        }
                   1816: }
                   1817: /* }}} */
                   1818: 
                   1819: /* {{{ proto string session_encode(void)
                   1820:    Serializes the current setup and returns the serialized representation */
                   1821: static PHP_FUNCTION(session_encode)
                   1822: {
                   1823:        int len;
                   1824:        char *enc;
                   1825: 
                   1826:        if (zend_parse_parameters_none() == FAILURE) {
                   1827:                return;
                   1828:        }
                   1829: 
                   1830:        enc = php_session_encode(&len TSRMLS_CC);
                   1831:        if (enc == NULL) {
                   1832:                RETURN_FALSE;
                   1833:        }
                   1834: 
                   1835:        RETVAL_STRINGL(enc, len, 0);
                   1836: }
                   1837: /* }}} */
                   1838: 
                   1839: /* {{{ proto bool session_decode(string data)
                   1840:    Deserializes data and reinitializes the variables */
                   1841: static PHP_FUNCTION(session_decode)
                   1842: {
                   1843:        char *str;
                   1844:        int str_len;
                   1845: 
                   1846:        if (PS(session_status) == php_session_none) {
                   1847:                RETURN_FALSE;
                   1848:        }
                   1849: 
                   1850:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
                   1851:                return;
                   1852:        }
                   1853: 
                   1854:        php_session_decode(str, str_len TSRMLS_CC);
                   1855: 
                   1856:        RETURN_TRUE;
                   1857: }
                   1858: /* }}} */
                   1859: 
                   1860: /* {{{ proto bool session_start(void)
                   1861:    Begin session - reinitializes freezed variables, registers browsers etc */
                   1862: static PHP_FUNCTION(session_start)
                   1863: {
                   1864:        /* skipping check for non-zero args for performance reasons here ?*/
                   1865:        php_session_start(TSRMLS_C);
                   1866: 
                   1867:        if (PS(session_status) != php_session_active) {
                   1868:                RETURN_FALSE;
                   1869:        }
                   1870:        RETURN_TRUE;
                   1871: }
                   1872: /* }}} */
                   1873: 
                   1874: /* {{{ proto bool session_destroy(void)
                   1875:    Destroy the current session and all data associated with it */
                   1876: static PHP_FUNCTION(session_destroy)
                   1877: {
                   1878:        if (zend_parse_parameters_none() == FAILURE) {
                   1879:                return;
                   1880:        }
                   1881: 
                   1882:        RETURN_BOOL(php_session_destroy(TSRMLS_C) == SUCCESS);
                   1883: }
                   1884: /* }}} */
                   1885: 
                   1886: /* {{{ proto void session_unset(void)
                   1887:    Unset all registered variables */
                   1888: static PHP_FUNCTION(session_unset)
                   1889: {
                   1890:        if (PS(session_status) == php_session_none) {
                   1891:                RETURN_FALSE;
                   1892:        }
                   1893: 
                   1894:        IF_SESSION_VARS() {
                   1895:                HashTable *ht_sess_var;
                   1896: 
                   1897:                SEPARATE_ZVAL_IF_NOT_REF(&PS(http_session_vars));
                   1898:                ht_sess_var = Z_ARRVAL_P(PS(http_session_vars));
                   1899: 
                   1900:                /* Clean $_SESSION. */
                   1901:                zend_hash_clean(ht_sess_var);
                   1902:        }
                   1903: }
                   1904: /* }}} */
                   1905: 
                   1906: /* {{{ proto void session_write_close(void)
                   1907:    Write session data and end session */
                   1908: static PHP_FUNCTION(session_write_close)
                   1909: {
                   1910:        php_session_flush(TSRMLS_C);
                   1911: }
                   1912: /* }}} */
                   1913: 
1.1.1.2   misho    1914: /* {{{ proto int session_status(void)
                   1915:    Returns the current session status */
                   1916: static PHP_FUNCTION(session_status)
1.1       misho    1917: {
1.1.1.2   misho    1918:        if (zend_parse_parameters_none() == FAILURE) {
1.1       misho    1919:                return;
                   1920:        }
                   1921: 
1.1.1.2   misho    1922:        RETURN_LONG(PS(session_status));
1.1       misho    1923: }
                   1924: /* }}} */
                   1925: 
1.1.1.2   misho    1926: /* {{{ proto void session_register_shutdown(void)
                   1927:    Registers session_write_close() as a shutdown function */
                   1928: static PHP_FUNCTION(session_register_shutdown)
                   1929: {
                   1930:        php_shutdown_function_entry shutdown_function_entry;
                   1931:        zval *callback;
                   1932: 
                   1933:        /* This function is registered itself as a shutdown function by
                   1934:         * session_set_save_handler($obj). The reason we now register another
                   1935:         * shutdown function is in case the user registered their own shutdown
                   1936:         * function after calling session_set_save_handler(), which expects
                   1937:         * the session still to be available.
                   1938:         */
                   1939: 
                   1940:        shutdown_function_entry.arg_count = 1;
                   1941:        shutdown_function_entry.arguments = (zval **) safe_emalloc(sizeof(zval *), 1, 0);
                   1942: 
                   1943:        MAKE_STD_ZVAL(callback);
                   1944:        ZVAL_STRING(callback, "session_write_close", 1);
                   1945:        shutdown_function_entry.arguments[0] = callback;
                   1946: 
                   1947:        if (!append_user_shutdown_function(shutdown_function_entry TSRMLS_CC)) {
                   1948:                zval_ptr_dtor(&callback);
                   1949:                efree(shutdown_function_entry.arguments);
                   1950: 
                   1951:                /* Unable to register shutdown function, presumably because of lack
                   1952:                 * of memory, so flush the session now. It would be done in rshutdown
                   1953:                 * anyway but the handler will have had it's dtor called by then.
                   1954:                 * If the user does have a later shutdown function which needs the
                   1955:                 * session then tough luck.
                   1956:                 */
                   1957:                php_session_flush(TSRMLS_C);
                   1958:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to register session flush function");
1.1       misho    1959:        }
                   1960: }
                   1961: /* }}} */
                   1962: 
                   1963: /* {{{ arginfo */
                   1964: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_name, 0, 0, 0)
                   1965:        ZEND_ARG_INFO(0, name)
                   1966: ZEND_END_ARG_INFO()
                   1967: 
                   1968: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_module_name, 0, 0, 0)
                   1969:        ZEND_ARG_INFO(0, module)
                   1970: ZEND_END_ARG_INFO()
                   1971: 
                   1972: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_save_path, 0, 0, 0)
                   1973:        ZEND_ARG_INFO(0, path)
                   1974: ZEND_END_ARG_INFO()
                   1975: 
                   1976: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_id, 0, 0, 0)
                   1977:        ZEND_ARG_INFO(0, id)
                   1978: ZEND_END_ARG_INFO()
                   1979: 
                   1980: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_regenerate_id, 0, 0, 0)
                   1981:        ZEND_ARG_INFO(0, delete_old_session)
                   1982: ZEND_END_ARG_INFO()
                   1983: 
                   1984: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_decode, 0, 0, 1)
                   1985:        ZEND_ARG_INFO(0, data)
                   1986: ZEND_END_ARG_INFO()
                   1987: 
                   1988: ZEND_BEGIN_ARG_INFO(arginfo_session_void, 0)
                   1989: ZEND_END_ARG_INFO()
                   1990: 
                   1991: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_set_save_handler, 0, 0, 6)
                   1992:        ZEND_ARG_INFO(0, open)
                   1993:        ZEND_ARG_INFO(0, close)
                   1994:        ZEND_ARG_INFO(0, read)
                   1995:        ZEND_ARG_INFO(0, write)
                   1996:        ZEND_ARG_INFO(0, destroy)
                   1997:        ZEND_ARG_INFO(0, gc)
                   1998: ZEND_END_ARG_INFO()
                   1999: 
                   2000: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_cache_limiter, 0, 0, 0)
                   2001:        ZEND_ARG_INFO(0, cache_limiter)
                   2002: ZEND_END_ARG_INFO()
                   2003: 
                   2004: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_cache_expire, 0, 0, 0)
                   2005:        ZEND_ARG_INFO(0, new_cache_expire)
                   2006: ZEND_END_ARG_INFO()
                   2007: 
                   2008: ZEND_BEGIN_ARG_INFO_EX(arginfo_session_set_cookie_params, 0, 0, 1)
                   2009:        ZEND_ARG_INFO(0, lifetime)
                   2010:        ZEND_ARG_INFO(0, path)
                   2011:        ZEND_ARG_INFO(0, domain)
                   2012:        ZEND_ARG_INFO(0, secure)
                   2013:        ZEND_ARG_INFO(0, httponly)
                   2014: ZEND_END_ARG_INFO()
1.1.1.2   misho    2015: 
                   2016: ZEND_BEGIN_ARG_INFO(arginfo_session_class_open, 0)
                   2017:        ZEND_ARG_INFO(0, save_path)
                   2018:        ZEND_ARG_INFO(0, session_name)
                   2019: ZEND_END_ARG_INFO()
                   2020: 
                   2021: ZEND_BEGIN_ARG_INFO(arginfo_session_class_close, 0)
                   2022: ZEND_END_ARG_INFO()
                   2023: 
                   2024: ZEND_BEGIN_ARG_INFO(arginfo_session_class_read, 0)
                   2025:        ZEND_ARG_INFO(0, key)
                   2026: ZEND_END_ARG_INFO()
                   2027: 
                   2028: ZEND_BEGIN_ARG_INFO(arginfo_session_class_write, 0)
                   2029:        ZEND_ARG_INFO(0, key)
                   2030:        ZEND_ARG_INFO(0, val)
                   2031: ZEND_END_ARG_INFO()
                   2032: 
                   2033: ZEND_BEGIN_ARG_INFO(arginfo_session_class_destroy, 0)
                   2034:        ZEND_ARG_INFO(0, key)
                   2035: ZEND_END_ARG_INFO()
                   2036: 
                   2037: ZEND_BEGIN_ARG_INFO(arginfo_session_class_gc, 0)
                   2038:        ZEND_ARG_INFO(0, maxlifetime)
                   2039: ZEND_END_ARG_INFO()
1.1       misho    2040: /* }}} */
                   2041: 
                   2042: /* {{{ session_functions[]
                   2043:  */
                   2044: static const zend_function_entry session_functions[] = {
                   2045:        PHP_FE(session_name,              arginfo_session_name)
                   2046:        PHP_FE(session_module_name,       arginfo_session_module_name)
                   2047:        PHP_FE(session_save_path,         arginfo_session_save_path)
                   2048:        PHP_FE(session_id,                arginfo_session_id)
                   2049:        PHP_FE(session_regenerate_id,     arginfo_session_regenerate_id)
                   2050:        PHP_FE(session_decode,            arginfo_session_decode)
                   2051:        PHP_FE(session_encode,            arginfo_session_void)
                   2052:        PHP_FE(session_start,             arginfo_session_void)
                   2053:        PHP_FE(session_destroy,           arginfo_session_void)
                   2054:        PHP_FE(session_unset,             arginfo_session_void)
                   2055:        PHP_FE(session_set_save_handler,  arginfo_session_set_save_handler)
                   2056:        PHP_FE(session_cache_limiter,     arginfo_session_cache_limiter)
                   2057:        PHP_FE(session_cache_expire,      arginfo_session_cache_expire)
                   2058:        PHP_FE(session_set_cookie_params, arginfo_session_set_cookie_params)
                   2059:        PHP_FE(session_get_cookie_params, arginfo_session_void)
                   2060:        PHP_FE(session_write_close,       arginfo_session_void)
1.1.1.2   misho    2061:        PHP_FE(session_status,            arginfo_session_void)
                   2062:        PHP_FE(session_register_shutdown, arginfo_session_void)
1.1       misho    2063:        PHP_FALIAS(session_commit, session_write_close, arginfo_session_void)
                   2064:        PHP_FE_END
                   2065: };
                   2066: /* }}} */
                   2067: 
1.1.1.2   misho    2068: /* {{{ SessionHandlerInterface functions[]
                   2069: */
                   2070: static const zend_function_entry php_session_iface_functions[] = {
                   2071:        PHP_ABSTRACT_ME(SessionHandlerInterface, open, arginfo_session_class_open)
                   2072:        PHP_ABSTRACT_ME(SessionHandlerInterface, close, arginfo_session_class_close)
                   2073:        PHP_ABSTRACT_ME(SessionHandlerInterface, read, arginfo_session_class_read)
                   2074:        PHP_ABSTRACT_ME(SessionHandlerInterface, write, arginfo_session_class_write)
                   2075:        PHP_ABSTRACT_ME(SessionHandlerInterface, destroy, arginfo_session_class_destroy)
                   2076:        PHP_ABSTRACT_ME(SessionHandlerInterface, gc, arginfo_session_class_gc)
                   2077:        { NULL, NULL, NULL }
                   2078: };
                   2079: /* }}} */
                   2080: 
                   2081: /* {{{ SessionHandler functions[]
                   2082:  */
                   2083: static const zend_function_entry php_session_class_functions[] = {
                   2084:        PHP_ME(SessionHandler, open, arginfo_session_class_open, ZEND_ACC_PUBLIC)
                   2085:        PHP_ME(SessionHandler, close, arginfo_session_class_close, ZEND_ACC_PUBLIC)
                   2086:        PHP_ME(SessionHandler, read, arginfo_session_class_read, ZEND_ACC_PUBLIC)
                   2087:        PHP_ME(SessionHandler, write, arginfo_session_class_write, ZEND_ACC_PUBLIC)
                   2088:        PHP_ME(SessionHandler, destroy, arginfo_session_class_destroy, ZEND_ACC_PUBLIC)
                   2089:        PHP_ME(SessionHandler, gc, arginfo_session_class_gc, ZEND_ACC_PUBLIC)
                   2090:        { NULL, NULL, NULL }
                   2091: };
                   2092: /* }}} */
                   2093: 
1.1       misho    2094: /* ********************************
                   2095:    * Module Setup and Destruction *
                   2096:    ******************************** */
                   2097: 
1.1.1.2   misho    2098: static int php_rinit_session(zend_bool auto_start TSRMLS_DC) /* {{{ */
1.1       misho    2099: {
                   2100:        php_rinit_session_globals(TSRMLS_C);
                   2101: 
                   2102:        if (PS(mod) == NULL) {
                   2103:                char *value;
                   2104: 
                   2105:                value = zend_ini_string("session.save_handler", sizeof("session.save_handler"), 0);
                   2106:                if (value) {
                   2107:                        PS(mod) = _php_find_ps_module(value TSRMLS_CC);
                   2108:                }
                   2109:        }
                   2110: 
                   2111:        if (PS(serializer) == NULL) {
                   2112:                char *value;
                   2113: 
                   2114:                value = zend_ini_string("session.serialize_handler", sizeof("session.serialize_handler"), 0);
                   2115:                if (value) {
                   2116:                        PS(serializer) = _php_find_ps_serializer(value TSRMLS_CC);
                   2117:                }
                   2118:        }
                   2119: 
                   2120:        if (PS(mod) == NULL || PS(serializer) == NULL) {
                   2121:                /* current status is unusable */
                   2122:                PS(session_status) = php_session_disabled;
                   2123:                return SUCCESS;
                   2124:        }
                   2125: 
1.1.1.2   misho    2126:        if (auto_start) {
1.1       misho    2127:                php_session_start(TSRMLS_C);
                   2128:        }
                   2129: 
                   2130:        return SUCCESS;
1.1.1.2   misho    2131: } /* }}} */
                   2132: 
                   2133: static PHP_RINIT_FUNCTION(session) /* {{{ */
                   2134: {
                   2135:        return php_rinit_session(PS(auto_start) TSRMLS_CC);
1.1       misho    2136: }
                   2137: /* }}} */
                   2138: 
                   2139: static PHP_RSHUTDOWN_FUNCTION(session) /* {{{ */
                   2140: {
                   2141:        int i;
                   2142: 
1.1.1.2   misho    2143:        zend_try {
                   2144:                php_session_flush(TSRMLS_C);
                   2145:        } zend_end_try();
1.1       misho    2146:        php_rshutdown_session_globals(TSRMLS_C);
                   2147: 
                   2148:        /* this should NOT be done in php_rshutdown_session_globals() */
                   2149:        for (i = 0; i < 6; i++) {
                   2150:                if (PS(mod_user_names).names[i] != NULL) {
                   2151:                        zval_ptr_dtor(&PS(mod_user_names).names[i]);
                   2152:                        PS(mod_user_names).names[i] = NULL;
                   2153:                }
                   2154:        }
                   2155: 
                   2156:        return SUCCESS;
                   2157: }
                   2158: /* }}} */
                   2159: 
                   2160: static PHP_GINIT_FUNCTION(ps) /* {{{ */
                   2161: {
                   2162:        int i;
                   2163: 
                   2164:        ps_globals->save_path = NULL;
                   2165:        ps_globals->session_name = NULL;
                   2166:        ps_globals->id = NULL;
                   2167:        ps_globals->mod = NULL;
                   2168:        ps_globals->serializer = NULL;
                   2169:        ps_globals->mod_data = NULL;
                   2170:        ps_globals->session_status = php_session_none;
1.1.1.2   misho    2171:        ps_globals->default_mod = NULL;
                   2172:        ps_globals->mod_user_implemented = 0;
                   2173:        ps_globals->mod_user_is_open = 0;
1.1       misho    2174:        for (i = 0; i < 6; i++) {
                   2175:                ps_globals->mod_user_names.names[i] = NULL;
                   2176:        }
                   2177:        ps_globals->http_session_vars = NULL;
                   2178: }
                   2179: /* }}} */
                   2180: 
                   2181: static PHP_MINIT_FUNCTION(session) /* {{{ */
                   2182: {
1.1.1.2   misho    2183:        zend_class_entry ce;
                   2184: 
                   2185:        zend_register_auto_global("_SESSION", sizeof("_SESSION")-1, 0, NULL TSRMLS_CC);
1.1       misho    2186: 
                   2187:        PS(module_number) = module_number; /* if we really need this var we need to init it in zts mode as well! */
                   2188: 
                   2189:        PS(session_status) = php_session_none;
                   2190:        REGISTER_INI_ENTRIES();
                   2191: 
                   2192: #ifdef HAVE_LIBMM
                   2193:        PHP_MINIT(ps_mm) (INIT_FUNC_ARGS_PASSTHRU);
                   2194: #endif
1.1.1.2   misho    2195:        php_session_rfc1867_orig_callback = php_rfc1867_callback;
                   2196:        php_rfc1867_callback = php_session_rfc1867_callback;
                   2197: 
                   2198:        /* Register interface */
                   2199:        INIT_CLASS_ENTRY(ce, PS_IFACE_NAME, php_session_iface_functions);
                   2200:        php_session_iface_entry = zend_register_internal_class(&ce TSRMLS_CC);
                   2201:        php_session_iface_entry->ce_flags |= ZEND_ACC_INTERFACE;
                   2202: 
                   2203:        /* Register base class */
                   2204:        INIT_CLASS_ENTRY(ce, PS_CLASS_NAME, php_session_class_functions);
                   2205:        php_session_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
                   2206:        zend_class_implements(php_session_class_entry TSRMLS_CC, 1, php_session_iface_entry);
                   2207: 
                   2208:        REGISTER_LONG_CONSTANT("PHP_SESSION_DISABLED", php_session_disabled, CONST_CS | CONST_PERSISTENT);
                   2209:        REGISTER_LONG_CONSTANT("PHP_SESSION_NONE", php_session_none, CONST_CS | CONST_PERSISTENT);
                   2210:        REGISTER_LONG_CONSTANT("PHP_SESSION_ACTIVE", php_session_active, CONST_CS | CONST_PERSISTENT);
                   2211: 
1.1       misho    2212:        return SUCCESS;
                   2213: }
                   2214: /* }}} */
                   2215: 
                   2216: static PHP_MSHUTDOWN_FUNCTION(session) /* {{{ */
                   2217: {
                   2218:        UNREGISTER_INI_ENTRIES();
                   2219: 
                   2220: #ifdef HAVE_LIBMM
                   2221:        PHP_MSHUTDOWN(ps_mm) (SHUTDOWN_FUNC_ARGS_PASSTHRU);
                   2222: #endif
                   2223: 
1.1.1.3 ! misho    2224:        /* restore the orig callback */
        !          2225:        php_rfc1867_callback = php_session_rfc1867_orig_callback;
        !          2226: 
1.1       misho    2227:        ps_serializers[PREDEFINED_SERIALIZERS].name = NULL;
                   2228:        memset(&ps_modules[PREDEFINED_MODULES], 0, (MAX_MODULES-PREDEFINED_MODULES)*sizeof(ps_module *));
                   2229: 
                   2230:        return SUCCESS;
                   2231: }
                   2232: /* }}} */
                   2233: 
                   2234: static PHP_MINFO_FUNCTION(session) /* {{{ */
                   2235: {
                   2236:        ps_module **mod;
                   2237:        ps_serializer *ser;
                   2238:        smart_str save_handlers = {0};
                   2239:        smart_str ser_handlers = {0};
                   2240:        int i;
                   2241: 
                   2242:        /* Get save handlers */
                   2243:        for (i = 0, mod = ps_modules; i < MAX_MODULES; i++, mod++) {
                   2244:                if (*mod && (*mod)->s_name) {
                   2245:                        smart_str_appends(&save_handlers, (*mod)->s_name);
                   2246:                        smart_str_appendc(&save_handlers, ' ');
                   2247:                }
                   2248:        }
                   2249: 
                   2250:        /* Get serializer handlers */
                   2251:        for (i = 0, ser = ps_serializers; i < MAX_SERIALIZERS; i++, ser++) {
                   2252:                if (ser && ser->name) {
                   2253:                        smart_str_appends(&ser_handlers, ser->name);
                   2254:                        smart_str_appendc(&ser_handlers, ' ');
                   2255:                }
                   2256:        }
                   2257: 
                   2258:        php_info_print_table_start();
                   2259:        php_info_print_table_row(2, "Session Support", "enabled" );
                   2260: 
                   2261:        if (save_handlers.c) {
                   2262:                smart_str_0(&save_handlers);
                   2263:                php_info_print_table_row(2, "Registered save handlers", save_handlers.c);
                   2264:                smart_str_free(&save_handlers);
                   2265:        } else {
                   2266:                php_info_print_table_row(2, "Registered save handlers", "none");
                   2267:        }
                   2268: 
                   2269:        if (ser_handlers.c) {
                   2270:                smart_str_0(&ser_handlers);
                   2271:                php_info_print_table_row(2, "Registered serializer handlers", ser_handlers.c);
                   2272:                smart_str_free(&ser_handlers);
                   2273:        } else {
                   2274:                php_info_print_table_row(2, "Registered serializer handlers", "none");
                   2275:        }
                   2276: 
                   2277:        php_info_print_table_end();
                   2278: 
                   2279:        DISPLAY_INI_ENTRIES();
                   2280: }
                   2281: /* }}} */
                   2282: 
                   2283: static const zend_module_dep session_deps[] = { /* {{{ */
                   2284:        ZEND_MOD_OPTIONAL("hash")
                   2285:        ZEND_MOD_REQUIRED("spl")
                   2286:        ZEND_MOD_END
                   2287: };
                   2288: /* }}} */
                   2289: 
1.1.1.2   misho    2290: /* ************************
                   2291:    * Upload hook handling *
                   2292:    ************************ */
                   2293: 
                   2294: static zend_bool early_find_sid_in(zval *dest, int where, php_session_rfc1867_progress *progress TSRMLS_DC) /* {{{ */
                   2295: {
                   2296:        zval **ppid;
                   2297: 
                   2298:        if (!PG(http_globals)[where]) {
                   2299:                return 0;
                   2300:        }
                   2301: 
                   2302:        if (zend_hash_find(Z_ARRVAL_P(PG(http_globals)[where]), PS(session_name), progress->sname_len+1, (void **)&ppid) == SUCCESS
                   2303:                        && Z_TYPE_PP(ppid) == IS_STRING) {
                   2304:                zval_dtor(dest);
                   2305:                ZVAL_ZVAL(dest, *ppid, 1, 0);
                   2306:                return 1;
                   2307:        }
                   2308: 
                   2309:        return 0;
                   2310: } /* }}} */
                   2311: 
                   2312: static void php_session_rfc1867_early_find_sid(php_session_rfc1867_progress *progress TSRMLS_DC) /* {{{ */
                   2313: {
                   2314: 
                   2315:        if (PS(use_cookies)) {
                   2316:                sapi_module.treat_data(PARSE_COOKIE, NULL, NULL TSRMLS_CC);
                   2317:                if (early_find_sid_in(&progress->sid, TRACK_VARS_COOKIE, progress TSRMLS_CC)) {
                   2318:                        progress->apply_trans_sid = 0;
                   2319:                        return;
                   2320:                }
                   2321:        }
                   2322:        if (PS(use_only_cookies)) {
                   2323:                return;
                   2324:        }
                   2325:        sapi_module.treat_data(PARSE_GET, NULL, NULL TSRMLS_CC);
                   2326:        early_find_sid_in(&progress->sid, TRACK_VARS_GET, progress TSRMLS_CC);
                   2327: } /* }}} */
                   2328: 
                   2329: static zend_bool php_check_cancel_upload(php_session_rfc1867_progress *progress TSRMLS_DC) /* {{{ */
                   2330: {
                   2331:        zval **progress_ary, **cancel_upload;
                   2332: 
                   2333:        if (zend_symtable_find(Z_ARRVAL_P(PS(http_session_vars)), progress->key.c, progress->key.len+1, (void**)&progress_ary) != SUCCESS) {
                   2334:                return 0;
                   2335:        }
                   2336:        if (Z_TYPE_PP(progress_ary) != IS_ARRAY) {
                   2337:                return 0;
                   2338:        }
                   2339:        if (zend_hash_find(Z_ARRVAL_PP(progress_ary), "cancel_upload", sizeof("cancel_upload"), (void**)&cancel_upload) != SUCCESS) {
                   2340:                return 0;
                   2341:        }
                   2342:        return Z_TYPE_PP(cancel_upload) == IS_BOOL && Z_LVAL_PP(cancel_upload);
                   2343: } /* }}} */
                   2344: 
                   2345: static void php_session_rfc1867_update(php_session_rfc1867_progress *progress, int force_update TSRMLS_DC) /* {{{ */
                   2346: {
                   2347:        if (!force_update) {
                   2348:                if (Z_LVAL_P(progress->post_bytes_processed) < progress->next_update) {
                   2349:                        return;
                   2350:                }
                   2351: #ifdef HAVE_GETTIMEOFDAY
                   2352:                if (PS(rfc1867_min_freq) > 0.0) {
                   2353:                        struct timeval tv = {0};
                   2354:                        double dtv;
                   2355:                        gettimeofday(&tv, NULL);
                   2356:                        dtv = (double) tv.tv_sec + tv.tv_usec / 1000000.0;
                   2357:                        if (dtv < progress->next_update_time) {
                   2358:                                return;
                   2359:                        }
                   2360:                        progress->next_update_time = dtv + PS(rfc1867_min_freq);
                   2361:                }
                   2362: #endif
                   2363:                progress->next_update = Z_LVAL_P(progress->post_bytes_processed) + progress->update_step;
                   2364:        }
                   2365: 
                   2366:        php_session_initialize(TSRMLS_C);
                   2367:        PS(session_status) = php_session_active;
                   2368:        IF_SESSION_VARS() {
                   2369:                progress->cancel_upload = php_check_cancel_upload(progress TSRMLS_CC);
                   2370:                ZEND_SET_SYMBOL_WITH_LENGTH(Z_ARRVAL_P(PS(http_session_vars)), progress->key.c, progress->key.len+1, progress->data, 2, 0);
                   2371:        }
                   2372:        php_session_flush(TSRMLS_C);
                   2373: } /* }}} */
                   2374: 
                   2375: static void php_session_rfc1867_cleanup(php_session_rfc1867_progress *progress TSRMLS_DC) /* {{{ */
                   2376: {
                   2377:        php_session_initialize(TSRMLS_C);
                   2378:        PS(session_status) = php_session_active;
                   2379:        IF_SESSION_VARS() {
                   2380:                zend_hash_del(Z_ARRVAL_P(PS(http_session_vars)), progress->key.c, progress->key.len+1);
                   2381:        }
                   2382:        php_session_flush(TSRMLS_C);
                   2383: } /* }}} */
                   2384: 
                   2385: static int php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra TSRMLS_DC) /* {{{ */
                   2386: {
                   2387:        php_session_rfc1867_progress *progress;
                   2388:        int retval = SUCCESS;
                   2389: 
                   2390:        if (php_session_rfc1867_orig_callback) {
                   2391:                retval = php_session_rfc1867_orig_callback(event, event_data, extra TSRMLS_CC);
                   2392:        }
                   2393:        if (!PS(rfc1867_enabled)) {
                   2394:                return retval;
                   2395:        }
                   2396: 
                   2397:        progress = PS(rfc1867_progress);
                   2398: 
                   2399:        switch(event) {
                   2400:                case MULTIPART_EVENT_START: {
                   2401:                        multipart_event_start *data = (multipart_event_start *) event_data;
                   2402:                        progress = ecalloc(1, sizeof(php_session_rfc1867_progress));
                   2403:                        progress->content_length = data->content_length;
                   2404:                        progress->sname_len  = strlen(PS(session_name));
                   2405:                        PS(rfc1867_progress) = progress;
                   2406:                }
                   2407:                break;
                   2408:                case MULTIPART_EVENT_FORMDATA: {
                   2409:                        multipart_event_formdata *data = (multipart_event_formdata *) event_data;
                   2410:                        size_t value_len;
                   2411: 
                   2412:                        if (Z_TYPE(progress->sid) && progress->key.c) {
                   2413:                                break;
                   2414:                        }
                   2415: 
                   2416:                        /* orig callback may have modified *data->newlength */
                   2417:                        if (data->newlength) {
                   2418:                                value_len = *data->newlength;
                   2419:                        } else {
                   2420:                                value_len = data->length;
                   2421:                        }
                   2422: 
                   2423:                        if (data->name && data->value && value_len) {
                   2424:                                size_t name_len = strlen(data->name);
                   2425: 
                   2426:                                if (name_len == progress->sname_len && memcmp(data->name, PS(session_name), name_len) == 0) {
                   2427:                                        zval_dtor(&progress->sid);
                   2428:                                        ZVAL_STRINGL(&progress->sid, (*data->value), value_len, 1);
                   2429: 
                   2430:                                } else if (name_len == PS(rfc1867_name).len && memcmp(data->name, PS(rfc1867_name).c, name_len) == 0) {
                   2431:                                        smart_str_free(&progress->key);
                   2432:                                        smart_str_appendl(&progress->key, PS(rfc1867_prefix).c, PS(rfc1867_prefix).len);
                   2433:                                        smart_str_appendl(&progress->key, *data->value, value_len);
                   2434:                                        smart_str_0(&progress->key);
                   2435: 
                   2436:                                        progress->apply_trans_sid = PS(use_trans_sid);
                   2437:                                        php_session_rfc1867_early_find_sid(progress TSRMLS_CC);
                   2438:                                }
                   2439:                        }
                   2440:                }
                   2441:                break;
                   2442:                case MULTIPART_EVENT_FILE_START: {
                   2443:                        multipart_event_file_start *data = (multipart_event_file_start *) event_data;
                   2444: 
                   2445:                        /* Do nothing when $_POST["PHP_SESSION_UPLOAD_PROGRESS"] is not set 
                   2446:                         * or when we have no session id */
                   2447:                        if (!Z_TYPE(progress->sid) || !progress->key.c) {
                   2448:                                break;
                   2449:                        }
                   2450:                        
                   2451:                        /* First FILE_START event, initializing data */
                   2452:                        if (!progress->data) {
                   2453: 
                   2454:                                if (PS(rfc1867_freq) >= 0) {
                   2455:                                        progress->update_step = PS(rfc1867_freq);
                   2456:                                } else if (PS(rfc1867_freq) < 0) { /* % of total size */
                   2457:                                        progress->update_step = progress->content_length * -PS(rfc1867_freq) / 100;
                   2458:                                }
                   2459:                                progress->next_update = 0;
                   2460:                                progress->next_update_time = 0.0;
                   2461: 
                   2462:                                ALLOC_INIT_ZVAL(progress->data);
                   2463:                                array_init(progress->data);
                   2464: 
                   2465:                                ALLOC_INIT_ZVAL(progress->post_bytes_processed);
                   2466:                                ZVAL_LONG(progress->post_bytes_processed, data->post_bytes_processed);
                   2467: 
                   2468:                                ALLOC_INIT_ZVAL(progress->files);
                   2469:                                array_init(progress->files);
                   2470: 
                   2471:                                add_assoc_long_ex(progress->data, "start_time",      sizeof("start_time"),      (long)sapi_get_request_time(TSRMLS_C));
                   2472:                                add_assoc_long_ex(progress->data, "content_length",  sizeof("content_length"),  progress->content_length);
                   2473:                                add_assoc_zval_ex(progress->data, "bytes_processed", sizeof("bytes_processed"), progress->post_bytes_processed);
                   2474:                                add_assoc_bool_ex(progress->data, "done",            sizeof("done"),            0);
                   2475:                                add_assoc_zval_ex(progress->data, "files",           sizeof("files"),           progress->files);
                   2476: 
                   2477:                                php_rinit_session(0 TSRMLS_CC);
                   2478:                                PS(id) = estrndup(Z_STRVAL(progress->sid), Z_STRLEN(progress->sid));
                   2479:                                PS(apply_trans_sid) = progress->apply_trans_sid;
                   2480:                                PS(send_cookie) = 0;
                   2481:                        }
                   2482: 
                   2483:                        ALLOC_INIT_ZVAL(progress->current_file);
                   2484:                        array_init(progress->current_file);
                   2485: 
                   2486:                        ALLOC_INIT_ZVAL(progress->current_file_bytes_processed);
                   2487:                        ZVAL_LONG(progress->current_file_bytes_processed, 0);
                   2488: 
                   2489:                        /* Each uploaded file has its own array. Trying to make it close to $_FILES entries. */
                   2490:                        add_assoc_string_ex(progress->current_file, "field_name",    sizeof("field_name"),      data->name, 1);
                   2491:                        add_assoc_string_ex(progress->current_file, "name",          sizeof("name"),            *data->filename, 1);
                   2492:                        add_assoc_null_ex(progress->current_file, "tmp_name",        sizeof("tmp_name"));
                   2493:                        add_assoc_long_ex(progress->current_file, "error",           sizeof("error"),           0);
                   2494: 
                   2495:                        add_assoc_bool_ex(progress->current_file, "done",            sizeof("done"),            0);
                   2496:                        add_assoc_long_ex(progress->current_file, "start_time",      sizeof("start_time"),      (long)time(NULL));
                   2497:                        add_assoc_zval_ex(progress->current_file, "bytes_processed", sizeof("bytes_processed"), progress->current_file_bytes_processed);
                   2498: 
                   2499:                        add_next_index_zval(progress->files, progress->current_file);
                   2500:                        
                   2501:                        Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed;
                   2502: 
                   2503:                        php_session_rfc1867_update(progress, 0 TSRMLS_CC);
                   2504:                }
                   2505:                break;
                   2506:                case MULTIPART_EVENT_FILE_DATA: {
                   2507:                        multipart_event_file_data *data = (multipart_event_file_data *) event_data;
                   2508: 
                   2509:                        if (!Z_TYPE(progress->sid) || !progress->key.c) {
                   2510:                                break;
                   2511:                        }
                   2512:                        
                   2513:                        Z_LVAL_P(progress->current_file_bytes_processed) = data->offset + data->length;
                   2514:                        Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed;
                   2515: 
                   2516:                        php_session_rfc1867_update(progress, 0 TSRMLS_CC);
                   2517:                }
                   2518:                break;
                   2519:                case MULTIPART_EVENT_FILE_END: {
                   2520:                        multipart_event_file_end *data = (multipart_event_file_end *) event_data;
                   2521: 
                   2522:                        if (!Z_TYPE(progress->sid) || !progress->key.c) {
                   2523:                                break;
                   2524:                        }
                   2525:                        
                   2526:                        if (data->temp_filename) {
                   2527:                                add_assoc_string_ex(progress->current_file, "tmp_name",  sizeof("tmp_name"), data->temp_filename, 1);
                   2528:                        }
                   2529:                        add_assoc_long_ex(progress->current_file, "error", sizeof("error"), data->cancel_upload);
                   2530:                        add_assoc_bool_ex(progress->current_file, "done",  sizeof("done"),  1);
                   2531: 
                   2532:                        Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed;
                   2533: 
                   2534:                        php_session_rfc1867_update(progress, 0 TSRMLS_CC);
                   2535:                }
                   2536:                break;
                   2537:                case MULTIPART_EVENT_END: {
                   2538:                        multipart_event_end *data = (multipart_event_end *) event_data;
                   2539: 
                   2540:                        if (Z_TYPE(progress->sid) && progress->key.c) {
                   2541:                                if (PS(rfc1867_cleanup)) {
                   2542:                                        php_session_rfc1867_cleanup(progress TSRMLS_CC);
                   2543:                                } else {
                   2544:                                        add_assoc_bool_ex(progress->data, "done", sizeof("done"), 1);
                   2545:                                        Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed;
                   2546:                                        php_session_rfc1867_update(progress, 1 TSRMLS_CC);
                   2547:                                }
                   2548:                                php_rshutdown_session_globals(TSRMLS_C);
                   2549:                        }
                   2550: 
                   2551:                        if (progress->data) {
                   2552:                                zval_ptr_dtor(&progress->data);
                   2553:                        }
                   2554:                        zval_dtor(&progress->sid);
                   2555:                        smart_str_free(&progress->key);
                   2556:                        efree(progress);
                   2557:                        progress = NULL;
                   2558:                        PS(rfc1867_progress) = NULL;
                   2559:                }
                   2560:                break;
                   2561:        }
                   2562: 
                   2563:        if (progress && progress->cancel_upload) {
                   2564:                return FAILURE;
                   2565:        }
                   2566:        return retval;
                   2567: 
                   2568: } /* }}} */
                   2569: 
1.1       misho    2570: zend_module_entry session_module_entry = {
                   2571:        STANDARD_MODULE_HEADER_EX,
                   2572:        NULL,
                   2573:        session_deps,
                   2574:        "session",
                   2575:        session_functions,
                   2576:        PHP_MINIT(session), PHP_MSHUTDOWN(session),
                   2577:        PHP_RINIT(session), PHP_RSHUTDOWN(session),
                   2578:        PHP_MINFO(session),
                   2579:        NO_VERSION_YET,
                   2580:        PHP_MODULE_GLOBALS(ps),
                   2581:        PHP_GINIT(ps),
                   2582:        NULL,
                   2583:        NULL,
                   2584:        STANDARD_MODULE_PROPERTIES_EX
                   2585: };
                   2586: 
                   2587: #ifdef COMPILE_DL_SESSION
                   2588: ZEND_GET_MODULE(session)
                   2589: #endif
                   2590: 
                   2591: /*
                   2592:  * Local variables:
                   2593:  * tab-width: 4
                   2594:  * c-basic-offset: 4
                   2595:  * End:
                   2596:  * vim600: noet sw=4 ts=4 fdm=marker
                   2597:  * vim<600: sw=4 ts=4
                   2598:  */

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