From: Sara Golemon Date: Thu, 4 Jan 2007 22:04:38 +0000 (+0000) Subject: Cleanup ext/session so that I can do a unicode update without going insane. X-Git-Tag: RELEASE_1_0_0RC1~404 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=21bac192e90d5e31a3da5dcf7b383d4c6a4a7364;p=php Cleanup ext/session so that I can do a unicode update without going insane. --- diff --git a/ext/session/mod_files.c b/ext/session/mod_files.c index f25d15dd2f..16f8e55895 100644 --- a/ext/session/mod_files.c +++ b/ext/session/mod_files.c @@ -87,9 +87,10 @@ static int ps_files_valid_key(const char *key) len = p - key; - if (len == 0) + if (len == 0) { ret = 0; - + } + return ret; } @@ -101,9 +102,11 @@ static char *ps_files_path_create(char *buf, size_t buflen, ps_files *data, cons int n; key_len = strlen(key); - if (key_len <= data->dirdepth || buflen < - (strlen(data->basedir) + 2 * data->dirdepth + key_len + 5 + sizeof(FILE_PREFIX))) + if (key_len <= data->dirdepth || + buflen < (strlen(data->basedir) + 2 * data->dirdepth + key_len + 5 + sizeof(FILE_PREFIX))) { return NULL; + } + p = key; memcpy(buf, data->basedir, data->basedir_len); n = data->basedir_len; @@ -149,27 +152,27 @@ static void ps_files_open(ps_files *data, const char *key TSRMLS_DC) } ps_files_close(data); - + if (!ps_files_valid_key(key)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "The session id contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,'"); PS(invalid_session_id) = 1; return; } - if (!ps_files_path_create(buf, sizeof(buf), data, key)) + if (!ps_files_path_create(buf, sizeof(buf), data, key)) { return; - + } + data->lastkey = estrdup(key); - - data->fd = VCWD_OPEN_MODE(buf, O_CREAT | O_RDWR | O_BINARY, - data->filemode); - + + data->fd = VCWD_OPEN_MODE(buf, O_CREAT | O_RDWR | O_BINARY, data->filemode); + if (data->fd != -1) { flock(data->fd, LOCK_EX); #ifdef F_SETFD -#ifndef FD_CLOEXEC -#define FD_CLOEXEC 1 -#endif +# ifndef FD_CLOEXEC +# define FD_CLOEXEC 1 +# endif if (fcntl(data->fd, F_SETFD, FD_CLOEXEC)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "fcntl(%d, F_SETFD, FD_CLOEXEC) failed: %s (%d)", data->fd, strerror(errno), errno); } @@ -209,15 +212,16 @@ static int ps_files_cleanup_dir(const char *dirname, int maxlifetime TSRMLS_DC) while (php_readdir_r(dir, (struct dirent *) dentry, &entry) == 0 && entry) { /* does the file start with our prefix? */ if (!strncmp(entry->d_name, FILE_PREFIX, sizeof(FILE_PREFIX) - 1)) { - size_t entry_len; + size_t entry_len = strlen(entry->d_name); - entry_len = strlen(entry->d_name); /* does it fit into our buffer? */ if (entry_len + dirname_len + 2 < MAXPATHLEN) { /* create the full path.. */ memcpy(buf + dirname_len + 1, entry->d_name, entry_len); + /* NUL terminate it and */ buf[dirname_len + entry_len + 1] = '\0'; + /* check whether its last access was more than maxlifet ago */ if (VCWD_STAT(buf, &sbuf) == 0 && #ifdef NETWARE @@ -268,8 +272,7 @@ PS_OPEN_FUNC(files) errno = 0; dirdepth = (size_t) strtol(argv[0], NULL, 10); if (errno == ERANGE) { - php_error(E_WARNING, - "The first parameter in session.save_path is invalid"); + php_error(E_WARNING, "The first parameter in session.save_path is invalid"); return FAILURE; } } @@ -278,15 +281,13 @@ PS_OPEN_FUNC(files) errno = 0; filemode = strtol(argv[1], NULL, 8); if (errno == ERANGE || filemode < 0 || filemode > 07777) { - php_error(E_WARNING, - "The second parameter in session.save_path is invalid"); + php_error(E_WARNING, "The second parameter in session.save_path is invalid"); return FAILURE; } } save_path = argv[argc - 1]; - data = emalloc(sizeof(*data)); - memset(data, 0, sizeof(*data)); + data = ecalloc(1, sizeof(*data)); data->fd = -1; data->dirdepth = dirdepth; @@ -305,8 +306,10 @@ PS_CLOSE_FUNC(files) ps_files_close(data); - if (data->lastkey) + if (data->lastkey) { efree(data->lastkey); + } + efree(data->basedir); efree(data); *mod_data = NULL; @@ -321,19 +324,21 @@ PS_READ_FUNC(files) PS_FILES_DATA; ps_files_open(data, key TSRMLS_CC); - if (data->fd < 0) + if (data->fd < 0) { return FAILURE; - - if (fstat(data->fd, &sbuf)) + } + + if (fstat(data->fd, &sbuf)) { return FAILURE; - + } + data->st_size = *vallen = sbuf.st_size; - + if (sbuf.st_size == 0) { *val = STR_EMPTY_ALLOC(); return SUCCESS; } - + *val = emalloc(sbuf.st_size); #if defined(HAVE_PREAD) @@ -344,10 +349,11 @@ PS_READ_FUNC(files) #endif if (n != sbuf.st_size) { - if (n == -1) + if (n == -1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "read failed: %s (%d)", strerror(errno), errno); - else + } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "read returned less bytes than requested"); + } efree(*val); return FAILURE; } @@ -361,16 +367,18 @@ PS_WRITE_FUNC(files) PS_FILES_DATA; ps_files_open(data, key TSRMLS_CC); - if (data->fd < 0) + if (data->fd < 0) { return FAILURE; + } /* * truncate file, if the amount of new data is smaller than * the existing data set. */ - if (vallen < (int)data->st_size) + if (vallen < (int)data->st_size) { ftruncate(data->fd, 0); + } #if defined(HAVE_PWRITE) n = pwrite(data->fd, val, vallen, 0); @@ -380,10 +388,11 @@ PS_WRITE_FUNC(files) #endif if (n != vallen) { - if (n == -1) + if (n == -1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "write failed: %s (%d)", strerror(errno), errno); - else + } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "write wrote less bytes than requested"); + } return FAILURE; } @@ -395,9 +404,10 @@ PS_DESTROY_FUNC(files) char buf[MAXPATHLEN]; PS_FILES_DATA; - if (!ps_files_path_create(buf, sizeof(buf), data, key)) + if (!ps_files_path_create(buf, sizeof(buf), data, key)) { return FAILURE; - + } + if (data->fd != -1) { ps_files_close(data); @@ -422,9 +432,10 @@ PS_GC_FUNC(files) we return SUCCESS, since all cleanup should be handled by an external entity (i.e. find -ctime x | xargs rm) */ - if (data->dirdepth == 0) + if (data->dirdepth == 0) { *nrdels = ps_files_cleanup_dir(data->basedir, maxlifetime TSRMLS_CC); - + } + return SUCCESS; } diff --git a/ext/session/mod_mm.c b/ext/session/mod_mm.c index bdc2651b06..c307bf7b9c 100644 --- a/ext/session/mod_mm.c +++ b/ext/session/mod_mm.c @@ -161,9 +161,9 @@ static void ps_sd_destroy(ps_mm *data, ps_sd *sd) slot = ps_sd_hash(sd->key, strlen(sd->key)) & data->hash_max; - if (data->hash[slot] == sd) + if (data->hash[slot] == sd) { data->hash[slot] = sd->next; - else { + } else { ps_sd *prev; /* There must be some entry before the one we want to delete */ @@ -172,8 +172,11 @@ static void ps_sd_destroy(ps_mm *data, ps_sd *sd) } data->hash_cnt--; - if (sd->data) + + if (sd->data) { mm_free(data->mm, sd->data); + } + mm_free(data->mm, sd); } @@ -185,15 +188,19 @@ static ps_sd *ps_sd_lookup(ps_mm *data, const char *key, int rw) hv = ps_sd_hash(key, strlen(key)); slot = hv & data->hash_max; - for (prev = NULL, ret = data->hash[slot]; ret; prev = ret, ret = ret->next) - if (ret->hv == hv && !strcmp(ret->key, key)) + for (prev = NULL, ret = data->hash[slot]; ret; prev = ret, ret = ret->next) { + if (ret->hv == hv && !strcmp(ret->key, key)) { break; - + } + } + if (ret && rw && ret != data->hash[slot]) { /* Move the entry to the top of the linked list */ - if (prev) + if (prev) { prev->next = ret->next; + } + ret->next = data->hash[slot]; data->hash[slot] = ret; } @@ -238,11 +245,12 @@ static void ps_mm_destroy(ps_mm *data) an Apache child dies! */ if (data->owner != getpid()) return; - for (h = 0; h < data->hash_max + 1; h++) + for (h = 0; h < data->hash_max + 1; h++) { for (sd = data->hash[h]; sd; sd = next) { next = sd->next; ps_sd_destroy(data, sd); } + } mm_free(data->mm, data->hash); mm_destroy(data->mm); @@ -257,13 +265,15 @@ PHP_MINIT_FUNCTION(ps_mm) int ret; ps_mm_instance = calloc(sizeof(*ps_mm_instance), 1); - if (!ps_mm_instance) + if (!ps_mm_instance) { return FAILURE; + } - if (!sprintf(euid,"%d", geteuid())) + if (!sprintf(euid,"%d", geteuid())) { return FAILURE; + } - /* Directory + '/' + File + Module Name + Effective UID + \0 */ + /* Directory + '/' + File + Module Name + Effective UID + \0 */ ps_mm_path = emalloc(save_path_len+1+sizeof(PS_MM_FILE)+mod_name_len+strlen(euid)+1); memcpy(ps_mm_path, PS(save_path), save_path_len + 1); @@ -271,6 +281,7 @@ PHP_MINIT_FUNCTION(ps_mm) ps_mm_path[save_path_len] = DEFAULT_SLASH; ps_mm_path[save_path_len+1] = '\0'; } + strcat(ps_mm_path, PS_MM_FILE); strcat(ps_mm_path, sapi_module.name); strcat(ps_mm_path, euid); @@ -302,8 +313,9 @@ PS_OPEN_FUNC(mm) { ps_mm_debug(("open: ps_mm_instance=%p\n", ps_mm_instance)); - if (!ps_mm_instance) + if (!ps_mm_instance) { return FAILURE; + } PS_SET_MOD_DATA(ps_mm_instance); @@ -354,8 +366,9 @@ PS_WRITE_FUNC(mm) if (sd) { if (vallen >= sd->alloclen) { - if (data->mm) + if (data->mm) { mm_free(data->mm, sd->data); + } sd->alloclen = vallen + 1; sd->data = mm_malloc(data->mm, sd->alloclen); @@ -385,9 +398,10 @@ PS_DESTROY_FUNC(mm) mm_lock(data->mm, MM_LOCK_RW); sd = ps_sd_lookup(data, key, 0); - if (sd) + if (sd) { ps_sd_destroy(data, sd); - + } + mm_unlock(data->mm); return SUCCESS; @@ -410,7 +424,7 @@ PS_GC_FUNC(mm) mm_lock(data->mm, MM_LOCK_RW); ehash = data->hash + data->hash_max + 1; - for (ohash = data->hash; ohash < ehash; ohash++) + for (ohash = data->hash; ohash < ehash; ohash++) { for (sd = *ohash; sd; sd = next) { next = sd->next; if (sd->ctime < limit) { @@ -419,6 +433,7 @@ PS_GC_FUNC(mm) (*nrdels)++; } } + } mm_unlock(data->mm); diff --git a/ext/session/mod_user.c b/ext/session/mod_user.c index 3e82e8dcd0..8b39c21fb3 100644 --- a/ext/session/mod_user.c +++ b/ext/session/mod_user.c @@ -29,25 +29,20 @@ ps_module ps_mod_user = { #define SESS_ZVAL_LONG(val, a) \ { \ MAKE_STD_ZVAL(a); \ - Z_TYPE_P(a) = IS_LONG; \ - Z_LVAL_P(a) = val; \ + ZVAL_LONG(a, val); \ } #define SESS_ZVAL_STRING(vl, a) \ { \ int len = strlen(vl); \ MAKE_STD_ZVAL(a); \ - Z_TYPE_P(a) = IS_STRING; \ - Z_STRLEN_P(a) = len; \ - Z_STRVAL_P(a) = estrndup(vl, len); \ + ZVAL_STRINGL(a, vl, len, 1); \ } #define SESS_ZVAL_STRINGN(vl, ln, a) \ { \ MAKE_STD_ZVAL(a); \ - Z_TYPE_P(a) = IS_STRING; \ - Z_STRLEN_P(a) = ln; \ - Z_STRVAL_P(a) = estrndup(vl, ln); \ + ZVAL_STRINGL(a, vl, ln, 1); \ } @@ -74,8 +69,7 @@ static zval *ps_call_handler(zval *func, int argc, zval **argv TSRMLS_DC) zval *retval; \ int ret = FAILURE; \ ps_user *mdata = PS_GET_MOD_DATA(); \ - if (!mdata) \ - return FAILURE + if (!mdata) { return FAILURE; } #define PSF(a) mdata->name.ps_##a @@ -92,8 +86,8 @@ PS_OPEN_FUNC(user) zval *args[2]; STDVARS; - SESS_ZVAL_STRING(save_path, args[0]); - SESS_ZVAL_STRING(session_name, args[1]); + SESS_ZVAL_STRING((char*)save_path, args[0]); + SESS_ZVAL_STRING((char*)session_name, args[1]); retval = ps_call_handler(PSF(open), 2, args TSRMLS_CC); @@ -107,8 +101,10 @@ PS_CLOSE_FUNC(user) retval = ps_call_handler(PSF(close), 0, NULL TSRMLS_CC); - for (i = 0; i < 6; i++) + for (i = 0; i < 6; i++) { zval_ptr_dtor(&mdata->names[i]); + } + efree(mdata); PS_SET_MOD_DATA(NULL); @@ -121,7 +117,7 @@ PS_READ_FUNC(user) zval *args[1]; STDVARS; - SESS_ZVAL_STRING(key, args[0]); + SESS_ZVAL_STRING((char*)key, args[0]); retval = ps_call_handler(PSF(read), 1, args TSRMLS_CC); @@ -142,8 +138,8 @@ PS_WRITE_FUNC(user) zval *args[2]; STDVARS; - SESS_ZVAL_STRING(key, args[0]); - SESS_ZVAL_STRINGN(val, vallen, args[1]); + SESS_ZVAL_STRING((char*)key, args[0]); + SESS_ZVAL_STRINGN((char*)val, vallen, args[1]); retval = ps_call_handler(PSF(write), 2, args TSRMLS_CC); @@ -155,7 +151,7 @@ PS_DESTROY_FUNC(user) zval *args[1]; STDVARS; - SESS_ZVAL_STRING(key, args[0]); + SESS_ZVAL_STRING((char*)key, args[0]); retval = ps_call_handler(PSF(destroy), 1, args TSRMLS_CC); diff --git a/ext/session/php_session.h b/ext/session/php_session.h index 69544aca5f..989740f1fe 100644 --- a/ext/session/php_session.h +++ b/ext/session/php_session.h @@ -132,23 +132,6 @@ typedef php_ps_globals zend_ps_globals; extern zend_module_entry session_module_entry; #define phpext_session_ptr &session_module_entry -PHP_FUNCTION(session_name); -PHP_FUNCTION(session_module_name); -PHP_FUNCTION(session_save_path); -PHP_FUNCTION(session_id); -PHP_FUNCTION(session_regenerate_id); -PHP_FUNCTION(session_decode); -PHP_FUNCTION(session_encode); -PHP_FUNCTION(session_start); -PHP_FUNCTION(session_destroy); -PHP_FUNCTION(session_unset); -PHP_FUNCTION(session_set_save_handler); -PHP_FUNCTION(session_cache_expire); -PHP_FUNCTION(session_cache_limiter); -PHP_FUNCTION(session_set_cookie_params); -PHP_FUNCTION(session_get_cookie_params); -PHP_FUNCTION(session_write_close); - #ifdef ZTS #define PS(v) TSRMG(ps_globals_id, php_ps_globals *, v) #else diff --git a/ext/session/session.c b/ext/session/session.c index 3ded1d1490..782758339f 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -54,38 +54,391 @@ #include "mod_mm.h" #endif -/* {{{ session_functions[] +PHPAPI ZEND_DECLARE_MODULE_GLOBALS(ps); + +/* *********** + * Helpers * + *********** */ + +#ifdef NETWARE +# define SESS_SB_MTIME(sb) ((sb).st_mtime.tv_sec) +#else +# define SESS_SB_MTIME(sb) ((sb).st_mtime) +#endif + +#define IF_SESSION_VARS() \ + if (PS(http_session_vars) && PS(http_session_vars)->type == IS_ARRAY) + +#define SESSION_CHECK_ACTIVE_STATE \ + if (PS(session_status) == php_session_active) { \ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "A session is active. You cannot change the session module's ini settings at this time"); \ + return FAILURE; \ + } + +/* Dispatched by RINIT and by php_session_destroy */ +static inline void php_rinit_session_globals(TSRMLS_D) +{ + PS(id) = NULL; + PS(session_status) = php_session_none; + PS(mod_data) = NULL; + PS(http_session_vars) = NULL; +} + +/* Dispatched by RSHUTDOWN and by php_session_destroy */ +static inline void php_rshutdown_session_globals(TSRMLS_D) +{ + if (PS(http_session_vars)) { + zval_ptr_dtor(&PS(http_session_vars)); + PS(http_session_vars) = NULL; + } + if (PS(mod_data)) { + zend_try { + PS(mod)->s_close(&PS(mod_data) TSRMLS_CC); + } zend_end_try(); + } + if (PS(id)) { + efree(PS(id)); + } +} + +static int php_session_destroy(TSRMLS_D) +{ + int retval = SUCCESS; + + if (PS(session_status) != php_session_active) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Trying to destroy uninitialized session"); + return FAILURE; + } + + if (PS(mod)->s_destroy(&PS(mod_data), PS(id) TSRMLS_CC) == FAILURE) { + retval = FAILURE; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session object destruction failed"); + } + + php_rshutdown_session_globals(TSRMLS_C); + php_rinit_session_globals(TSRMLS_C); + + return retval; +} + +PHPAPI void php_add_session_var(char *name, size_t namelen TSRMLS_DC) +{ + zval **sym_track = NULL; + + IF_SESSION_VARS() { + zend_rt_hash_find(Z_ARRVAL_P(PS(http_session_vars)), name, namelen + 1, + (void *) &sym_track); + } else { + return; + } + + if (sym_track == NULL) { + zval *empty_var; + + ALLOC_INIT_ZVAL(empty_var); + ZEND_SET_SYMBOL_WITH_LENGTH(Z_ARRVAL_P(PS(http_session_vars)), name, namelen+1, empty_var, 1, 0); + } +} + +PHPAPI void php_set_session_var(char *name, size_t namelen, zval *state_val, php_unserialize_data_t *var_hash TSRMLS_DC) +{ + zend_set_hash_symbol(state_val, name, namelen, PZVAL_IS_REF(state_val), 1, Z_ARRVAL_P(PS(http_session_vars))); +} + +PHPAPI int php_get_session_var(char *name, size_t namelen, zval ***state_var TSRMLS_DC) +{ + int ret = FAILURE; + + IF_SESSION_VARS() { + ret = zend_rt_hash_find(Z_ARRVAL_P(PS(http_session_vars)), name, + namelen+1, (void **) state_var); + } + + return ret; +} + +static void php_session_track_init(TSRMLS_D) +{ + zval *session_vars = NULL; + + /* Unconditionally destroy existing arrays -- possible dirty data */ + zend_delete_global_variable("_SESSION", sizeof("_SESSION")-1 TSRMLS_CC); + + if (PS(http_session_vars)) { + zval_ptr_dtor(&PS(http_session_vars)); + } + + MAKE_STD_ZVAL(session_vars); + array_init(session_vars); + PS(http_session_vars) = session_vars; + + ZEND_SET_GLOBAL_VAR_WITH_LENGTH("_SESSION", sizeof("_SESSION"), PS(http_session_vars), 2, 1); +} + +static char *php_session_encode(int *newlen TSRMLS_DC) +{ + char *ret = NULL; + + IF_SESSION_VARS() { + if (!PS(serializer)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown session.serialize_handler. Failed to encode session object"); + ret = NULL; + } else if (PS(serializer)->encode(&ret, newlen TSRMLS_CC) == FAILURE) { + ret = NULL; + } + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot encode non-existent session"); + } + + return ret; +} + +static void php_session_decode(const char *val, int vallen TSRMLS_DC) +{ + if (!PS(serializer)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown session.serialize_handler. Failed to decode session object"); + return; + } + if (PS(serializer)->decode(val, vallen TSRMLS_CC) == FAILURE) { + php_session_destroy(TSRMLS_C); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to decode session object. Session has been destroyed"); + } +} + + +/* + * Note that we cannot use the BASE64 alphabet here, because + * it contains "/" and "+": both are unacceptable for simple inclusion + * into URLs. */ -zend_function_entry session_functions[] = { - PHP_FE(session_name, NULL) - PHP_FE(session_module_name, NULL) - PHP_FE(session_save_path, NULL) - PHP_FE(session_id, NULL) - PHP_FE(session_regenerate_id, NULL) - PHP_FE(session_decode, NULL) - PHP_FE(session_encode, NULL) - PHP_FE(session_start, NULL) - PHP_FE(session_destroy, NULL) - PHP_FE(session_unset, NULL) - PHP_FE(session_set_save_handler, NULL) - PHP_FE(session_cache_limiter, NULL) - PHP_FE(session_cache_expire, NULL) - PHP_FE(session_set_cookie_params, NULL) - PHP_FE(session_get_cookie_params, NULL) - PHP_FE(session_write_close, NULL) - PHP_FALIAS(session_commit, session_write_close, NULL) - {NULL, NULL, NULL} + +static char hexconvtab[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,-"; + +enum { + PS_HASH_FUNC_MD5, + PS_HASH_FUNC_SHA1 }; -/* }}} */ -PHPAPI ZEND_DECLARE_MODULE_GLOBALS(ps); -static PHP_GINIT_FUNCTION(ps); +/* returns a pointer to the byte after the last valid character in out */ +static char *bin_to_readable(char *in, size_t inlen, char *out, char nbits) +{ + unsigned char *p, *q; + unsigned short w; + int mask; + int have; + + p = (unsigned char *) in; + q = (unsigned char *)in + inlen; + + w = 0; + have = 0; + mask = (1 << nbits) - 1; + + while (1) { + if (have < nbits) { + if (p < q) { + w |= *p++ << have; + have += 8; + } else { + /* consumed everything? */ + if (have == 0) break; + /* No? We need a final round */ + have = nbits; + } + } + + /* consume nbits */ + *out++ = hexconvtab[w & mask]; + w >>= nbits; + have -= nbits; + } + + *out = '\0'; + return out; +} + +PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS) +{ + PHP_MD5_CTX md5_context; + PHP_SHA1_CTX sha1_context; + unsigned char digest[21]; + int digest_len; + int j; + char *buf; + struct timeval tv; + zval **array; + zval **token; + char *remote_addr = NULL; + + gettimeofday(&tv, NULL); + + if (zend_ascii_hash_find(&EG(symbol_table), "_SERVER", + sizeof("_SERVER"), (void **) &array) == SUCCESS && + Z_TYPE_PP(array) == IS_ARRAY && + zend_ascii_hash_find(Z_ARRVAL_PP(array), "REMOTE_ADDR", + sizeof("REMOTE_ADDR"), (void **) &token) == SUCCESS) { + remote_addr = Z_STRVAL_PP(token); + } + + buf = emalloc(100); + + /* maximum 15+19+19+10 bytes */ + sprintf(buf, "%.15s%ld%ld%0.8F", remote_addr ? remote_addr : "", + tv.tv_sec, (long int)tv.tv_usec, php_combined_lcg(TSRMLS_C) * 10); + + switch (PS(hash_func)) { + case PS_HASH_FUNC_MD5: + PHP_MD5Init(&md5_context); + PHP_MD5Update(&md5_context, (unsigned char *) buf, strlen(buf)); + digest_len = 16; + break; + case PS_HASH_FUNC_SHA1: + PHP_SHA1Init(&sha1_context); + PHP_SHA1Update(&sha1_context, (unsigned char *) buf, strlen(buf)); + digest_len = 20; + break; + default: + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid session hash function"); + efree(buf); + return NULL; + } + + if (PS(entropy_length) > 0) { + int fd; + + fd = VCWD_OPEN(PS(entropy_file), O_RDONLY); + if (fd >= 0) { + unsigned char rbuf[2048]; + int n; + int to_read = PS(entropy_length); + + while (to_read > 0) { + n = read(fd, rbuf, MIN(to_read, sizeof(rbuf))); + if (n <= 0) break; + + switch (PS(hash_func)) { + case PS_HASH_FUNC_MD5: + PHP_MD5Update(&md5_context, rbuf, n); + break; + case PS_HASH_FUNC_SHA1: + PHP_SHA1Update(&sha1_context, rbuf, n); + break; + } + to_read -= n; + } + close(fd); + } + } + + switch (PS(hash_func)) { + case PS_HASH_FUNC_MD5: + PHP_MD5Final(digest, &md5_context); + break; + case PS_HASH_FUNC_SHA1: + PHP_SHA1Final(digest, &sha1_context); + break; + } -#define SESSION_CHECK_ACTIVE_STATE \ - if (PS(session_status) == php_session_active) { \ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "A session is active. You cannot change the session module's ini settings at this time"); \ - return FAILURE; \ - } \ + if (PS(hash_bits_per_character) < 4 + || PS(hash_bits_per_character) > 6) { + PS(hash_bits_per_character) = 4; + + 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"); + } + j = (int) (bin_to_readable((char *)digest, digest_len, buf, PS(hash_bits_per_character)) - buf); + + if (newlen) { + *newlen = j; + } + + return buf; +} + +static void php_session_initialize(TSRMLS_D) +{ + char *val; + int vallen; + + /* check session name for invalid characters */ + if (PS(id) && strpbrk(PS(id), "\r\n\t <>'\"\\")) { + efree(PS(id)); + PS(id) = NULL; + } + + if (!PS(mod)) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "No storage module chosen - failed to initialize session"); + return; + } + + /* Open session handler first */ + if (PS(mod)->s_open(&PS(mod_data), PS(save_path), PS(session_name) TSRMLS_CC) == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to initialize storage module: %s (path: %s)", PS(mod)->s_name, PS(save_path)); + return; + } + + /* If there is no ID, use session module to create one */ + if (!PS(id)) { +new_session: + PS(id) = PS(mod)->s_create_sid(&PS(mod_data), NULL TSRMLS_CC); + if (PS(use_cookies)) { + PS(send_cookie) = 1; + } + } + + /* Read data */ + /* Question: if you create a SID here, should you also try to read data? + * I'm not sure, but while not doing so will remove one session operation + * it could prove usefull for those sites which wish to have "default" + * session information + */ + php_session_track_init(TSRMLS_C); + PS(invalid_session_id) = 0; + if (PS(mod)->s_read(&PS(mod_data), PS(id), &val, &vallen TSRMLS_CC) == SUCCESS) { + php_session_decode(val, vallen TSRMLS_CC); + efree(val); + } else if (PS(invalid_session_id)) { /* address instances where the session read fails due to an invalid id */ + PS(invalid_session_id) = 0; + efree(PS(id)); + goto new_session; + } +} + +static void php_session_save_current_state(TSRMLS_D) +{ + int ret = FAILURE; + + IF_SESSION_VARS() { + + if (PS(mod_data)) { + char *val; + int vallen; + + val = php_session_encode(&vallen TSRMLS_CC); + if (val) { + ret = PS(mod)->s_write(&PS(mod_data), PS(id), val, vallen TSRMLS_CC); + efree(val); + } else { + ret = PS(mod)->s_write(&PS(mod_data), PS(id), "", 0 TSRMLS_CC); + } + } + + if (ret == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write session data (%s). Please " + "verify that the current setting of session.save_path " + "is correct (%s)", + PS(mod)->s_name, + PS(save_path)); + } + } + + if (PS(mod_data)) { + PS(mod)->s_close(&PS(mod_data) TSRMLS_CC); + } +} + +/* ************************* + * INI Settings/Handlers * + ************************* */ static PHP_INI_MH(OnUpdateSaveHandler) { @@ -96,11 +449,13 @@ static PHP_INI_MH(OnUpdateSaveHandler) if (PG(modules_activated) && !tmp) { int err_type; + if (stage == ZEND_INI_STAGE_RUNTIME) { err_type = E_WARNING; } else { err_type = E_ERROR; } + php_error_docref(NULL TSRMLS_CC, err_type, "Cannot find save handler %s", new_value); return FAILURE; } @@ -164,179 +519,46 @@ static PHP_INI_MH(OnUpdateSaveDir) return FAILURE; } } + OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); return SUCCESS; } /* {{{ PHP_INI */ -PHP_INI_BEGIN() - STD_PHP_INI_ENTRY("session.save_path", "", PHP_INI_ALL, OnUpdateSaveDir,save_path, php_ps_globals, ps_globals) - STD_PHP_INI_ENTRY("session.name", "PHPSESSID", PHP_INI_ALL, OnUpdateString, session_name, php_ps_globals, ps_globals) - PHP_INI_ENTRY("session.save_handler", "files", PHP_INI_ALL, OnUpdateSaveHandler) - STD_PHP_INI_BOOLEAN("session.auto_start", "0", PHP_INI_ALL, OnUpdateBool, auto_start, php_ps_globals, ps_globals) - STD_PHP_INI_ENTRY("session.gc_probability", "1", PHP_INI_ALL, OnUpdateLong, gc_probability, php_ps_globals, ps_globals) - STD_PHP_INI_ENTRY("session.gc_divisor", "100", PHP_INI_ALL, OnUpdateLong, gc_divisor, php_ps_globals, ps_globals) - STD_PHP_INI_ENTRY("session.gc_maxlifetime", "1440", PHP_INI_ALL, OnUpdateLong, gc_maxlifetime, php_ps_globals, ps_globals) - PHP_INI_ENTRY("session.serialize_handler", "php", PHP_INI_ALL, OnUpdateSerializer) - STD_PHP_INI_ENTRY("session.cookie_lifetime", "0", PHP_INI_ALL, OnUpdateLong, cookie_lifetime, php_ps_globals, ps_globals) - STD_PHP_INI_ENTRY("session.cookie_path", "/", PHP_INI_ALL, OnUpdateString, cookie_path, php_ps_globals, ps_globals) - STD_PHP_INI_ENTRY("session.cookie_domain", "", PHP_INI_ALL, OnUpdateString, cookie_domain, php_ps_globals, ps_globals) - STD_PHP_INI_BOOLEAN("session.cookie_secure", "", PHP_INI_ALL, OnUpdateBool, cookie_secure, php_ps_globals, ps_globals) - STD_PHP_INI_BOOLEAN("session.cookie_httponly", "", PHP_INI_ALL, OnUpdateBool, cookie_httponly, php_ps_globals, ps_globals) - STD_PHP_INI_BOOLEAN("session.use_cookies", "1", PHP_INI_ALL, OnUpdateBool, use_cookies, php_ps_globals, ps_globals) - STD_PHP_INI_BOOLEAN("session.use_only_cookies", "1", PHP_INI_ALL, OnUpdateBool, use_only_cookies, php_ps_globals, ps_globals) - STD_PHP_INI_ENTRY("session.referer_check", "", PHP_INI_ALL, OnUpdateString, extern_referer_chk, php_ps_globals, ps_globals) - STD_PHP_INI_ENTRY("session.entropy_file", "", PHP_INI_ALL, OnUpdateString, entropy_file, php_ps_globals, ps_globals) - STD_PHP_INI_ENTRY("session.entropy_length", "0", PHP_INI_ALL, OnUpdateLong, entropy_length, php_ps_globals, ps_globals) - STD_PHP_INI_ENTRY("session.cache_limiter", "nocache", PHP_INI_ALL, OnUpdateString, cache_limiter, php_ps_globals, ps_globals) - STD_PHP_INI_ENTRY("session.cache_expire", "180", PHP_INI_ALL, OnUpdateLong, cache_expire, php_ps_globals, ps_globals) - PHP_INI_ENTRY("session.use_trans_sid", "0", PHP_INI_ALL, OnUpdateTransSid) - STD_PHP_INI_ENTRY("session.hash_function", "0", PHP_INI_ALL, OnUpdateLong, hash_func, php_ps_globals, ps_globals) - STD_PHP_INI_ENTRY("session.hash_bits_per_character", "4", PHP_INI_ALL, OnUpdateLong, hash_bits_per_character, php_ps_globals, ps_globals) - - /* Commented out until future discussion */ - /* PHP_INI_ENTRY("session.encode_sources", "globals,track", PHP_INI_ALL, NULL) */ -PHP_INI_END() -/* }}} */ - -PS_SERIALIZER_FUNCS(php); -PS_SERIALIZER_FUNCS(php_binary); - -#define MAX_SERIALIZERS 10 -#define PREDEFINED_SERIALIZERS 2 - -static ps_serializer ps_serializers[MAX_SERIALIZERS + 1] = { - PS_SERIALIZER_ENTRY(php), - PS_SERIALIZER_ENTRY(php_binary) -}; - -#define MAX_MODULES 10 -#define PREDEFINED_MODULES 2 - -static ps_module *ps_modules[MAX_MODULES + 1] = { - ps_files_ptr, - ps_user_ptr -}; - -#define IF_SESSION_VARS() \ - if (PS(http_session_vars) && PS(http_session_vars)->type == IS_ARRAY) - -PHPAPI int php_session_register_serializer(const char *name, - int (*encode)(PS_SERIALIZER_ENCODE_ARGS), - int (*decode)(PS_SERIALIZER_DECODE_ARGS)) -{ - int ret = -1; - int i; - - for (i = 0; i < MAX_SERIALIZERS; i++) { - if (ps_serializers[i].name == NULL) { - ps_serializers[i].name = name; - ps_serializers[i].encode = encode; - ps_serializers[i].decode = decode; - ps_serializers[i + 1].name = NULL; - ret = 0; - break; - } - } - - return ret; -} - -PHPAPI int php_session_register_module(ps_module *ptr) -{ - int ret = -1; - int i; - - for (i = 0; i < MAX_MODULES; i++) { - if (!ps_modules[i]) { - ps_modules[i] = ptr; - ret = 0; - break; - } - } - - return ret; -} - -PHP_MINIT_FUNCTION(session); -PHP_RINIT_FUNCTION(session); -PHP_MSHUTDOWN_FUNCTION(session); -PHP_RSHUTDOWN_FUNCTION(session); -PHP_MINFO_FUNCTION(session); - -static void php_rinit_session_globals(TSRMLS_D); -static void php_rshutdown_session_globals(TSRMLS_D); -static int php_session_destroy(TSRMLS_D); - -zend_module_entry session_module_entry = { - STANDARD_MODULE_HEADER, - "session", - session_functions, - PHP_MINIT(session), PHP_MSHUTDOWN(session), - PHP_RINIT(session), PHP_RSHUTDOWN(session), - PHP_MINFO(session), - NO_VERSION_YET, - PHP_MODULE_GLOBALS(ps), - PHP_GINIT(ps), - NULL, - NULL, - STANDARD_MODULE_PROPERTIES_EX -}; - -#ifdef COMPILE_DL_SESSION -ZEND_GET_MODULE(session) -#endif - -typedef struct { - char *name; - void (*func)(TSRMLS_D); -} php_session_cache_limiter_t; - -#define CACHE_LIMITER(name) _php_cache_limiter_##name -#define CACHE_LIMITER_FUNC(name) static void CACHE_LIMITER(name)(TSRMLS_D) -#define CACHE_LIMITER_ENTRY(name) { #name, CACHE_LIMITER(name) }, - -#define ADD_HEADER(a) sapi_add_header(a, strlen(a), 1); - -#define MAX_STR 512 - -PHPAPI void php_add_session_var(char *name, size_t namelen TSRMLS_DC) -{ - zval **sym_track = NULL; - - IF_SESSION_VARS() { - zend_rt_hash_find(Z_ARRVAL_P(PS(http_session_vars)), name, namelen + 1, - (void *) &sym_track); - } else { - return; - } - - if (sym_track == NULL) { - zval *empty_var; - - ALLOC_INIT_ZVAL(empty_var); - ZEND_SET_SYMBOL_WITH_LENGTH(Z_ARRVAL_P(PS(http_session_vars)), name, namelen+1, empty_var, 1, 0); - } -} - -PHPAPI void php_set_session_var(char *name, size_t namelen, zval *state_val, php_unserialize_data_t *var_hash TSRMLS_DC) -{ - zend_set_hash_symbol(state_val, name, namelen, PZVAL_IS_REF(state_val), 1, Z_ARRVAL_P(PS(http_session_vars))); -} - -PHPAPI int php_get_session_var(char *name, size_t namelen, zval ***state_var TSRMLS_DC) -{ - int ret = FAILURE; +PHP_INI_BEGIN() + STD_PHP_INI_ENTRY("session.save_path", "", PHP_INI_ALL, OnUpdateSaveDir,save_path, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.name", "PHPSESSID", PHP_INI_ALL, OnUpdateString, session_name, php_ps_globals, ps_globals) + PHP_INI_ENTRY("session.save_handler", "files", PHP_INI_ALL, OnUpdateSaveHandler) + STD_PHP_INI_BOOLEAN("session.auto_start", "0", PHP_INI_ALL, OnUpdateBool, auto_start, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.gc_probability", "1", PHP_INI_ALL, OnUpdateLong, gc_probability, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.gc_divisor", "100", PHP_INI_ALL, OnUpdateLong, gc_divisor, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.gc_maxlifetime", "1440", PHP_INI_ALL, OnUpdateLong, gc_maxlifetime, php_ps_globals, ps_globals) + PHP_INI_ENTRY("session.serialize_handler", "php", PHP_INI_ALL, OnUpdateSerializer) + STD_PHP_INI_ENTRY("session.cookie_lifetime", "0", PHP_INI_ALL, OnUpdateLong, cookie_lifetime, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.cookie_path", "/", PHP_INI_ALL, OnUpdateString, cookie_path, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.cookie_domain", "", PHP_INI_ALL, OnUpdateString, cookie_domain, php_ps_globals, ps_globals) + STD_PHP_INI_BOOLEAN("session.cookie_secure", "", PHP_INI_ALL, OnUpdateBool, cookie_secure, php_ps_globals, ps_globals) + STD_PHP_INI_BOOLEAN("session.cookie_httponly", "", PHP_INI_ALL, OnUpdateBool, cookie_httponly, php_ps_globals, ps_globals) + STD_PHP_INI_BOOLEAN("session.use_cookies", "1", PHP_INI_ALL, OnUpdateBool, use_cookies, php_ps_globals, ps_globals) + STD_PHP_INI_BOOLEAN("session.use_only_cookies", "1", PHP_INI_ALL, OnUpdateBool, use_only_cookies, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.referer_check", "", PHP_INI_ALL, OnUpdateString, extern_referer_chk, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.entropy_file", "", PHP_INI_ALL, OnUpdateString, entropy_file, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.entropy_length", "0", PHP_INI_ALL, OnUpdateLong, entropy_length, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.cache_limiter", "nocache", PHP_INI_ALL, OnUpdateString, cache_limiter, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.cache_expire", "180", PHP_INI_ALL, OnUpdateLong, cache_expire, php_ps_globals, ps_globals) + PHP_INI_ENTRY("session.use_trans_sid", "0", PHP_INI_ALL, OnUpdateTransSid) + STD_PHP_INI_ENTRY("session.hash_function", "0", PHP_INI_ALL, OnUpdateLong, hash_func, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.hash_bits_per_character", "4", PHP_INI_ALL, OnUpdateLong, hash_bits_per_character, php_ps_globals, ps_globals) - IF_SESSION_VARS() { - ret = zend_rt_hash_find(Z_ARRVAL_P(PS(http_session_vars)), name, - namelen+1, (void **) state_var); + /* Commented out until future discussion */ + /* PHP_INI_ENTRY("session.encode_sources", "globals,track", PHP_INI_ALL, NULL) */ +PHP_INI_END() +/* }}} */ - } - - return ret; -} +/* *************** + * Serializers * + *************** */ #define PS_BIN_NR_OF_BITS 8 #define PS_BIN_UNDEF (1<<(PS_BIN_NR_OF_BITS-1)) @@ -356,7 +578,7 @@ PS_SERIALIZER_ENCODE_FUNC(php_binary) smart_str_appendl(&buf, key.s, key_length); php_var_serialize(&buf, struc, &var_hash TSRMLS_CC); - } else { + } else { if (key_length > PS_BIN_MAX) continue; smart_str_appendc(&buf, (unsigned char) (key_length & PS_BIN_UNDEF)); smart_str_appendl(&buf, key.s, key_length); @@ -439,7 +661,7 @@ PS_SERIALIZER_ENCODE_FUNC(php) smart_str_appendc(&buf, PS_DELIMITER); php_var_serialize(&buf, struc, &var_hash TSRMLS_CC); - } else { + } else { smart_str_appendc(&buf, PS_UNDEF_MARKER); smart_str_appendl(&buf, key.s, key_length); smart_str_appendc(&buf, PS_DELIMITER); @@ -469,8 +691,9 @@ PS_SERIALIZER_DECODE_FUNC(php) while (p < endptr) { zval **tmp; q = p; - while (*q != PS_DELIMITER) + while (*q != PS_DELIMITER) { if (++q >= endptr) goto break_outer_loop; + } if (p[0] == PS_UNDEF_MARKER) { p++; @@ -509,281 +732,78 @@ break_outer_loop: return SUCCESS; } -static void php_session_track_init(TSRMLS_D) -{ - zval *session_vars = NULL; - - /* Unconditionally destroy existing arrays -- possible dirty data */ - zend_delete_global_variable("_SESSION", sizeof("_SESSION")-1 TSRMLS_CC); - - if (PS(http_session_vars)) { - zval_ptr_dtor(&PS(http_session_vars)); - } - - MAKE_STD_ZVAL(session_vars); - array_init(session_vars); - PS(http_session_vars) = session_vars; - - ZEND_SET_GLOBAL_VAR_WITH_LENGTH("_SESSION", sizeof("_SESSION"), PS(http_session_vars), 2, 1); -} - -static char *php_session_encode(int *newlen TSRMLS_DC) -{ - char *ret = NULL; - - IF_SESSION_VARS() { - if (!PS(serializer)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown session.serialize_handler. Failed to encode session object"); - ret = NULL; - } - else if (PS(serializer)->encode(&ret, newlen TSRMLS_CC) == FAILURE) - ret = NULL; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot encode non-existent session"); - } - - return ret; -} - -static void php_session_decode(const char *val, int vallen TSRMLS_DC) -{ - if (!PS(serializer)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown session.serialize_handler. Failed to decode session object"); - return; - } - if (PS(serializer)->decode(val, vallen TSRMLS_CC) == FAILURE) { - php_session_destroy(TSRMLS_C); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to decode session object. Session has been destroyed"); - } -} - - -/* - * Note that we cannot use the BASE64 alphabet here, because - * it contains "/" and "+": both are unacceptable for simple inclusion - * into URLs. - */ - -static char hexconvtab[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,-"; +#define MAX_SERIALIZERS 10 +#define PREDEFINED_SERIALIZERS 2 -enum { - PS_HASH_FUNC_MD5, - PS_HASH_FUNC_SHA1 +static ps_serializer ps_serializers[MAX_SERIALIZERS + 1] = { + PS_SERIALIZER_ENTRY(php), + PS_SERIALIZER_ENTRY(php_binary) }; -/* returns a pointer to the byte after the last valid character in out */ -static char *bin_to_readable(char *in, size_t inlen, char *out, char nbits) -{ - unsigned char *p, *q; - unsigned short w; - int mask; - int have; - - p = (unsigned char *) in; - q = (unsigned char *)in + inlen; - - w = 0; - have = 0; - mask = (1 << nbits) - 1; - - while (1) { - if (have < nbits) { - if (p < q) { - w |= *p++ << have; - have += 8; - } else { - /* consumed everything? */ - if (have == 0) break; - /* No? We need a final round */ - have = nbits; - } - } - - /* consume nbits */ - *out++ = hexconvtab[w & mask]; - w >>= nbits; - have -= nbits; - } - - *out = '\0'; - return out; -} - -PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS) -{ - PHP_MD5_CTX md5_context; - PHP_SHA1_CTX sha1_context; - unsigned char digest[21]; - int digest_len; - int j; - char *buf; - struct timeval tv; - zval **array; - zval **token; - char *remote_addr = NULL; - - gettimeofday(&tv, NULL); - - if (zend_ascii_hash_find(&EG(symbol_table), "_SERVER", - sizeof("_SERVER"), (void **) &array) == SUCCESS && - Z_TYPE_PP(array) == IS_ARRAY && - zend_ascii_hash_find(Z_ARRVAL_PP(array), "REMOTE_ADDR", - sizeof("REMOTE_ADDR"), (void **) &token) == SUCCESS) { - remote_addr = Z_STRVAL_PP(token); - } - - buf = emalloc(100); - - /* maximum 15+19+19+10 bytes */ - sprintf(buf, "%.15s%ld%ld%0.8F", remote_addr ? remote_addr : "", - tv.tv_sec, (long int)tv.tv_usec, php_combined_lcg(TSRMLS_C) * 10); - - switch (PS(hash_func)) { - case PS_HASH_FUNC_MD5: - PHP_MD5Init(&md5_context); - PHP_MD5Update(&md5_context, (unsigned char *) buf, strlen(buf)); - digest_len = 16; - break; - case PS_HASH_FUNC_SHA1: - PHP_SHA1Init(&sha1_context); - PHP_SHA1Update(&sha1_context, (unsigned char *) buf, strlen(buf)); - digest_len = 20; - break; - default: - php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid session hash function"); - efree(buf); - return NULL; - } - - if (PS(entropy_length) > 0) { - int fd; - - fd = VCWD_OPEN(PS(entropy_file), O_RDONLY); - if (fd >= 0) { - unsigned char rbuf[2048]; - int n; - int to_read = PS(entropy_length); - - while (to_read > 0) { - n = read(fd, rbuf, MIN(to_read, sizeof(rbuf))); - if (n <= 0) break; - - switch (PS(hash_func)) { - case PS_HASH_FUNC_MD5: - PHP_MD5Update(&md5_context, rbuf, n); - break; - case PS_HASH_FUNC_SHA1: - PHP_SHA1Update(&sha1_context, rbuf, n); - break; - } - to_read -= n; - } - close(fd); - } - } - - switch (PS(hash_func)) { - case PS_HASH_FUNC_MD5: - PHP_MD5Final(digest, &md5_context); - break; - case PS_HASH_FUNC_SHA1: - PHP_SHA1Final(digest, &sha1_context); - break; - } - - if (PS(hash_bits_per_character) < 4 - || PS(hash_bits_per_character) > 6) { - PS(hash_bits_per_character) = 4; - - 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"); - } - j = (int) (bin_to_readable((char *)digest, digest_len, buf, PS(hash_bits_per_character)) - buf); - - if (newlen) - *newlen = j; - return buf; -} - -static void php_session_initialize(TSRMLS_D) +PHPAPI int php_session_register_serializer(const char *name, + int (*encode)(PS_SERIALIZER_ENCODE_ARGS), + int (*decode)(PS_SERIALIZER_DECODE_ARGS)) { - char *val; - int vallen; - - /* check session name for invalid characters */ - if (PS(id) && strpbrk(PS(id), "\r\n\t <>'\"\\")) { - efree(PS(id)); - PS(id) = NULL; - } - - if (!PS(mod)) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "No storage module chosen - failed to initialize session"); - return; - } + int ret = -1; + int i; - /* Open session handler first */ - if (PS(mod)->s_open(&PS(mod_data), PS(save_path), PS(session_name) TSRMLS_CC) == FAILURE) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to initialize storage module: %s (path: %s)", PS(mod)->s_name, PS(save_path)); - return; - } - - /* If there is no ID, use session module to create one */ - if (!PS(id)) { -new_session: - PS(id) = PS(mod)->s_create_sid(&PS(mod_data), NULL TSRMLS_CC); - if (PS(use_cookies)) { - PS(send_cookie) = 1; - } - } - - /* Read data */ - /* Question: if you create a SID here, should you also try to read data? - * I'm not sure, but while not doing so will remove one session operation - * it could prove usefull for those sites which wish to have "default" - * session information - */ - php_session_track_init(TSRMLS_C); - PS(invalid_session_id) = 0; - if (PS(mod)->s_read(&PS(mod_data), PS(id), &val, &vallen TSRMLS_CC) == SUCCESS) { - php_session_decode(val, vallen TSRMLS_CC); - efree(val); - } else if (PS(invalid_session_id)) { /* address instances where the session read fails due to an invalid id */ - PS(invalid_session_id) = 0; - efree(PS(id)); - goto new_session; + for (i = 0; i < MAX_SERIALIZERS; i++) { + if (ps_serializers[i].name == NULL) { + ps_serializers[i].name = name; + ps_serializers[i].encode = encode; + ps_serializers[i].decode = decode; + ps_serializers[i + 1].name = NULL; + ret = 0; + break; + } } + + return ret; } -static void php_session_save_current_state(TSRMLS_D) -{ - int ret = FAILURE; - - IF_SESSION_VARS() { +/* ******************* + * Storage Modules * + ******************* */ - if (PS(mod_data)) { - char *val; - int vallen; +#define MAX_MODULES 10 +#define PREDEFINED_MODULES 2 - val = php_session_encode(&vallen TSRMLS_CC); - if (val) { - ret = PS(mod)->s_write(&PS(mod_data), PS(id), val, vallen TSRMLS_CC); - efree(val); - } else { - ret = PS(mod)->s_write(&PS(mod_data), PS(id), "", 0 TSRMLS_CC); - } - } +static ps_module *ps_modules[MAX_MODULES + 1] = { + ps_files_ptr, + ps_user_ptr +}; - if (ret == FAILURE) - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write session data (%s). Please " - "verify that the current setting of session.save_path " - "is correct (%s)", - PS(mod)->s_name, - PS(save_path)); +PHPAPI int php_session_register_module(ps_module *ptr) +{ + int ret = -1; + int i; + + for (i = 0; i < MAX_MODULES; i++) { + if (!ps_modules[i]) { + ps_modules[i] = ptr; + ret = 0; + break; + } } - if (PS(mod_data)) - PS(mod)->s_close(&PS(mod_data) TSRMLS_CC); + return ret; } +/* ****************** + * Cache Limiters * + ****************** */ + +typedef struct { + char *name; + void (*func)(TSRMLS_D); +} php_session_cache_limiter_t; + +#define CACHE_LIMITER(name) _php_cache_limiter_##name +#define CACHE_LIMITER_FUNC(name) static void CACHE_LIMITER(name)(TSRMLS_D) +#define CACHE_LIMITER_ENTRY(name) { #name, CACHE_LIMITER(name) }, +#define ADD_HEADER(a) sapi_add_header(a, strlen(a), 1); +#define MAX_STR 512 + static char *month_names[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" @@ -793,7 +813,7 @@ static char *week_days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; -static void strcpy_gmt(char *ubuf, time_t *when) +static inline void strcpy_gmt(char *ubuf, time_t *when) { char buf[MAX_STR]; struct tm tm; @@ -810,7 +830,7 @@ static void strcpy_gmt(char *ubuf, time_t *when) ubuf[n] = '\0'; } -static void last_modified(TSRMLS_D) +static inline void last_modified(TSRMLS_D) { const char *path; struct stat sb; @@ -824,15 +844,12 @@ static void last_modified(TSRMLS_D) #define LAST_MODIFIED "Last-Modified: " memcpy(buf, LAST_MODIFIED, sizeof(LAST_MODIFIED) - 1); -#ifdef NETWARE - strcpy_gmt(buf + sizeof(LAST_MODIFIED) - 1, &(sb.st_mtime.tv_sec)); -#else - strcpy_gmt(buf + sizeof(LAST_MODIFIED) - 1, &sb.st_mtime); -#endif + strcpy_gmt(buf + sizeof(LAST_MODIFIED) - 1, &SESS_SB_MTIME(sb)); ADD_HEADER(buf); } } +#define EXPIRES "Expires: " CACHE_LIMITER_FUNC(public) { char buf[MAX_STR + 1]; @@ -841,7 +858,6 @@ CACHE_LIMITER_FUNC(public) gettimeofday(&tv, NULL); now = tv.tv_sec + PS(cache_expire) * 60; -#define EXPIRES "Expires: " memcpy(buf, EXPIRES, sizeof(EXPIRES) - 1); strcpy_gmt(buf + sizeof(EXPIRES) - 1, &now); ADD_HEADER(buf); @@ -871,8 +887,10 @@ CACHE_LIMITER_FUNC(private) CACHE_LIMITER_FUNC(nocache) { ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT"); + /* For HTTP/1.1 conforming clients and the rest (MSIE 5) */ ADD_HEADER("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); + /* For HTTP/1.0 conforming clients */ ADD_HEADER("Pragma: no-cache"); } @@ -914,6 +932,13 @@ static int php_session_cache_limiter(TSRMLS_D) return -1; } + + +/* ********************* + * Cookie Management * + ********************* */ + + #define COOKIE_SET_COOKIE "Set-Cookie: " #define COOKIE_EXPIRES "; expires=" #define COOKIE_PATH "; path=" @@ -990,11 +1015,12 @@ PHPAPI ps_module *_php_find_ps_module(char *name TSRMLS_DC) ps_module **mod; int i; - for (i = 0, mod = ps_modules; i < MAX_MODULES; i++, mod++) + for (i = 0, mod = ps_modules; i < MAX_MODULES; i++, mod++) { if (*mod && !strcasecmp(name, (*mod)->s_name)) { ret = *mod; break; } + } return ret; } @@ -1004,11 +1030,12 @@ PHPAPI const ps_serializer *_php_find_ps_serializer(char *name TSRMLS_DC) const ps_serializer *ret = NULL; const ps_serializer *mod; - for (mod = ps_serializers; mod->name; mod++) + for (mod = ps_serializers; mod->name; mod++) { if (!strcasecmp(name, mod->name)) { ret = mod; break; } + } return ret; } @@ -1068,8 +1095,7 @@ PHPAPI void php_session_start(TSRMLS_D) if (value) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot find save handler %s", value); - } - else { + } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot find unknown save handler"); } return; @@ -1133,8 +1159,9 @@ PHPAPI void php_session_start(TSRMLS_D) char *q; p += lensess + 1; - if ((q = strpbrk(p, "/?\\"))) + if ((q = strpbrk(p, "/?\\"))) { PS(id) = estrndup(p, q - p); + } } /* check whether the current request was referred to by @@ -1151,15 +1178,17 @@ PHPAPI void php_session_start(TSRMLS_D) efree(PS(id)); PS(id) = NULL; PS(send_cookie) = 1; - if (PS(use_trans_sid)) + if (PS(use_trans_sid)) { PS(apply_trans_sid) = 1; + } } php_session_initialize(TSRMLS_C); if (!PS(use_cookies) && PS(send_cookie)) { - if (PS(use_trans_sid)) + if (PS(use_trans_sid)) { PS(apply_trans_sid) = 1; + } PS(send_cookie) = 0; } @@ -1175,74 +1204,74 @@ PHPAPI void php_session_start(TSRMLS_D) nrand = (int) ((float) PS(gc_divisor) * php_combined_lcg(TSRMLS_C)); if (nrand < PS(gc_probability)) { PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &nrdels TSRMLS_CC); -#if 0 - if (nrdels != -1) +#ifdef SESSION_DEBUG + if (nrdels != -1) { php_error_docref(NULL TSRMLS_CC, E_NOTICE, "purged %d expired session objects", nrdels); + } #endif } } } -static int php_session_destroy(TSRMLS_D) +static void php_session_flush(TSRMLS_D) { - int retval = SUCCESS; - - if (PS(session_status) != php_session_active) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Trying to destroy uninitialized session"); - return FAILURE; + if (PS(session_status) == php_session_active) { + PS(session_status) = php_session_none; + zend_try { + php_session_save_current_state(TSRMLS_C); + } zend_end_try(); } +} - if (PS(mod)->s_destroy(&PS(mod_data), PS(id) TSRMLS_CC) == FAILURE) { - retval = FAILURE; - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session object destruction failed"); - } - - php_rshutdown_session_globals(TSRMLS_C); - php_rinit_session_globals(TSRMLS_C); - return retval; +PHPAPI void session_adapt_url(const char *url, size_t urllen, char **new, size_t *newlen TSRMLS_DC) +{ + if (PS(apply_trans_sid) && (PS(session_status) == php_session_active)) { + *new = php_url_scanner_adapt_single_url(url, urllen, PS(session_name), PS(id), newlen TSRMLS_CC); + } } +/* ******************************** + * Userspace exported functions * + ******************************** */ + /* {{{ proto void session_set_cookie_params(int lifetime [, string path [, string domain [, bool secure[, bool httponly]]]]) Set session cookie parameters */ -PHP_FUNCTION(session_set_cookie_params) +static PHP_FUNCTION(session_set_cookie_params) { - zval **lifetime, **path, **domain, **secure, **httponly; - - if (!PS(use_cookies)) + /* lifetime is really a numeric, but the alter_ini_entry method wants a string */ + char *lifetime, *path = NULL, *domain = NULL; + int lifetime_len, path_len, domain_len, argc = ZEND_NUM_ARGS(); + zend_bool secure = 0, httponly = 0; + + if (!PS(use_cookies) || + zend_parse_parameters(argc TSRMLS_CC, "s|ssbb", &lifetime, &lifetime_len, &path, &path_len, + &domain, &domain_len, &secure, &httponly) == FAILURE) { return; + } - if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 5 || - zend_get_parameters_ex(ZEND_NUM_ARGS(), &lifetime, &path, &domain, &secure, &httponly) == FAILURE) - WRONG_PARAM_COUNT; - - convert_to_string_ex(lifetime); - 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); + zend_alter_ini_entry("session.cookie_lifetime", sizeof("session.cookie_lifetime"), lifetime, lifetime_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); - if (ZEND_NUM_ARGS() > 1) { - convert_to_string_ex(path); - zend_alter_ini_entry("session.cookie_path", sizeof("session.cookie_path"), Z_STRVAL_PP(path), Z_STRLEN_PP(path), PHP_INI_USER, PHP_INI_STAGE_RUNTIME); + if (path) { + zend_alter_ini_entry("session.cookie_path", sizeof("session.cookie_path"), path, path_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); + } + if (domain) { + zend_alter_ini_entry("session.cookie_domain", sizeof("session.cookie_domain"), domain, domain_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); + } - if (ZEND_NUM_ARGS() > 2) { - convert_to_string_ex(domain); - zend_alter_ini_entry("session.cookie_domain", sizeof("session.cookie_domain"), Z_STRVAL_PP(domain), Z_STRLEN_PP(domain), PHP_INI_USER, PHP_INI_STAGE_RUNTIME); - if (ZEND_NUM_ARGS() > 3) { - convert_to_long_ex(secure); - zend_alter_ini_entry("session.cookie_secure", sizeof("session.cookie_secure"), Z_BVAL_PP(secure)?"1":"0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); - } - if (ZEND_NUM_ARGS() > 4) { - convert_to_long_ex(httponly); - zend_alter_ini_entry("session.cookie_httponly", sizeof("session.cookie_httponly"), Z_BVAL_PP(httponly)?"1":"0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); - } - } + if (argc > 3) { + zend_alter_ini_entry("session.cookie_secure", sizeof("session.cookie_secure"), secure ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); + } + if (argc > 4) { + zend_alter_ini_entry("session.cookie_httponly", sizeof("session.cookie_httponly"), httponly ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); } } /* }}} */ /* {{{ proto array session_get_cookie_params(void) Return the session cookie parameters */ -PHP_FUNCTION(session_get_cookie_params) +static PHP_FUNCTION(session_get_cookie_params) { if (ZEND_NUM_ARGS() != 0) { WRONG_PARAM_COUNT; @@ -1260,35 +1289,32 @@ PHP_FUNCTION(session_get_cookie_params) /* {{{ proto string session_name([string newname]) Return the current session name. If newname is given, the session name is replaced with newname */ -PHP_FUNCTION(session_name) +static PHP_FUNCTION(session_name) { - zval **p_name; - int ac = ZEND_NUM_ARGS(); - char *old; + char *name = NULL; + int name_len; - if (ac < 0 || ac > 1 || zend_get_parameters_ex(ac, &p_name) == FAILURE) - WRONG_PARAM_COUNT; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) { + return; + } - old = estrdup(PS(session_name)); + RETVAL_STRING(PS(session_name), 1); - if (ac == 1) { - convert_to_string_ex(p_name); - zend_alter_ini_entry("session.name", sizeof("session.name"), Z_STRVAL_PP(p_name), Z_STRLEN_PP(p_name), PHP_INI_USER, PHP_INI_STAGE_RUNTIME); + if (name) { + zend_alter_ini_entry("session.name", sizeof("session.name"), name, name_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); } - - RETVAL_STRING(old, 0); } /* }}} */ /* {{{ proto string session_module_name([string newname]) Return the current module name used for accessing session data. If newname is given, the module name is replaced with newname */ -PHP_FUNCTION(session_module_name) +static PHP_FUNCTION(session_module_name) { - zval **p_name; - int ac = ZEND_NUM_ARGS(); + char *name = NULL; + int name_len; - if (ac < 0 || ac > 1 || zend_get_parameters_ex(ac, &p_name) == FAILURE) { - WRONG_PARAM_COUNT; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) { + return; } /* Set return_value to current module name */ @@ -1298,11 +1324,10 @@ PHP_FUNCTION(session_module_name) RETVAL_EMPTY_STRING(); } - if (ac == 1) { - convert_to_string_ex(p_name); - if (!_php_find_ps_module(Z_STRVAL_PP(p_name) TSRMLS_CC)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot find named PHP session module (%s)", - Z_STRVAL_PP(p_name)); + if (name) { + if (!_php_find_ps_module(name TSRMLS_CC)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot find named PHP session module (%s)", name); + zval_dtor(return_value); RETURN_FALSE; } @@ -1311,26 +1336,29 @@ PHP_FUNCTION(session_module_name) } PS(mod_data) = NULL; - zend_alter_ini_entry("session.save_handler", sizeof("session.save_handler"), Z_STRVAL_PP(p_name), Z_STRLEN_PP(p_name), PHP_INI_USER, PHP_INI_STAGE_RUNTIME); + zend_alter_ini_entry("session.save_handler", sizeof("session.save_handler"), name, name_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); } } /* }}} */ /* {{{ proto void session_set_save_handler(string open, string close, string read, string write, string destroy, string gc) Sets user-level functions */ -PHP_FUNCTION(session_set_save_handler) +static PHP_FUNCTION(session_set_save_handler) { zval **args[6]; int i; ps_user *mdata; zval name; - if (ZEND_NUM_ARGS() != 6 || zend_get_parameters_array_ex(6, args) == FAILURE) - WRONG_PARAM_COUNT; - - if (PS(session_status) != php_session_none) + if (PS(session_status) != php_session_none) { RETURN_FALSE; + } + + if (ZEND_NUM_ARGS() != 6 || zend_get_parameters_array_ex(6, args) == FAILURE) { + WRONG_PARAM_COUNT; + } + for (i = 0; i < 6; i++) { if (!zend_is_callable(*args[i], 0, &name)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument %d is not a valid callback", i+1); @@ -1357,61 +1385,56 @@ PHP_FUNCTION(session_set_save_handler) /* {{{ proto string session_save_path([string newname]) Return the current save path passed to module_name. If newname is given, the save path is replaced with newname */ -PHP_FUNCTION(session_save_path) +static PHP_FUNCTION(session_save_path) { - zval **p_name; - int ac = ZEND_NUM_ARGS(); - char *old; + char *name; + int name_len; - if (ac < 0 || ac > 1 || zend_get_parameters_ex(ac, &p_name) == FAILURE) - WRONG_PARAM_COUNT; - - old = estrdup(PS(save_path)); + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) { + return; + } - if (ac == 1) { - convert_to_string_ex(p_name); - if (memchr(Z_STRVAL_PP(p_name), '\0', Z_STRLEN_PP(p_name)) != NULL) { + RETVAL_STRING(PS(save_path), 1); + + if (name) { + if (memchr(name, '\0', name_len) != NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "The save_path cannot contain NULL characters."); - efree(old); + + zval_dtor(return_value); RETURN_FALSE; } - zend_alter_ini_entry("session.save_path", sizeof("session.save_path"), Z_STRVAL_PP(p_name), Z_STRLEN_PP(p_name), PHP_INI_USER, PHP_INI_STAGE_RUNTIME); + zend_alter_ini_entry("session.save_path", sizeof("session.save_path"), name, name_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); } - - RETVAL_STRING(old, 0); } /* }}} */ /* {{{ proto string session_id([string newid]) Return the current session id. If newid is given, the session id is replaced with newid */ -PHP_FUNCTION(session_id) +static PHP_FUNCTION(session_id) { - zval **p_name; - int ac = ZEND_NUM_ARGS(); - char *old; + char *name; + int name_len; - if (ac < 0 || ac > 1 || zend_get_parameters_ex(ac, &p_name) == FAILURE) - WRONG_PARAM_COUNT; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) { + return; + } if (PS(id)) { - old = estrdup(PS(id)); + RETVAL_STRING(PS(id), name ? 0 : 1); } else { - old = STR_EMPTY_ALLOC(); + RETVAL_EMPTY_STRING(); } - if (ac == 1) { - convert_to_string_ex(p_name); - if (PS(id)) efree(PS(id)); - PS(id) = estrndup(Z_STRVAL_PP(p_name), Z_STRLEN_PP(p_name)); + if (name) { + /* PS(id) was given to retval, doesn't need to be freed */ + PS(id) = estrndup(name, name_len); } - - RETVAL_STRING(old, 0); } /* }}} */ /* {{{ proto bool session_regenerate_id([bool delete_old_session]) Update the current session id with a newly generated one. If delete_old_session is set to true, remove the old session. */ -PHP_FUNCTION(session_regenerate_id) +static PHP_FUNCTION(session_regenerate_id) { zend_bool del_ses = 0; @@ -1446,45 +1469,40 @@ PHP_FUNCTION(session_regenerate_id) /* {{{ proto string session_cache_limiter([string new_cache_limiter]) Return the current cache limiter. If new_cache_limited is given, the current cache_limiter is replaced with new_cache_limiter */ -PHP_FUNCTION(session_cache_limiter) +static PHP_FUNCTION(session_cache_limiter) { - zval **p_cache_limiter; - int ac = ZEND_NUM_ARGS(); - char *old; + char *limiter; + int limiter_len; - if (ac < 0 || ac > 1 || zend_get_parameters_ex(ac, &p_cache_limiter) == FAILURE) - WRONG_PARAM_COUNT; - - old = estrdup(PS(cache_limiter)); + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &limiter, &limiter_len) == FAILURE) { + return; + } - if (ac == 1) { - convert_to_string_ex(p_cache_limiter); - zend_alter_ini_entry("session.cache_limiter", sizeof("session.cache_limiter"), Z_STRVAL_PP(p_cache_limiter), Z_STRLEN_PP(p_cache_limiter), PHP_INI_USER, PHP_INI_STAGE_RUNTIME); + RETVAL_STRING(PS(cache_limiter), 1); + + if (limiter) { + zend_alter_ini_entry("session.cache_limiter", sizeof("session.cache_limiter"), limiter, limiter_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); } - - RETVAL_STRING(old, 0); } /* }}} */ /* {{{ proto int session_cache_expire([int new_cache_expire]) Return the current cache expire. If new_cache_expire is given, the current cache_expire is replaced with new_cache_expire */ -PHP_FUNCTION(session_cache_expire) +static PHP_FUNCTION(session_cache_expire) { - zval **p_cache_expire; - int ac = ZEND_NUM_ARGS(); - long old; + /* Expires is really a numeric, but the alter_ini_entry method wants a string */ + char *expires; + int expires_len; - old = PS(cache_expire); + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &expires, &expires_len) == FAILURE) { + return; + } - if (ac < 0 || ac > 1 || zend_get_parameters_ex(ac, &p_cache_expire) == FAILURE) - WRONG_PARAM_COUNT; + RETVAL_LONG(PS(cache_expire)); - if (ac == 1) { - convert_to_string_ex(p_cache_expire); - zend_alter_ini_entry("session.cache_expire", sizeof("session.cache_expire"), Z_STRVAL_PP(p_cache_expire), Z_STRLEN_PP(p_cache_expire), ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); + if (expires) { + zend_alter_ini_entry("session.cache_expire", sizeof("session.cache_expire"), expires, expires_len, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME); } - - RETVAL_LONG(old); } /* }}} */ @@ -1512,7 +1530,7 @@ static void php_register_var(zval** entry TSRMLS_DC) /* {{{ proto string session_encode(void) Serializes the current setup and returns the serialized representation */ -PHP_FUNCTION(session_encode) +static PHP_FUNCTION(session_encode) { int len; char *enc; @@ -1532,21 +1550,20 @@ PHP_FUNCTION(session_encode) /* {{{ proto bool session_decode(string data) Deserializes data and reinitializes the variables */ -PHP_FUNCTION(session_decode) +static PHP_FUNCTION(session_decode) { - zval **str; - - if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) { - WRONG_PARAM_COUNT; - } + char *str; + int str_len; if (PS(session_status) == php_session_none) { RETURN_FALSE; } - convert_to_string_ex(str); + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { + return; + } - php_session_decode(Z_STRVAL_PP(str), Z_STRLEN_PP(str) TSRMLS_CC); + php_session_decode(str, str_len TSRMLS_CC); RETURN_TRUE; } @@ -1554,7 +1571,7 @@ PHP_FUNCTION(session_decode) /* {{{ proto bool session_start(void) Begin session - reinitializes freezed variables, registers browsers etc */ -PHP_FUNCTION(session_start) +static PHP_FUNCTION(session_start) { /* skipping check for non-zero args for performance reasons here ?*/ php_session_start(TSRMLS_C); @@ -1564,27 +1581,24 @@ PHP_FUNCTION(session_start) /* {{{ proto bool session_destroy(void) Destroy the current session and all data associated with it */ -PHP_FUNCTION(session_destroy) +static PHP_FUNCTION(session_destroy) { if (ZEND_NUM_ARGS() != 0) { WRONG_PARAM_COUNT; } - if (php_session_destroy(TSRMLS_C) == SUCCESS) { - RETURN_TRUE; - } else { - RETURN_FALSE; - } + RETURN_BOOL(php_session_destroy(TSRMLS_C) == SUCCESS); } /* }}} */ /* {{{ proto void session_unset(void) Unset all registered variables */ -PHP_FUNCTION(session_unset) +static PHP_FUNCTION(session_unset) { - if (PS(session_status) == php_session_none) + if (PS(session_status) == php_session_none) { RETURN_FALSE; + } IF_SESSION_VARS() { HashTable *ht = Z_ARRVAL_P(PS(http_session_vars)); @@ -1595,39 +1609,45 @@ PHP_FUNCTION(session_unset) } /* }}} */ -PHPAPI void session_adapt_url(const char *url, size_t urllen, char **new, size_t *newlen TSRMLS_DC) +/* {{{ proto void session_write_close(void) + Write session data and end session */ +static PHP_FUNCTION(session_write_close) { - if (PS(apply_trans_sid) && (PS(session_status) == php_session_active)) { - *new = php_url_scanner_adapt_single_url(url, urllen, PS(session_name), PS(id), newlen TSRMLS_CC); - } + php_session_flush(TSRMLS_C); } +/* }}} */ -static void php_rinit_session_globals(TSRMLS_D) -{ - PS(id) = NULL; - PS(session_status) = php_session_none; - PS(mod_data) = NULL; - PS(http_session_vars) = NULL; -} +/* {{{ session_functions[] + */ +static zend_function_entry session_functions[] = { + PHP_FE(session_name, NULL) + PHP_FE(session_module_name, NULL) + PHP_FE(session_save_path, NULL) + PHP_FE(session_id, NULL) + PHP_FE(session_regenerate_id, NULL) + PHP_FE(session_decode, NULL) + PHP_FE(session_encode, NULL) + PHP_FE(session_start, NULL) + PHP_FE(session_destroy, NULL) + PHP_FE(session_unset, NULL) + PHP_FE(session_set_save_handler, NULL) + PHP_FE(session_cache_limiter, NULL) + PHP_FE(session_cache_expire, NULL) + PHP_FE(session_set_cookie_params, NULL) + PHP_FE(session_get_cookie_params, NULL) + PHP_FE(session_write_close, NULL) -static void php_rshutdown_session_globals(TSRMLS_D) -{ - if (PS(http_session_vars)) { - zval_ptr_dtor(&PS(http_session_vars)); - PS(http_session_vars) = NULL; - } - if (PS(mod_data)) { - zend_try { - PS(mod)->s_close(&PS(mod_data) TSRMLS_CC); - } zend_end_try(); - } - if (PS(id)) { - efree(PS(id)); - } -} + PHP_FALIAS(session_commit, session_write_close, NULL) + {NULL, NULL, NULL} +}; +/* }}} */ -PHP_RINIT_FUNCTION(session) +/* ******************************** + * Module Setup and Destruction * + ******************************** */ + +static PHP_RINIT_FUNCTION(session) { php_rinit_session_globals(TSRMLS_C); @@ -1653,24 +1673,7 @@ PHP_RINIT_FUNCTION(session) return SUCCESS; } -static void php_session_flush(TSRMLS_D) -{ - if (PS(session_status) == php_session_active) { - PS(session_status) = php_session_none; - zend_try { - php_session_save_current_state(TSRMLS_C); - } zend_end_try(); - } -} - -/* {{{ proto void session_write_close(void) - Write session data and end session */ -PHP_FUNCTION(session_write_close) -{ - php_session_flush(TSRMLS_C); -} - -PHP_RSHUTDOWN_FUNCTION(session) +static PHP_RSHUTDOWN_FUNCTION(session) { php_session_flush(TSRMLS_C); php_rshutdown_session_globals(TSRMLS_C); @@ -1690,7 +1693,7 @@ static PHP_GINIT_FUNCTION(ps) ps_globals->http_session_vars = NULL; } -PHP_MINIT_FUNCTION(session) +static PHP_MINIT_FUNCTION(session) { zend_register_auto_global("_SESSION", sizeof("_SESSION")-1, NULL TSRMLS_CC); @@ -1705,7 +1708,7 @@ PHP_MINIT_FUNCTION(session) return SUCCESS; } -PHP_MSHUTDOWN_FUNCTION(session) +static PHP_MSHUTDOWN_FUNCTION(session) { UNREGISTER_INI_ENTRIES(); @@ -1720,7 +1723,7 @@ PHP_MSHUTDOWN_FUNCTION(session) } -PHP_MINFO_FUNCTION(session) +static PHP_MINFO_FUNCTION(session) { ps_module **mod; ps_serializer *ser; @@ -1768,6 +1771,25 @@ PHP_MINFO_FUNCTION(session) DISPLAY_INI_ENTRIES(); } +zend_module_entry session_module_entry = { + STANDARD_MODULE_HEADER, + "session", + session_functions, + PHP_MINIT(session), PHP_MSHUTDOWN(session), + PHP_RINIT(session), PHP_RSHUTDOWN(session), + PHP_MINFO(session), + NO_VERSION_YET, + PHP_MODULE_GLOBALS(ps), + PHP_GINIT(ps), + NULL, + NULL, + STANDARD_MODULE_PROPERTIES_EX +}; + +#ifdef COMPILE_DL_SESSION +ZEND_GET_MODULE(session) +#endif + /* * Local variables: