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