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

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

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