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