session.c 82 KB

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