-
Notifications
You must be signed in to change notification settings - Fork 7.9k
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 all commits
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 |
---|---|---|
|
@@ -468,7 +468,7 @@ PS_GC_FUNC(mm) | |
|
||
mm_unlock(data->mm); | ||
|
||
return SUCCESS; | ||
return nrdels; | ||
} | ||
|
||
PS_CREATE_SID_FUNC(mm) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -353,19 +353,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; | ||
zend_long num = -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 (nrand < PS(gc_probability)) { | ||
PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &nrdels); | ||
if ((PS(mod_data) || PS(mod_user_implemented))) { | ||
if (immediate) { | ||
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 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. 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), &num); | ||
return num; | ||
} | ||
nrand = (zend_long) ((float) PS(gc_divisor) * php_combined_lcg()); | ||
if (PS(gc_probability) > 0 && nrand < PS(gc_probability)) { | ||
PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &num); | ||
} | ||
} | ||
return num; | ||
} /* }}} */ | ||
|
||
static void php_session_initialize(void) /* {{{ */ | ||
|
@@ -430,7 +434,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)); | ||
|
@@ -2239,6 +2243,32 @@ 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 num; | ||
|
||
if (zend_parse_parameters_none() == FAILURE) { | ||
return; | ||
} | ||
|
||
if (PS(session_status) != php_session_active) { | ||
php_error_docref(NULL, E_WARNING, "Session is not active"); | ||
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? 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. 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? 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? 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 ;) 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 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. 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? 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?!") 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; | ||
} | ||
|
||
num = php_session_gc(1); | ||
if (num < 0) { | ||
php_error_docref(NULL, E_WARNING, "Failed to perfom session GC"); | ||
RETURN_FALSE; | ||
} | ||
|
||
RETURN_LONG(num); | ||
} | ||
/* }}} */ | ||
|
||
|
||
/* {{{ proto void session_write_close(void) | ||
Write session data and end session */ | ||
static PHP_FUNCTION(session_write_close) | ||
|
@@ -2416,6 +2446,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,40 @@ | ||
--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"; | ||
|
||
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 %d | ||
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)