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