#include "php_ini.h"
#include "SAPI.h"
+#include "rfc1867.h"
+#include "php_variables.h"
#include "php_session.h"
#include "ext/standard/md5.h"
#include "ext/standard/sha1.h"
PHPAPI ZEND_DECLARE_MODULE_GLOBALS(ps);
+static int (*php_session_rfc1867_orig_callback)(unsigned int event, void *event_data, void **extra TSRMLS_DC);
+static int php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra TSRMLS_DC);
+
/* ***********
* Helpers *
*********** */
return SUCCESS;
}
}
-#endif /* HAVE_HASH_EXT */
+#endif /* HAVE_HASH_EXT }}} */
return FAILURE;
}
/* }}} */
+static PHP_INI_MH(OnUpdateRfc1867Freq) /* {{{ */
+{
+ int tmp;
+ tmp = zend_atoi(new_value, new_value_length);
+ if(tmp < 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "session.upload_progress.freq must be greater than or equal to zero");
+ return FAILURE;
+ }
+ if(new_value_length > 0 && new_value[new_value_length-1] == '%') {
+ if(tmp > 100) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "session.upload_progress.freq cannot be over 100%%");
+ return FAILURE;
+ }
+ PS(rfc1867_freq) = -tmp;
+ } else {
+ PS(rfc1867_freq) = tmp;
+ }
+ return SUCCESS;
+} /* }}} */
+
/* {{{ PHP_INI
*/
PHP_INI_BEGIN()
PHP_INI_ENTRY("session.hash_function", "0", PHP_INI_ALL, OnUpdateHashFunc)
STD_PHP_INI_ENTRY("session.hash_bits_per_character", "4", PHP_INI_ALL, OnUpdateLong, hash_bits_per_character, php_ps_globals, ps_globals)
+ /* Upload progress */
+ STD_PHP_INI_BOOLEAN("session.upload_progress.enabled",
+ "1", ZEND_INI_PERDIR, OnUpdateBool, rfc1867_enabled, php_ps_globals, ps_globals)
+ STD_PHP_INI_ENTRY("session.upload_progress.prefix",
+ "upload_progress_", ZEND_INI_PERDIR, OnUpdateUTF8String, rfc1867_prefix, php_ps_globals, ps_globals)
+ STD_PHP_INI_ENTRY("session.upload_progress.name",
+ "PHP_SESSION_UPLOAD_PROGRESS", ZEND_INI_PERDIR, OnUpdateUTF8String, rfc1867_name, php_ps_globals, ps_globals)
+ STD_PHP_INI_ENTRY("session.upload_progress.freq", "1%", ZEND_INI_PERDIR, OnUpdateRfc1867Freq, rfc1867_freq, php_ps_globals, ps_globals)
+
/* Commented out until future discussion */
/* PHP_INI_ENTRY("session.encode_sources", "globals,track", PHP_INI_ALL, NULL) */
PHP_INI_END()
* Module Setup and Destruction *
******************************** */
-static PHP_RINIT_FUNCTION(session) /* {{{ */
+static inline int php_rinit_session(zend_bool auto_start TSRMLS_DC) /* {{{ */
{
php_rinit_session_globals(TSRMLS_C);
return SUCCESS;
}
- if (PS(auto_start)) {
+ if (auto_start) {
php_session_start(TSRMLS_C);
}
return SUCCESS;
+} /* }}} */
+
+static PHP_RINIT_FUNCTION(session) /* {{{ */
+{
+ return php_rinit_session(PS(auto_start) TSRMLS_CC);
}
/* }}} */
#ifdef HAVE_LIBMM
PHP_MINIT(ps_mm) (INIT_FUNC_ARGS_PASSTHRU);
#endif
+ php_session_rfc1867_orig_callback = php_rfc1867_callback;
+ php_rfc1867_callback = php_session_rfc1867_callback;
return SUCCESS;
}
/* }}} */
}
/* }}} */
+/* ************************
+ * Upload hook handling *
+ ************************ */
+
+#define USTR_EQUAL(s1, len1, s2, len2) \
+ ((len1) == (len2) && \
+ (UG(unicode) ? \
+ (zend_u_binary_strcmp((s1).u, (len1), (s2).u, (len2)) == 0) \
+ : (zend_binary_strcmp((s1).s, (len1), (s2).s, (len2)) == 0)))
+
+static inline void php_session_rfc1867_early_find_sid(php_session_rfc1867_progress *progress TSRMLS_DC) /* {{{ */
+{
+ zval **ppid;
+
+ if (PS(use_cookies)) {
+ sapi_module.treat_data(PARSE_COOKIE, NULL, NULL TSRMLS_CC);
+ if (PG(http_globals)[TRACK_VARS_COOKIE]
+ && zend_u_hash_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]), Z_TYPE(progress->sname), Z_UNIVAL(progress->sname), Z_UNILEN(progress->sname)+1, (void **)&ppid) == SUCCESS) {
+
+ zval_dtor(&progress->sid);
+ ZVAL_ZVAL(&progress->sid, *ppid, 1, 0);
+ convert_to_string(&progress->sid);
+ progress->apply_trans_sid = 0;
+ return;
+ }
+ }
+ if (PS(use_only_cookies)) {
+ return;
+ }
+ sapi_module.treat_data(PARSE_GET, NULL, NULL TSRMLS_CC);
+ if (PG(http_globals)[TRACK_VARS_GET]
+ && zend_u_hash_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_GET]), Z_TYPE(progress->sname), Z_UNIVAL(progress->sname), Z_UNILEN(progress->sname)+1, (void **)&ppid) == SUCCESS) {
+
+ zval_dtor(&progress->sid);
+ ZVAL_ZVAL(&progress->sid, *ppid, 1, 0);
+ convert_to_string(&progress->sid);
+ }
+} /* }}} */
+
+static inline void php_session_rfc1867_update(php_session_rfc1867_progress *progress TSRMLS_DC) /* {{{ */
+{
+ php_session_initialize(TSRMLS_C);
+ PS(session_status) = php_session_active;
+ IF_SESSION_VARS() {
+ Z_ADDREF_P(progress->data);
+ zend_u_symtable_update(Z_ARRVAL_P(PS(http_session_vars)), Z_TYPE(progress->key), Z_UNIVAL(progress->key), Z_UNILEN(progress->key)+1, &progress->data, sizeof(zval *), NULL);
+ }
+ php_session_flush(TSRMLS_C);
+} /* }}} */
+
+static int php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra TSRMLS_DC) /* {{{ */
+{
+ php_session_rfc1867_progress *progress;
+ int retval = SUCCESS;
+
+ if (php_session_rfc1867_orig_callback) {
+ retval = php_session_rfc1867_orig_callback(event, event_data, extra TSRMLS_CC);
+ }
+ if (!PS(rfc1867_enabled)) {
+ return retval;
+ }
+
+ progress = PS(rfc1867_progress);
+
+ switch(event) {
+ case MULTIPART_EVENT_START: {
+ multipart_event_start *data = (multipart_event_start *) event_data;
+
+ progress = ecalloc(1, sizeof(php_session_rfc1867_progress));
+ progress->content_length = data->content_length;
+
+ /* We need to have a runtime-encoding encoded PS(session_name) so that
+ * we can compare to incomming POST variables name. zvals also allow
+ * to keep track of length. */
+ ZVAL_RT_STRING(&progress->sname, PS(session_name), ZSTR_DUPLICATE);
+ ZVAL_TEXT(&progress->prefix, PS(rfc1867_prefix), 0);
+ ZVAL_TEXT(&progress->name, PS(rfc1867_name), 0);
+
+ PS(rfc1867_progress) = progress;
+ }
+ break;
+ case MULTIPART_EVENT_FORMDATA: {
+ multipart_event_formdata *data = (multipart_event_formdata *) event_data;
+ size_t name_len, value_len;
+ zstr str;
+
+ /* orig callback may have modified *data->newlength */
+ if (data->newlength) {
+ value_len = *data->newlength;
+ } else {
+ value_len = data->length;
+ }
+
+ /* Search PS(session_name) and PS(rfc1867_name) in incomming POST variables */
+ if (data->name.v && data->value && value_len) {
+ name_len = USTR_LEN(data->name);
+
+ if (USTR_EQUAL(Z_UNIVAL(progress->sname), Z_UNILEN(progress->sname), data->name, name_len)) {
+ zval_dtor(&progress->sid);
+ ZVAL_TEXTL(&progress->sid, (*data->value), value_len, ZSTR_DUPLICATE);
+ convert_to_string(&progress->sid);
+
+ } else if (USTR_EQUAL(Z_UNIVAL(progress->name), Z_UNILEN(progress->name), data->name, name_len)) {
+ size_t len = Z_UNILEN(progress->prefix) + value_len;
+ str.v = emalloc(TEXT_BYTES(len+1));
+ memcpy(str.s, Z_UNIVAL(progress->prefix).v, TEXT_BYTES(Z_UNILEN(progress->prefix)));
+ memcpy(str.s+TEXT_BYTES(Z_UNILEN(progress->prefix)), (*data->value).v, TEXT_BYTES(value_len+1));
+
+ zval_dtor(&progress->key);
+ ZVAL_TEXTL(&progress->key, str, len, 0);
+
+ progress->apply_trans_sid = PS(use_trans_sid);
+ php_session_rfc1867_early_find_sid(progress TSRMLS_CC);
+ }
+ }
+ }
+ break;
+ case MULTIPART_EVENT_FILE_START: {
+ multipart_event_file_start *data = (multipart_event_file_start *) event_data;
+
+ /* Do nothing when $_POST[session.upload_progress.name] is not set
+ * or when no session id was sent */
+ if (!Z_TYPE(progress->sid) || !Z_TYPE(progress->key)) {
+ break;
+ }
+
+ /* First FILE_START event, initializing */
+ if (!progress->data) {
+
+ php_rinit_session(0 TSRMLS_CC);
+ PS(id) = estrndup(Z_STRVAL(progress->sid), Z_STRLEN(progress->sid));
+ PS(apply_trans_sid) = progress->apply_trans_sid;
+ PS(send_cookie) = 0;
+
+ if (PS(rfc1867_freq) >= 0) {
+ progress->update_step = PS(rfc1867_freq);
+ } else if (PS(rfc1867_freq) < 0) { /* % of total size */
+ progress->update_step = progress->content_length * -PS(rfc1867_freq) / 100;
+ }
+ progress->next_update = 0;
+
+ ALLOC_INIT_ZVAL(progress->data);
+ array_init(progress->data);
+
+ ALLOC_INIT_ZVAL(progress->post_bytes_processed);
+ ZVAL_LONG(progress->post_bytes_processed, data->post_bytes_processed);
+
+ ALLOC_INIT_ZVAL(progress->files);
+ array_init(progress->files);
+
+ add_ascii_assoc_long_ex(progress->data, "start_time", sizeof("start_time"), (long)sapi_get_request_time(TSRMLS_C));
+ add_ascii_assoc_long_ex(progress->data, "content_length", sizeof("content_length"), progress->content_length);
+ add_ascii_assoc_zval_ex(progress->data, "bytes_processed", sizeof("bytes_processed"), progress->post_bytes_processed);
+ add_ascii_assoc_bool_ex(progress->data, "done", sizeof("done"), 0);
+ add_ascii_assoc_zval_ex(progress->data, "files", sizeof("files"), progress->files);
+ }
+
+ ALLOC_INIT_ZVAL(progress->current_file);
+ array_init(progress->current_file);
+
+ ALLOC_INIT_ZVAL(progress->current_file_bytes_processed);
+ ZVAL_LONG(progress->current_file_bytes_processed, 0);
+
+ add_ascii_assoc_text_ex(progress->current_file, "field_name", sizeof("field_name"), data->name, 1);
+ add_ascii_assoc_text_ex(progress->current_file, "name", sizeof("name"), *data->filename, 1);
+ add_ascii_assoc_null_ex(progress->current_file, "tmp_name", sizeof("tmp_name"));
+ add_ascii_assoc_long_ex(progress->current_file, "error", sizeof("error"), 0);
+
+ add_ascii_assoc_long_ex(progress->current_file, "done", sizeof("done"), 0);
+ add_ascii_assoc_long_ex(progress->current_file, "start_time", sizeof("start_time"), (long)time(NULL));
+ add_ascii_assoc_zval_ex(progress->current_file, "bytes_processed", sizeof("bytes_processed"), progress->current_file_bytes_processed);
+
+ add_next_index_zval(progress->files, progress->current_file);
+
+ Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed;
+
+ if (data->post_bytes_processed >= progress->next_update) {
+ php_session_rfc1867_update(progress TSRMLS_CC);
+ progress->next_update = data->post_bytes_processed + progress->update_step;
+ }
+ }
+ break;
+ case MULTIPART_EVENT_FILE_DATA: {
+ multipart_event_file_data *data = (multipart_event_file_data *) event_data;
+
+ if (!Z_TYPE(progress->sid) || !Z_TYPE(progress->key)) {
+ break;
+ }
+
+ Z_LVAL_P(progress->current_file_bytes_processed) = data->offset + data->length;
+ Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed;
+
+ if (data->post_bytes_processed >= progress->next_update) {
+ php_session_rfc1867_update(progress TSRMLS_CC);
+ progress->next_update = data->post_bytes_processed + progress->update_step;
+ }
+ }
+ break;
+ case MULTIPART_EVENT_FILE_END: {
+ multipart_event_file_end *data = (multipart_event_file_end *) event_data;
+
+ if (!Z_TYPE(progress->sid) || !Z_TYPE(progress->key)) {
+ break;
+ }
+
+ if (data->temp_filename.v) {
+ add_ascii_assoc_text_ex(progress->current_file, "tmp_name", sizeof("tmp_name"), data->temp_filename, 1);
+ }
+ add_ascii_assoc_long_ex(progress->current_file, "error", sizeof("error"), data->cancel_upload);
+ add_ascii_assoc_bool_ex(progress->current_file, "done", sizeof("done"), 1);
+
+ Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed;
+
+ if (data->post_bytes_processed >= progress->next_update) {
+ php_session_rfc1867_update(progress TSRMLS_CC);
+ progress->next_update = data->post_bytes_processed + progress->update_step;
+ }
+ }
+ break;
+ case MULTIPART_EVENT_END: {
+ multipart_event_end *data = (multipart_event_end *) event_data;
+
+ if (Z_TYPE(progress->sid) && Z_TYPE(progress->key)) {
+ add_ascii_assoc_bool_ex(progress->data, "done", sizeof("done"), 1);
+ Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed;
+ php_session_rfc1867_update(progress TSRMLS_CC);
+ php_rshutdown_session_globals(TSRMLS_C);
+ }
+
+ zval_dtor(&progress->sname);
+ zval_dtor(&progress->sid);
+ zval_dtor(&progress->key);
+ if (progress->data) {
+ zval_ptr_dtor(&progress->data);
+ }
+ efree(progress);
+ }
+ break;
+ }
+
+ return retval;
+
+} /* }}} */
+
zend_module_entry session_module_entry = {
STANDARD_MODULE_HEADER,
"session",