lbarnaud                Thu Sep 11 11:51:07 2008 UTC

  Modified files:              
    /php-src/ext/session        php_session.h session.c 
  Log:
  Implemented ability to provide upload progress feedback through session 
  data.
  
  
http://cvs.php.net/viewvc.cgi/php-src/ext/session/php_session.h?r1=1.116&r2=1.117&diff_format=u
Index: php-src/ext/session/php_session.h
diff -u php-src/ext/session/php_session.h:1.116 
php-src/ext/session/php_session.h:1.117
--- php-src/ext/session/php_session.h:1.116     Fri Mar  7 23:20:15 2008
+++ php-src/ext/session/php_session.h   Thu Sep 11 11:51:07 2008
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: php_session.h,v 1.116 2008/03/07 23:20:15 gwynne Exp $ */
+/* $Id: php_session.h,v 1.117 2008/09/11 11:51:07 lbarnaud Exp $ */
 
 #ifndef PHP_SESSION_H
 #define PHP_SESSION_H
@@ -95,6 +95,23 @@
        php_session_active
 } php_session_status;
 
+typedef struct _php_session_rfc1867_progress {
+       zval      prefix;
+       zval      name;
+       zval      sname;
+       zval      sid;
+       zval      key;
+       long      update_step;
+       long      next_update;
+       zval      *data;
+       size_t    content_length;
+       zval      *post_bytes_processed;
+       zval      *files;
+       zval      *current_file;
+       zval      *current_file_bytes_processed;
+       zend_bool apply_trans_sid;
+} php_session_rfc1867_progress;
+
 typedef struct _php_ps_globals {
        char *save_path;
        char *session_name;
@@ -143,6 +160,12 @@
        int send_cookie;
        int define_sid;
        zend_bool invalid_session_id;   /* allows the driver to report about an 
invalid session id and request id regeneration */
+
+       zend_bool rfc1867_enabled;
+       zstr rfc1867_prefix;
+       zstr rfc1867_name;
+       long rfc1867_freq;
+       php_session_rfc1867_progress *rfc1867_progress;
 } php_ps_globals;
 
 typedef php_ps_globals zend_ps_globals;
http://cvs.php.net/viewvc.cgi/php-src/ext/session/session.c?r1=1.492&r2=1.493&diff_format=u
Index: php-src/ext/session/session.c
diff -u php-src/ext/session/session.c:1.492 php-src/ext/session/session.c:1.493
--- php-src/ext/session/session.c:1.492 Wed Aug  6 05:34:55 2008
+++ php-src/ext/session/session.c       Thu Sep 11 11:51:07 2008
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: session.c,v 1.492 2008/08/06 05:34:55 jani Exp $ */
+/* $Id: session.c,v 1.493 2008/09/11 11:51:07 lbarnaud Exp $ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -36,6 +36,8 @@
 
 #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"
@@ -57,6 +59,9 @@
 
 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 *
    *********** */
@@ -630,12 +635,32 @@
                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()
@@ -663,6 +688,15 @@
        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()
@@ -1917,7 +1951,7 @@
    * 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);
 
@@ -1945,11 +1979,16 @@
                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);
 }
 /* }}} */
 
@@ -2002,6 +2041,8 @@
 #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;
 }
 /* }}} */
@@ -2070,6 +2111,250 @@
 }
 /* }}} */
 
+/* ************************
+   * 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",

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to