PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/ext/session/session.c

http://github.com/infusion/PHP
C | 2228 lines | 1866 code | 215 blank | 147 comment | 205 complexity | cad0fa04c76dae1b8ebf5db577d3ba50 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2011 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. /* $Id: session.c 307671 2011-01-23 10:02:06Z pajoye $ */
  20. #ifdef HAVE_CONFIG_H
  21. #include "config.h"
  22. #endif
  23. #include "php.h"
  24. #ifdef PHP_WIN32
  25. # include "win32/winutil.h"
  26. # include "win32/time.h"
  27. #else
  28. #include <sys/time.h>
  29. #endif
  30. #include <sys/stat.h>
  31. #include <fcntl.h>
  32. #include "php_ini.h"
  33. #include "SAPI.h"
  34. #include "php_session.h"
  35. #include "ext/standard/md5.h"
  36. #include "ext/standard/sha1.h"
  37. #include "ext/standard/php_var.h"
  38. #include "ext/date/php_date.h"
  39. #include "ext/standard/php_lcg.h"
  40. #include "ext/standard/url_scanner_ex.h"
  41. #include "ext/standard/php_rand.h" /* for RAND_MAX */
  42. #include "ext/standard/info.h"
  43. #include "ext/standard/php_smart_str.h"
  44. #include "ext/standard/url.h"
  45. #include "mod_files.h"
  46. #include "mod_user.h"
  47. #ifdef HAVE_LIBMM
  48. #include "mod_mm.h"
  49. #endif
  50. PHPAPI ZEND_DECLARE_MODULE_GLOBALS(ps);
  51. /* ***********
  52. * Helpers *
  53. *********** */
  54. #define IF_SESSION_VARS() \
  55. if (PS(http_session_vars) && PS(http_session_vars)->type == IS_ARRAY)
  56. #define SESSION_CHECK_ACTIVE_STATE \
  57. if (PS(session_status) == php_session_active) { \
  58. php_error_docref(NULL TSRMLS_CC, E_WARNING, "A session is active. You cannot change the session module's ini settings at this time"); \
  59. return FAILURE; \
  60. }
  61. /* Dispatched by RINIT and by php_session_destroy */
  62. static inline void php_rinit_session_globals(TSRMLS_D) /* {{{ */
  63. {
  64. PS(id) = NULL;
  65. PS(session_status) = php_session_none;
  66. PS(mod_data) = NULL;
  67. /* Do NOT init PS(mod_user_names) here! */
  68. PS(http_session_vars) = NULL;
  69. }
  70. /* }}} */
  71. /* Dispatched by RSHUTDOWN and by php_session_destroy */
  72. static inline void php_rshutdown_session_globals(TSRMLS_D) /* {{{ */
  73. {
  74. if (PS(http_session_vars)) {
  75. zval_ptr_dtor(&PS(http_session_vars));
  76. PS(http_session_vars) = NULL;
  77. }
  78. /* Do NOT destroy PS(mod_user_names) here! */
  79. if (PS(mod_data)) {
  80. zend_try {
  81. PS(mod)->s_close(&PS(mod_data) TSRMLS_CC);
  82. } zend_end_try();
  83. }
  84. if (PS(id)) {
  85. efree(PS(id));
  86. }
  87. }
  88. /* }}} */
  89. static int php_session_destroy(TSRMLS_D) /* {{{ */
  90. {
  91. int retval = SUCCESS;
  92. if (PS(session_status) != php_session_active) {
  93. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Trying to destroy uninitialized session");
  94. return FAILURE;
  95. }
  96. if (PS(mod)->s_destroy(&PS(mod_data), PS(id) TSRMLS_CC) == FAILURE) {
  97. retval = FAILURE;
  98. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session object destruction failed");
  99. }
  100. php_rshutdown_session_globals(TSRMLS_C);
  101. php_rinit_session_globals(TSRMLS_C);
  102. return retval;
  103. }
  104. /* }}} */
  105. PHPAPI void php_add_session_var(char *name, size_t namelen TSRMLS_DC) /* {{{ */
  106. {
  107. zval **sym_track = NULL;
  108. IF_SESSION_VARS() {
  109. zend_hash_find(Z_ARRVAL_P(PS(http_session_vars)), name, namelen + 1, (void *) &sym_track);
  110. } else {
  111. return;
  112. }
  113. /* Set up a proper reference between $_SESSION["x"] and $x. */
  114. {
  115. if (sym_track == NULL) {
  116. zval *empty_var;
  117. ALLOC_INIT_ZVAL(empty_var);
  118. ZEND_SET_SYMBOL_WITH_LENGTH(Z_ARRVAL_P(PS(http_session_vars)), name, namelen+1, empty_var, 1, 0);
  119. }
  120. }
  121. }
  122. /* }}} */
  123. PHPAPI void php_set_session_var(char *name, size_t namelen, zval *state_val, php_unserialize_data_t *var_hash TSRMLS_DC) /* {{{ */
  124. {
  125. IF_SESSION_VARS() {
  126. zend_set_hash_symbol(state_val, name, namelen, PZVAL_IS_REF(state_val), 1, Z_ARRVAL_P(PS(http_session_vars)));
  127. }
  128. }
  129. /* }}} */
  130. PHPAPI int php_get_session_var(char *name, size_t namelen, zval ***state_var TSRMLS_DC) /* {{{ */
  131. {
  132. int ret = FAILURE;
  133. IF_SESSION_VARS() {
  134. ret = zend_hash_find(Z_ARRVAL_P(PS(http_session_vars)), name, namelen + 1, (void **) state_var);
  135. }
  136. return ret;
  137. }
  138. /* }}} */
  139. static void php_session_track_init(TSRMLS_D) /* {{{ */
  140. {
  141. zval *session_vars = NULL;
  142. /* Unconditionally destroy existing arrays -- possible dirty data */
  143. zend_delete_global_variable("HTTP_SESSION_VARS", sizeof("HTTP_SESSION_VARS")-1 TSRMLS_CC);
  144. zend_delete_global_variable("_SESSION", sizeof("_SESSION")-1 TSRMLS_CC);
  145. if (PS(http_session_vars)) {
  146. zval_ptr_dtor(&PS(http_session_vars));
  147. }
  148. MAKE_STD_ZVAL(session_vars);
  149. array_init(session_vars);
  150. PS(http_session_vars) = session_vars;
  151. {
  152. ZEND_SET_GLOBAL_VAR_WITH_LENGTH("_SESSION", sizeof("_SESSION"), PS(http_session_vars), 2, 1);
  153. }
  154. }
  155. /* }}} */
  156. static char *php_session_encode(int *newlen TSRMLS_DC) /* {{{ */
  157. {
  158. char *ret = NULL;
  159. IF_SESSION_VARS() {
  160. if (!PS(serializer)) {
  161. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown session.serialize_handler. Failed to encode session object");
  162. ret = NULL;
  163. } else if (PS(serializer)->encode(&ret, newlen TSRMLS_CC) == FAILURE) {
  164. ret = NULL;
  165. }
  166. } else {
  167. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot encode non-existent session");
  168. }
  169. return ret;
  170. }
  171. /* }}} */
  172. static void php_session_decode(const char *val, int vallen TSRMLS_DC) /* {{{ */
  173. {
  174. if (!PS(serializer)) {
  175. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown session.serialize_handler. Failed to decode session object");
  176. return;
  177. }
  178. if (PS(serializer)->decode(val, vallen TSRMLS_CC) == FAILURE) {
  179. php_session_destroy(TSRMLS_C);
  180. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to decode session object. Session has been destroyed");
  181. }
  182. }
  183. /* }}} */
  184. /*
  185. * Note that we cannot use the BASE64 alphabet here, because
  186. * it contains "/" and "+": both are unacceptable for simple inclusion
  187. * into URLs.
  188. */
  189. static char hexconvtab[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,-";
  190. enum {
  191. PS_HASH_FUNC_MD5,
  192. PS_HASH_FUNC_SHA1,
  193. PS_HASH_FUNC_OTHER
  194. };
  195. /* returns a pointer to the byte after the last valid character in out */
  196. static char *bin_to_readable(char *in, size_t inlen, char *out, char nbits) /* {{{ */
  197. {
  198. unsigned char *p, *q;
  199. unsigned short w;
  200. int mask;
  201. int have;
  202. p = (unsigned char *) in;
  203. q = (unsigned char *)in + inlen;
  204. w = 0;
  205. have = 0;
  206. mask = (1 << nbits) - 1;
  207. while (1) {
  208. if (have < nbits) {
  209. if (p < q) {
  210. w |= *p++ << have;
  211. have += 8;
  212. } else {
  213. /* consumed everything? */
  214. if (have == 0) break;
  215. /* No? We need a final round */
  216. have = nbits;
  217. }
  218. }
  219. /* consume nbits */
  220. *out++ = hexconvtab[w & mask];
  221. w >>= nbits;
  222. have -= nbits;
  223. }
  224. *out = '\0';
  225. return out;
  226. }
  227. /* }}} */
  228. PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS) /* {{{ */
  229. {
  230. PHP_MD5_CTX md5_context;
  231. PHP_SHA1_CTX sha1_context;
  232. #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
  233. void *hash_context;
  234. #endif
  235. unsigned char *digest;
  236. int digest_len;
  237. int j;
  238. char *buf, *outid;
  239. struct timeval tv;
  240. zval **array;
  241. zval **token;
  242. char *remote_addr = NULL;
  243. gettimeofday(&tv, NULL);
  244. if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &array) == SUCCESS &&
  245. Z_TYPE_PP(array) == IS_ARRAY &&
  246. zend_hash_find(Z_ARRVAL_PP(array), "REMOTE_ADDR", sizeof("REMOTE_ADDR"), (void **) &token) == SUCCESS
  247. ) {
  248. remote_addr = Z_STRVAL_PP(token);
  249. }
  250. /* maximum 15+19+19+10 bytes */
  251. 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);
  252. switch (PS(hash_func)) {
  253. case PS_HASH_FUNC_MD5:
  254. PHP_MD5Init(&md5_context);
  255. PHP_MD5Update(&md5_context, (unsigned char *) buf, strlen(buf));
  256. digest_len = 16;
  257. break;
  258. case PS_HASH_FUNC_SHA1:
  259. PHP_SHA1Init(&sha1_context);
  260. PHP_SHA1Update(&sha1_context, (unsigned char *) buf, strlen(buf));
  261. digest_len = 20;
  262. break;
  263. #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
  264. case PS_HASH_FUNC_OTHER:
  265. if (!PS(hash_ops)) {
  266. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid session hash function");
  267. efree(buf);
  268. return NULL;
  269. }
  270. hash_context = emalloc(PS(hash_ops)->context_size);
  271. PS(hash_ops)->hash_init(hash_context);
  272. PS(hash_ops)->hash_update(hash_context, (unsigned char *) buf, strlen(buf));
  273. digest_len = PS(hash_ops)->digest_size;
  274. break;
  275. #endif /* HAVE_HASH_EXT */
  276. default:
  277. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid session hash function");
  278. efree(buf);
  279. return NULL;
  280. }
  281. efree(buf);
  282. if (PS(entropy_length) > 0) {
  283. #ifdef PHP_WIN32
  284. unsigned char rbuf[2048];
  285. size_t toread = PS(entropy_length);
  286. if (php_win32_get_random_bytes(rbuf, (size_t) toread) == SUCCESS){
  287. switch (PS(hash_func)) {
  288. case PS_HASH_FUNC_MD5:
  289. PHP_MD5Update(&md5_context, rbuf, toread);
  290. break;
  291. case PS_HASH_FUNC_SHA1:
  292. PHP_SHA1Update(&sha1_context, rbuf, toread);
  293. break;
  294. # if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
  295. case PS_HASH_FUNC_OTHER:
  296. PS(hash_ops)->hash_update(hash_context, rbuf, toread);
  297. break;
  298. # endif /* HAVE_HASH_EXT */
  299. }
  300. }
  301. #else
  302. int fd;
  303. fd = VCWD_OPEN(PS(entropy_file), O_RDONLY);
  304. if (fd >= 0) {
  305. unsigned char rbuf[2048];
  306. int n;
  307. int to_read = PS(entropy_length);
  308. while (to_read > 0) {
  309. n = read(fd, rbuf, MIN(to_read, sizeof(rbuf)));
  310. if (n <= 0) break;
  311. switch (PS(hash_func)) {
  312. case PS_HASH_FUNC_MD5:
  313. PHP_MD5Update(&md5_context, rbuf, n);
  314. break;
  315. case PS_HASH_FUNC_SHA1:
  316. PHP_SHA1Update(&sha1_context, rbuf, n);
  317. break;
  318. #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
  319. case PS_HASH_FUNC_OTHER:
  320. PS(hash_ops)->hash_update(hash_context, rbuf, n);
  321. break;
  322. #endif /* HAVE_HASH_EXT */
  323. }
  324. to_read -= n;
  325. }
  326. close(fd);
  327. }
  328. #endif
  329. }
  330. digest = emalloc(digest_len + 1);
  331. switch (PS(hash_func)) {
  332. case PS_HASH_FUNC_MD5:
  333. PHP_MD5Final(digest, &md5_context);
  334. break;
  335. case PS_HASH_FUNC_SHA1:
  336. PHP_SHA1Final(digest, &sha1_context);
  337. break;
  338. #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
  339. case PS_HASH_FUNC_OTHER:
  340. PS(hash_ops)->hash_final(digest, hash_context);
  341. efree(hash_context);
  342. break;
  343. #endif /* HAVE_HASH_EXT */
  344. }
  345. if (PS(hash_bits_per_character) < 4
  346. || PS(hash_bits_per_character) > 6) {
  347. PS(hash_bits_per_character) = 4;
  348. 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");
  349. }
  350. outid = emalloc((size_t)((digest_len + 2) * ((8.0f / PS(hash_bits_per_character)) + 0.5)));
  351. j = (int) (bin_to_readable((char *)digest, digest_len, outid, (char)PS(hash_bits_per_character)) - outid);
  352. efree(digest);
  353. if (newlen) {
  354. *newlen = j;
  355. }
  356. return outid;
  357. }
  358. /* }}} */
  359. static void php_session_initialize(TSRMLS_D) /* {{{ */
  360. {
  361. char *val;
  362. int vallen;
  363. /* check session name for invalid characters */
  364. if (PS(id) && strpbrk(PS(id), "\r\n\t <>'\"\\")) {
  365. efree(PS(id));
  366. PS(id) = NULL;
  367. }
  368. if (!PS(mod)) {
  369. php_error_docref(NULL TSRMLS_CC, E_ERROR, "No storage module chosen - failed to initialize session");
  370. return;
  371. }
  372. /* Open session handler first */
  373. if (PS(mod)->s_open(&PS(mod_data), PS(save_path), PS(session_name) TSRMLS_CC) == FAILURE) {
  374. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to initialize storage module: %s (path: %s)", PS(mod)->s_name, PS(save_path));
  375. return;
  376. }
  377. /* If there is no ID, use session module to create one */
  378. if (!PS(id)) {
  379. new_session:
  380. PS(id) = PS(mod)->s_create_sid(&PS(mod_data), NULL TSRMLS_CC);
  381. if (PS(use_cookies)) {
  382. PS(send_cookie) = 1;
  383. }
  384. }
  385. /* Read data */
  386. /* Question: if you create a SID here, should you also try to read data?
  387. * I'm not sure, but while not doing so will remove one session operation
  388. * it could prove usefull for those sites which wish to have "default"
  389. * session information. */
  390. php_session_track_init(TSRMLS_C);
  391. PS(invalid_session_id) = 0;
  392. if (PS(mod)->s_read(&PS(mod_data), PS(id), &val, &vallen TSRMLS_CC) == SUCCESS) {
  393. php_session_decode(val, vallen TSRMLS_CC);
  394. efree(val);
  395. } else if (PS(invalid_session_id)) { /* address instances where the session read fails due to an invalid id */
  396. PS(invalid_session_id) = 0;
  397. efree(PS(id));
  398. PS(id) = NULL;
  399. goto new_session;
  400. }
  401. }
  402. /* }}} */
  403. static int migrate_global(HashTable *ht, HashPosition *pos TSRMLS_DC) /* {{{ */
  404. {
  405. char *str;
  406. uint str_len;
  407. ulong num_key;
  408. int n;
  409. zval **val;
  410. int ret = 0;
  411. n = zend_hash_get_current_key_ex(ht, &str, &str_len, &num_key, 0, pos);
  412. switch (n) {
  413. case HASH_KEY_IS_STRING:
  414. if (zend_hash_find(&EG(symbol_table), str, str_len, (void **) &val) == SUCCESS &&
  415. val && Z_TYPE_PP(val) != IS_NULL
  416. ) {
  417. ZEND_SET_SYMBOL_WITH_LENGTH(ht, str, str_len, *val, Z_REFCOUNT_PP(val) + 1, 1);
  418. ret = 1;
  419. }
  420. break;
  421. case HASH_KEY_IS_LONG:
  422. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "The session bug compatibility code will not "
  423. "try to locate the global variable $%lu due to its "
  424. "numeric nature", num_key);
  425. break;
  426. }
  427. return ret;
  428. }
  429. /* }}} */
  430. static void php_session_save_current_state(TSRMLS_D) /* {{{ */
  431. {
  432. int ret = FAILURE;
  433. IF_SESSION_VARS() {
  434. if (PS(bug_compat)) {
  435. HashTable *ht = Z_ARRVAL_P(PS(http_session_vars));
  436. HashPosition pos;
  437. zval **val;
  438. int do_warn = 0;
  439. zend_hash_internal_pointer_reset_ex(ht, &pos);
  440. while (zend_hash_get_current_data_ex(ht, (void **) &val, &pos) != FAILURE) {
  441. if (Z_TYPE_PP(val) == IS_NULL) {
  442. if (migrate_global(ht, &pos TSRMLS_CC)) {
  443. do_warn = 1;
  444. }
  445. }
  446. zend_hash_move_forward_ex(ht, &pos);
  447. }
  448. if (do_warn && PS(bug_compat_warn)) {
  449. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Your script possibly relies on a session side-effect which existed until PHP 4.2.3. Please be advised that the session extension does not consider global variables as a source of data, unless register_globals is enabled. You can disable this functionality and this warning by setting session.bug_compat_42 or session.bug_compat_warn to off, respectively");
  450. }
  451. }
  452. if (PS(mod_data)) {
  453. char *val;
  454. int vallen;
  455. val = php_session_encode(&vallen TSRMLS_CC);
  456. if (val) {
  457. ret = PS(mod)->s_write(&PS(mod_data), PS(id), val, vallen TSRMLS_CC);
  458. efree(val);
  459. } else {
  460. ret = PS(mod)->s_write(&PS(mod_data), PS(id), "", 0 TSRMLS_CC);
  461. }
  462. }
  463. if (ret == FAILURE) {
  464. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write session data (%s). Please "
  465. "verify that the current setting of session.save_path "
  466. "is correct (%s)",
  467. PS(mod)->s_name,
  468. PS(save_path));
  469. }
  470. }
  471. if (PS(mod_data)) {
  472. PS(mod)->s_close(&PS(mod_data) TSRMLS_CC);
  473. }
  474. }
  475. /* }}} */
  476. /* *************************
  477. * INI Settings/Handlers *
  478. ************************* */
  479. static PHP_INI_MH(OnUpdateSaveHandler) /* {{{ */
  480. {
  481. ps_module *tmp;
  482. SESSION_CHECK_ACTIVE_STATE;
  483. tmp = _php_find_ps_module(new_value TSRMLS_CC);
  484. if (PG(modules_activated) && !tmp) {
  485. int err_type;
  486. if (stage == ZEND_INI_STAGE_RUNTIME) {
  487. err_type = E_WARNING;
  488. } else {
  489. err_type = E_ERROR;
  490. }
  491. /* Do not output error when restoring ini options. */
  492. if (stage != ZEND_INI_STAGE_DEACTIVATE) {
  493. php_error_docref(NULL TSRMLS_CC, err_type, "Cannot find save handler '%s'", new_value);
  494. }
  495. return FAILURE;
  496. }
  497. PS(mod) = tmp;
  498. return SUCCESS;
  499. }
  500. /* }}} */
  501. static PHP_INI_MH(OnUpdateSerializer) /* {{{ */
  502. {
  503. const ps_serializer *tmp;
  504. SESSION_CHECK_ACTIVE_STATE;
  505. tmp = _php_find_ps_serializer(new_value TSRMLS_CC);
  506. if (PG(modules_activated) && !tmp) {
  507. int err_type;
  508. if (stage == ZEND_INI_STAGE_RUNTIME) {
  509. err_type = E_WARNING;
  510. } else {
  511. err_type = E_ERROR;
  512. }
  513. /* Do not output error when restoring ini options. */
  514. if (stage != ZEND_INI_STAGE_DEACTIVATE) {
  515. php_error_docref(NULL TSRMLS_CC, err_type, "Cannot find serialization handler '%s'", new_value);
  516. }
  517. return FAILURE;
  518. }
  519. PS(serializer) = tmp;
  520. return SUCCESS;
  521. }
  522. /* }}} */
  523. static PHP_INI_MH(OnUpdateTransSid) /* {{{ */
  524. {
  525. SESSION_CHECK_ACTIVE_STATE;
  526. if (!strncasecmp(new_value, "on", sizeof("on"))) {
  527. PS(use_trans_sid) = (zend_bool) 1;
  528. } else {
  529. PS(use_trans_sid) = (zend_bool) atoi(new_value);
  530. }
  531. return SUCCESS;
  532. }
  533. /* }}} */
  534. static PHP_INI_MH(OnUpdateSaveDir) /* {{{ */
  535. {
  536. /* Only do the safemode/open_basedir check at runtime */
  537. if (stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) {
  538. char *p;
  539. if (memchr(new_value, '\0', new_value_length) != NULL) {
  540. return FAILURE;
  541. }
  542. /* we do not use zend_memrchr() since path can contain ; itself */
  543. if ((p = strchr(new_value, ';'))) {
  544. char *p2;
  545. p++;
  546. if ((p2 = strchr(p, ';'))) {
  547. p = p2 + 1;
  548. }
  549. } else {
  550. p = new_value;
  551. }
  552. if (PG(open_basedir) && *p && php_check_open_basedir(p TSRMLS_CC)) {
  553. return FAILURE;
  554. }
  555. }
  556. OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
  557. return SUCCESS;
  558. }
  559. /* }}} */
  560. static PHP_INI_MH(OnUpdateHashFunc) /* {{{ */
  561. {
  562. long val;
  563. char *endptr = NULL;
  564. #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
  565. PS(hash_ops) = NULL;
  566. #endif
  567. val = strtol(new_value, &endptr, 10);
  568. if (endptr && (*endptr == '\0')) {
  569. /* Numeric value */
  570. PS(hash_func) = val ? 1 : 0;
  571. return SUCCESS;
  572. }
  573. if (new_value_length == (sizeof("md5") - 1) &&
  574. strncasecmp(new_value, "md5", sizeof("md5") - 1) == 0) {
  575. PS(hash_func) = PS_HASH_FUNC_MD5;
  576. return SUCCESS;
  577. }
  578. if (new_value_length == (sizeof("sha1") - 1) &&
  579. strncasecmp(new_value, "sha1", sizeof("sha1") - 1) == 0) {
  580. PS(hash_func) = PS_HASH_FUNC_SHA1;
  581. return SUCCESS;
  582. }
  583. #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH) /* {{{ */
  584. {
  585. php_hash_ops *ops = (php_hash_ops*)php_hash_fetch_ops(new_value, new_value_length);
  586. if (ops) {
  587. PS(hash_func) = PS_HASH_FUNC_OTHER;
  588. PS(hash_ops) = ops;
  589. return SUCCESS;
  590. }
  591. }
  592. #endif /* HAVE_HASH_EXT }}} */
  593. return FAILURE;
  594. }
  595. /* }}} */
  596. /* {{{ PHP_INI
  597. */
  598. PHP_INI_BEGIN()
  599. STD_PHP_INI_BOOLEAN("session.bug_compat_42", "1", PHP_INI_ALL, OnUpdateBool, bug_compat, php_ps_globals, ps_globals)
  600. STD_PHP_INI_BOOLEAN("session.bug_compat_warn", "1", PHP_INI_ALL, OnUpdateBool, bug_compat_warn, php_ps_globals, ps_globals)
  601. STD_PHP_INI_ENTRY("session.save_path", "", PHP_INI_ALL, OnUpdateSaveDir,save_path, php_ps_globals, ps_globals)
  602. STD_PHP_INI_ENTRY("session.name", "PHPSESSID", PHP_INI_ALL, OnUpdateString, session_name, php_ps_globals, ps_globals)
  603. PHP_INI_ENTRY("session.save_handler", "files", PHP_INI_ALL, OnUpdateSaveHandler)
  604. STD_PHP_INI_BOOLEAN("session.auto_start", "0", PHP_INI_ALL, OnUpdateBool, auto_start, php_ps_globals, ps_globals)
  605. STD_PHP_INI_ENTRY("session.gc_probability", "1", PHP_INI_ALL, OnUpdateLong, gc_probability, php_ps_globals, ps_globals)
  606. STD_PHP_INI_ENTRY("session.gc_divisor", "100", PHP_INI_ALL, OnUpdateLong, gc_divisor, php_ps_globals, ps_globals)
  607. STD_PHP_INI_ENTRY("session.gc_maxlifetime", "1440", PHP_INI_ALL, OnUpdateLong, gc_maxlifetime, php_ps_globals, ps_globals)
  608. PHP_INI_ENTRY("session.serialize_handler", "php", PHP_INI_ALL, OnUpdateSerializer)
  609. STD_PHP_INI_ENTRY("session.cookie_lifetime", "0", PHP_INI_ALL, OnUpdateLong, cookie_lifetime, php_ps_globals, ps_globals)
  610. STD_PHP_INI_ENTRY("session.cookie_path", "/", PHP_INI_ALL, OnUpdateString, cookie_path, php_ps_globals, ps_globals)
  611. STD_PHP_INI_ENTRY("session.cookie_domain", "", PHP_INI_ALL, OnUpdateString, cookie_domain, php_ps_globals, ps_globals)
  612. STD_PHP_INI_BOOLEAN("session.cookie_secure", "", PHP_INI_ALL, OnUpdateBool, cookie_secure, php_ps_globals, ps_globals)
  613. STD_PHP_INI_BOOLEAN("session.cookie_httponly", "", PHP_INI_ALL, OnUpdateBool, cookie_httponly, php_ps_globals, ps_globals)
  614. STD_PHP_INI_BOOLEAN("session.use_cookies", "1", PHP_INI_ALL, OnUpdateBool, use_cookies, php_ps_globals, ps_globals)
  615. STD_PHP_INI_BOOLEAN("session.use_only_cookies", "1", PHP_INI_ALL, OnUpdateBool, use_only_cookies, php_ps_globals, ps_globals)
  616. STD_PHP_INI_ENTRY("session.referer_check", "", PHP_INI_ALL, OnUpdateString, extern_referer_chk, php_ps_globals, ps_globals)
  617. STD_PHP_INI_ENTRY("session.entropy_file", "", PHP_INI_ALL, OnUpdateString, entropy_file, php_ps_globals, ps_globals)
  618. STD_PHP_INI_ENTRY("session.entropy_length", "0", PHP_INI_ALL, OnUpdateLong, entropy_length, php_ps_globals, ps_globals)
  619. STD_PHP_INI_ENTRY("session.cache_limiter", "nocache", PHP_INI_ALL, OnUpdateString, cache_limiter, php_ps_globals, ps_globals)
  620. STD_PHP_INI_ENTRY("session.cache_expire", "180", PHP_INI_ALL, OnUpdateLong, cache_expire, php_ps_globals, ps_globals)
  621. PHP_INI_ENTRY("session.use_trans_sid", "0", PHP_INI_ALL, OnUpdateTransSid)
  622. PHP_INI_ENTRY("session.hash_function", "0", PHP_INI_ALL, OnUpdateHashFunc)
  623. STD_PHP_INI_ENTRY("session.hash_bits_per_character", "4", PHP_INI_ALL, OnUpdateLong, hash_bits_per_character, php_ps_globals, ps_globals)
  624. /* Commented out until future discussion */
  625. /* PHP_INI_ENTRY("session.encode_sources", "globals,track", PHP_INI_ALL, NULL) */
  626. PHP_INI_END()
  627. /* }}} */
  628. /* ***************
  629. * Serializers *
  630. *************** */
  631. #define PS_BIN_NR_OF_BITS 8
  632. #define PS_BIN_UNDEF (1<<(PS_BIN_NR_OF_BITS-1))
  633. #define PS_BIN_MAX (PS_BIN_UNDEF-1)
  634. PS_SERIALIZER_ENCODE_FUNC(php_binary) /* {{{ */
  635. {
  636. smart_str buf = {0};
  637. php_serialize_data_t var_hash;
  638. PS_ENCODE_VARS;
  639. PHP_VAR_SERIALIZE_INIT(var_hash);
  640. PS_ENCODE_LOOP(
  641. if (key_length > PS_BIN_MAX) continue;
  642. smart_str_appendc(&buf, (unsigned char) key_length);
  643. smart_str_appendl(&buf, key, key_length);
  644. php_var_serialize(&buf, struc, &var_hash TSRMLS_CC);
  645. } else {
  646. if (key_length > PS_BIN_MAX) continue;
  647. smart_str_appendc(&buf, (unsigned char) (key_length & PS_BIN_UNDEF));
  648. smart_str_appendl(&buf, key, key_length);
  649. );
  650. if (newlen) {
  651. *newlen = buf.len;
  652. }
  653. smart_str_0(&buf);
  654. *newstr = buf.c;
  655. PHP_VAR_SERIALIZE_DESTROY(var_hash);
  656. return SUCCESS;
  657. }
  658. /* }}} */
  659. PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */
  660. {
  661. const char *p;
  662. char *name;
  663. const char *endptr = val + vallen;
  664. zval *current;
  665. int namelen;
  666. int has_value;
  667. php_unserialize_data_t var_hash;
  668. PHP_VAR_UNSERIALIZE_INIT(var_hash);
  669. for (p = val; p < endptr; ) {
  670. zval **tmp;
  671. namelen = ((unsigned char)(*p)) & (~PS_BIN_UNDEF);
  672. if (namelen < 0 || namelen > PS_BIN_MAX || (p + namelen) >= endptr) {
  673. return FAILURE;
  674. }
  675. has_value = *p & PS_BIN_UNDEF ? 0 : 1;
  676. name = estrndup(p + 1, namelen);
  677. p += namelen + 1;
  678. if (zend_hash_find(&EG(symbol_table), name, namelen + 1, (void **) &tmp) == SUCCESS) {
  679. if ((Z_TYPE_PP(tmp) == IS_ARRAY && Z_ARRVAL_PP(tmp) == &EG(symbol_table)) || *tmp == PS(http_session_vars)) {
  680. efree(name);
  681. continue;
  682. }
  683. }
  684. if (has_value) {
  685. ALLOC_INIT_ZVAL(current);
  686. if (php_var_unserialize(&current, (const unsigned char **) &p, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) {
  687. php_set_session_var(name, namelen, current, &var_hash TSRMLS_CC);
  688. }
  689. zval_ptr_dtor(&current);
  690. }
  691. PS_ADD_VARL(name, namelen);
  692. efree(name);
  693. }
  694. PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
  695. return SUCCESS;
  696. }
  697. /* }}} */
  698. #define PS_DELIMITER '|'
  699. #define PS_UNDEF_MARKER '!'
  700. PS_SERIALIZER_ENCODE_FUNC(php) /* {{{ */
  701. {
  702. smart_str buf = {0};
  703. php_serialize_data_t var_hash;
  704. PS_ENCODE_VARS;
  705. PHP_VAR_SERIALIZE_INIT(var_hash);
  706. PS_ENCODE_LOOP(
  707. smart_str_appendl(&buf, key, key_length);
  708. if (memchr(key, PS_DELIMITER, key_length) || memchr(key, PS_UNDEF_MARKER, key_length)) {
  709. PHP_VAR_SERIALIZE_DESTROY(var_hash);
  710. smart_str_free(&buf);
  711. return FAILURE;
  712. }
  713. smart_str_appendc(&buf, PS_DELIMITER);
  714. php_var_serialize(&buf, struc, &var_hash TSRMLS_CC);
  715. } else {
  716. smart_str_appendc(&buf, PS_UNDEF_MARKER);
  717. smart_str_appendl(&buf, key, key_length);
  718. smart_str_appendc(&buf, PS_DELIMITER);
  719. );
  720. if (newlen) {
  721. *newlen = buf.len;
  722. }
  723. smart_str_0(&buf);
  724. *newstr = buf.c;
  725. PHP_VAR_SERIALIZE_DESTROY(var_hash);
  726. return SUCCESS;
  727. }
  728. /* }}} */
  729. PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */
  730. {
  731. const char *p, *q;
  732. char *name;
  733. const char *endptr = val + vallen;
  734. zval *current;
  735. int namelen;
  736. int has_value;
  737. php_unserialize_data_t var_hash;
  738. PHP_VAR_UNSERIALIZE_INIT(var_hash);
  739. p = val;
  740. while (p < endptr) {
  741. zval **tmp;
  742. q = p;
  743. while (*q != PS_DELIMITER) {
  744. if (++q >= endptr) goto break_outer_loop;
  745. }
  746. if (p[0] == PS_UNDEF_MARKER) {
  747. p++;
  748. has_value = 0;
  749. } else {
  750. has_value = 1;
  751. }
  752. namelen = q - p;
  753. name = estrndup(p, namelen);
  754. q++;
  755. if (zend_hash_find(&EG(symbol_table), name, namelen + 1, (void **) &tmp) == SUCCESS) {
  756. if ((Z_TYPE_PP(tmp) == IS_ARRAY && Z_ARRVAL_PP(tmp) == &EG(symbol_table)) || *tmp == PS(http_session_vars)) {
  757. goto skip;
  758. }
  759. }
  760. if (has_value) {
  761. ALLOC_INIT_ZVAL(current);
  762. if (php_var_unserialize(&current, (const unsigned char **) &q, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) {
  763. php_set_session_var(name, namelen, current, &var_hash TSRMLS_CC);
  764. }
  765. zval_ptr_dtor(&current);
  766. }
  767. PS_ADD_VARL(name, namelen);
  768. skip:
  769. efree(name);
  770. p = q;
  771. }
  772. break_outer_loop:
  773. PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
  774. return SUCCESS;
  775. }
  776. /* }}} */
  777. #define MAX_SERIALIZERS 10
  778. #define PREDEFINED_SERIALIZERS 2
  779. static ps_serializer ps_serializers[MAX_SERIALIZERS + 1] = {
  780. PS_SERIALIZER_ENTRY(php),
  781. PS_SERIALIZER_ENTRY(php_binary)
  782. };
  783. PHPAPI int php_session_register_serializer(const char *name, int (*encode)(PS_SERIALIZER_ENCODE_ARGS), int (*decode)(PS_SERIALIZER_DECODE_ARGS)) /* {{{ */
  784. {
  785. int ret = -1;
  786. int i;
  787. for (i = 0; i < MAX_SERIALIZERS; i++) {
  788. if (ps_serializers[i].name == NULL) {
  789. ps_serializers[i].name = name;
  790. ps_serializers[i].encode = encode;
  791. ps_serializers[i].decode = decode;
  792. ps_serializers[i + 1].name = NULL;
  793. ret = 0;
  794. break;
  795. }
  796. }
  797. return ret;
  798. }
  799. /* }}} */
  800. /* *******************
  801. * Storage Modules *
  802. ******************* */
  803. #define MAX_MODULES 10
  804. #define PREDEFINED_MODULES 2
  805. static ps_module *ps_modules[MAX_MODULES + 1] = {
  806. ps_files_ptr,
  807. ps_user_ptr
  808. };
  809. PHPAPI int php_session_register_module(ps_module *ptr) /* {{{ */
  810. {
  811. int ret = -1;
  812. int i;
  813. for (i = 0; i < MAX_MODULES; i++) {
  814. if (!ps_modules[i]) {
  815. ps_modules[i] = ptr;
  816. ret = 0;
  817. break;
  818. }
  819. }
  820. return ret;
  821. }
  822. /* }}} */
  823. /* ******************
  824. * Cache Limiters *
  825. ****************** */
  826. typedef struct {
  827. char *name;
  828. void (*func)(TSRMLS_D);
  829. } php_session_cache_limiter_t;
  830. #define CACHE_LIMITER(name) _php_cache_limiter_##name
  831. #define CACHE_LIMITER_FUNC(name) static void CACHE_LIMITER(name)(TSRMLS_D)
  832. #define CACHE_LIMITER_ENTRY(name) { #name, CACHE_LIMITER(name) },
  833. #define ADD_HEADER(a) sapi_add_header(a, strlen(a), 1);
  834. #define MAX_STR 512
  835. static char *month_names[] = {
  836. "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  837. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  838. };
  839. static char *week_days[] = {
  840. "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
  841. };
  842. static inline void strcpy_gmt(char *ubuf, time_t *when) /* {{{ */
  843. {
  844. char buf[MAX_STR];
  845. struct tm tm, *res;
  846. int n;
  847. res = php_gmtime_r(when, &tm);
  848. if (!res) {
  849. buf[0] = '\0';
  850. return;
  851. }
  852. n = slprintf(buf, sizeof(buf), "%s, %02d %s %d %02d:%02d:%02d GMT", /* SAFE */
  853. week_days[tm.tm_wday], tm.tm_mday,
  854. month_names[tm.tm_mon], tm.tm_year + 1900,
  855. tm.tm_hour, tm.tm_min,
  856. tm.tm_sec);
  857. memcpy(ubuf, buf, n);
  858. ubuf[n] = '\0';
  859. }
  860. /* }}} */
  861. static inline void last_modified(TSRMLS_D) /* {{{ */
  862. {
  863. const char *path;
  864. struct stat sb;
  865. char buf[MAX_STR + 1];
  866. path = SG(request_info).path_translated;
  867. if (path) {
  868. if (VCWD_STAT(path, &sb) == -1) {
  869. return;
  870. }
  871. #define LAST_MODIFIED "Last-Modified: "
  872. memcpy(buf, LAST_MODIFIED, sizeof(LAST_MODIFIED) - 1);
  873. strcpy_gmt(buf + sizeof(LAST_MODIFIED) - 1, &sb.st_mtime);
  874. ADD_HEADER(buf);
  875. }
  876. }
  877. /* }}} */
  878. #define EXPIRES "Expires: "
  879. CACHE_LIMITER_FUNC(public) /* {{{ */
  880. {
  881. char buf[MAX_STR + 1];
  882. struct timeval tv;
  883. time_t now;
  884. gettimeofday(&tv, NULL);
  885. now = tv.tv_sec + PS(cache_expire) * 60;
  886. memcpy(buf, EXPIRES, sizeof(EXPIRES) - 1);
  887. strcpy_gmt(buf + sizeof(EXPIRES) - 1, &now);
  888. ADD_HEADER(buf);
  889. snprintf(buf, sizeof(buf) , "Cache-Control: public, max-age=%ld", PS(cache_expire) * 60); /* SAFE */
  890. ADD_HEADER(buf);
  891. last_modified(TSRMLS_C);
  892. }
  893. /* }}} */
  894. CACHE_LIMITER_FUNC(private_no_expire) /* {{{ */
  895. {
  896. char buf[MAX_STR + 1];
  897. snprintf(buf, sizeof(buf), "Cache-Control: private, max-age=%ld, pre-check=%ld", PS(cache_expire) * 60, PS(cache_expire) * 60); /* SAFE */
  898. ADD_HEADER(buf);
  899. last_modified(TSRMLS_C);
  900. }
  901. /* }}} */
  902. CACHE_LIMITER_FUNC(private) /* {{{ */
  903. {
  904. ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT");
  905. CACHE_LIMITER(private_no_expire)(TSRMLS_C);
  906. }
  907. /* }}} */
  908. CACHE_LIMITER_FUNC(nocache) /* {{{ */
  909. {
  910. ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT");
  911. /* For HTTP/1.1 conforming clients and the rest (MSIE 5) */
  912. ADD_HEADER("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
  913. /* For HTTP/1.0 conforming clients */
  914. ADD_HEADER("Pragma: no-cache");
  915. }
  916. /* }}} */
  917. static php_session_cache_limiter_t php_session_cache_limiters[] = {
  918. CACHE_LIMITER_ENTRY(public)
  919. CACHE_LIMITER_ENTRY(private)
  920. CACHE_LIMITER_ENTRY(private_no_expire)
  921. CACHE_LIMITER_ENTRY(nocache)
  922. {0}
  923. };
  924. static int php_session_cache_limiter(TSRMLS_D) /* {{{ */
  925. {
  926. php_session_cache_limiter_t *lim;
  927. if (PS(cache_limiter)[0] == '\0') return 0;
  928. if (SG(headers_sent)) {
  929. char *output_start_filename = php_get_output_start_filename(TSRMLS_C);
  930. int output_start_lineno = php_get_output_start_lineno(TSRMLS_C);
  931. if (output_start_filename) {
  932. 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);
  933. } else {
  934. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot send session cache limiter - headers already sent");
  935. }
  936. return -2;
  937. }
  938. for (lim = php_session_cache_limiters; lim->name; lim++) {
  939. if (!strcasecmp(lim->name, PS(cache_limiter))) {
  940. lim->func(TSRMLS_C);
  941. return 0;
  942. }
  943. }
  944. return -1;
  945. }
  946. /* }}} */
  947. /* *********************
  948. * Cookie Management *
  949. ********************* */
  950. #define COOKIE_SET_COOKIE "Set-Cookie: "
  951. #define COOKIE_EXPIRES "; expires="
  952. #define COOKIE_PATH "; path="
  953. #define COOKIE_DOMAIN "; domain="
  954. #define COOKIE_SECURE "; secure"
  955. #define COOKIE_HTTPONLY "; HttpOnly"
  956. static void php_session_send_cookie(TSRMLS_D) /* {{{ */
  957. {
  958. smart_str ncookie = {0};
  959. char *date_fmt = NULL;
  960. char *e_session_name, *e_id;
  961. if (SG(headers_sent)) {
  962. char *output_start_filename = php_get_output_start_filename(TSRMLS_C);
  963. int output_start_lineno = php_get_output_start_lineno(TSRMLS_C);
  964. if (output_start_filename) {
  965. 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);
  966. } else {
  967. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot send session cookie - headers already sent");
  968. }
  969. return;
  970. }
  971. /* URL encode session_name and id because they might be user supplied */
  972. e_session_name = php_url_encode(PS(session_name), strlen(PS(session_name)), NULL);
  973. e_id = php_url_encode(PS(id), strlen(PS(id)), NULL);
  974. smart_str_appends(&ncookie, COOKIE_SET_COOKIE);
  975. smart_str_appends(&ncookie, e_session_name);
  976. smart_str_appendc(&ncookie, '=');
  977. smart_str_appends(&ncookie, e_id);
  978. efree(e_session_name);
  979. efree(e_id);
  980. if (PS(cookie_lifetime) > 0) {
  981. struct timeval tv;
  982. time_t t;
  983. gettimeofday(&tv, NULL);
  984. t = tv.tv_sec + PS(cookie_lifetime);
  985. if (t > 0) {
  986. 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);
  987. smart_str_appends(&ncookie, COOKIE_EXPIRES);
  988. smart_str_appends(&ncookie, date_fmt);
  989. efree(date_fmt);
  990. }
  991. }
  992. if (PS(cookie_path)[0]) {
  993. smart_str_appends(&ncookie, COOKIE_PATH);
  994. smart_str_appends(&ncookie, PS(cookie_path));
  995. }
  996. if (PS(cookie_domain)[0]) {
  997. smart_str_appends(&ncookie, COOKIE_DOMAIN);
  998. smart_str_appends(&ncookie, PS(cookie_domain));
  999. }
  1000. if (PS(cookie_secure)) {
  1001. smart_str_appends(&ncookie, COOKIE_SECURE);
  1002. }
  1003. if (PS(cookie_httponly)) {
  1004. smart_str_appends(&ncookie, COOKIE_HTTPONLY);
  1005. }
  1006. smart_str_0(&ncookie);
  1007. /* 'replace' must be 0 here, else a previous Set-Cookie
  1008. header, probably sent with setcookie() will be replaced! */
  1009. sapi_add_header_ex(ncookie.c, ncookie.len, 0, 0 TSRMLS_CC);
  1010. }
  1011. /* }}} */
  1012. PHPAPI ps_module *_php_find_ps_module(char *name TSRMLS_DC) /* {{{ */
  1013. {
  1014. ps_module *ret = NULL;
  1015. ps_module **mod;
  1016. int i;
  1017. for (i = 0, mod = ps_modules; i < MAX_MODULES; i++, mod++) {
  1018. if (*mod && !strcasecmp(name, (*mod)->s_name)) {
  1019. ret = *mod;
  1020. break;
  1021. }
  1022. }
  1023. return ret;
  1024. }
  1025. /* }}} */
  1026. PHPAPI const ps_serializer *_php_find_ps_serializer(char *name TSRMLS_DC) /* {{{ */
  1027. {
  1028. const ps_serializer *ret = NULL;
  1029. const ps_serializer *mod;
  1030. for (mod = ps_serializers; mod->name; mod++) {
  1031. if (!strcasecmp(name, mod->name)) {
  1032. ret = mod;
  1033. break;
  1034. }
  1035. }
  1036. return ret;
  1037. }
  1038. /* }}} */
  1039. #define PPID2SID \
  1040. convert_to_string((*ppid)); \
  1041. PS(id) = estrndup(Z_STRVAL_PP(ppid), Z_STRLEN_PP(ppid))
  1042. static void php_session_reset_id(TSRMLS_D) /* {{{ */
  1043. {
  1044. int module_number = PS(module_number);
  1045. if (PS(use_cookies) && PS(send_cookie)) {
  1046. php_session_send_cookie(TSRMLS_C);
  1047. PS(send_cookie) = 0;
  1048. }
  1049. /* if the SID constant exists, destroy it. */
  1050. zend_hash_del(EG(zend_constants), "sid", sizeof("sid"));
  1051. if (PS(define_sid)) {
  1052. smart_str var = {0};
  1053. smart_str_appends(&var, PS(session_name));
  1054. smart_str_appendc(&var, '=');
  1055. smart_str_appends(&var, PS(id));
  1056. smart_str_0(&var);
  1057. REGISTER_STRINGL_CONSTANT("SID", var.c, var.len, 0);
  1058. } else {
  1059. REGISTER_STRINGL_CONSTANT("SID", STR_EMPTY_ALLOC(), 0, 0);
  1060. }
  1061. if (PS(apply_trans_sid)) {
  1062. php_url_scanner_reset_vars(TSRMLS_C);
  1063. php_url_scanner_add_var(PS(session_name), strlen(PS(session_name)), PS(id), strlen(PS(id)), 1 TSRMLS_CC);
  1064. }
  1065. }
  1066. /* }}} */
  1067. PHPAPI void php_session_start(TSRMLS_D) /* {{{ */
  1068. {
  1069. zval **ppid;
  1070. zval **data;
  1071. char *p, *value;
  1072. int nrand;
  1073. int lensess;
  1074. if (PS(use_only_cookies)) {
  1075. PS(apply_trans_sid) = 0;
  1076. } else {
  1077. PS(apply_trans_sid) = PS(use_trans_sid);
  1078. }
  1079. switch (PS(session_status)) {
  1080. case php_session_active:
  1081. php_error(E_NOTICE, "A session had already been started - ignoring session_start()");
  1082. return;
  1083. break;
  1084. case php_session_disabled:
  1085. value = zend_ini_string("session.save_handler", sizeof("session.save_handler"), 0);
  1086. if (!PS(mod) && value) {
  1087. PS(mod) = _php_find_ps_module(value TSRMLS_CC);
  1088. if (!PS(mod)) {
  1089. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot find save handler '%s' - session startup failed", value);
  1090. return;
  1091. }
  1092. }
  1093. value = zend_ini_string("session.serialize_handler", sizeof("session.serialize_handler"), 0);
  1094. if (!PS(serializer) && value) {
  1095. PS(serializer) = _php_find_ps_serializer(value TSRMLS_CC);
  1096. if (!PS(serializer)) {
  1097. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot find serialization handler '%s' - session startup failed", value);
  1098. return;
  1099. }
  1100. }
  1101. PS(session_status) = php_session_none;
  1102. /* fallthrough */
  1103. default:
  1104. case php_session_none:
  1105. PS(define_sid) = 1;
  1106. PS(send_cookie) = 1;
  1107. }
  1108. lensess = strlen(PS(session_name));
  1109. /* Cookies are preferred, because initially
  1110. * cookie and get variables will be available. */
  1111. if (!PS(id)) {
  1112. if (PS(use_cookies) && zend_hash_find(&EG(symbol_table), "_COOKIE", sizeof("_COOKIE"), (void **) &data) == SUCCESS &&
  1113. Z_TYPE_PP(data) == IS_ARRAY &&
  1114. zend_hash_find(Z_ARRVAL_PP(data), PS(session_name), lensess + 1, (void **) &ppid) == SUCCESS
  1115. ) {
  1116. PPID2SID;
  1117. PS(apply_trans_sid) = 0;
  1118. PS(send_cookie) = 0;
  1119. PS(define_sid) = 0;
  1120. }
  1121. if (!PS(use_only_cookies) && !PS(id) &&
  1122. zend_hash_find(&EG(symbol_table), "_GET", sizeof("_GET"), (void **) &data) == SUCCESS &&
  1123. Z_TYPE_PP(data) == IS_ARRAY &&
  1124. zend_hash_find(Z_ARRVAL_PP(data), PS(session_name), lensess + 1, (void **) &ppid) == SUCCESS
  1125. ) {
  1126. PPID2SID;
  1127. PS(send_cookie) = 0;
  1128. }
  1129. if (!PS(use_only_cookies) && !PS(id) &&
  1130. zend_hash_find(&EG(symbol_table), "_POST", sizeof("_POST"), (void **) &data) == SUCCESS &&
  1131. Z_TYPE_PP(data) == IS_ARRAY &&
  1132. zend_hash_find(Z_ARRVAL_PP(data), PS(session_name), lensess + 1, (void **) &ppid) == SUCCESS
  1133. ) {
  1134. PPID2SID;
  1135. PS(send_cookie) = 0;
  1136. }
  1137. }
  1138. /* Check the REQUEST_URI symbol for a string of the form
  1139. * '<session-name>=<session-id>' to allow URLs of the form
  1140. * http://yoursite/<session-name>=<session-id>/script.php */
  1141. if (!PS(use_only_cookies) && !PS(id) && PG(http_globals)[TRACK_VARS_SERVER] &&
  1142. zend_hash_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), "REQUEST_URI", sizeof("REQUEST_URI"), (void **) &data) == SUCCESS &&
  1143. Z_TYPE_PP(data) == IS_STRING &&
  1144. (p = strstr(Z_STRVAL_PP(data), PS(session_name))) &&
  1145. p[lensess] == '='
  1146. ) {
  1147. char *q;
  1148. p += lensess + 1;
  1149. if ((q = strpbrk(p, "/?\\"))) {
  1150. PS(id) = estrndup(p, q - p);
  1151. PS(send_cookie) = 0;
  1152. }
  1153. }
  1154. /* Check whether the current request was referred to by
  1155. * an external site which invalidates the previously found id. */
  1156. if (PS(id) &&
  1157. PS(extern_referer_chk)[0] != '\0' &&
  1158. PG(http_globals)[TRACK_VARS_SERVER] &&
  1159. zend_hash_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_REFERER", sizeof("HTTP_REFERER"), (void **) &data) == SUCCESS &&
  1160. Z_TYPE_PP(data) == IS_STRING &&
  1161. Z_STRLEN_PP(data) != 0 &&
  1162. strstr(Z_STRVAL_PP(data), PS(extern_referer_chk)) == NULL
  1163. ) {
  1164. efree(PS(id));
  1165. PS(id) = NULL;
  1166. PS(send_cookie) = 1;
  1167. if (PS(use_trans_sid) && !PS(use_only_cookies)) {
  1168. PS(apply_trans_sid) = 1;
  1169. }
  1170. }
  1171. php_session_initialize(TSRMLS_C);
  1172. if (!PS(use_cookies) && PS(send_cookie)) {
  1173. if (PS(use_trans_sid) && !PS(use_only_cookies)) {
  1174. PS(apply_trans_sid) = 1;
  1175. }
  1176. PS(send_cookie) = 0;
  1177. }
  1178. php_session_reset_id(TSRMLS_C);
  1179. PS(session_status) = php_session_active;
  1180. php_session_cache_limiter(TSRMLS_C);
  1181. if (PS(mod_data) && PS(gc_probability) > 0) {
  1182. int nrdels = -1;
  1183. nrand = (int) ((float) PS(gc_divisor) * php_combined_lcg(TSRMLS_C));
  1184. if (nrand < PS(gc_probability)) {
  1185. PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &nrdels TSRMLS_CC);
  1186. #ifdef SESSION_DEBUG
  1187. if (nrdels != -1) {
  1188. php_error_docref(NULL TSRMLS_CC, E_NOTICE, "purged %d expired session objects", nrdels);
  1189. }
  1190. #endif
  1191. }
  1192. }
  1193. }
  1194. /* }}} */
  1195. static void php_session_flush(TSRMLS_D) /* {{{ */
  1196. {
  1197. if (PS(session_status) == php_session_active) {
  1198. PS(session_status) = php_session_none;
  1199. zend_try {
  1200. php_session_save_current_state(TSRMLS_C);
  1201. } zend_end_try();
  1202. }
  1203. }
  1204. /* }}} */
  1205. PHPAPI void session_adapt_url(const char *url, size_t urllen, char **new, size_t *newlen TSRMLS_DC) /* {{{ */
  1206. {
  1207. if (PS(apply_trans_sid) && (PS(session_status) == php_session_active)) {
  1208. *new = php_url_scanner_adapt_single_url(url, urllen, PS(session_name), PS(id), newlen TSRMLS_CC);
  1209. }
  1210. }
  1211. /* }}} */
  1212. /* ********************************
  1213. * Userspace exported functions *
  1214. ******************************** */
  1215. /* {{{ proto void session_set_cookie_params(int lifetime [, string path [, string domain [, bool secure[, bool httponly]]]])
  1216. Set session cookie parameters */
  1217. static PHP_FUNCTION(session_set_cookie_params)
  1218. {
  1219. zval **lifetime = NULL;
  1220. char *path = NULL, *domain = NULL;
  1221. int path_len, domain_len, argc = ZEND_NUM_ARGS();
  1222. zend_bool secure = 0, httponly = 0;
  1223. if (!PS(use_cookies) ||
  1224. zend_parse_parameters(argc TSRMLS_CC, "Z|ssbb", &lifetime, &path, &path_len, &domain, &domain_len, &secure, &httponly) == FAILURE) {
  1225. return;
  1226. }
  1227. convert_to_string_ex(lifetime);
  1228. 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);
  1229. if (path) {
  1230. zend_alter_ini_entry("session.cookie_path", sizeof("session.cookie_path"), path, path_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
  1231. }
  1232. if (domain) {
  1233. zend_alter_ini_entry("session.cookie_domain", sizeof("session.cookie_domain"), domain, domain_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
  1234. }
  1235. if (argc > 3) {
  1236. zend_alter_ini_entry("session.cookie_secure", sizeof("session.cookie_secure"), secure ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
  1237. }
  1238. if (argc > 4) {
  1239. zend_alter_ini_entry("session.cookie_httponly", sizeof("session.cookie_httponly"), httponly ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
  1240. }
  1241. }
  1242. /* }}} */
  1243. /* {{{ proto array session_get_cookie_params(void)
  1244. Return the session cookie parameters */
  1245. static PHP_FUNCTION(session_get_cookie_params)
  1246. {
  1247. if (zend_parse_parameters_none() == FAILURE) {
  1248. return;
  1249. }
  1250. array_init(return_value);
  1251. add_assoc_long(return_value, "lifetime", PS(cookie_lifetime));
  1252. add_assoc_string(return_value, "path", PS(cookie_path), 1);
  1253. add_assoc_string(return_value, "domain", PS(cookie_domain), 1);
  1254. add_assoc_bool(return_value, "secure", PS(cookie_secure));
  1255. add_assoc_bool(return_value, "httponly", PS(cookie_httponly));
  1256. }
  1257. /* }}} */
  1258. /* {{{ proto string session_name([string newname])
  1259. Return the current session name. If newname is given, the session name is replaced with newname */
  1260. static PHP_FUNCTION(session_name)
  1261. {
  1262. char *name = NULL;
  1263. int name_len;
  1264. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {
  1265. return;
  1266. }
  1267. RETVAL_STRING(PS(session_name), 1);
  1268. if (name) {
  1269. zend_alter_ini_entry("session.name", sizeof("session.name"), name, name_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
  1270. }
  1271. }
  1272. /* }}} */
  1273. /* {{{ proto string session_module_name([string newname])
  1274. Return the current module name used for accessing session data. If newname is given, the module name is replaced with newname */
  1275. static PHP_FUNCTION(session_module_name)
  1276. {
  1277. char *name = NULL;
  1278. int name_len;
  1279. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {
  1280. return;
  1281. }
  1282. /* Set return_value to current module name */
  1283. if (PS(mod) && PS(mod)->s_name) {
  1284. RETVAL_STRING(safe_estrdup(PS(mod)->s_name), 0);
  1285. } else {
  1286. RETVAL_EMPTY_STRING();
  1287. }
  1288. if (name) {
  1289. if (!_php_find_ps_module(name TSRMLS_CC)) {
  1290. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot find named PHP session module (%s)", name);
  1291. zval_dtor(return_value);
  1292. RETURN_FALSE;
  1293. }
  1294. if (PS(mod_data)) {
  1295. PS(mod)->s_close(&PS(mod_data) TSRMLS_CC);
  1296. }
  1297. PS(mod_data) = NULL;
  1298. zend_alter_ini_entry("session.save_handler", sizeof("session.save_handler"), name, name_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
  1299. }
  1300. }
  1301. /* }}} */
  1302. /* {{{ proto void session_set_save_handler(string open, string close, string read, string write, string destroy, string gc)
  1303. Sets user-level functions */
  1304. static PHP_FUNCTION(session_set_save_handler)
  1305. {
  1306. zval ***args = NULL;
  1307. int i, num_args, argc = ZEND_NUM_ARGS();
  1308. char *name;
  1309. if (PS(session_status) != php_session_none) {
  1310. RETURN_FALSE;
  1311. }
  1312. if (argc != 6) {
  1313. WRONG_PARAM_COUNT;
  1314. }
  1315. if (zend_parse_parameters(argc TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
  1316. return;
  1317. }
  1318. for (i = 0; i < 6; i++) {
  1319. if (!zend_is_callable(*args[i], 0, &name TSRMLS_CC)) {
  1320. efree(args);
  1321. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument %d is not a valid callback", i+1);
  1322. efree(name);
  1323. RETURN_FALSE;
  1324. }
  1325. efree(name);
  1326. }
  1327. zend_alter_ini_entry("session.save_handler", sizeof("session.save_handler"), "user", sizeof("user")-1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
  1328. for (i = 0; i < 6; i++) {
  1329. if (PS(mod_user_names).names[i] != NULL) {
  1330. zval_ptr_dtor(&PS(mod_user_names).names[i]);
  1331. }
  1332. Z_ADDREF_PP(args[i]);
  1333. PS(mod_user_names).names[i] = *args[i];
  1334. }
  1335. efree(args);
  1336. RETURN_TRUE;
  1337. }
  1338. /* }}} */
  1339. /* {{{ proto string session_save_path([string newname])
  1340. Return the current save path passed to module_name. If newname is given, the save path is replaced with newname */
  1341. static PHP_FUNCTION(session_save_path)
  1342. {
  1343. char *name = NULL;
  1344. int name_len;
  1345. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {
  1346. return;
  1347. }
  1348. RETVAL_STRING(PS(save_path), 1);
  1349. if (name) {
  1350. if (memchr(name, '\0', name_len) != NULL) {
  1351. php_error_docref(NULL TSRMLS_CC, E_WARNING, "The save_path cannot contain NULL characters");
  1352. zval_dtor(return_value);
  1353. RETURN_FALSE;
  1354. }
  1355. zend_alter_ini_entry("session.save_path", sizeof("session.save_path"), name, name_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
  1356. }
  1357. }
  1358. /* }}} */
  1359. /* {{{ proto string session_id([string newid])
  1360. Return the current session id. If newid is given, the session id is replaced with newid */
  1361. static PHP_FUNCTION(session_id)
  1362. {
  1363. char *name = NULL;
  1364. int name_len;
  1365. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {
  1366. return;
  1367. }
  1368. if (PS(id)) {
  1369. RETVAL_STRING(PS(id), 1);
  1370. } else {
  1371. RETVAL_EMPTY_STRING();
  1372. }
  1373. if (name) {
  1374. if (PS(id)) {
  1375. efree(PS(id));
  1376. }
  1377. PS(id) = estrndup(name, name_len);
  1378. }
  1379. }
  1380. /* }}} */
  1381. /* {{{ proto bool session_regenerate_id([bool delete_old_session])
  1382. Update the current session id with a newly generated one. If delete_old_session is set to true, remove the old session. */
  1383. static PHP_FUNCTION(session_regenerate_id)
  1384. {
  1385. zend_bool del_ses = 0;
  1386. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &del_ses) == FAILURE) {
  1387. return;
  1388. }
  1389. if (SG(headers_sent)) {
  1390. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot regenerate session id - headers already sent");
  1391. RETURN_FALSE;
  1392. }
  1393. if (PS(session_status) == php_session_active) {
  1394. if (PS(id)) {
  1395. if (del_ses && PS(mod)->s_destroy(&PS(mod_data), PS(id) TSRMLS_CC) == FAILURE) {
  1396. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session object destruction failed");
  1397. RETURN_FALSE;
  1398. }
  1399. efree(PS(id));
  1400. PS(id) = NULL;
  1401. }
  1402. PS(id) = PS(mod)->s_create_sid(&PS(mod_data), NULL TSRMLS_CC);
  1403. PS(send_cookie) = 1;
  1404. php_session_reset_id(TSRMLS_C);
  1405. RETURN_TRUE;
  1406. }
  1407. RETURN_FALSE;
  1408. }
  1409. /* }}} */
  1410. /* {{{ proto string session_cache_limiter([string new_cache_limiter])
  1411. Return the current cache limiter. If new_cache_limited is given, the current cache_limiter is replaced with new_cache_limiter */
  1412. static PHP_FUNCTION(session_cache_limiter)
  1413. {
  1414. char *limiter = NULL;
  1415. int limiter_len;
  1416. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &limiter, &limiter_len) == FAILURE) {
  1417. return;
  1418. }
  1419. RETVAL_STRING(PS(cache_limiter), 1);
  1420. if (limiter) {
  1421. zend_alter_ini_entry("session.cache_limiter", sizeof("session.cache_limiter"), limiter, limiter_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
  1422. }
  1423. }
  1424. /* }}} */
  1425. /* {{{ proto int session_cache_expire([int new_cache_expire])
  1426. Return the current cache expire. If new_cache_expire is given, the current cache_expire is replaced with new_cache_expire */
  1427. static PHP_FUNCTION(session_cache_expire)
  1428. {
  1429. zval **expires = NULL;
  1430. int argc = ZEND_NUM_ARGS();
  1431. if (zend_parse_parameters(argc TSRMLS_CC, "|Z", &expires) == FAILURE) {
  1432. return;
  1433. }
  1434. RETVAL_LONG(PS(cache_expire));
  1435. if (argc == 1) {
  1436. convert_to_string_ex(expires);
  1437. 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);
  1438. }
  1439. }
  1440. /* }}} */
  1441. /* {{{ static void php_register_var(zval** entry TSRMLS_DC) */
  1442. static void php_register_var(zval** entry TSRMLS_DC)
  1443. {
  1444. zval **value;
  1445. if (Z_TYPE_PP(entry) == IS_ARRAY) {
  1446. if (Z_ARRVAL_PP(entry)->nApplyCount > 1) {
  1447. return;
  1448. }
  1449. zend_hash_internal_pointer_reset(Z_ARRVAL_PP(entry));
  1450. Z_ARRVAL_PP(entry)->nApplyCount++;
  1451. while (zend_hash_get_current_data(Z_ARRVAL_PP(entry), (void**)&value) == SUCCESS) {
  1452. php_register_var(value TSRMLS_CC);
  1453. zend_hash_move_forward(Z_ARRVAL_PP(entry));
  1454. }
  1455. Z_ARRVAL_PP(entry)->nApplyCount--;
  1456. } else {
  1457. convert_to_string_ex(entry);
  1458. if ((strcmp(Z_STRVAL_PP(entry), "HTTP_SESSION_VARS") != 0) &&
  1459. (strcmp(Z_STRVAL_PP(entry), "_SESSION") != 0)
  1460. ) {
  1461. PS_ADD_VARL(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry));
  1462. }
  1463. }
  1464. }
  1465. /* }}} */
  1466. /* {{{ proto string session_encode(void)
  1467. Serializes the current setup and returns the serialized representation */
  1468. static PHP_FUNCTION(session_encode)
  1469. {
  1470. int len;
  1471. char *enc;
  1472. if (zend_parse_parameters_none() == FAILURE) {
  1473. return;
  1474. }
  1475. enc = php_session_encode(&len TSRMLS_CC);
  1476. if (enc == NULL) {
  1477. RETURN_FALSE;
  1478. }
  1479. RETVAL_STRINGL(enc, len, 0);
  1480. }
  1481. /* }}} */
  1482. /* {{{ proto bool session_decode(string data)
  1483. Deserializes data and reinitializes the variables */
  1484. static PHP_FUNCTION(session_decode)
  1485. {
  1486. char *str;
  1487. int str_len;
  1488. if (PS(session_status) == php_session_none) {
  1489. RETURN_FALSE;
  1490. }
  1491. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
  1492. return;
  1493. }
  1494. php_session_decode(str, str_len TSRMLS_CC);
  1495. RETURN_TRUE;
  1496. }
  1497. /* }}} */
  1498. /* {{{ proto bool session_start(void)
  1499. Begin session - reinitializes freezed variables, registers browsers etc */
  1500. static PHP_FUNCTION(session_start)
  1501. {
  1502. /* skipping check for non-zero args for performance reasons here ?*/
  1503. php_session_start(TSRMLS_C);
  1504. if (PS(session_status) != php_session_active) {
  1505. RETURN_FALSE;
  1506. }
  1507. RETURN_TRUE;
  1508. }
  1509. /* }}} */
  1510. /* {{{ proto bool session_destroy(void)
  1511. Destroy the current session and all data associated with it */
  1512. static PHP_FUNCTION(session_destroy)
  1513. {
  1514. if (zend_parse_parameters_none() == FAIL

Large files files are truncated, but you can click here to view the full file