- Notifications
You must be signed in to change notification settings - Fork 8k
Add session_gc() #1852
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add session_gc() #1852
Changes from 1 commit
6737717 abbc9cf dc130ee bf49371 c398b0d fbe15ee e22cf71 15e143b 5455c9f 9614406 c3b19c5 3e8792f 1015d9c File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| | @@ -485,24 +485,23 @@ PHPAPI int php_session_valid_key(const char *key) /* {{{ */ | |
| /* }}} */ | ||
| | ||
| | ||
| static void php_session_gc(void) /* {{{ */ | ||
| static zend_long php_session_gc(zend_bool immediate) /* {{{ */ | ||
| { | ||
| int nrand; | ||
| int nrdels = -1; | ||
| | ||
| /* GC must be done before reading session data. */ | ||
| if ((PS(mod_data) || PS(mod_user_implemented)) && PS(gc_probability) > 0) { | ||
| int nrdels = -1; | ||
| | ||
| nrand = (int) ((float) PS(gc_divisor) * php_combined_lcg()); | ||
| ||
| if (immediate) { | ||
| Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't this beat the point of checking Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree, this looks wrong. If you want immediate cleanup, no reason to check probability. Better would be to split the check and cleanup into separate functions and call the latter directly when you need unconditional cleanup. Contributor Author There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right it does not needed at all. I'll fix it later :) | ||
| PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &nrdels); | ||
| return (zend_long)nrdels; | ||
| } | ||
| ||
| if (nrand < PS(gc_probability)) { | ||
| PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &nrdels); | ||
| #ifdef SESSION_DEBUG | ||
| if (nrdels != -1) { | ||
| php_error_docref(NULL, E_NOTICE, "purged %d expired session objects", nrdels); | ||
| } | ||
| #endif | ||
| } | ||
| } | ||
| return (zend_long)nrdels; | ||
| } /* }}} */ | ||
| | ||
| | ||
| | @@ -568,7 +567,7 @@ static void php_session_initialize(void) /* {{{ */ | |
| } | ||
| | ||
| /* GC must be done after read */ | ||
| php_session_gc(); | ||
| php_session_gc(0); | ||
| | ||
| if (PS(session_vars)) { | ||
| zend_string_release(PS(session_vars)); | ||
| | @@ -2381,6 +2380,31 @@ static PHP_FUNCTION(session_unset) | |
| } | ||
| /* }}} */ | ||
| | ||
| /* {{{ proto int session_gc(void) | ||
| Perform GC and return number of deleted sessions */ | ||
| static PHP_FUNCTION(session_gc) | ||
| { | ||
| zend_long nrdels; | ||
| ||
| if (zend_parse_parameters_none() == FAILURE) { | ||
| return; | ||
| } | ||
| | ||
| if (PS(session_status) != php_session_active) { | ||
| php_error_docref(NULL, E_WARNING, "Session is not active"); | ||
| Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why you need session to be active for GC to happen? Contributor Author There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because save handler must be activated. Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How so? And can't that be changed? Contributor Author There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. session_gc() handler is defined in save handlers. Unless save handler storage is initialized, gc function won't work. e.g. However, since this is C code, I can write code that open, gc, close session. In this case, session must be inactive. Otherwise, I'll destroy save handler data structure. If above code is written. GC cron tack code would be Modules should do more work rather than users. I'll implement it. Is this satisfactory? Contributor Author There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @arfbg Andrey, if above code is written session_start(); There may be users write session_gc(); though ;) Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can still check if the session is already active and don't call Contributor Author There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It may work with many save handlers, but I cannot control how 3rd party/user save handlers are implemented. It's risky. Taking risk does not worth, IMO. I've probably seen too many unexpected usages. Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pseudo-code: How can that be a problem? Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Static session ID" hack looks very ugly. If we need init happen before we run GC, we should hide it from the user, instead of requiring them to write boilerplate code that makes absolutely no sense for them ("why I need to start dummy session to just run GC?!") Contributor Author There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll document "session_gc() is supposed to be called from periodical task manager such as cron". IMHO, users shouldn't care extra new session ID created by session_gc() because many useless session IDs are created by cookie disabled browsers anyway, for example. | ||
| RETURN_FALSE; | ||
| } | ||
| | ||
| nrdels = php_session_gc(1); | ||
| if (nrdels < -1) { | ||
| php_error_docref(NULL, E_WARNING, "Failed to perfom session GC"); | ||
| RETURN_FALSE; | ||
| } | ||
| | ||
| RETURN_LONG(nrdels); | ||
| } | ||
| /* }}} */ | ||
| | ||
| | ||
| /* {{{ proto void session_write_close(void) | ||
| Write session data and end session */ | ||
| static PHP_FUNCTION(session_write_close) | ||
| | @@ -2558,6 +2582,7 @@ static const zend_function_entry session_functions[] = { | |
| PHP_FE(session_start, arginfo_session_void) | ||
| PHP_FE(session_destroy, arginfo_session_void) | ||
| PHP_FE(session_unset, arginfo_session_void) | ||
| PHP_FE(session_gc, arginfo_session_void) | ||
| PHP_FE(session_set_save_handler, arginfo_session_set_save_handler) | ||
| PHP_FE(session_cache_limiter, arginfo_session_cache_limiter) | ||
| PHP_FE(session_cache_expire, arginfo_session_cache_expire) | ||
| | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| --TEST-- | ||
| Test session_gc() function : basic functionality | ||
| --SKIPIF-- | ||
| <?php include('skipif.inc'); ?> | ||
| --FILE-- | ||
| <?php | ||
| | ||
| ob_start(); | ||
| | ||
| /* | ||
| * Prototype : int session_gc(void) | ||
| * Description : Perform GC | ||
| * Source code : ext/session/session.c | ||
| */ | ||
| | ||
| echo "*** Testing session_gc() : basic functionality ***\n"; | ||
| | ||
| // Turn off strice mode, since it does not allow uninitialized session ID | ||
| ini_set('session.use_strict_mode',false); | ||
| | ||
| var_dump(session_gc()); | ||
| | ||
| var_dump(session_start()); | ||
| var_dump(session_gc(), session_gc() >= -1); | ||
| var_dump(session_destroy()); | ||
| var_dump(session_id()); | ||
| | ||
| echo "Done"; | ||
| ob_end_flush(); | ||
| ?> | ||
| --EXPECTF-- | ||
| *** Testing session_gc() : basic functionality *** | ||
| | ||
| Warning: session_gc(): Session is not active in %s on line 16 | ||
| bool(false) | ||
| bool(true) | ||
| int(%d) | ||
| bool(true) | ||
| bool(true) | ||
| string(0) "" | ||
| Done | ||
| | ||
| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why zend_long here, and lots of casting below...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PHP 7 and up uses zend_long and I would like to get zend_long return value for "num of deleted session" from 3rd party handler in the future.
It could be int for now. If you insist, I don't mind at all using int here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in that case, why you don't use zend_long num? I don't care about zend_long or int, just seems a little ugly you are doing casting without a good reason.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree casting is ugly.
I'll simply use zend_long. I'll commit changes soon. Please review.
BTW, sorry for the delay. I didn't see notification mails...
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated patch so that it can simply use zend_long.
User handlers are modified to be able to return LONG or BOOL. User GC functions are supposed to be implemented just like 3rd party C save handlers by returning LONG (0 > for number of deleted session, negative number of errors). FALSE is treated as negative num of deleted sessions. TRUE is treated as 1. Since return value of user handler should not be used by user code, there is no BC.
NOTE: Negative number is used to indicate GC errors for a long time. (IIRC, it's since session module was introduced)