there is a new patch available that fixes problems with apache2! Also, I have noticed that sapi module for apache2handler and apache2filter do not initialize SG(request_info).content_length during request init. I had to add 3 lines of code to each one to initialize it. looks like it works.
is this normal ? does the rest of sapi modules initialize this or not ?!?! also there are some changes to the .php scripts too to fix some warnings. visit http://pdoru.from.ro/ to get the new ones. FYI, I am also thinking on a version that will use shared memory to store upload progress information. Best regards, Doru Petrescu Senior Software Engineer Astral Telecom Bucuresti ----------------------------------------------------------- diff -rubB orig/php-4.3.2/main/main.c php-4.3.2/main/main.c --- orig/php-4.3.2/main/main.c Thu May 22 01:54:38 2003 +++ php-4.3.2/main/main.c Sun Jun 15 01:27:59 2003 @@ -345,7 +345,9 @@ STD_PHP_INI_BOOLEAN("file_uploads", "1", PHP_INI_SYSTEM, OnUpdateBool, file_uploads, php_core_globals, core_globals) STD_PHP_INI_ENTRY("upload_max_filesize", "2M", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateInt, upload_max_filesize, php_core_globals, core_globals) STD_PHP_INI_ENTRY("post_max_size", "8M", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateInt, post_max_size, sapi_globals_struct,sapi_globals) - STD_PHP_INI_ENTRY("upload_tmp_dir", NULL, PHP_INI_SYSTEM, OnUpdateStringUnempty, upload_tmp_dir, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("upload_tmp_dir", NULL, PHP_INI_ALL, OnUpdateStringUnempty, upload_tmp_dir, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("upload_metter", "0", PHP_INI_ALL, OnUpdateBool, upload_metter, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("upload_metter_dir", NULL, PHP_INI_ALL, OnUpdateStringUnempty, upload_metter_dir, php_core_globals, core_globals) STD_PHP_INI_ENTRY("user_dir", NULL, PHP_INI_SYSTEM, OnUpdateString, user_dir, php_core_globals, core_globals) STD_PHP_INI_ENTRY("variables_order", NULL, PHP_INI_ALL, OnUpdateStringUnempty, variables_order, php_core_globals, core_globals) diff -rubB orig/php-4.3.2/main/php_globals.h php-4.3.2/main/php_globals.h --- orig/php-4.3.2/main/php_globals.h Sun May 18 13:22:16 2003 +++ php-4.3.2/main/php_globals.h Sun Jun 15 01:27:59 2003 @@ -133,6 +133,8 @@ zend_bool modules_activated; zend_bool file_uploads; + zend_bool upload_metter; + char * upload_metter_dir; zend_bool during_request_startup; diff -rubB orig/php-4.3.2/main/rfc1867.c php-4.3.2/main/rfc1867.c --- orig/php-4.3.2/main/rfc1867.c Sat May 24 00:37:16 2003 +++ php-4.3.2/main/rfc1867.c Sun Jun 15 01:46:19 2003 @@ -676,6 +676,84 @@ return out; } +typedef struct _Xdata { + int time_start; + int time_last; + int speed_average; + int speed_last; + int bytes_uploaded; + int bytes_total; + int files_uploaded; + char progress[1024]; +} Xdata; + +static void update_progress_metter_file(Xdata *X) +{ + int eta,s; + FILE *F; + TSRMLS_FETCH(); + + F = VCWD_FOPEN(X->progress, "wb"); + + s = X->speed_average; if (s < 1) s=1; + eta = (X->bytes_total - X->bytes_uploaded) / s; + + if (F) { + fprintf(F, "time_start=%d\ntime_last=%d\nspeed_average=%d\nspeed_last=%d\nbytes_uploaded=%d\nbytes_total=%d\nfiles_uploaded=%d\neta=%d\n", + X->time_start, X->time_last, X->speed_average, X->speed_last, X->bytes_uploaded, X->bytes_total, X->files_uploaded, eta + ); + fclose(F); + } + +// sapi_module.sapi_error(E_NOTICE, "metter: read %d of %d", SG(read_post_bytes), SG(request_info).content_length ); +} + +static void update_progress_metter(Xdata *X, int read, int total) +{ + int d,dt,dtx; + int bu; + int sp; + + + if (!X->time_start) { + X->time_start = X->time_last = time(NULL); + + X->bytes_total = total; + X->bytes_uploaded = read; + + X->speed_average = X->speed_last = X->bytes_uploaded; + + update_progress_metter_file(X); + return; + } + + dt = time(NULL) - X->time_last; + d = read - X->bytes_uploaded; + + if (dt < 1) { + if (read < total) + return; // avoid divide by zero + if (d < 1) + return; + dt = 1; + } + + + + sp = d/dt; + + + X->bytes_uploaded = read; + X->time_last = time(NULL); + + dtx = X->time_last - X->time_start; if (dtx < 1) dtx = 1; + X->speed_average = X->bytes_uploaded / dtx; + + X->speed_last = sp; + + update_progress_metter_file(X); +} + /* * The combined READER/HANDLER @@ -693,6 +771,10 @@ zval *array_ptr = (zval *) arg; FILE *fp; zend_llist header; + Xdata X; + int progress_metter=0; + + bzero(&X,sizeof(X)); if (SG(request_info).content_length > SG(post_max_size)) { sapi_module.sapi_error(E_WARNING, "POST Content-Length of %d bytes exceeds the limit of %d bytes", SG(request_info).content_length, SG(post_max_size)); @@ -753,6 +835,9 @@ zend_llist_clean(&header); if (!multipart_buffer_headers(mbuff, &header TSRMLS_CC)) { + + + if (progress_metter) update_progress_metter( &X, SG(read_post_bytes), SG(request_info).content_length ); SAFE_RETURN; } @@ -806,6 +891,35 @@ max_file_size = atol(value); } + + + if (!strcmp(param, "UPLOAD_METTER_ID") && PG(upload_metter) && PG(upload_metter_dir)) { + char *c,*v = estrdup(value); + for (c=v;*c;c++) { + if ( (*c >= '0' && *c <= '9') || + (*c >= 'a' && *c <= 'z') || + (*c >= 'A' && *c <= 'Z') || + *c == '.' || *c == '_' || + *c == ',' || *c == '@' || + *c == '-' || *c == '%') { + }else{ + *c=0; + break; + } + } + + if (v && *v) { + if (strlen(v) > 64) v[64]=0; + progress_metter=1; + snprintf(X.progress,1000, "%s/%s", PG(upload_metter_dir), v); + } + efree(v); + + + + } + + efree(param); efree(value); continue; @@ -831,6 +945,9 @@ SAFE_RETURN; } + if (progress_metter) update_progress_metter( &X, SG(read_post_bytes), SG(request_info).content_length ); + X.files_uploaded++; + if (!skip_upload) { /* Handle file */ fp = php_open_temporary_file(PG(upload_tmp_dir), "php", &temp_filename TSRMLS_CC); @@ -872,6 +989,10 @@ } else { total_bytes += wlen; } + + + + if (progress_metter) update_progress_metter( &X, SG(read_post_bytes), SG(request_info).content_length ); } } fclose(fp); @@ -1047,6 +1168,10 @@ efree(param); } } + + + + if (progress_metter) update_progress_metter( &X, SG(read_post_bytes), SG(request_info).content_length ); SAFE_RETURN; } diff -rubB orig/php-4.3.2/sapi/apache2filter/sapi_apache2.c php-4.3.2/sapi/apache2filter/sapi_apache2.c --- orig/php-4.3.2/sapi/apache2filter/sapi_apache2.c Fri May 23 05:42:22 2003 +++ php-4.3.2/sapi/apache2filter/sapi_apache2.c Sun Jun 15 01:44:10 2003 @@ -385,6 +385,15 @@ SG(request_info).request_uri = safe_strdup(f->r->uri); SG(request_info).path_translated = safe_strdup(f->r->filename); f->r->no_local_copy = 1; + + // add this --- cut here --- + { + char *content_length = (char *) apr_table_get(r->headers_in, "Content-Length"); + SG(request_info).content_length = (content_length ? atoi(content_length) : 0); + } // --cut here -- + + + content_type = sapi_get_default_content_type(TSRMLS_C); f->r->content_type = apr_pstrdup(f->r->pool, content_type); SG(request_info).post_data = ctx->post_data; diff -rubB orig/php-4.3.2/sapi/apache2handler/sapi_apache2.c php-4.3.2/sapi/apache2handler/sapi_apache2.c --- orig/php-4.3.2/sapi/apache2handler/sapi_apache2.c Fri May 23 05:42:22 2003 +++ php-4.3.2/sapi/apache2handler/sapi_apache2.c Sun Jun 15 01:21:54 2003 @@ -420,6 +420,13 @@ SG(request_info).path_translated = apr_pstrdup(r->pool, r->filename); r->no_local_copy = 1; + // add this --- cut here --- + { + char *content_length = (char *) apr_table_get(r->headers_in, "Content-Length"); + SG(request_info).content_length = (content_length ? atoi(content_length) : 0); + } // --cut here -- + + content_type = sapi_get_default_content_type(TSRMLS_C); ap_set_content_type(r, apr_pstrdup(r->pool, content_type)); efree(content_type); ------------------------------------------------------------------------- On Fri, 6 Jun 2003, Doru Petrescu wrote: > > Hi, > > To make a long story short, I needed an upload progress metter, so the > users will something while their huge files are uploaded to the server. I > searched the net but only found for ASP, so I wrote one. > Unfortunatly PHP needs a little patch to be willing to do this ... > > Here is how it works: > 1. apply patch to php and recompile php (and apache if needed) > 2. add something like this to http.conf > > #for php-upload-progress-bar > <Directory /www/htdocs/upload> > php_value upload_metter 1 > php_value upload_metter_dir "/tmp/uploadbar" > </Directory> > > - This will activate the progress metter for /upload > - And will tell it to write progress informations to /tmp/uploadbar > > 3. mkdir /tmp/uploadbar; chmod 777 /tmp/uploadbar > I have to say that 0777 and /tmp are not the best choises from a > security point of view. you should find a better place! > > 4. copy the demo scripts to /upload directory > 5. point your browser to the index.php script. upload some files. enjoy! > > > Here is how it really works: > 1. index.php will generate and uniq ID for each upload. This ID will be > used to track the progress and report it. > 2. a special field named 'UPLOAD_METTER_ID' is used to store this ID. make > sure this field is BEFORE any 'file' fields. put it at the begining of the > form! > 3. onSubmit()-ing the form a small window will open where the progress.php > will display the actual progress bar. > 4. php will check the value of 'upload_metter' and 'upload_metter_dir' > configuration options and the presence and value of 'UPLOAD_METTER_ID' > field > 5. the progress file is stored in the directory named by 'upload_metter_dir' > and the vlaue of UPLOAD_METTER_ID field is used as the name of the file > 6. progress information is updated once a second by the php engine > 7. script progress.php will use the ID field which it receives as a > parameter to locate the associated progress-file and read progress > information from it. then generate the little proggress bar > 8. the progress bar will 'refresh' about once a second, depending on how > fast the network is going > 9. when upload is completed, the progress.php script will remove the > progress file, and close the pop-up window. > > > NOTE: there is a good chance that this progress files will not be deleted > from various reasons (client don't have JS activated, or it closes the > popup while data is still uploaded, etc...), so there is a need to > periodically cleanup the directory of old files. > > > What the PATCH does: > - adding 2 new cinfiguration options to PHP: upload_metter and upload_metter_dir > - in rfc1867.c: changes rfc1867_post_handler() to make some calls to a > newly defined function that will update the progress metter: > update_progress_metter() > - in turn it calls update_progress_metter_file(), trying its best not to > update the file more than once a second. > > I have tested it with php-4.2.3 and 4.3.2. atch for php-4.3.2 is attached. > a patch for 4.2.3 is also available. basically is the same thing. > > the rest of the files and a live demo can be found here: http://pdoru.from.ro/ > > > Please let me know if you have any problems/suggestions :-) > > > Best regards, > Doru Petrescu > Senior Software Engineer > Astral Telecom Bucuresti > > -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php