This source file includes following definitions.
- php_rinit_session_globals
- php_rshutdown_session_globals
- php_session_destroy
- php_add_session_var
- php_set_session_var
- php_get_session_var
- php_session_track_init
- php_session_encode
- php_session_decode
- bin_to_readable
- php_session_create_id
- php_session_valid_key
- php_session_gc
- php_session_initialize
- php_session_save_current_state
- PHP_INI_MH
- PHP_INI_MH
- PHP_INI_MH
- PHP_INI_MH
- PHP_INI_MH
- PHP_INI_MH
- PHP_INI_MH
- PHP_INI_BEGIN
- PS_SERIALIZER_DECODE_FUNC
- PS_SERIALIZER_ENCODE_FUNC
- PS_SERIALIZER_DECODE_FUNC
- PS_SERIALIZER_ENCODE_FUNC
- PS_SERIALIZER_DECODE_FUNC
- php_session_register_serializer
- php_session_register_module
- php_session_validate_sid
- php_session_update_timestamp
- strcpy_gmt
- last_modified
- CACHE_LIMITER_FUNC
- CACHE_LIMITER_FUNC
- CACHE_LIMITER_FUNC
- CACHE_LIMITER_FUNC
- php_session_cache_limiter
- php_session_remove_cookie
- php_session_send_cookie
- _php_find_ps_module
- _php_find_ps_serializer
- ppid2sid
- php_session_reset_id
- php_session_start
- php_session_flush
- php_session_abort
- php_session_reset
- session_adapt_url
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- php_session_start_set_ini
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- php_rinit_session
- PHP_RINIT_FUNCTION
- PHP_RSHUTDOWN_FUNCTION
- PHP_GINIT_FUNCTION
- PHP_MINIT_FUNCTION
- PHP_MSHUTDOWN_FUNCTION
- PHP_MINFO_FUNCTION
- early_find_sid_in
- php_session_rfc1867_early_find_sid
- php_check_cancel_upload
- php_session_rfc1867_update
- php_session_rfc1867_cleanup
- php_session_rfc1867_callback
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 "rfc1867.h"
41 #include "php_variables.h"
42 #include "php_session.h"
43 #include "ext/standard/md5.h"
44 #include "ext/standard/sha1.h"
45 #include "ext/standard/php_var.h"
46 #include "ext/date/php_date.h"
47 #include "ext/standard/php_lcg.h"
48 #include "ext/standard/url_scanner_ex.h"
49 #include "ext/standard/php_rand.h"
50 #include "ext/standard/info.h"
51 #include "zend_smart_str.h"
52 #include "ext/standard/url.h"
53 #include "ext/standard/basic_functions.h"
54 #include "ext/standard/head.h"
55
56 #include "mod_files.h"
57 #include "mod_user.h"
58
59 #ifdef HAVE_LIBMM
60 #include "mod_mm.h"
61 #endif
62
63 PHPAPI ZEND_DECLARE_MODULE_GLOBALS(ps)
64
65 static int php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra);
66 static int (*php_session_rfc1867_orig_callback)(unsigned int event, void *event_data, void **extra);
67 static void php_session_track_init(void);
68
69
70 zend_class_entry *php_session_class_entry;
71
72
73 zend_class_entry *php_session_iface_entry;
74
75
76 zend_class_entry *php_session_id_iface_entry;
77
78
79 zend_class_entry *php_session_update_timestamp_class_entry;
80
81
82 zend_class_entry *php_session_update_timestamp_iface_entry;
83
84
85
86
87
88 #define IF_SESSION_VARS() \
89 if (Z_ISREF_P(&PS(http_session_vars)) && Z_TYPE_P(Z_REFVAL(PS(http_session_vars))) == IS_ARRAY)
90
91 #define SESSION_CHECK_ACTIVE_STATE \
92 if (PS(session_status) == php_session_active) { \
93 php_error_docref(NULL, E_WARNING, "A session is active. You cannot change the session module's ini settings at this time"); \
94 return FAILURE; \
95 }
96
97 #define APPLY_TRANS_SID (PS(use_trans_sid) && !PS(use_only_cookies))
98
99 static void php_session_send_cookie(void);
100
101
102 static inline void php_rinit_session_globals(void)
103 {
104
105 PS(id) = NULL;
106 PS(session_status) = php_session_none;
107 PS(mod_data) = NULL;
108 PS(mod_user_is_open) = 0;
109 PS(define_sid) = 1;
110 PS(session_vars) = NULL;
111 ZVAL_UNDEF(&PS(http_session_vars));
112 }
113
114
115
116 static inline void php_rshutdown_session_globals(void)
117 {
118
119 if (!Z_ISUNDEF(PS(http_session_vars))) {
120 zval_ptr_dtor(&PS(http_session_vars));
121 ZVAL_UNDEF(&PS(http_session_vars));
122 }
123 if (PS(mod_data) || PS(mod_user_implemented)) {
124 zend_try {
125 PS(mod)->s_close(&PS(mod_data));
126 } zend_end_try();
127 }
128 if (PS(id)) {
129 zend_string_release(PS(id));
130 PS(id) = NULL;
131 }
132 if (PS(session_vars)) {
133 zend_string_release(PS(session_vars));
134 PS(session_vars) = NULL;
135 }
136 }
137
138
139 static int php_session_destroy(void)
140 {
141 int retval = SUCCESS;
142
143 if (PS(session_status) != php_session_active) {
144 php_error_docref(NULL, E_WARNING, "Trying to destroy uninitialized session");
145 return FAILURE;
146 }
147
148 if (PS(id) && PS(mod)->s_destroy(&PS(mod_data), PS(id)) == FAILURE) {
149 retval = FAILURE;
150 php_error_docref(NULL, E_WARNING, "Session object destruction failed");
151 }
152
153 php_rshutdown_session_globals();
154 php_rinit_session_globals();
155
156 return retval;
157 }
158
159
160 PHPAPI void php_add_session_var(zend_string *name)
161 {
162 zval *sym_track = NULL;
163
164 IF_SESSION_VARS() {
165 sym_track = zend_hash_find(Z_ARRVAL_P(Z_REFVAL(PS(http_session_vars))), name);
166 } else {
167 return;
168 }
169
170 if (sym_track == NULL) {
171 zval empty_var;
172
173 ZVAL_NULL(&empty_var);
174 zend_hash_update(Z_ARRVAL_P(Z_REFVAL(PS(http_session_vars))), name, &empty_var);
175 }
176 }
177
178
179 PHPAPI zval* php_set_session_var(zend_string *name, zval *state_val, php_unserialize_data_t *var_hash)
180 {
181 IF_SESSION_VARS() {
182 return zend_hash_update(Z_ARRVAL_P(Z_REFVAL(PS(http_session_vars))), name, state_val);
183 }
184 return NULL;
185 }
186
187
188 PHPAPI zval* php_get_session_var(zend_string *name)
189 {
190 IF_SESSION_VARS() {
191 return zend_hash_find(Z_ARRVAL_P(Z_REFVAL(PS(http_session_vars))), name);
192 }
193 return NULL;
194 }
195
196
197 static void php_session_track_init(void)
198 {
199 zval session_vars;
200 zend_string *var_name = zend_string_init("_SESSION", sizeof("_SESSION") - 1, 0);
201
202 zend_delete_global_variable(var_name);
203
204 if (!Z_ISUNDEF(PS(http_session_vars))) {
205 zval_ptr_dtor(&PS(http_session_vars));
206 }
207
208 array_init(&session_vars);
209 ZVAL_NEW_REF(&PS(http_session_vars), &session_vars);
210 Z_ADDREF_P(&PS(http_session_vars));
211 zend_hash_update_ind(&EG(symbol_table), var_name, &PS(http_session_vars));
212 zend_string_release(var_name);
213 }
214
215
216 static zend_string *php_session_encode(void)
217 {
218 IF_SESSION_VARS() {
219 if (!PS(serializer)) {
220 php_error_docref(NULL, E_WARNING, "Unknown session.serialize_handler. Failed to encode session object");
221 return NULL;
222 }
223 return PS(serializer)->encode();
224 } else {
225 php_error_docref(NULL, E_WARNING, "Cannot encode non-existent session");
226 }
227 return NULL;
228 }
229
230
231 static int php_session_decode(zend_string *data)
232 {
233 if (!PS(serializer)) {
234 php_error_docref(NULL, E_WARNING, "Unknown session.serialize_handler. Failed to decode session object");
235 return FAILURE;
236 }
237 if (PS(serializer)->decode(ZSTR_VAL(data), ZSTR_LEN(data)) == FAILURE) {
238 php_session_destroy();
239 php_session_track_init();
240 php_error_docref(NULL, E_WARNING, "Failed to decode session object. Session has been destroyed");
241 return FAILURE;
242 }
243 return SUCCESS;
244 }
245
246
247
248
249
250
251
252
253 static char hexconvtab[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,-";
254
255 enum {
256 PS_HASH_FUNC_MD5,
257 PS_HASH_FUNC_SHA1,
258 PS_HASH_FUNC_OTHER
259 };
260
261
262 static char *bin_to_readable(char *in, size_t inlen, char *out, char nbits)
263 {
264 unsigned char *p, *q;
265 unsigned short w;
266 int mask;
267 int have;
268
269 p = (unsigned char *)in;
270 q = (unsigned char *)in + inlen;
271
272 w = 0;
273 have = 0;
274 mask = (1 << nbits) - 1;
275
276 while (1) {
277 if (have < nbits) {
278 if (p < q) {
279 w |= *p++ << have;
280 have += 8;
281 } else {
282
283 if (have == 0) break;
284
285 have = nbits;
286 }
287 }
288
289
290 *out++ = hexconvtab[w & mask];
291 w >>= nbits;
292 have -= nbits;
293 }
294
295 *out = '\0';
296 return out;
297 }
298
299
300 PHPAPI zend_string *php_session_create_id(PS_CREATE_SID_ARGS)
301 {
302 PHP_MD5_CTX md5_context;
303 PHP_SHA1_CTX sha1_context;
304 #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
305 void *hash_context = NULL;
306 #endif
307 unsigned char *digest;
308 size_t digest_len;
309 char *buf;
310 struct timeval tv;
311 zval *array;
312 zval *token;
313 zend_string *outid;
314 char *remote_addr = NULL;
315
316 gettimeofday(&tv, NULL);
317
318 if ((array = zend_hash_str_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER") - 1)) &&
319 Z_TYPE_P(array) == IS_ARRAY &&
320 (token = zend_hash_str_find(Z_ARRVAL_P(array), "REMOTE_ADDR", sizeof("REMOTE_ADDR") - 1)) &&
321 Z_TYPE_P(token) == IS_STRING
322 ) {
323 remote_addr = Z_STRVAL_P(token);
324 }
325
326
327 spprintf(&buf, 0, "%.15s%ld" ZEND_LONG_FMT "%0.8F", remote_addr ? remote_addr : "", tv.tv_sec, (zend_long)tv.tv_usec, php_combined_lcg() * 10);
328
329 switch (PS(hash_func)) {
330 case PS_HASH_FUNC_MD5:
331 PHP_MD5Init(&md5_context);
332 PHP_MD5Update(&md5_context, (unsigned char *) buf, strlen(buf));
333 digest_len = 16;
334 break;
335 case PS_HASH_FUNC_SHA1:
336 PHP_SHA1Init(&sha1_context);
337 PHP_SHA1Update(&sha1_context, (unsigned char *) buf, strlen(buf));
338 digest_len = 20;
339 break;
340 #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
341 case PS_HASH_FUNC_OTHER:
342 if (!PS(hash_ops)) {
343 efree(buf);
344 php_error_docref(NULL, E_ERROR, "Invalid session hash function");
345 return NULL;
346 }
347
348 hash_context = emalloc(PS(hash_ops)->context_size);
349 PS(hash_ops)->hash_init(hash_context);
350 PS(hash_ops)->hash_update(hash_context, (unsigned char *) buf, strlen(buf));
351 digest_len = PS(hash_ops)->digest_size;
352 break;
353 #endif
354 default:
355 efree(buf);
356 php_error_docref(NULL, E_ERROR, "Invalid session hash function");
357 return NULL;
358 }
359 efree(buf);
360
361 if (PS(entropy_length) > 0) {
362 #ifdef PHP_WIN32
363 unsigned char rbuf[2048];
364 size_t toread = PS(entropy_length);
365
366 if (php_win32_get_random_bytes(rbuf, MIN(toread, sizeof(rbuf))) == SUCCESS){
367
368 switch (PS(hash_func)) {
369 case PS_HASH_FUNC_MD5:
370 PHP_MD5Update(&md5_context, rbuf, toread);
371 break;
372 case PS_HASH_FUNC_SHA1:
373 PHP_SHA1Update(&sha1_context, rbuf, toread);
374 break;
375 # if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
376 case PS_HASH_FUNC_OTHER:
377 PS(hash_ops)->hash_update(hash_context, rbuf, toread);
378 break;
379 # endif
380 }
381 }
382 #else
383 int fd;
384
385 fd = VCWD_OPEN(PS(entropy_file), O_RDONLY);
386 if (fd >= 0) {
387 unsigned char rbuf[2048];
388 int n;
389 int to_read = PS(entropy_length);
390
391 while (to_read > 0) {
392 n = read(fd, rbuf, MIN(to_read, sizeof(rbuf)));
393 if (n <= 0) break;
394
395 switch (PS(hash_func)) {
396 case PS_HASH_FUNC_MD5:
397 PHP_MD5Update(&md5_context, rbuf, n);
398 break;
399 case PS_HASH_FUNC_SHA1:
400 PHP_SHA1Update(&sha1_context, rbuf, n);
401 break;
402 #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
403 case PS_HASH_FUNC_OTHER:
404 PS(hash_ops)->hash_update(hash_context, rbuf, n);
405 break;
406 #endif
407 }
408 to_read -= n;
409 }
410 close(fd);
411 }
412 #endif
413 }
414
415 digest = emalloc(digest_len + 1);
416 switch (PS(hash_func)) {
417 case PS_HASH_FUNC_MD5:
418 PHP_MD5Final(digest, &md5_context);
419 break;
420 case PS_HASH_FUNC_SHA1:
421 PHP_SHA1Final(digest, &sha1_context);
422 break;
423 #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
424 case PS_HASH_FUNC_OTHER:
425 PS(hash_ops)->hash_final(digest, hash_context);
426 efree(hash_context);
427 break;
428 #endif
429 }
430
431 if (PS(hash_bits_per_character) < 4
432 || PS(hash_bits_per_character) > 6) {
433 PS(hash_bits_per_character) = 4;
434
435 php_error_docref(NULL, E_WARNING, "The ini setting hash_bits_per_character is out of range (should be 4, 5, or 6) - using 4 for now");
436 }
437
438 outid = zend_string_alloc((digest_len + 2) * ((8.0f / PS(hash_bits_per_character) + 0.5)), 0);
439 ZSTR_LEN(outid) = (size_t)(bin_to_readable((char *)digest, digest_len, ZSTR_VAL(outid), (char)PS(hash_bits_per_character)) - (char *)&ZSTR_VAL(outid));
440 efree(digest);
441
442 return outid;
443 }
444
445
446
447
448
449 PHPAPI int php_session_valid_key(const char *key)
450 {
451 size_t len;
452 const char *p;
453 char c;
454 int ret = SUCCESS;
455
456 for (p = key; (c = *p); p++) {
457
458 if (!((c >= 'a' && c <= 'z')
459 || (c >= 'A' && c <= 'Z')
460 || (c >= '0' && c <= '9')
461 || c == ','
462 || c == '-')) {
463 ret = FAILURE;
464 break;
465 }
466 }
467
468 len = p - key;
469
470
471
472 if (len == 0 || len > 128) {
473 ret = FAILURE;
474 }
475
476 return ret;
477 }
478
479
480
481 static void php_session_gc(void)
482 {
483 int nrand;
484
485
486 if ((PS(mod_data) || PS(mod_user_implemented)) && PS(gc_probability) > 0) {
487 int nrdels = -1;
488
489 nrand = (int) ((float) PS(gc_divisor) * php_combined_lcg());
490 if (nrand < PS(gc_probability)) {
491 PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &nrdels);
492 #ifdef SESSION_DEBUG
493 if (nrdels != -1) {
494 php_error_docref(NULL, E_NOTICE, "purged %d expired session objects", nrdels);
495 }
496 #endif
497 }
498 }
499 }
500
501
502 static void php_session_initialize(void)
503 {
504 zend_string *val = NULL;
505
506 if (!PS(mod)) {
507 php_error_docref(NULL, E_ERROR, "No storage module chosen - failed to initialize session");
508 return;
509 }
510
511
512 if (PS(mod)->s_open(&PS(mod_data), PS(save_path), PS(session_name)) == FAILURE
513
514 ) {
515 php_error_docref(NULL, E_ERROR, "Failed to initialize storage module: %s (path: %s)", PS(mod)->s_name, PS(save_path));
516 return;
517 }
518
519
520 if (!PS(id)) {
521 PS(id) = PS(mod)->s_create_sid(&PS(mod_data));
522 if (!PS(id)) {
523 php_error_docref(NULL, E_ERROR, "Failed to create session ID: %s (path: %s)", PS(mod)->s_name, PS(save_path));
524 return;
525 }
526 if (PS(use_cookies)) {
527 PS(send_cookie) = 1;
528 }
529 } else if (PS(use_strict_mode) && PS(mod)->s_validate_sid &&
530 PS(mod)->s_validate_sid(&PS(mod_data), PS(id)) == FAILURE) {
531 if (PS(id)) {
532 zend_string_release(PS(id));
533 }
534 PS(id) = PS(mod)->s_create_sid(&PS(mod_data));
535 if (!PS(id)) {
536 PS(id) = php_session_create_id(NULL);
537 }
538 if (PS(use_cookies)) {
539 PS(send_cookie) = 1;
540 }
541 }
542
543 php_session_reset_id();
544 PS(session_status) = php_session_active;
545
546
547 php_session_track_init();
548 if (PS(mod)->s_read(&PS(mod_data), PS(id), &val, PS(gc_maxlifetime)) == FAILURE) {
549
550
551
552
553
554 }
555
556
557 php_session_gc();
558
559 if (PS(session_vars)) {
560 zend_string_release(PS(session_vars));
561 PS(session_vars) = NULL;
562 }
563 if (val) {
564 if (PS(lazy_write)) {
565 PS(session_vars) = zend_string_copy(val);
566 }
567 php_session_decode(val);
568 zend_string_release(val);
569 }
570 }
571
572
573 static void php_session_save_current_state(int write)
574 {
575 int ret = FAILURE;
576
577 if (write) {
578 IF_SESSION_VARS() {
579 if (PS(mod_data) || PS(mod_user_implemented)) {
580 zend_string *val;
581
582 val = php_session_encode();
583 if (val) {
584 if (PS(lazy_write) && PS(session_vars)
585 && PS(mod)->s_update_timestamp
586 && PS(mod)->s_update_timestamp != php_session_update_timestamp
587 && ZSTR_LEN(val) == ZSTR_LEN(PS(session_vars))
588 && !memcmp(ZSTR_VAL(val), ZSTR_VAL(PS(session_vars)), ZSTR_LEN(val))
589 ) {
590 ret = PS(mod)->s_update_timestamp(&PS(mod_data), PS(id), val, PS(gc_maxlifetime));
591 } else {
592 ret = PS(mod)->s_write(&PS(mod_data), PS(id), val, PS(gc_maxlifetime));
593 }
594 zend_string_release(val);
595 } else {
596 ret = PS(mod)->s_write(&PS(mod_data), PS(id), ZSTR_EMPTY_ALLOC(), PS(gc_maxlifetime));
597 }
598 }
599
600 if ((ret == FAILURE) && !EG(exception)) {
601 php_error_docref(NULL, E_WARNING, "Failed to write session data (%s). Please "
602 "verify that the current setting of session.save_path "
603 "is correct (%s)",
604 PS(mod)->s_name,
605 PS(save_path));
606 }
607 }
608 }
609
610 if (PS(mod_data) || PS(mod_user_implemented)) {
611 PS(mod)->s_close(&PS(mod_data));
612 }
613 }
614
615
616
617
618
619
620 static PHP_INI_MH(OnUpdateSaveHandler)
621 {
622 ps_module *tmp;
623 SESSION_CHECK_ACTIVE_STATE;
624
625 tmp = _php_find_ps_module(ZSTR_VAL(new_value));
626
627 if (PG(modules_activated) && !tmp) {
628 int err_type;
629
630 if (stage == ZEND_INI_STAGE_RUNTIME) {
631 err_type = E_WARNING;
632 } else {
633 err_type = E_ERROR;
634 }
635
636
637 if (stage != ZEND_INI_STAGE_DEACTIVATE) {
638 php_error_docref(NULL, err_type, "Cannot find save handler '%s'", ZSTR_VAL(new_value));
639 }
640 return FAILURE;
641 }
642
643 PS(default_mod) = PS(mod);
644 PS(mod) = tmp;
645
646 return SUCCESS;
647 }
648
649
650 static PHP_INI_MH(OnUpdateSerializer)
651 {
652 const ps_serializer *tmp;
653 SESSION_CHECK_ACTIVE_STATE;
654
655 tmp = _php_find_ps_serializer(ZSTR_VAL(new_value));
656
657 if (PG(modules_activated) && !tmp) {
658 int err_type;
659
660 if (stage == ZEND_INI_STAGE_RUNTIME) {
661 err_type = E_WARNING;
662 } else {
663 err_type = E_ERROR;
664 }
665
666
667 if (stage != ZEND_INI_STAGE_DEACTIVATE) {
668 php_error_docref(NULL, err_type, "Cannot find serialization handler '%s'", ZSTR_VAL(new_value));
669 }
670 return FAILURE;
671 }
672 PS(serializer) = tmp;
673
674 return SUCCESS;
675 }
676
677
678 static PHP_INI_MH(OnUpdateTransSid)
679 {
680 SESSION_CHECK_ACTIVE_STATE;
681
682 if (!strncasecmp(ZSTR_VAL(new_value), "on", sizeof("on"))) {
683 PS(use_trans_sid) = (zend_bool) 1;
684 } else {
685 PS(use_trans_sid) = (zend_bool) atoi(ZSTR_VAL(new_value));
686 }
687
688 return SUCCESS;
689 }
690
691
692 static PHP_INI_MH(OnUpdateSaveDir)
693 {
694
695 if (stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) {
696 char *p;
697
698 if (memchr(ZSTR_VAL(new_value), '\0', ZSTR_LEN(new_value)) != NULL) {
699 return FAILURE;
700 }
701
702
703 if ((p = strchr(ZSTR_VAL(new_value), ';'))) {
704 char *p2;
705 p++;
706 if ((p2 = strchr(p, ';'))) {
707 p = p2 + 1;
708 }
709 } else {
710 p = ZSTR_VAL(new_value);
711 }
712
713 if (PG(open_basedir) && *p && php_check_open_basedir(p)) {
714 return FAILURE;
715 }
716 }
717
718 OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
719 return SUCCESS;
720 }
721
722
723 static PHP_INI_MH(OnUpdateName)
724 {
725
726 if ((!ZSTR_LEN(new_value) || is_numeric_string(ZSTR_VAL(new_value), ZSTR_LEN(new_value), NULL, NULL, 0))) {
727 int err_type;
728
729 if (stage == ZEND_INI_STAGE_RUNTIME || stage == ZEND_INI_STAGE_ACTIVATE || stage == ZEND_INI_STAGE_STARTUP) {
730 err_type = E_WARNING;
731 } else {
732 err_type = E_ERROR;
733 }
734
735
736 if (stage != ZEND_INI_STAGE_DEACTIVATE) {
737 php_error_docref(NULL, err_type, "session.name cannot be a numeric or empty '%s'", ZSTR_VAL(new_value));
738 }
739 return FAILURE;
740 }
741
742 OnUpdateStringUnempty(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
743 return SUCCESS;
744 }
745
746
747 static PHP_INI_MH(OnUpdateHashFunc)
748 {
749 zend_long val;
750 char *endptr = NULL;
751
752 #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
753 PS(hash_ops) = NULL;
754 #endif
755
756 val = ZEND_STRTOL(ZSTR_VAL(new_value), &endptr, 10);
757 if (endptr && (*endptr == '\0')) {
758
759 PS(hash_func) = val ? 1 : 0;
760
761 return SUCCESS;
762 }
763
764 if (ZSTR_LEN(new_value) == (sizeof("md5") - 1) &&
765 strncasecmp(ZSTR_VAL(new_value), "md5", sizeof("md5") - 1) == 0) {
766 PS(hash_func) = PS_HASH_FUNC_MD5;
767
768 return SUCCESS;
769 }
770
771 if (ZSTR_LEN(new_value) == (sizeof("sha1") - 1) &&
772 strncasecmp(ZSTR_VAL(new_value), "sha1", sizeof("sha1") - 1) == 0) {
773 PS(hash_func) = PS_HASH_FUNC_SHA1;
774
775 return SUCCESS;
776 }
777
778 #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
779 {
780 php_hash_ops *ops = (php_hash_ops*)php_hash_fetch_ops(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
781
782 if (ops) {
783 PS(hash_func) = PS_HASH_FUNC_OTHER;
784 PS(hash_ops) = ops;
785
786 return SUCCESS;
787 }
788 }
789 #endif
790
791 php_error_docref(NULL, E_WARNING, "session.configuration 'session.hash_function' must be existing hash function. %s does not exist.", ZSTR_VAL(new_value));
792 return FAILURE;
793 }
794
795
796 static PHP_INI_MH(OnUpdateRfc1867Freq)
797 {
798 int tmp;
799 tmp = zend_atoi(ZSTR_VAL(new_value), (int)ZSTR_LEN(new_value));
800 if(tmp < 0) {
801 php_error_docref(NULL, E_WARNING, "session.upload_progress.freq must be greater than or equal to zero");
802 return FAILURE;
803 }
804 if(ZSTR_LEN(new_value) > 0 && ZSTR_VAL(new_value)[ZSTR_LEN(new_value)-1] == '%') {
805 if(tmp > 100) {
806 php_error_docref(NULL, E_WARNING, "session.upload_progress.freq cannot be over 100%%");
807 return FAILURE;
808 }
809 PS(rfc1867_freq) = -tmp;
810 } else {
811 PS(rfc1867_freq) = tmp;
812 }
813 return SUCCESS;
814 }
815
816
817
818 PHP_INI_BEGIN()
819 STD_PHP_INI_ENTRY("session.save_path", "", PHP_INI_ALL, OnUpdateSaveDir,save_path, php_ps_globals, ps_globals)
820 STD_PHP_INI_ENTRY("session.name", "PHPSESSID", PHP_INI_ALL, OnUpdateName, session_name, php_ps_globals, ps_globals)
821 PHP_INI_ENTRY("session.save_handler", "files", PHP_INI_ALL, OnUpdateSaveHandler)
822 STD_PHP_INI_BOOLEAN("session.auto_start", "0", PHP_INI_PERDIR, OnUpdateBool, auto_start, php_ps_globals, ps_globals)
823 STD_PHP_INI_ENTRY("session.gc_probability", "1", PHP_INI_ALL, OnUpdateLong, gc_probability, php_ps_globals, ps_globals)
824 STD_PHP_INI_ENTRY("session.gc_divisor", "100", PHP_INI_ALL, OnUpdateLong, gc_divisor, php_ps_globals, ps_globals)
825 STD_PHP_INI_ENTRY("session.gc_maxlifetime", "1440", PHP_INI_ALL, OnUpdateLong, gc_maxlifetime, php_ps_globals, ps_globals)
826 PHP_INI_ENTRY("session.serialize_handler", "php", PHP_INI_ALL, OnUpdateSerializer)
827 STD_PHP_INI_ENTRY("session.cookie_lifetime", "0", PHP_INI_ALL, OnUpdateLong, cookie_lifetime, php_ps_globals, ps_globals)
828 STD_PHP_INI_ENTRY("session.cookie_path", "/", PHP_INI_ALL, OnUpdateString, cookie_path, php_ps_globals, ps_globals)
829 STD_PHP_INI_ENTRY("session.cookie_domain", "", PHP_INI_ALL, OnUpdateString, cookie_domain, php_ps_globals, ps_globals)
830 STD_PHP_INI_BOOLEAN("session.cookie_secure", "", PHP_INI_ALL, OnUpdateBool, cookie_secure, php_ps_globals, ps_globals)
831 STD_PHP_INI_BOOLEAN("session.cookie_httponly", "", PHP_INI_ALL, OnUpdateBool, cookie_httponly, php_ps_globals, ps_globals)
832 STD_PHP_INI_BOOLEAN("session.use_cookies", "1", PHP_INI_ALL, OnUpdateBool, use_cookies, php_ps_globals, ps_globals)
833 STD_PHP_INI_BOOLEAN("session.use_only_cookies", "1", PHP_INI_ALL, OnUpdateBool, use_only_cookies, php_ps_globals, ps_globals)
834 STD_PHP_INI_BOOLEAN("session.use_strict_mode", "0", PHP_INI_ALL, OnUpdateBool, use_strict_mode, php_ps_globals, ps_globals)
835 STD_PHP_INI_ENTRY("session.referer_check", "", PHP_INI_ALL, OnUpdateString, extern_referer_chk, php_ps_globals, ps_globals)
836 #if HAVE_DEV_URANDOM
837 STD_PHP_INI_ENTRY("session.entropy_file", "/dev/urandom", PHP_INI_ALL, OnUpdateString, entropy_file, php_ps_globals, ps_globals)
838 STD_PHP_INI_ENTRY("session.entropy_length", "32", PHP_INI_ALL, OnUpdateLong, entropy_length, php_ps_globals, ps_globals)
839 #elif HAVE_DEV_ARANDOM
840 STD_PHP_INI_ENTRY("session.entropy_file", "/dev/arandom", PHP_INI_ALL, OnUpdateString, entropy_file, php_ps_globals, ps_globals)
841 STD_PHP_INI_ENTRY("session.entropy_length", "32", PHP_INI_ALL, OnUpdateLong, entropy_length, php_ps_globals, ps_globals)
842 #else
843 STD_PHP_INI_ENTRY("session.entropy_file", "", PHP_INI_ALL, OnUpdateString, entropy_file, php_ps_globals, ps_globals)
844 STD_PHP_INI_ENTRY("session.entropy_length", "0", PHP_INI_ALL, OnUpdateLong, entropy_length, php_ps_globals, ps_globals)
845 #endif
846 STD_PHP_INI_ENTRY("session.cache_limiter", "nocache", PHP_INI_ALL, OnUpdateString, cache_limiter, php_ps_globals, ps_globals)
847 STD_PHP_INI_ENTRY("session.cache_expire", "180", PHP_INI_ALL, OnUpdateLong, cache_expire, php_ps_globals, ps_globals)
848 PHP_INI_ENTRY("session.use_trans_sid", "0", PHP_INI_ALL, OnUpdateTransSid)
849 PHP_INI_ENTRY("session.hash_function", "0", PHP_INI_ALL, OnUpdateHashFunc)
850 STD_PHP_INI_ENTRY("session.hash_bits_per_character", "4", PHP_INI_ALL, OnUpdateLong, hash_bits_per_character, php_ps_globals, ps_globals)
851 STD_PHP_INI_BOOLEAN("session.lazy_write", "1", PHP_INI_ALL, OnUpdateBool, lazy_write, php_ps_globals, ps_globals)
852
853
854 STD_PHP_INI_BOOLEAN("session.upload_progress.enabled",
855 "1", ZEND_INI_PERDIR, OnUpdateBool, rfc1867_enabled, php_ps_globals, ps_globals)
856 STD_PHP_INI_BOOLEAN("session.upload_progress.cleanup",
857 "1", ZEND_INI_PERDIR, OnUpdateBool, rfc1867_cleanup, php_ps_globals, ps_globals)
858 STD_PHP_INI_ENTRY("session.upload_progress.prefix",
859 "upload_progress_", ZEND_INI_PERDIR, OnUpdateString, rfc1867_prefix, php_ps_globals, ps_globals)
860 STD_PHP_INI_ENTRY("session.upload_progress.name",
861 "PHP_SESSION_UPLOAD_PROGRESS", ZEND_INI_PERDIR, OnUpdateString, rfc1867_name, php_ps_globals, ps_globals)
862 STD_PHP_INI_ENTRY("session.upload_progress.freq", "1%", ZEND_INI_PERDIR, OnUpdateRfc1867Freq, rfc1867_freq, php_ps_globals, ps_globals)
863 STD_PHP_INI_ENTRY("session.upload_progress.min_freq",
864 "1", ZEND_INI_PERDIR, OnUpdateReal, rfc1867_min_freq,php_ps_globals, ps_globals)
865
866
867
868 PHP_INI_END()
869
870
871
872
873
874 PS_SERIALIZER_ENCODE_FUNC(php_serialize)
875 {
876 smart_str buf = {0};
877 php_serialize_data_t var_hash;
878
879 IF_SESSION_VARS() {
880 PHP_VAR_SERIALIZE_INIT(var_hash);
881 php_var_serialize(&buf, Z_REFVAL(PS(http_session_vars)), &var_hash);
882 PHP_VAR_SERIALIZE_DESTROY(var_hash);
883 }
884 return buf.s;
885 }
886
887
888 PS_SERIALIZER_DECODE_FUNC(php_serialize)
889 {
890 const char *endptr = val + vallen;
891 zval session_vars;
892 php_unserialize_data_t var_hash;
893 zend_string *var_name = zend_string_init("_SESSION", sizeof("_SESSION") - 1, 0);
894
895 ZVAL_NULL(&session_vars);
896 PHP_VAR_UNSERIALIZE_INIT(var_hash);
897 php_var_unserialize(&session_vars, (const unsigned char **)&val, (const unsigned char *)endptr, &var_hash);
898 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
899 if (!Z_ISUNDEF(PS(http_session_vars))) {
900 zval_ptr_dtor(&PS(http_session_vars));
901 }
902 if (Z_TYPE(session_vars) == IS_NULL) {
903 array_init(&session_vars);
904 }
905 ZVAL_NEW_REF(&PS(http_session_vars), &session_vars);
906 Z_ADDREF_P(&PS(http_session_vars));
907 zend_hash_update_ind(&EG(symbol_table), var_name, &PS(http_session_vars));
908 zend_string_release(var_name);
909 return SUCCESS;
910 }
911
912
913 #define PS_BIN_NR_OF_BITS 8
914 #define PS_BIN_UNDEF (1<<(PS_BIN_NR_OF_BITS-1))
915 #define PS_BIN_MAX (PS_BIN_UNDEF-1)
916
917 PS_SERIALIZER_ENCODE_FUNC(php_binary)
918 {
919 smart_str buf = {0};
920 php_serialize_data_t var_hash;
921 PS_ENCODE_VARS;
922
923 PHP_VAR_SERIALIZE_INIT(var_hash);
924
925 PS_ENCODE_LOOP(
926 if (ZSTR_LEN(key) > PS_BIN_MAX) continue;
927 smart_str_appendc(&buf, (unsigned char)ZSTR_LEN(key));
928 smart_str_appendl(&buf, ZSTR_VAL(key), ZSTR_LEN(key));
929 php_var_serialize(&buf, struc, &var_hash);
930 } else {
931 if (ZSTR_LEN(key) > PS_BIN_MAX) continue;
932 smart_str_appendc(&buf, (unsigned char) (ZSTR_LEN(key) & PS_BIN_UNDEF));
933 smart_str_appendl(&buf, ZSTR_VAL(key), ZSTR_LEN(key));
934 );
935
936 smart_str_0(&buf);
937 PHP_VAR_SERIALIZE_DESTROY(var_hash);
938
939 return buf.s;
940 }
941
942
943 PS_SERIALIZER_DECODE_FUNC(php_binary)
944 {
945 const char *p;
946 const char *endptr = val + vallen;
947 zval current;
948 int has_value;
949 int namelen;
950 zend_string *name;
951 php_unserialize_data_t var_hash;
952
953 PHP_VAR_UNSERIALIZE_INIT(var_hash);
954
955 for (p = val; p < endptr; ) {
956 zval *tmp;
957 namelen = ((unsigned char)(*p)) & (~PS_BIN_UNDEF);
958
959 if (namelen < 0 || namelen > PS_BIN_MAX || (p + namelen) >= endptr) {
960 return FAILURE;
961 }
962
963 has_value = *p & PS_BIN_UNDEF ? 0 : 1;
964
965 name = zend_string_init(p + 1, namelen, 0);
966
967 p += namelen + 1;
968
969 if ((tmp = zend_hash_find(&EG(symbol_table), name))) {
970 if ((Z_TYPE_P(tmp) == IS_ARRAY && Z_ARRVAL_P(tmp) == &EG(symbol_table)) || tmp == &PS(http_session_vars)) {
971 zend_string_release(name);
972 continue;
973 }
974 }
975
976 if (has_value) {
977 ZVAL_UNDEF(¤t);
978 if (php_var_unserialize(¤t, (const unsigned char **) &p, (const unsigned char *) endptr, &var_hash)) {
979 zval *zv = php_set_session_var(name, ¤t, &var_hash );
980 var_replace(&var_hash, ¤t, zv);
981 } else {
982 zval_ptr_dtor(¤t);
983 zend_string_release(name);
984 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
985 return FAILURE;
986 }
987 }
988 PS_ADD_VARL(name);
989 zend_string_release(name);
990 }
991
992 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
993
994 return SUCCESS;
995 }
996
997
998 #define PS_DELIMITER '|'
999 #define PS_UNDEF_MARKER '!'
1000
1001 PS_SERIALIZER_ENCODE_FUNC(php)
1002 {
1003 smart_str buf = {0};
1004 php_serialize_data_t var_hash;
1005 PS_ENCODE_VARS;
1006
1007 PHP_VAR_SERIALIZE_INIT(var_hash);
1008
1009 PS_ENCODE_LOOP(
1010 smart_str_appendl(&buf, ZSTR_VAL(key), ZSTR_LEN(key));
1011 if (memchr(ZSTR_VAL(key), PS_DELIMITER, ZSTR_LEN(key)) || memchr(ZSTR_VAL(key), PS_UNDEF_MARKER, ZSTR_LEN(key))) {
1012 PHP_VAR_SERIALIZE_DESTROY(var_hash);
1013 smart_str_free(&buf);
1014 return NULL;
1015 }
1016 smart_str_appendc(&buf, PS_DELIMITER);
1017
1018 php_var_serialize(&buf, struc, &var_hash);
1019 } else {
1020 smart_str_appendc(&buf, PS_UNDEF_MARKER);
1021 smart_str_appendl(&buf, ZSTR_VAL(key), ZSTR_LEN(key));
1022 smart_str_appendc(&buf, PS_DELIMITER);
1023 );
1024
1025 smart_str_0(&buf);
1026
1027 PHP_VAR_SERIALIZE_DESTROY(var_hash);
1028 return buf.s;
1029 }
1030
1031
1032 PS_SERIALIZER_DECODE_FUNC(php)
1033 {
1034 const char *p, *q;
1035 const char *endptr = val + vallen;
1036 zval current;
1037 int has_value;
1038 ptrdiff_t namelen;
1039 zend_string *name;
1040 php_unserialize_data_t var_hash;
1041
1042 PHP_VAR_UNSERIALIZE_INIT(var_hash);
1043
1044 p = val;
1045
1046 while (p < endptr) {
1047 zval *tmp;
1048 q = p;
1049 while (*q != PS_DELIMITER) {
1050 if (++q >= endptr) goto break_outer_loop;
1051 }
1052 if (p[0] == PS_UNDEF_MARKER) {
1053 p++;
1054 has_value = 0;
1055 } else {
1056 has_value = 1;
1057 }
1058
1059 namelen = q - p;
1060 name = zend_string_init(p, namelen, 0);
1061 q++;
1062
1063 if ((tmp = zend_hash_find(&EG(symbol_table), name))) {
1064 if ((Z_TYPE_P(tmp) == IS_ARRAY && Z_ARRVAL_P(tmp) == &EG(symbol_table)) || tmp == &PS(http_session_vars)) {
1065 goto skip;
1066 }
1067 }
1068
1069 if (has_value) {
1070 ZVAL_UNDEF(¤t);
1071 if (php_var_unserialize(¤t, (const unsigned char **) &q, (const unsigned char *) endptr, &var_hash)) {
1072 zval *zv = php_set_session_var(name, ¤t, &var_hash);
1073 var_replace(&var_hash, ¤t, zv);
1074 } else {
1075 zval_ptr_dtor(¤t);
1076 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1077 zend_string_release(name);
1078 return FAILURE;
1079 }
1080 }
1081 PS_ADD_VARL(name);
1082 skip:
1083 zend_string_release(name);
1084
1085 p = q;
1086 }
1087 break_outer_loop:
1088
1089 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1090
1091 return SUCCESS;
1092 }
1093
1094
1095 #define MAX_SERIALIZERS 32
1096 #define PREDEFINED_SERIALIZERS 3
1097
1098 static ps_serializer ps_serializers[MAX_SERIALIZERS + 1] = {
1099 PS_SERIALIZER_ENTRY(php_serialize),
1100 PS_SERIALIZER_ENTRY(php),
1101 PS_SERIALIZER_ENTRY(php_binary)
1102 };
1103
1104 PHPAPI int php_session_register_serializer(const char *name, zend_string *(*encode)(PS_SERIALIZER_ENCODE_ARGS), int (*decode)(PS_SERIALIZER_DECODE_ARGS))
1105 {
1106 int ret = -1;
1107 int i;
1108
1109 for (i = 0; i < MAX_SERIALIZERS; i++) {
1110 if (ps_serializers[i].name == NULL) {
1111 ps_serializers[i].name = name;
1112 ps_serializers[i].encode = encode;
1113 ps_serializers[i].decode = decode;
1114 ps_serializers[i + 1].name = NULL;
1115 ret = 0;
1116 break;
1117 }
1118 }
1119 return ret;
1120 }
1121
1122
1123
1124
1125
1126
1127 #define MAX_MODULES 32
1128 #define PREDEFINED_MODULES 2
1129
1130 static ps_module *ps_modules[MAX_MODULES + 1] = {
1131 ps_files_ptr,
1132 ps_user_ptr
1133 };
1134
1135 PHPAPI int php_session_register_module(ps_module *ptr)
1136 {
1137 int ret = -1;
1138 int i;
1139
1140 for (i = 0; i < MAX_MODULES; i++) {
1141 if (!ps_modules[i]) {
1142 ps_modules[i] = ptr;
1143 ret = 0;
1144 break;
1145 }
1146 }
1147 return ret;
1148 }
1149
1150
1151
1152 PHPAPI int php_session_validate_sid(PS_VALIDATE_SID_ARGS) {
1153 return SUCCESS;
1154 }
1155
1156
1157 PHPAPI int php_session_update_timestamp(PS_UPDATE_TIMESTAMP_ARGS) {
1158 return SUCCESS;
1159 }
1160
1161
1162
1163
1164
1165
1166 typedef struct {
1167 char *name;
1168 void (*func)(void);
1169 } php_session_cache_limiter_t;
1170
1171 #define CACHE_LIMITER(name) _php_cache_limiter_##name
1172 #define CACHE_LIMITER_FUNC(name) static void CACHE_LIMITER(name)(void)
1173 #define CACHE_LIMITER_ENTRY(name) { #name, CACHE_LIMITER(name) },
1174 #define ADD_HEADER(a) sapi_add_header(a, strlen(a), 1);
1175 #define MAX_STR 512
1176
1177 static char *month_names[] = {
1178 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1179 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1180 };
1181
1182 static char *week_days[] = {
1183 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
1184 };
1185
1186 static inline void strcpy_gmt(char *ubuf, time_t *when)
1187 {
1188 char buf[MAX_STR];
1189 struct tm tm, *res;
1190 int n;
1191
1192 res = php_gmtime_r(when, &tm);
1193
1194 if (!res) {
1195 ubuf[0] = '\0';
1196 return;
1197 }
1198
1199 n = slprintf(buf, sizeof(buf), "%s, %02d %s %d %02d:%02d:%02d GMT",
1200 week_days[tm.tm_wday], tm.tm_mday,
1201 month_names[tm.tm_mon], tm.tm_year + 1900,
1202 tm.tm_hour, tm.tm_min,
1203 tm.tm_sec);
1204 memcpy(ubuf, buf, n);
1205 ubuf[n] = '\0';
1206 }
1207
1208
1209 static inline void last_modified(void)
1210 {
1211 const char *path;
1212 zend_stat_t sb;
1213 char buf[MAX_STR + 1];
1214
1215 path = SG(request_info).path_translated;
1216 if (path) {
1217 if (VCWD_STAT(path, &sb) == -1) {
1218 return;
1219 }
1220
1221 #define LAST_MODIFIED "Last-Modified: "
1222 memcpy(buf, LAST_MODIFIED, sizeof(LAST_MODIFIED) - 1);
1223 strcpy_gmt(buf + sizeof(LAST_MODIFIED) - 1, &sb.st_mtime);
1224 ADD_HEADER(buf);
1225 }
1226 }
1227
1228
1229 #define EXPIRES "Expires: "
1230 CACHE_LIMITER_FUNC(public)
1231 {
1232 char buf[MAX_STR + 1];
1233 struct timeval tv;
1234 time_t now;
1235
1236 gettimeofday(&tv, NULL);
1237 now = tv.tv_sec + PS(cache_expire) * 60;
1238 memcpy(buf, EXPIRES, sizeof(EXPIRES) - 1);
1239 strcpy_gmt(buf + sizeof(EXPIRES) - 1, &now);
1240 ADD_HEADER(buf);
1241
1242 snprintf(buf, sizeof(buf) , "Cache-Control: public, max-age=" ZEND_LONG_FMT, PS(cache_expire) * 60);
1243 ADD_HEADER(buf);
1244
1245 last_modified();
1246 }
1247
1248
1249 CACHE_LIMITER_FUNC(private_no_expire)
1250 {
1251 char buf[MAX_STR + 1];
1252
1253 snprintf(buf, sizeof(buf), "Cache-Control: private, max-age=" ZEND_LONG_FMT, PS(cache_expire) * 60);
1254 ADD_HEADER(buf);
1255
1256 last_modified();
1257 }
1258
1259
1260 CACHE_LIMITER_FUNC(private)
1261 {
1262 ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT");
1263 CACHE_LIMITER(private_no_expire)();
1264 }
1265
1266
1267 CACHE_LIMITER_FUNC(nocache)
1268 {
1269 ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT");
1270
1271
1272 ADD_HEADER("Cache-Control: no-store, no-cache, must-revalidate");
1273
1274
1275 ADD_HEADER("Pragma: no-cache");
1276 }
1277
1278
1279 static php_session_cache_limiter_t php_session_cache_limiters[] = {
1280 CACHE_LIMITER_ENTRY(public)
1281 CACHE_LIMITER_ENTRY(private)
1282 CACHE_LIMITER_ENTRY(private_no_expire)
1283 CACHE_LIMITER_ENTRY(nocache)
1284 {0}
1285 };
1286
1287 static int php_session_cache_limiter(void)
1288 {
1289 php_session_cache_limiter_t *lim;
1290
1291 if (PS(cache_limiter)[0] == '\0') return 0;
1292
1293 if (SG(headers_sent)) {
1294 const char *output_start_filename = php_output_get_start_filename();
1295 int output_start_lineno = php_output_get_start_lineno();
1296
1297 if (output_start_filename) {
1298 php_error_docref(NULL, E_WARNING, "Cannot send session cache limiter - headers already sent (output started at %s:%d)", output_start_filename, output_start_lineno);
1299 } else {
1300 php_error_docref(NULL, E_WARNING, "Cannot send session cache limiter - headers already sent");
1301 }
1302 return -2;
1303 }
1304
1305 for (lim = php_session_cache_limiters; lim->name; lim++) {
1306 if (!strcasecmp(lim->name, PS(cache_limiter))) {
1307 lim->func();
1308 return 0;
1309 }
1310 }
1311
1312 return -1;
1313 }
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325 static void php_session_remove_cookie(void) {
1326 sapi_header_struct *header;
1327 zend_llist *l = &SG(sapi_headers).headers;
1328 zend_llist_element *next;
1329 zend_llist_element *current;
1330 char *session_cookie;
1331 zend_string *e_session_name;
1332 size_t session_cookie_len;
1333 size_t len = sizeof("Set-Cookie")-1;
1334
1335 e_session_name = php_url_encode(PS(session_name), strlen(PS(session_name)));
1336 spprintf(&session_cookie, 0, "Set-Cookie: %s=", ZSTR_VAL(e_session_name));
1337 zend_string_free(e_session_name);
1338
1339 session_cookie_len = strlen(session_cookie);
1340 current = l->head;
1341 while (current) {
1342 header = (sapi_header_struct *)(current->data);
1343 next = current->next;
1344 if (header->header_len > len && header->header[len] == ':'
1345 && !strncmp(header->header, session_cookie, session_cookie_len)) {
1346 if (current->prev) {
1347 current->prev->next = next;
1348 } else {
1349 l->head = next;
1350 }
1351 if (next) {
1352 next->prev = current->prev;
1353 } else {
1354 l->tail = current->prev;
1355 }
1356 sapi_free_header(header);
1357 efree(current);
1358 --l->count;
1359 }
1360 current = next;
1361 }
1362 efree(session_cookie);
1363 }
1364
1365 static void php_session_send_cookie(void)
1366 {
1367 smart_str ncookie = {0};
1368 zend_string *date_fmt = NULL;
1369 zend_string *e_session_name, *e_id;
1370
1371 if (SG(headers_sent)) {
1372 const char *output_start_filename = php_output_get_start_filename();
1373 int output_start_lineno = php_output_get_start_lineno();
1374
1375 if (output_start_filename) {
1376 php_error_docref(NULL, E_WARNING, "Cannot send session cookie - headers already sent by (output started at %s:%d)", output_start_filename, output_start_lineno);
1377 } else {
1378 php_error_docref(NULL, E_WARNING, "Cannot send session cookie - headers already sent");
1379 }
1380 return;
1381 }
1382
1383
1384 e_session_name = php_url_encode(PS(session_name), strlen(PS(session_name)));
1385 e_id = php_url_encode(ZSTR_VAL(PS(id)), ZSTR_LEN(PS(id)));
1386
1387 smart_str_appendl(&ncookie, "Set-Cookie: ", sizeof("Set-Cookie: ")-1);
1388 smart_str_appendl(&ncookie, ZSTR_VAL(e_session_name), ZSTR_LEN(e_session_name));
1389 smart_str_appendc(&ncookie, '=');
1390 smart_str_appendl(&ncookie, ZSTR_VAL(e_id), ZSTR_LEN(e_id));
1391
1392 zend_string_release(e_session_name);
1393 zend_string_release(e_id);
1394
1395 if (PS(cookie_lifetime) > 0) {
1396 struct timeval tv;
1397 time_t t;
1398
1399 gettimeofday(&tv, NULL);
1400 t = tv.tv_sec + PS(cookie_lifetime);
1401
1402 if (t > 0) {
1403 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);
1404 smart_str_appends(&ncookie, COOKIE_EXPIRES);
1405 smart_str_appendl(&ncookie, ZSTR_VAL(date_fmt), ZSTR_LEN(date_fmt));
1406 zend_string_release(date_fmt);
1407
1408 smart_str_appends(&ncookie, COOKIE_MAX_AGE);
1409 smart_str_append_long(&ncookie, PS(cookie_lifetime));
1410 }
1411 }
1412
1413 if (PS(cookie_path)[0]) {
1414 smart_str_appends(&ncookie, COOKIE_PATH);
1415 smart_str_appends(&ncookie, PS(cookie_path));
1416 }
1417
1418 if (PS(cookie_domain)[0]) {
1419 smart_str_appends(&ncookie, COOKIE_DOMAIN);
1420 smart_str_appends(&ncookie, PS(cookie_domain));
1421 }
1422
1423 if (PS(cookie_secure)) {
1424 smart_str_appends(&ncookie, COOKIE_SECURE);
1425 }
1426
1427 if (PS(cookie_httponly)) {
1428 smart_str_appends(&ncookie, COOKIE_HTTPONLY);
1429 }
1430
1431 smart_str_0(&ncookie);
1432
1433 php_session_remove_cookie();
1434
1435
1436 sapi_add_header_ex(estrndup(ZSTR_VAL(ncookie.s), ZSTR_LEN(ncookie.s)), ZSTR_LEN(ncookie.s), 0, 0);
1437 smart_str_free(&ncookie);
1438 }
1439
1440
1441 PHPAPI ps_module *_php_find_ps_module(char *name)
1442 {
1443 ps_module *ret = NULL;
1444 ps_module **mod;
1445 int i;
1446
1447 for (i = 0, mod = ps_modules; i < MAX_MODULES; i++, mod++) {
1448 if (*mod && !strcasecmp(name, (*mod)->s_name)) {
1449 ret = *mod;
1450 break;
1451 }
1452 }
1453 return ret;
1454 }
1455
1456
1457 PHPAPI const ps_serializer *_php_find_ps_serializer(char *name)
1458 {
1459 const ps_serializer *ret = NULL;
1460 const ps_serializer *mod;
1461
1462 for (mod = ps_serializers; mod->name; mod++) {
1463 if (!strcasecmp(name, mod->name)) {
1464 ret = mod;
1465 break;
1466 }
1467 }
1468 return ret;
1469 }
1470
1471
1472 static void ppid2sid(zval *ppid) {
1473 ZVAL_DEREF(ppid);
1474 if (Z_TYPE_P(ppid) == IS_STRING) {
1475 PS(id) = zend_string_init(Z_STRVAL_P(ppid), Z_STRLEN_P(ppid), 0);
1476 PS(send_cookie) = 0;
1477 } else {
1478 PS(id) = NULL;
1479 PS(send_cookie) = 1;
1480 }
1481 }
1482
1483 PHPAPI void php_session_reset_id(void)
1484 {
1485 int module_number = PS(module_number);
1486 zval *sid;
1487
1488 if (!PS(id)) {
1489 php_error_docref(NULL, E_WARNING, "Cannot set session ID - session ID is not initialized");
1490 return;
1491 }
1492
1493 if (PS(use_cookies) && PS(send_cookie)) {
1494 php_session_send_cookie();
1495 PS(send_cookie) = 0;
1496 }
1497
1498
1499
1500
1501 sid = zend_get_constant_str("SID", sizeof("SID") - 1);
1502
1503 if (PS(define_sid)) {
1504 smart_str var = {0};
1505
1506 smart_str_appends(&var, PS(session_name));
1507 smart_str_appendc(&var, '=');
1508 smart_str_appends(&var, ZSTR_VAL(PS(id)));
1509 smart_str_0(&var);
1510 if (sid) {
1511 zend_string_release(Z_STR_P(sid));
1512 ZVAL_NEW_STR(sid, var.s);
1513 } else {
1514 REGISTER_STRINGL_CONSTANT("SID", ZSTR_VAL(var.s), ZSTR_LEN(var.s), 0);
1515 smart_str_free(&var);
1516 }
1517 } else {
1518 if (sid) {
1519 zend_string_release(Z_STR_P(sid));
1520 ZVAL_EMPTY_STRING(sid);
1521 } else {
1522 REGISTER_STRINGL_CONSTANT("SID", "", 0, 0);
1523 }
1524 }
1525
1526 if (APPLY_TRANS_SID) {
1527
1528
1529
1530
1531
1532 php_url_scanner_add_var(PS(session_name), strlen(PS(session_name)), ZSTR_VAL(PS(id)), ZSTR_LEN(PS(id)), 1);
1533 }
1534 }
1535
1536
1537 PHPAPI void php_session_start(void)
1538 {
1539 zval *ppid;
1540 zval *data;
1541 char *p, *value;
1542 size_t lensess;
1543
1544 switch (PS(session_status)) {
1545 case php_session_active:
1546 php_error(E_NOTICE, "A session had already been started - ignoring session_start()");
1547 return;
1548 break;
1549
1550 case php_session_disabled:
1551 value = zend_ini_string("session.save_handler", sizeof("session.save_handler") - 1, 0);
1552 if (!PS(mod) && value) {
1553 PS(mod) = _php_find_ps_module(value);
1554 if (!PS(mod)) {
1555 php_error_docref(NULL, E_WARNING, "Cannot find save handler '%s' - session startup failed", value);
1556 return;
1557 }
1558 }
1559 value = zend_ini_string("session.serialize_handler", sizeof("session.serialize_handler") - 1, 0);
1560 if (!PS(serializer) && value) {
1561 PS(serializer) = _php_find_ps_serializer(value);
1562 if (!PS(serializer)) {
1563 php_error_docref(NULL, E_WARNING, "Cannot find serialization handler '%s' - session startup failed", value);
1564 return;
1565 }
1566 }
1567 PS(session_status) = php_session_none;
1568
1569
1570 default:
1571 case php_session_none:
1572
1573 PS(define_sid) = !PS(use_only_cookies);
1574 PS(send_cookie) = PS(use_cookies) || PS(use_only_cookies);
1575 }
1576
1577 lensess = strlen(PS(session_name));
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587 if (!PS(id)) {
1588 if (PS(use_cookies) && (data = zend_hash_str_find(&EG(symbol_table), "_COOKIE", sizeof("_COOKIE") - 1))) {
1589 ZVAL_DEREF(data);
1590 if (Z_TYPE_P(data) == IS_ARRAY && (ppid = zend_hash_str_find(Z_ARRVAL_P(data), PS(session_name), lensess))) {
1591 ppid2sid(ppid);
1592 PS(send_cookie) = 0;
1593 }
1594 }
1595
1596 if (PS(define_sid) && !PS(id) && (data = zend_hash_str_find(&EG(symbol_table), "_GET", sizeof("_GET") - 1))) {
1597 ZVAL_DEREF(data);
1598 if (Z_TYPE_P(data) == IS_ARRAY && (ppid = zend_hash_str_find(Z_ARRVAL_P(data), PS(session_name), lensess))) {
1599 ppid2sid(ppid);
1600 }
1601 }
1602
1603 if (PS(define_sid) && !PS(id) && (data = zend_hash_str_find(&EG(symbol_table), "_POST", sizeof("_POST") - 1))) {
1604 ZVAL_DEREF(data);
1605 if (Z_TYPE_P(data) == IS_ARRAY && (ppid = zend_hash_str_find(Z_ARRVAL_P(data), PS(session_name), lensess))) {
1606 ppid2sid(ppid);
1607 }
1608 }
1609
1610
1611
1612
1613 if (PS(define_sid) && !PS(id) &&
1614 zend_is_auto_global_str("_SERVER", sizeof("_SERVER") - 1) == SUCCESS &&
1615 (data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "REQUEST_URI", sizeof("REQUEST_URI") - 1)) &&
1616 Z_TYPE_P(data) == IS_STRING &&
1617 (p = strstr(Z_STRVAL_P(data), PS(session_name))) &&
1618 p[lensess] == '='
1619 ) {
1620 char *q;
1621 p += lensess + 1;
1622 if ((q = strpbrk(p, "/?\\"))) {
1623 PS(id) = zend_string_init(p, q - p, 0);
1624 }
1625 }
1626
1627
1628
1629 if (PS(define_sid) && PS(id) &&
1630 PS(extern_referer_chk)[0] != '\0' &&
1631 !Z_ISUNDEF(PG(http_globals)[TRACK_VARS_SERVER]) &&
1632 (data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_REFERER", sizeof("HTTP_REFERER") - 1)) &&
1633 Z_TYPE_P(data) == IS_STRING &&
1634 Z_STRLEN_P(data) != 0 &&
1635 strstr(Z_STRVAL_P(data), PS(extern_referer_chk)) == NULL
1636 ) {
1637 zend_string_release(PS(id));
1638 PS(id) = NULL;
1639 }
1640 }
1641
1642
1643
1644 if (PS(id) && strpbrk(ZSTR_VAL(PS(id)), "\r\n\t <>'\"\\")) {
1645 zend_string_release(PS(id));
1646 PS(id) = NULL;
1647 }
1648
1649 php_session_initialize();
1650 php_session_cache_limiter();
1651 }
1652
1653
1654 static void php_session_flush(int write)
1655 {
1656 if (PS(session_status) == php_session_active) {
1657 PS(session_status) = php_session_none;
1658 php_session_save_current_state(write);
1659 }
1660 }
1661
1662
1663 static void php_session_abort(void)
1664 {
1665 if (PS(session_status) == php_session_active) {
1666 PS(session_status) = php_session_none;
1667 if (PS(mod_data) || PS(mod_user_implemented)) {
1668 PS(mod)->s_close(&PS(mod_data));
1669 }
1670 }
1671 }
1672
1673
1674 static void php_session_reset(void)
1675 {
1676 if (PS(session_status) == php_session_active) {
1677 php_session_initialize();
1678 }
1679 }
1680
1681
1682
1683
1684
1685
1686 PHPAPI void session_adapt_url(const char *url, size_t urllen, char **new, size_t *newlen)
1687 {
1688 if (APPLY_TRANS_SID && (PS(session_status) == php_session_active)) {
1689 *new = php_url_scanner_adapt_single_url(url, urllen, PS(session_name), ZSTR_VAL(PS(id)), newlen, 1);
1690 }
1691 }
1692
1693
1694
1695
1696
1697
1698
1699
1700 static PHP_FUNCTION(session_set_cookie_params)
1701 {
1702 zval *lifetime;
1703 zend_string *path = NULL, *domain = NULL;
1704 int argc = ZEND_NUM_ARGS();
1705 zend_bool secure = 0, httponly = 0;
1706 zend_string *ini_name;
1707
1708 if (!PS(use_cookies) ||
1709 zend_parse_parameters(argc, "z|SSbb", &lifetime, &path, &domain, &secure, &httponly) == FAILURE) {
1710 return;
1711 }
1712
1713 convert_to_string_ex(lifetime);
1714
1715 ini_name = zend_string_init("session.cookie_lifetime", sizeof("session.cookie_lifetime") - 1, 0);
1716 zend_alter_ini_entry(ini_name, Z_STR_P(lifetime), PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1717 zend_string_release(ini_name);
1718
1719 if (path) {
1720 ini_name = zend_string_init("session.cookie_path", sizeof("session.cookie_path") - 1, 0);
1721 zend_alter_ini_entry(ini_name, path, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1722 zend_string_release(ini_name);
1723 }
1724 if (domain) {
1725 ini_name = zend_string_init("session.cookie_domain", sizeof("session.cookie_domain") - 1, 0);
1726 zend_alter_ini_entry(ini_name, domain, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1727 zend_string_release(ini_name);
1728 }
1729
1730 if (argc > 3) {
1731 ini_name = zend_string_init("session.cookie_secure", sizeof("session.cookie_secure") - 1, 0);
1732 zend_alter_ini_entry_chars(ini_name, secure ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1733 zend_string_release(ini_name);
1734 }
1735 if (argc > 4) {
1736 ini_name = zend_string_init("session.cookie_httponly", sizeof("session.cookie_httponly") - 1, 0);
1737 zend_alter_ini_entry_chars(ini_name, httponly ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1738 zend_string_release(ini_name);
1739 }
1740 }
1741
1742
1743
1744
1745 static PHP_FUNCTION(session_get_cookie_params)
1746 {
1747 if (zend_parse_parameters_none() == FAILURE) {
1748 return;
1749 }
1750
1751 array_init(return_value);
1752
1753 add_assoc_long(return_value, "lifetime", PS(cookie_lifetime));
1754 add_assoc_string(return_value, "path", PS(cookie_path));
1755 add_assoc_string(return_value, "domain", PS(cookie_domain));
1756 add_assoc_bool(return_value, "secure", PS(cookie_secure));
1757 add_assoc_bool(return_value, "httponly", PS(cookie_httponly));
1758 }
1759
1760
1761
1762
1763 static PHP_FUNCTION(session_name)
1764 {
1765 zend_string *name = NULL;
1766 zend_string *ini_name;
1767
1768 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S", &name) == FAILURE) {
1769 return;
1770 }
1771
1772 RETVAL_STRING(PS(session_name));
1773
1774 if (name) {
1775 ini_name = zend_string_init("session.name", sizeof("session.name") - 1, 0);
1776 zend_alter_ini_entry(ini_name, name, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1777 zend_string_release(ini_name);
1778 }
1779 }
1780
1781
1782
1783
1784 static PHP_FUNCTION(session_module_name)
1785 {
1786 zend_string *name = NULL;
1787 zend_string *ini_name;
1788
1789 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S", &name) == FAILURE) {
1790 return;
1791 }
1792
1793
1794 if (PS(mod) && PS(mod)->s_name) {
1795 RETVAL_STRING(PS(mod)->s_name);
1796 } else {
1797 RETVAL_EMPTY_STRING();
1798 }
1799
1800 if (name) {
1801 if (!_php_find_ps_module(ZSTR_VAL(name))) {
1802 php_error_docref(NULL, E_WARNING, "Cannot find named PHP session module (%s)", ZSTR_VAL(name));
1803
1804 zval_dtor(return_value);
1805 RETURN_FALSE;
1806 }
1807 if (PS(mod_data) || PS(mod_user_implemented)) {
1808 PS(mod)->s_close(&PS(mod_data));
1809 }
1810 PS(mod_data) = NULL;
1811
1812 ini_name = zend_string_init("session.save_handler", sizeof("session.save_handler") - 1, 0);
1813 zend_alter_ini_entry(ini_name, name, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1814 zend_string_release(ini_name);
1815 }
1816 }
1817
1818
1819
1820
1821 static PHP_FUNCTION(session_set_save_handler)
1822 {
1823 zval *args = NULL;
1824 int i, num_args, argc = ZEND_NUM_ARGS();
1825 zend_string *name;
1826 zend_string *ini_name, *ini_val;
1827
1828 if (PS(session_status) != php_session_none) {
1829 RETURN_FALSE;
1830 }
1831
1832 if (argc > 0 && argc <= 2) {
1833 zval *obj = NULL;
1834 zend_string *func_name;
1835 zend_function *current_mptr;
1836 zend_bool register_shutdown = 1;
1837
1838 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|b", &obj, php_session_iface_entry, ®ister_shutdown) == FAILURE) {
1839 RETURN_FALSE;
1840 }
1841
1842
1843
1844 i = 0;
1845 ZEND_HASH_FOREACH_STR_KEY(&php_session_iface_entry->function_table, func_name) {
1846 if ((current_mptr = zend_hash_find_ptr(&Z_OBJCE_P(obj)->function_table, func_name))) {
1847 if (!Z_ISUNDEF(PS(mod_user_names).names[i])) {
1848 zval_ptr_dtor(&PS(mod_user_names).names[i]);
1849 }
1850
1851 array_init_size(&PS(mod_user_names).names[i], 2);
1852 Z_ADDREF_P(obj);
1853 add_next_index_zval(&PS(mod_user_names).names[i], obj);
1854 add_next_index_str(&PS(mod_user_names).names[i], zend_string_copy(func_name));
1855 } else {
1856 php_error_docref(NULL, E_ERROR, "Session handler's function table is corrupt");
1857 RETURN_FALSE;
1858 }
1859
1860 ++i;
1861 } ZEND_HASH_FOREACH_END();
1862
1863
1864 ZEND_HASH_FOREACH_STR_KEY(&php_session_id_iface_entry->function_table, func_name) {
1865 if ((current_mptr = zend_hash_find_ptr(&Z_OBJCE_P(obj)->function_table, func_name))) {
1866 if (!Z_ISUNDEF(PS(mod_user_names).names[i])) {
1867 zval_ptr_dtor(&PS(mod_user_names).names[i]);
1868 }
1869 array_init_size(&PS(mod_user_names).names[i], 2);
1870 Z_ADDREF_P(obj);
1871 add_next_index_zval(&PS(mod_user_names).names[i], obj);
1872 add_next_index_str(&PS(mod_user_names).names[i], zend_string_copy(func_name));
1873 } else {
1874 if (!Z_ISUNDEF(PS(mod_user_names).names[i])) {
1875 zval_ptr_dtor(&PS(mod_user_names).names[i]);
1876 ZVAL_UNDEF(&PS(mod_user_names).names[i]);
1877 }
1878 }
1879
1880 ++i;
1881 } ZEND_HASH_FOREACH_END();
1882
1883
1884 ZEND_HASH_FOREACH_STR_KEY(&php_session_update_timestamp_iface_entry->function_table, func_name) {
1885 if ((current_mptr = zend_hash_find_ptr(&Z_OBJCE_P(obj)->function_table, func_name))) {
1886 if (!Z_ISUNDEF(PS(mod_user_names).names[i])) {
1887 zval_ptr_dtor(&PS(mod_user_names).names[i]);
1888 }
1889 array_init_size(&PS(mod_user_names).names[i], 2);
1890 Z_ADDREF_P(obj);
1891 add_next_index_zval(&PS(mod_user_names).names[i], obj);
1892 add_next_index_str(&PS(mod_user_names).names[i], zend_string_copy(func_name));
1893 } else {
1894 if (!Z_ISUNDEF(PS(mod_user_names).names[i])) {
1895 zval_ptr_dtor(&PS(mod_user_names).names[i]);
1896 ZVAL_UNDEF(&PS(mod_user_names).names[i]);
1897 }
1898 }
1899 ++i;
1900 } ZEND_HASH_FOREACH_END();
1901
1902 if (register_shutdown) {
1903
1904 php_shutdown_function_entry shutdown_function_entry;
1905 shutdown_function_entry.arg_count = 1;
1906 shutdown_function_entry.arguments = (zval *) safe_emalloc(sizeof(zval), 1, 0);
1907
1908 ZVAL_STRING(&shutdown_function_entry.arguments[0], "session_register_shutdown");
1909
1910
1911 if (!register_user_shutdown_function("session_shutdown", sizeof("session_shutdown") - 1, &shutdown_function_entry)) {
1912 zval_ptr_dtor(&shutdown_function_entry.arguments[0]);
1913 efree(shutdown_function_entry.arguments);
1914 php_error_docref(NULL, E_WARNING, "Unable to register session shutdown function");
1915 RETURN_FALSE;
1916 }
1917 } else {
1918
1919 remove_user_shutdown_function("session_shutdown", sizeof("session_shutdown") - 1);
1920 }
1921
1922 if (PS(mod) && PS(session_status) != php_session_active && PS(mod) != &ps_mod_user) {
1923 ini_name = zend_string_init("session.save_handler", sizeof("session.save_handler") - 1, 0);
1924 ini_val = zend_string_init("user", sizeof("user") - 1, 0);
1925 zend_alter_ini_entry(ini_name, ini_val, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1926 zend_string_release(ini_val);
1927 zend_string_release(ini_name);
1928 }
1929
1930 RETURN_TRUE;
1931 }
1932
1933
1934 if (argc < 6 || PS_NUM_APIS < argc) {
1935 WRONG_PARAM_COUNT;
1936 }
1937
1938 if (zend_parse_parameters(argc, "+", &args, &num_args) == FAILURE) {
1939 return;
1940 }
1941
1942
1943 remove_user_shutdown_function("session_shutdown", sizeof("session_shutdown") - 1);
1944
1945
1946 for (i = 0; i < argc; i++) {
1947 if (!zend_is_callable(&args[i], 0, &name)) {
1948 php_error_docref(NULL, E_WARNING, "Argument %d is not a valid callback", i+1);
1949 zend_string_release(name);
1950 RETURN_FALSE;
1951 }
1952 zend_string_release(name);
1953 }
1954
1955 if (PS(mod) && PS(mod) != &ps_mod_user) {
1956 ini_name = zend_string_init("session.save_handler", sizeof("session.save_handler") - 1, 0);
1957 ini_val = zend_string_init("user", sizeof("user") - 1, 0);
1958 zend_alter_ini_entry(ini_name, ini_val, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1959 zend_string_release(ini_val);
1960 zend_string_release(ini_name);
1961 }
1962
1963 for (i = 0; i < argc; i++) {
1964 if (!Z_ISUNDEF(PS(mod_user_names).names[i])) {
1965 zval_ptr_dtor(&PS(mod_user_names).names[i]);
1966 }
1967 ZVAL_COPY(&PS(mod_user_names).names[i], &args[i]);
1968 }
1969
1970 RETURN_TRUE;
1971 }
1972
1973
1974
1975
1976 static PHP_FUNCTION(session_save_path)
1977 {
1978 zend_string *name = NULL;
1979 zend_string *ini_name;
1980
1981 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S", &name) == FAILURE) {
1982 return;
1983 }
1984
1985 RETVAL_STRING(PS(save_path));
1986
1987 if (name) {
1988 if (memchr(ZSTR_VAL(name), '\0', ZSTR_LEN(name)) != NULL) {
1989 php_error_docref(NULL, E_WARNING, "The save_path cannot contain NULL characters");
1990 zval_dtor(return_value);
1991 RETURN_FALSE;
1992 }
1993 ini_name = zend_string_init("session.save_path", sizeof("session.save_path") - 1, 0);
1994 zend_alter_ini_entry(ini_name, name, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1995 zend_string_release(ini_name);
1996 }
1997 }
1998
1999
2000
2001
2002 static PHP_FUNCTION(session_id)
2003 {
2004 zend_string *name = NULL;
2005 int argc = ZEND_NUM_ARGS();
2006
2007 if (zend_parse_parameters(argc, "|S", &name) == FAILURE) {
2008 return;
2009 }
2010
2011 if (PS(id)) {
2012
2013
2014 size_t len = strlen(ZSTR_VAL(PS(id)));
2015 if (UNEXPECTED(len != ZSTR_LEN(PS(id)))) {
2016 RETVAL_NEW_STR(zend_string_init(ZSTR_VAL(PS(id)), len, 0));
2017 } else {
2018 RETVAL_STR_COPY(PS(id));
2019 }
2020 } else {
2021 RETVAL_EMPTY_STRING();
2022 }
2023
2024 if (name) {
2025 if (PS(id)) {
2026 zend_string_release(PS(id));
2027 }
2028 PS(id) = zend_string_copy(name);
2029 }
2030 }
2031
2032
2033
2034
2035 static PHP_FUNCTION(session_regenerate_id)
2036 {
2037 zend_bool del_ses = 0;
2038 zend_string *data;
2039
2040 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &del_ses) == FAILURE) {
2041 return;
2042 }
2043
2044 if (SG(headers_sent) && PS(use_cookies)) {
2045 php_error_docref(NULL, E_WARNING, "Cannot regenerate session id - headers already sent");
2046 RETURN_FALSE;
2047 }
2048
2049 if (PS(session_status) != php_session_active) {
2050 php_error_docref(NULL, E_WARNING, "Cannot regenerate session id - session is not active");
2051 RETURN_FALSE;
2052 }
2053
2054
2055 if (del_ses) {
2056 if (PS(mod)->s_destroy(&PS(mod_data), PS(id)) == FAILURE) {
2057 PS(mod)->s_close(&PS(mod_data));
2058 PS(session_status) = php_session_none;
2059 php_error_docref(NULL, E_WARNING, "Session object destruction failed. ID: %s (path: %s)", PS(mod)->s_name, PS(save_path));
2060 RETURN_FALSE;
2061 }
2062 } else {
2063 int ret;
2064 data = php_session_encode();
2065 if (data) {
2066 ret = PS(mod)->s_write(&PS(mod_data), PS(id), data, PS(gc_maxlifetime));
2067 zend_string_release(data);
2068 } else {
2069 ret = PS(mod)->s_write(&PS(mod_data), PS(id), ZSTR_EMPTY_ALLOC(), PS(gc_maxlifetime));
2070 }
2071 if (ret == FAILURE) {
2072 PS(mod)->s_close(&PS(mod_data));
2073 PS(session_status) = php_session_none;
2074 php_error_docref(NULL, E_WARNING, "Session write failed. ID: %s (path: %s)", PS(mod)->s_name, PS(save_path));
2075 RETURN_FALSE;
2076 }
2077 }
2078 PS(mod)->s_close(&PS(mod_data));
2079
2080
2081 if (PS(session_vars)) {
2082 zend_string_release(PS(session_vars));
2083 PS(session_vars) = NULL;
2084 }
2085 zend_string_release(PS(id));
2086 PS(id) = PS(mod)->s_create_sid(&PS(mod_data));
2087 if (!PS(id)) {
2088 PS(session_status) = php_session_none;
2089 php_error_docref(NULL, E_RECOVERABLE_ERROR, "Failed to create new session ID: %s (path: %s)", PS(mod)->s_name, PS(save_path));
2090 RETURN_FALSE;
2091 }
2092 if (PS(mod)->s_open(&PS(mod_data), PS(save_path), PS(session_name)) == FAILURE) {
2093 PS(session_status) = php_session_none;
2094 php_error_docref(NULL, E_RECOVERABLE_ERROR, "Failed to create(open) session ID: %s (path: %s)", PS(mod)->s_name, PS(save_path));
2095 RETURN_FALSE;
2096 }
2097 if (PS(use_strict_mode) && PS(mod)->s_validate_sid &&
2098 PS(mod)->s_validate_sid(&PS(mod_data), PS(id)) == FAILURE) {
2099 zend_string_release(PS(id));
2100 PS(id) = PS(mod)->s_create_sid(&PS(mod_data));
2101 if (!PS(id)) {
2102 PS(session_status) = php_session_none;
2103 php_error_docref(NULL, E_RECOVERABLE_ERROR, "Failed to create session ID by collision: %s (path: %s)", PS(mod)->s_name, PS(save_path));
2104 RETURN_FALSE;
2105 }
2106 }
2107
2108 if (PS(mod)->s_read(&PS(mod_data), PS(id), &data, PS(gc_maxlifetime)) == FAILURE) {
2109 PS(session_status) = php_session_none;
2110 php_error_docref(NULL, E_RECOVERABLE_ERROR, "Failed to create(read) session ID: %s (path: %s)", PS(mod)->s_name, PS(save_path));
2111 RETURN_FALSE;
2112 }
2113 if (data) {
2114 zend_string_release(data);
2115 }
2116
2117 if (PS(use_cookies)) {
2118 PS(send_cookie) = 1;
2119 }
2120 php_session_reset_id();
2121
2122 RETURN_TRUE;
2123 }
2124
2125
2126
2127
2128 #if 0
2129
2130 static PHP_FUNCTION(session_create_id)
2131 {
2132 zend_string *prefix = NULL, *new_id;
2133 smart_str id = {0};
2134
2135 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S", &prefix) == FAILURE) {
2136 return;
2137 }
2138
2139 if (prefix && ZSTR_LEN(prefix)) {
2140 if (php_session_valid_key(ZSTR_VAL(prefix)) == FAILURE) {
2141
2142 php_error_docref(NULL, E_WARNING, "Prefix cannot contain special characters. Only aphanumeric, ',', '-' are allowed");
2143 RETURN_FALSE;
2144 } else {
2145 smart_str_append(&id, prefix);
2146 }
2147 }
2148
2149 if (PS(session_status) == php_session_active) {
2150 new_id = PS(mod)->s_create_sid(&PS(mod_data));
2151 } else {
2152 new_id = php_session_create_id(NULL);
2153 }
2154
2155 if (new_id) {
2156 smart_str_append(&id, new_id);
2157 zend_string_release(new_id);
2158 } else {
2159 smart_str_free(&id);
2160 php_error_docref(NULL, E_WARNING, "Failed to create new ID");
2161 RETURN_FALSE;
2162 }
2163 smart_str_0(&id);
2164 RETVAL_NEW_STR(id.s);
2165 smart_str_free(&id);
2166 }
2167 #endif
2168
2169
2170
2171
2172 static PHP_FUNCTION(session_cache_limiter)
2173 {
2174 zend_string *limiter = NULL;
2175 zend_string *ini_name;
2176
2177 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S", &limiter) == FAILURE) {
2178 return;
2179 }
2180
2181 RETVAL_STRING(PS(cache_limiter));
2182
2183 if (limiter) {
2184 ini_name = zend_string_init("session.cache_limiter", sizeof("session.cache_limiter") - 1, 0);
2185 zend_alter_ini_entry(ini_name, limiter, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
2186 zend_string_release(ini_name);
2187 }
2188 }
2189
2190
2191
2192
2193 static PHP_FUNCTION(session_cache_expire)
2194 {
2195 zval *expires = NULL;
2196 zend_string *ini_name;
2197
2198 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &expires) == FAILURE) {
2199 return;
2200 }
2201
2202 RETVAL_LONG(PS(cache_expire));
2203
2204 if (expires) {
2205 convert_to_string_ex(expires);
2206 ini_name = zend_string_init("session.cache_expire", sizeof("session.cache_expire") - 1, 0);
2207 zend_alter_ini_entry(ini_name, Z_STR_P(expires), ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME);
2208 zend_string_release(ini_name);
2209 }
2210 }
2211
2212
2213
2214
2215 static PHP_FUNCTION(session_encode)
2216 {
2217 zend_string *enc;
2218
2219 if (zend_parse_parameters_none() == FAILURE) {
2220 return;
2221 }
2222
2223 enc = php_session_encode();
2224 if (enc == NULL) {
2225 RETURN_FALSE;
2226 }
2227
2228 RETURN_STR(enc);
2229 }
2230
2231
2232
2233
2234 static PHP_FUNCTION(session_decode)
2235 {
2236 zend_string *str = NULL;
2237
2238 if (PS(session_status) != php_session_active) {
2239 php_error_docref(NULL, E_WARNING, "Session is not active. You cannot decode session data");
2240 RETURN_FALSE;
2241 }
2242
2243 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
2244 return;
2245 }
2246
2247 if (php_session_decode(str) == FAILURE) {
2248 RETURN_FALSE;
2249 }
2250 RETURN_TRUE;
2251 }
2252
2253
2254 static int php_session_start_set_ini(zend_string *varname, zend_string *new_value) {
2255 int ret;
2256 smart_str buf ={0};
2257 smart_str_appends(&buf, "session");
2258 smart_str_appendc(&buf, '.');
2259 smart_str_append(&buf, varname);
2260 smart_str_0(&buf);
2261 ret = zend_alter_ini_entry_ex(buf.s, new_value, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0);
2262 smart_str_free(&buf);
2263 return ret;
2264 }
2265
2266
2267
2268 static PHP_FUNCTION(session_start)
2269 {
2270 zval *options = NULL;
2271 zval *value;
2272 zend_ulong num_idx;
2273 zend_string *str_idx;
2274 zend_long read_and_close = 0;
2275
2276 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a", &options) == FAILURE) {
2277 RETURN_FALSE;
2278 }
2279
2280 if (PS(id) && !(ZSTR_LEN(PS(id)))) {
2281 php_error_docref(NULL, E_WARNING, "Cannot start session with empty session ID");
2282 RETURN_FALSE;
2283 }
2284
2285
2286 if (options) {
2287 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(options), num_idx, str_idx, value) {
2288 if (str_idx) {
2289 switch(Z_TYPE_P(value)) {
2290 case IS_STRING:
2291 case IS_TRUE:
2292 case IS_FALSE:
2293 case IS_LONG:
2294 if (zend_string_equals_literal(str_idx, "read_and_close")) {
2295 read_and_close = zval_get_long(value);
2296 } else {
2297 zend_string *val = zval_get_string(value);
2298 if (php_session_start_set_ini(str_idx, val) == FAILURE) {
2299 php_error_docref(NULL, E_WARNING, "Setting option '%s' failed", ZSTR_VAL(str_idx));
2300 }
2301 zend_string_release(val);
2302 }
2303 break;
2304 default:
2305 php_error_docref(NULL, E_WARNING, "Option(%s) value must be string, boolean or long", ZSTR_VAL(str_idx));
2306 break;
2307 }
2308 }
2309 (void) num_idx;
2310 } ZEND_HASH_FOREACH_END();
2311 }
2312
2313 php_session_start();
2314
2315 if (PS(session_status) != php_session_active) {
2316 RETURN_FALSE;
2317 }
2318
2319 if (read_and_close) {
2320 php_session_flush(0);
2321 }
2322
2323 RETURN_TRUE;
2324 }
2325
2326
2327
2328
2329 static PHP_FUNCTION(session_destroy)
2330 {
2331 if (zend_parse_parameters_none() == FAILURE) {
2332 return;
2333 }
2334
2335 RETURN_BOOL(php_session_destroy() == SUCCESS);
2336 }
2337
2338
2339
2340
2341 static PHP_FUNCTION(session_unset)
2342 {
2343 if (PS(session_status) != php_session_active) {
2344 RETURN_FALSE;
2345 }
2346
2347 IF_SESSION_VARS() {
2348 HashTable *ht_sess_var = Z_ARRVAL_P(Z_REFVAL(PS(http_session_vars)));
2349
2350
2351 zend_hash_clean(ht_sess_var);
2352 }
2353 }
2354
2355
2356
2357
2358 static PHP_FUNCTION(session_write_close)
2359 {
2360 php_session_flush(1);
2361 }
2362
2363
2364
2365
2366 static PHP_FUNCTION(session_abort)
2367 {
2368 php_session_abort();
2369 }
2370
2371
2372
2373
2374 static PHP_FUNCTION(session_reset)
2375 {
2376 php_session_reset();
2377 }
2378
2379
2380
2381
2382 static PHP_FUNCTION(session_status)
2383 {
2384 if (zend_parse_parameters_none() == FAILURE) {
2385 return;
2386 }
2387
2388 RETURN_LONG(PS(session_status));
2389 }
2390
2391
2392
2393
2394 static PHP_FUNCTION(session_register_shutdown)
2395 {
2396 php_shutdown_function_entry shutdown_function_entry;
2397
2398
2399
2400
2401
2402
2403
2404
2405 shutdown_function_entry.arg_count = 1;
2406 shutdown_function_entry.arguments = (zval *) safe_emalloc(sizeof(zval), 1, 0);
2407
2408 ZVAL_STRING(&shutdown_function_entry.arguments[0], "session_write_close");
2409
2410 if (!append_user_shutdown_function(shutdown_function_entry)) {
2411 zval_ptr_dtor(&shutdown_function_entry.arguments[0]);
2412 efree(shutdown_function_entry.arguments);
2413
2414
2415
2416
2417
2418
2419
2420 php_session_flush(1);
2421 php_error_docref(NULL, E_WARNING, "Unable to register session flush function");
2422 }
2423 }
2424
2425
2426
2427 ZEND_BEGIN_ARG_INFO_EX(arginfo_session_name, 0, 0, 0)
2428 ZEND_ARG_INFO(0, name)
2429 ZEND_END_ARG_INFO()
2430
2431 ZEND_BEGIN_ARG_INFO_EX(arginfo_session_module_name, 0, 0, 0)
2432 ZEND_ARG_INFO(0, module)
2433 ZEND_END_ARG_INFO()
2434
2435 ZEND_BEGIN_ARG_INFO_EX(arginfo_session_save_path, 0, 0, 0)
2436 ZEND_ARG_INFO(0, path)
2437 ZEND_END_ARG_INFO()
2438
2439 ZEND_BEGIN_ARG_INFO_EX(arginfo_session_id, 0, 0, 0)
2440 ZEND_ARG_INFO(0, id)
2441 ZEND_END_ARG_INFO()
2442
2443 ZEND_BEGIN_ARG_INFO_EX(arginfo_session_regenerate_id, 0, 0, 0)
2444 ZEND_ARG_INFO(0, delete_old_session)
2445 ZEND_END_ARG_INFO()
2446
2447 ZEND_BEGIN_ARG_INFO_EX(arginfo_session_decode, 0, 0, 1)
2448 ZEND_ARG_INFO(0, data)
2449 ZEND_END_ARG_INFO()
2450
2451 ZEND_BEGIN_ARG_INFO(arginfo_session_void, 0)
2452 ZEND_END_ARG_INFO()
2453
2454 ZEND_BEGIN_ARG_INFO_EX(arginfo_session_set_save_handler, 0, 0, 1)
2455 ZEND_ARG_INFO(0, open)
2456 ZEND_ARG_INFO(0, close)
2457 ZEND_ARG_INFO(0, read)
2458 ZEND_ARG_INFO(0, write)
2459 ZEND_ARG_INFO(0, destroy)
2460 ZEND_ARG_INFO(0, gc)
2461 ZEND_ARG_INFO(0, create_sid)
2462 ZEND_ARG_INFO(0, validate_sid)
2463 ZEND_ARG_INFO(0, update_timestamp)
2464 ZEND_END_ARG_INFO()
2465
2466 ZEND_BEGIN_ARG_INFO_EX(arginfo_session_cache_limiter, 0, 0, 0)
2467 ZEND_ARG_INFO(0, cache_limiter)
2468 ZEND_END_ARG_INFO()
2469
2470 ZEND_BEGIN_ARG_INFO_EX(arginfo_session_cache_expire, 0, 0, 0)
2471 ZEND_ARG_INFO(0, new_cache_expire)
2472 ZEND_END_ARG_INFO()
2473
2474 ZEND_BEGIN_ARG_INFO_EX(arginfo_session_set_cookie_params, 0, 0, 1)
2475 ZEND_ARG_INFO(0, lifetime)
2476 ZEND_ARG_INFO(0, path)
2477 ZEND_ARG_INFO(0, domain)
2478 ZEND_ARG_INFO(0, secure)
2479 ZEND_ARG_INFO(0, httponly)
2480 ZEND_END_ARG_INFO()
2481
2482 ZEND_BEGIN_ARG_INFO(arginfo_session_class_open, 0)
2483 ZEND_ARG_INFO(0, save_path)
2484 ZEND_ARG_INFO(0, session_name)
2485 ZEND_END_ARG_INFO()
2486
2487 ZEND_BEGIN_ARG_INFO(arginfo_session_class_close, 0)
2488 ZEND_END_ARG_INFO()
2489
2490 ZEND_BEGIN_ARG_INFO(arginfo_session_class_read, 0)
2491 ZEND_ARG_INFO(0, key)
2492 ZEND_END_ARG_INFO()
2493
2494 ZEND_BEGIN_ARG_INFO(arginfo_session_class_write, 0)
2495 ZEND_ARG_INFO(0, key)
2496 ZEND_ARG_INFO(0, val)
2497 ZEND_END_ARG_INFO()
2498
2499 ZEND_BEGIN_ARG_INFO(arginfo_session_class_destroy, 0)
2500 ZEND_ARG_INFO(0, key)
2501 ZEND_END_ARG_INFO()
2502
2503 ZEND_BEGIN_ARG_INFO(arginfo_session_class_gc, 0)
2504 ZEND_ARG_INFO(0, maxlifetime)
2505 ZEND_END_ARG_INFO()
2506
2507 ZEND_BEGIN_ARG_INFO(arginfo_session_class_create_sid, 0)
2508 ZEND_END_ARG_INFO()
2509
2510 ZEND_BEGIN_ARG_INFO(arginfo_session_class_validateId, 0)
2511 ZEND_ARG_INFO(0, key)
2512 ZEND_END_ARG_INFO()
2513
2514 ZEND_BEGIN_ARG_INFO(arginfo_session_class_updateTimestamp, 0)
2515 ZEND_ARG_INFO(0, key)
2516 ZEND_ARG_INFO(0, val)
2517 ZEND_END_ARG_INFO()
2518
2519
2520
2521
2522 static const zend_function_entry session_functions[] = {
2523 PHP_FE(session_name, arginfo_session_name)
2524 PHP_FE(session_module_name, arginfo_session_module_name)
2525 PHP_FE(session_save_path, arginfo_session_save_path)
2526 PHP_FE(session_id, arginfo_session_id)
2527 PHP_FE(session_regenerate_id, arginfo_session_regenerate_id)
2528 PHP_FE(session_decode, arginfo_session_decode)
2529 PHP_FE(session_encode, arginfo_session_void)
2530 PHP_FE(session_start, arginfo_session_void)
2531 PHP_FE(session_destroy, arginfo_session_void)
2532 PHP_FE(session_unset, arginfo_session_void)
2533 PHP_FE(session_set_save_handler, arginfo_session_set_save_handler)
2534 PHP_FE(session_cache_limiter, arginfo_session_cache_limiter)
2535 PHP_FE(session_cache_expire, arginfo_session_cache_expire)
2536 PHP_FE(session_set_cookie_params, arginfo_session_set_cookie_params)
2537 PHP_FE(session_get_cookie_params, arginfo_session_void)
2538 PHP_FE(session_write_close, arginfo_session_void)
2539 PHP_FE(session_abort, arginfo_session_void)
2540 PHP_FE(session_reset, arginfo_session_void)
2541 PHP_FE(session_status, arginfo_session_void)
2542 PHP_FE(session_register_shutdown, arginfo_session_void)
2543 PHP_FALIAS(session_commit, session_write_close, arginfo_session_void)
2544 PHP_FE_END
2545 };
2546
2547
2548
2549
2550 static const zend_function_entry php_session_iface_functions[] = {
2551 PHP_ABSTRACT_ME(SessionHandlerInterface, open, arginfo_session_class_open)
2552 PHP_ABSTRACT_ME(SessionHandlerInterface, close, arginfo_session_class_close)
2553 PHP_ABSTRACT_ME(SessionHandlerInterface, read, arginfo_session_class_read)
2554 PHP_ABSTRACT_ME(SessionHandlerInterface, write, arginfo_session_class_write)
2555 PHP_ABSTRACT_ME(SessionHandlerInterface, destroy, arginfo_session_class_destroy)
2556 PHP_ABSTRACT_ME(SessionHandlerInterface, gc, arginfo_session_class_gc)
2557 { NULL, NULL, NULL }
2558 };
2559
2560
2561
2562
2563 static const zend_function_entry php_session_id_iface_functions[] = {
2564 PHP_ABSTRACT_ME(SessionIdInterface, create_sid, arginfo_session_class_create_sid)
2565 { NULL, NULL, NULL }
2566 };
2567
2568
2569
2570
2571 static const zend_function_entry php_session_update_timestamp_iface_functions[] = {
2572 PHP_ABSTRACT_ME(SessionUpdateTimestampHandlerInterface, validateId, arginfo_session_class_validateId)
2573 PHP_ABSTRACT_ME(SessionUpdateTimestampHandlerInterface, updateTimestamp, arginfo_session_class_updateTimestamp)
2574 { NULL, NULL, NULL }
2575 };
2576
2577
2578
2579
2580 static const zend_function_entry php_session_class_functions[] = {
2581 PHP_ME(SessionHandler, open, arginfo_session_class_open, ZEND_ACC_PUBLIC)
2582 PHP_ME(SessionHandler, close, arginfo_session_class_close, ZEND_ACC_PUBLIC)
2583 PHP_ME(SessionHandler, read, arginfo_session_class_read, ZEND_ACC_PUBLIC)
2584 PHP_ME(SessionHandler, write, arginfo_session_class_write, ZEND_ACC_PUBLIC)
2585 PHP_ME(SessionHandler, destroy, arginfo_session_class_destroy, ZEND_ACC_PUBLIC)
2586 PHP_ME(SessionHandler, gc, arginfo_session_class_gc, ZEND_ACC_PUBLIC)
2587 PHP_ME(SessionHandler, create_sid, arginfo_session_class_create_sid, ZEND_ACC_PUBLIC)
2588 { NULL, NULL, NULL }
2589 };
2590
2591
2592
2593
2594
2595
2596 static int php_rinit_session(zend_bool auto_start)
2597 {
2598 php_rinit_session_globals();
2599
2600 if (PS(mod) == NULL) {
2601 char *value;
2602
2603 value = zend_ini_string("session.save_handler", sizeof("session.save_handler") - 1, 0);
2604 if (value) {
2605 PS(mod) = _php_find_ps_module(value);
2606 }
2607 }
2608
2609 if (PS(serializer) == NULL) {
2610 char *value;
2611
2612 value = zend_ini_string("session.serialize_handler", sizeof("session.serialize_handler") - 1, 0);
2613 if (value) {
2614 PS(serializer) = _php_find_ps_serializer(value);
2615 }
2616 }
2617
2618 if (PS(mod) == NULL || PS(serializer) == NULL) {
2619
2620 PS(session_status) = php_session_disabled;
2621 return SUCCESS;
2622 }
2623
2624 if (auto_start) {
2625 php_session_start();
2626 }
2627
2628 return SUCCESS;
2629 }
2630
2631 static PHP_RINIT_FUNCTION(session)
2632 {
2633 return php_rinit_session(PS(auto_start));
2634 }
2635
2636
2637 static PHP_RSHUTDOWN_FUNCTION(session)
2638 {
2639 int i;
2640
2641 zend_try {
2642 php_session_flush(1);
2643 } zend_end_try();
2644 php_rshutdown_session_globals();
2645
2646
2647 for (i = 0; i < PS_NUM_APIS; i++) {
2648 if (!Z_ISUNDEF(PS(mod_user_names).names[i])) {
2649 zval_ptr_dtor(&PS(mod_user_names).names[i]);
2650 ZVAL_UNDEF(&PS(mod_user_names).names[i]);
2651 }
2652 }
2653
2654 return SUCCESS;
2655 }
2656
2657
2658 static PHP_GINIT_FUNCTION(ps)
2659 {
2660 int i;
2661
2662 #if defined(COMPILE_DL_SESSION) && defined(ZTS)
2663 ZEND_TSRMLS_CACHE_UPDATE();
2664 #endif
2665
2666 ps_globals->save_path = NULL;
2667 ps_globals->session_name = NULL;
2668 ps_globals->id = NULL;
2669 ps_globals->mod = NULL;
2670 ps_globals->serializer = NULL;
2671 ps_globals->mod_data = NULL;
2672 ps_globals->session_status = php_session_none;
2673 ps_globals->default_mod = NULL;
2674 ps_globals->mod_user_implemented = 0;
2675 ps_globals->mod_user_is_open = 0;
2676 ps_globals->session_vars = NULL;
2677 for (i = 0; i < PS_NUM_APIS; i++) {
2678 ZVAL_UNDEF(&ps_globals->mod_user_names.names[i]);
2679 }
2680 ZVAL_UNDEF(&ps_globals->http_session_vars);
2681 }
2682
2683
2684 static PHP_MINIT_FUNCTION(session)
2685 {
2686 zend_class_entry ce;
2687
2688 zend_register_auto_global(zend_string_init("_SESSION", sizeof("_SESSION") - 1, 1), 0, NULL);
2689
2690 PS(module_number) = module_number;
2691
2692 PS(session_status) = php_session_none;
2693 REGISTER_INI_ENTRIES();
2694
2695 #ifdef HAVE_LIBMM
2696 PHP_MINIT(ps_mm) (INIT_FUNC_ARGS_PASSTHRU);
2697 #endif
2698 php_session_rfc1867_orig_callback = php_rfc1867_callback;
2699 php_rfc1867_callback = php_session_rfc1867_callback;
2700
2701
2702 INIT_CLASS_ENTRY(ce, PS_IFACE_NAME, php_session_iface_functions);
2703 php_session_iface_entry = zend_register_internal_class(&ce);
2704 php_session_iface_entry->ce_flags |= ZEND_ACC_INTERFACE;
2705
2706 INIT_CLASS_ENTRY(ce, PS_SID_IFACE_NAME, php_session_id_iface_functions);
2707 php_session_id_iface_entry = zend_register_internal_class(&ce);
2708 php_session_id_iface_entry->ce_flags |= ZEND_ACC_INTERFACE;
2709
2710 INIT_CLASS_ENTRY(ce, PS_UPDATE_TIMESTAMP_IFACE_NAME, php_session_update_timestamp_iface_functions);
2711 php_session_update_timestamp_iface_entry = zend_register_internal_class(&ce);
2712 php_session_update_timestamp_iface_entry->ce_flags |= ZEND_ACC_INTERFACE;
2713
2714
2715 INIT_CLASS_ENTRY(ce, PS_CLASS_NAME, php_session_class_functions);
2716 php_session_class_entry = zend_register_internal_class(&ce);
2717 zend_class_implements(php_session_class_entry, 1, php_session_iface_entry);
2718 zend_class_implements(php_session_class_entry, 1, php_session_id_iface_entry);
2719
2720 REGISTER_LONG_CONSTANT("PHP_SESSION_DISABLED", php_session_disabled, CONST_CS | CONST_PERSISTENT);
2721 REGISTER_LONG_CONSTANT("PHP_SESSION_NONE", php_session_none, CONST_CS | CONST_PERSISTENT);
2722 REGISTER_LONG_CONSTANT("PHP_SESSION_ACTIVE", php_session_active, CONST_CS | CONST_PERSISTENT);
2723
2724 return SUCCESS;
2725 }
2726
2727
2728 static PHP_MSHUTDOWN_FUNCTION(session)
2729 {
2730 UNREGISTER_INI_ENTRIES();
2731
2732 #ifdef HAVE_LIBMM
2733 PHP_MSHUTDOWN(ps_mm) (SHUTDOWN_FUNC_ARGS_PASSTHRU);
2734 #endif
2735
2736
2737 php_session_rfc1867_orig_callback = NULL;
2738 if (php_rfc1867_callback == php_session_rfc1867_callback) {
2739 php_rfc1867_callback = NULL;
2740 }
2741
2742 ps_serializers[PREDEFINED_SERIALIZERS].name = NULL;
2743 memset(&ps_modules[PREDEFINED_MODULES], 0, (MAX_MODULES-PREDEFINED_MODULES)*sizeof(ps_module *));
2744
2745 return SUCCESS;
2746 }
2747
2748
2749 static PHP_MINFO_FUNCTION(session)
2750 {
2751 ps_module **mod;
2752 ps_serializer *ser;
2753 smart_str save_handlers = {0};
2754 smart_str ser_handlers = {0};
2755 int i;
2756
2757
2758 for (i = 0, mod = ps_modules; i < MAX_MODULES; i++, mod++) {
2759 if (*mod && (*mod)->s_name) {
2760 smart_str_appends(&save_handlers, (*mod)->s_name);
2761 smart_str_appendc(&save_handlers, ' ');
2762 }
2763 }
2764
2765
2766 for (i = 0, ser = ps_serializers; i < MAX_SERIALIZERS; i++, ser++) {
2767 if (ser && ser->name) {
2768 smart_str_appends(&ser_handlers, ser->name);
2769 smart_str_appendc(&ser_handlers, ' ');
2770 }
2771 }
2772
2773 php_info_print_table_start();
2774 php_info_print_table_row(2, "Session Support", "enabled" );
2775
2776 if (save_handlers.s) {
2777 smart_str_0(&save_handlers);
2778 php_info_print_table_row(2, "Registered save handlers", ZSTR_VAL(save_handlers.s));
2779 smart_str_free(&save_handlers);
2780 } else {
2781 php_info_print_table_row(2, "Registered save handlers", "none");
2782 }
2783
2784 if (ser_handlers.s) {
2785 smart_str_0(&ser_handlers);
2786 php_info_print_table_row(2, "Registered serializer handlers", ZSTR_VAL(ser_handlers.s));
2787 smart_str_free(&ser_handlers);
2788 } else {
2789 php_info_print_table_row(2, "Registered serializer handlers", "none");
2790 }
2791
2792 php_info_print_table_end();
2793
2794 DISPLAY_INI_ENTRIES();
2795 }
2796
2797
2798 static const zend_module_dep session_deps[] = {
2799 ZEND_MOD_OPTIONAL("hash")
2800 ZEND_MOD_REQUIRED("spl")
2801 ZEND_MOD_END
2802 };
2803
2804
2805
2806
2807
2808
2809 static zend_bool early_find_sid_in(zval *dest, int where, php_session_rfc1867_progress *progress)
2810 {
2811 zval *ppid;
2812
2813 if (Z_ISUNDEF(PG(http_globals)[where])) {
2814 return 0;
2815 }
2816
2817 if ((ppid = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[where]), PS(session_name), progress->sname_len))
2818 && Z_TYPE_P(ppid) == IS_STRING) {
2819 zval_dtor(dest);
2820 ZVAL_DEREF(ppid);
2821 ZVAL_COPY(dest, ppid);
2822 return 1;
2823 }
2824
2825 return 0;
2826 }
2827
2828 static void php_session_rfc1867_early_find_sid(php_session_rfc1867_progress *progress)
2829 {
2830
2831 if (PS(use_cookies)) {
2832 sapi_module.treat_data(PARSE_COOKIE, NULL, NULL);
2833 if (early_find_sid_in(&progress->sid, TRACK_VARS_COOKIE, progress)) {
2834 progress->apply_trans_sid = 0;
2835 return;
2836 }
2837 }
2838 if (PS(use_only_cookies)) {
2839 return;
2840 }
2841 sapi_module.treat_data(PARSE_GET, NULL, NULL);
2842 early_find_sid_in(&progress->sid, TRACK_VARS_GET, progress);
2843 }
2844
2845 static zend_bool php_check_cancel_upload(php_session_rfc1867_progress *progress)
2846 {
2847 zval *progress_ary, *cancel_upload;
2848
2849 if ((progress_ary = zend_symtable_find(Z_ARRVAL_P(Z_REFVAL(PS(http_session_vars))), progress->key.s)) == NULL) {
2850 return 0;
2851 }
2852 if (Z_TYPE_P(progress_ary) != IS_ARRAY) {
2853 return 0;
2854 }
2855 if ((cancel_upload = zend_hash_str_find(Z_ARRVAL_P(progress_ary), "cancel_upload", sizeof("cancel_upload") - 1)) == NULL) {
2856 return 0;
2857 }
2858 return Z_TYPE_P(cancel_upload) == IS_TRUE;
2859 }
2860
2861 static void php_session_rfc1867_update(php_session_rfc1867_progress *progress, int force_update)
2862 {
2863 if (!force_update) {
2864 if (Z_LVAL_P(progress->post_bytes_processed) < progress->next_update) {
2865 return;
2866 }
2867 #ifdef HAVE_GETTIMEOFDAY
2868 if (PS(rfc1867_min_freq) > 0.0) {
2869 struct timeval tv = {0};
2870 double dtv;
2871 gettimeofday(&tv, NULL);
2872 dtv = (double) tv.tv_sec + tv.tv_usec / 1000000.0;
2873 if (dtv < progress->next_update_time) {
2874 return;
2875 }
2876 progress->next_update_time = dtv + PS(rfc1867_min_freq);
2877 }
2878 #endif
2879 progress->next_update = Z_LVAL_P(progress->post_bytes_processed) + progress->update_step;
2880 }
2881
2882 php_session_initialize();
2883 PS(session_status) = php_session_active;
2884 IF_SESSION_VARS() {
2885 progress->cancel_upload |= php_check_cancel_upload(progress);
2886 if (Z_REFCOUNTED(progress->data)) Z_ADDREF(progress->data);
2887 zend_hash_update(Z_ARRVAL_P(Z_REFVAL(PS(http_session_vars))), progress->key.s, &progress->data);
2888 }
2889 php_session_flush(1);
2890 }
2891
2892 static void php_session_rfc1867_cleanup(php_session_rfc1867_progress *progress)
2893 {
2894 php_session_initialize();
2895 PS(session_status) = php_session_active;
2896 IF_SESSION_VARS() {
2897 zend_hash_del(Z_ARRVAL_P(Z_REFVAL(PS(http_session_vars))), progress->key.s);
2898 }
2899 php_session_flush(1);
2900 }
2901
2902 static int php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra)
2903 {
2904 php_session_rfc1867_progress *progress;
2905 int retval = SUCCESS;
2906
2907 if (php_session_rfc1867_orig_callback) {
2908 retval = php_session_rfc1867_orig_callback(event, event_data, extra);
2909 }
2910 if (!PS(rfc1867_enabled)) {
2911 return retval;
2912 }
2913
2914 progress = PS(rfc1867_progress);
2915
2916 switch(event) {
2917 case MULTIPART_EVENT_START: {
2918 multipart_event_start *data = (multipart_event_start *) event_data;
2919 progress = ecalloc(1, sizeof(php_session_rfc1867_progress));
2920 progress->content_length = data->content_length;
2921 progress->sname_len = strlen(PS(session_name));
2922 PS(rfc1867_progress) = progress;
2923 }
2924 break;
2925 case MULTIPART_EVENT_FORMDATA: {
2926 multipart_event_formdata *data = (multipart_event_formdata *) event_data;
2927 size_t value_len;
2928
2929 if (Z_TYPE(progress->sid) && progress->key.s) {
2930 break;
2931 }
2932
2933
2934 if (data->newlength) {
2935 value_len = *data->newlength;
2936 } else {
2937 value_len = data->length;
2938 }
2939
2940 if (data->name && data->value && value_len) {
2941 size_t name_len = strlen(data->name);
2942
2943 if (name_len == progress->sname_len && memcmp(data->name, PS(session_name), name_len) == 0) {
2944 zval_dtor(&progress->sid);
2945 ZVAL_STRINGL(&progress->sid, (*data->value), value_len);
2946 } else if (name_len == strlen(PS(rfc1867_name)) && memcmp(data->name, PS(rfc1867_name), name_len + 1) == 0) {
2947 smart_str_free(&progress->key);
2948 smart_str_appends(&progress->key, PS(rfc1867_prefix));
2949 smart_str_appendl(&progress->key, *data->value, value_len);
2950 smart_str_0(&progress->key);
2951
2952 progress->apply_trans_sid = APPLY_TRANS_SID;
2953 php_session_rfc1867_early_find_sid(progress);
2954 }
2955 }
2956 }
2957 break;
2958 case MULTIPART_EVENT_FILE_START: {
2959 multipart_event_file_start *data = (multipart_event_file_start *) event_data;
2960
2961
2962
2963 if (!Z_TYPE(progress->sid) || !progress->key.s) {
2964 break;
2965 }
2966
2967
2968 if (Z_ISUNDEF(progress->data)) {
2969
2970 if (PS(rfc1867_freq) >= 0) {
2971 progress->update_step = PS(rfc1867_freq);
2972 } else if (PS(rfc1867_freq) < 0) {
2973 progress->update_step = progress->content_length * -PS(rfc1867_freq) / 100;
2974 }
2975 progress->next_update = 0;
2976 progress->next_update_time = 0.0;
2977
2978 array_init(&progress->data);
2979 array_init(&progress->files);
2980
2981 add_assoc_long_ex(&progress->data, "start_time", sizeof("start_time") - 1, (zend_long)sapi_get_request_time());
2982 add_assoc_long_ex(&progress->data, "content_length", sizeof("content_length") - 1, progress->content_length);
2983 add_assoc_long_ex(&progress->data, "bytes_processed", sizeof("bytes_processed") - 1, data->post_bytes_processed);
2984 add_assoc_bool_ex(&progress->data, "done", sizeof("done") - 1, 0);
2985 add_assoc_zval_ex(&progress->data, "files", sizeof("files") - 1, &progress->files);
2986
2987 progress->post_bytes_processed = zend_hash_str_find(Z_ARRVAL(progress->data), "bytes_processed", sizeof("bytes_processed") - 1);
2988
2989 php_rinit_session(0);
2990 PS(id) = zend_string_init(Z_STRVAL(progress->sid), Z_STRLEN(progress->sid), 0);
2991 if (progress->apply_trans_sid) {
2992
2993 PS(use_trans_sid) = 1;
2994 PS(use_only_cookies) = 0;
2995 }
2996 PS(send_cookie) = 0;
2997 }
2998
2999 array_init(&progress->current_file);
3000
3001
3002 add_assoc_string_ex(&progress->current_file, "field_name", sizeof("field_name") - 1, data->name);
3003 add_assoc_string_ex(&progress->current_file, "name", sizeof("name") - 1, *data->filename);
3004 add_assoc_null_ex(&progress->current_file, "tmp_name", sizeof("tmp_name") - 1);
3005 add_assoc_long_ex(&progress->current_file, "error", sizeof("error") - 1, 0);
3006
3007 add_assoc_bool_ex(&progress->current_file, "done", sizeof("done") - 1, 0);
3008 add_assoc_long_ex(&progress->current_file, "start_time", sizeof("start_time") - 1, (zend_long)time(NULL));
3009 add_assoc_long_ex(&progress->current_file, "bytes_processed", sizeof("bytes_processed") - 1, 0);
3010
3011 add_next_index_zval(&progress->files, &progress->current_file);
3012
3013 progress->current_file_bytes_processed = zend_hash_str_find(Z_ARRVAL(progress->current_file), "bytes_processed", sizeof("bytes_processed") - 1);
3014
3015 Z_LVAL_P(progress->current_file_bytes_processed) = data->post_bytes_processed;
3016 php_session_rfc1867_update(progress, 0);
3017 }
3018 break;
3019 case MULTIPART_EVENT_FILE_DATA: {
3020 multipart_event_file_data *data = (multipart_event_file_data *) event_data;
3021
3022 if (!Z_TYPE(progress->sid) || !progress->key.s) {
3023 break;
3024 }
3025
3026 Z_LVAL_P(progress->current_file_bytes_processed) = data->offset + data->length;
3027 Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed;
3028
3029 php_session_rfc1867_update(progress, 0);
3030 }
3031 break;
3032 case MULTIPART_EVENT_FILE_END: {
3033 multipart_event_file_end *data = (multipart_event_file_end *) event_data;
3034
3035 if (!Z_TYPE(progress->sid) || !progress->key.s) {
3036 break;
3037 }
3038
3039 if (data->temp_filename) {
3040 add_assoc_string_ex(&progress->current_file, "tmp_name", sizeof("tmp_name") - 1, data->temp_filename);
3041 }
3042
3043 add_assoc_long_ex(&progress->current_file, "error", sizeof("error") - 1, data->cancel_upload);
3044 add_assoc_bool_ex(&progress->current_file, "done", sizeof("done") - 1, 1);
3045
3046 Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed;
3047
3048 php_session_rfc1867_update(progress, 0);
3049 }
3050 break;
3051 case MULTIPART_EVENT_END: {
3052 multipart_event_end *data = (multipart_event_end *) event_data;
3053
3054 if (Z_TYPE(progress->sid) && progress->key.s) {
3055 if (PS(rfc1867_cleanup)) {
3056 php_session_rfc1867_cleanup(progress);
3057 } else {
3058 add_assoc_bool_ex(&progress->data, "done", sizeof("done") - 1, 1);
3059 Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed;
3060 php_session_rfc1867_update(progress, 1);
3061 }
3062 php_rshutdown_session_globals();
3063 }
3064
3065 if (!Z_ISUNDEF(progress->data)) {
3066 zval_ptr_dtor(&progress->data);
3067 }
3068 zval_ptr_dtor(&progress->sid);
3069 smart_str_free(&progress->key);
3070 efree(progress);
3071 progress = NULL;
3072 PS(rfc1867_progress) = NULL;
3073 }
3074 break;
3075 }
3076
3077 if (progress && progress->cancel_upload) {
3078 return FAILURE;
3079 }
3080 return retval;
3081
3082 }
3083
3084 zend_module_entry session_module_entry = {
3085 STANDARD_MODULE_HEADER_EX,
3086 NULL,
3087 session_deps,
3088 "session",
3089 session_functions,
3090 PHP_MINIT(session), PHP_MSHUTDOWN(session),
3091 PHP_RINIT(session), PHP_RSHUTDOWN(session),
3092 PHP_MINFO(session),
3093 PHP_SESSION_VERSION,
3094 PHP_MODULE_GLOBALS(ps),
3095 PHP_GINIT(ps),
3096 NULL,
3097 NULL,
3098 STANDARD_MODULE_PROPERTIES_EX
3099 };
3100
3101 #ifdef COMPILE_DL_SESSION
3102 #ifdef ZTS
3103 ZEND_TSRMLS_CACHE_DEFINE()
3104 #endif
3105 ZEND_GET_MODULE(session)
3106 #endif
3107
3108
3109
3110
3111
3112
3113
3114
3115