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