Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:2191 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 26614 invoked from network); 5 Jun 2003 22:29:40 -0000 Received: from unknown (HELO dimsmail.digitalims.net) (12.144.148.54) by pb1.pair.com with SMTP; 5 Jun 2003 22:29:40 -0000 Received: (qmail 19456 invoked by uid 778); 5 Jun 2003 22:29:39 -0000 Received: from unknown (HELO corp.digitalims.com) (65.221.143.39) by mail.digitalims.net with SMTP; 5 Jun 2003 22:29:39 -0000 X-MimeOLE: Produced By Microsoft Exchange V6.0.6249.0 content-class: urn:content-classes:message MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Date: Thu, 5 Jun 2003 17:29:38 -0500 Message-ID: X-MS-Has-Attach: X-MS-TNEF-Correlator: Thread-Topic: [PHP-DEV] [PATCH] upload progress metter Thread-Index: AcMrp6zYGnNxaIPASaCmjI1RbnS50gACbLrg To: , Subject: RE: [PHP-DEV] [PATCH] upload progress metter From: DEnderson@DigitalIMS.com ("David Enderson") I also developed upload status capability for my company that works very similarly to yours. I am currently working on integrating the changes I made into a patch for 4.3.2 for members of this list to evaluate (I originally made the upgrade to 4.1.2). I see you came to the same conclusion I did, that the easiest way to pass information seemed to be through the use of temporary files. I was hoping that once I submitted my patch that someone on this list might have a better suggestion like direction on using shared memory or something. --David -----=3D+=3D----- David Enderson Programmer Digital IMS 402.437.0137 denderson@digitalims.com > Hi, >=20 > To make a long story short, I needed an upload progress=20 > metter, so the users will something while their huge files=20 > are uploaded to the server. I searched the net but only found=20 > for ASP, so I wrote one. Unfortunatly PHP needs a little=20 > patch to be willing to do this ... >=20 > Here is how it works: > 1. apply patch to php and recompile php (and apache if=20 > needed) 2. add something like this to http.conf >=20 > #for php-upload-progress-bar > > php_value upload_metter 1 > php_value upload_metter_dir "/tmp/uploadbar" > >=20 > - This will activate the progress metter for /upload > - And will tell it to write progress informations to /tmp/uploadbar >=20 > 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! >=20 > 4. copy the demo scripts to /upload directory > 5. point your browser to the index.php script. upload some=20 > files. enjoy! >=20 >=20 > Here is how it really works: > 1. index.php will generate and uniq ID for each upload. This=20 > ID will be used to track the progress and report it. 2. a=20 > special field named 'UPLOAD_METTER_ID' is used to store this=20 > ID. make sure this field is BEFORE any 'file' fields. put it=20 > at the begining of the form! 3. onSubmit()-ing the form a=20 > small window will open where the progress.php will display=20 > the actual progress bar. 4. php will check the value of=20 > 'upload_metter' and 'upload_metter_dir' configuration options=20 > and the presence and value of 'UPLOAD_METTER_ID' field 5. the=20 > progress file is stored in the directory named by 'upload_metter_dir' > and the vlaue of UPLOAD_METTER_ID field is used as the=20 > name of the file 6. progress information is updated once a=20 > second by the php engine 7. script progress.php will use the=20 > ID field which it receives as a parameter to locate the=20 > associated progress-file and read progress information from=20 > it. then generate the little proggress bar 8. the progress=20 > bar will 'refresh' about once a second, depending on how fast=20 > the network is going 9. when upload is completed, the=20 > progress.php script will remove the progress file, and close=20 > the pop-up window. >=20 >=20 > NOTE: there is a good chance that this progress files will=20 > not be deleted from various reasons (client don't have JS=20 > activated, or it closes the popup while data is still=20 > uploaded, etc...), so there is a need to periodically cleanup=20 > the directory of old files. >=20 >=20 > What the PATCH does: > - adding 2 new cinfiguration options to PHP: upload_metter=20 > and upload_metter_dir > - in rfc1867.c: changes rfc1867_post_handler() to make some=20 > calls to a newly defined function that will update the=20 > progress metter: > update_progress_metter() > - in turn it calls update_progress_metter_file(), trying its=20 > best not to update the file more than once a second. >=20 > I have tested it with php-4.2.3 and 4.3.2. atch for php-4.3.2=20 > is attached. a patch for 4.2.3 is also available. basically=20 > is the same thing. >=20 > the rest of the files and a live demo can be found here:=20 > http://pdoru.from.ro/ >=20 >=20 > Please let me know if you have any problems/suggestions :-) >=20 >=20 > Best regards, > Doru Petrescu > Senior Software Engineer > Astral Telecom Bucuresti >=20 >=20 >=20 >=20 > -------------------------------------------------------------- > --------------------- > 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 Thu Jun 5 22:58:46 2003 > @@ -345,7 +345,9 @@ > STD_PHP_INI_BOOLEAN("file_uploads", =09 > "1", PHP_INI_SYSTEM, OnUpdateBool, =09 > file_uploads, php_core_globals,=09 > core_globals) > STD_PHP_INI_ENTRY("upload_max_filesize", "2M",=09 > PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateInt,=09 > upload_max_filesize, php_core_globals,=09 > core_globals) > STD_PHP_INI_ENTRY("post_max_size", =09 > "8M", PHP_INI_SYSTEM|PHP_INI_PERDIR, =09 > OnUpdateInt, post_max_size, =09 > sapi_globals_struct,sapi_globals) > - STD_PHP_INI_ENTRY("upload_tmp_dir", =09 > NULL, PHP_INI_SYSTEM, OnUpdateStringUnempty,=09 > upload_tmp_dir, php_core_globals,=09 > core_globals) > + STD_PHP_INI_ENTRY("upload_tmp_dir", =09 > NULL, PHP_INI_ALL, OnUpdateStringUnempty,=09 > upload_tmp_dir, =09 > php_core_globals, core_globals) > + STD_PHP_INI_ENTRY("upload_metter", =09 > "0", PHP_INI_ALL, OnUpdateBool, =09 > upload_metter, php_core_globals,=09 > core_globals) > + STD_PHP_INI_ENTRY("upload_metter_dir", =09 > NULL, PHP_INI_ALL, OnUpdateStringUnempty,=09 > upload_metter_dir, php_core_globals,=09 > core_globals) >=20 > STD_PHP_INI_ENTRY("user_dir", =09 > NULL, PHP_INI_SYSTEM, OnUpdateString, =09 > user_dir, =09 > php_core_globals, core_globals) > STD_PHP_INI_ENTRY("variables_order", NULL,=09 > PHP_INI_ALL, OnUpdateStringUnempty,=09 > variables_order, php_core_globals, core_globals) > diff -rubB orig/php-4.3.2/main/php_globals.h=20 > 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 Thu Jun 5 22:56:57 2003 > @@ -133,6 +133,8 @@ > zend_bool modules_activated; >=20 > zend_bool file_uploads; > + zend_bool upload_metter; > + char * upload_metter_dir; >=20 > zend_bool during_request_startup; >=20 > 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 Thu Jun 5 22:59:45 2003 > @@ -676,6 +678,81 @@ > return out; > } >=20 > +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 =3D VCWD_FOPEN(X->progress, "wb"); > + > + s =3D X->speed_average; if (s < 1) s=3D1; > + eta =3D (X->bytes_total - X->bytes_uploaded) / s; > + > + if (F) { > + fprintf(F,=20 > "time_start=3D%d\ntime_last=3D%d\nspeed_average=3D%d\nspeed_last=3D%d\ > = nbytes_uploaded=3D%d\nbytes_total=3D%d\nfiles_uploaded=3D%d\neta=3D%d\n",= > + X->time_start, X->time_last,=20 > X->speed_average, X->speed_last, X->bytes_uploaded,=20 > X->bytes_total, X->files_uploaded, eta > + ); > + fclose(F); > + } > + > + sapi_module.sapi_error(E_NOTICE, "metter: read %d of %d",=20 > +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 =3D X->time_last =3D time(NULL); > + > + X->bytes_total =3D total; > + X->bytes_uploaded =3D read; > + > + X->speed_average =3D X->speed_last =3D X->bytes_uploaded; > + > + update_progress_metter_file(X); > + return; > + } > + > + dt =3D time(NULL) - X->time_last; > + d =3D read - X->bytes_uploaded; > + > + if (dt < 1) { > + if (read < total) > + return; // avoid divide by zero > + if (d < 1) > + return; > + dt =3D 1; > + } > + > + > + > + sp =3D d/dt; > + > + > + X->bytes_uploaded =3D read; > + X->time_last =3D time(NULL); > + > + dtx =3D X->time_last - X->time_start; if (dtx=20 > < 1) dtx =3D 1; > + X->speed_average =3D X->bytes_uploaded / dtx; > + > + X->speed_last =3D sp; > + > + update_progress_metter_file(X); > +} > + >=20 > /* > * The combined READER/HANDLER > @@ -693,6 +770,10 @@ > zval *array_ptr =3D (zval *) arg; > FILE *fp; > zend_llist header; > + Xdata X; > + int progress_metter=3D0; > + > + bzero(&X,sizeof(X)); >=20 > if (SG(request_info).content_length > SG(post_max_size)) { > sapi_module.sapi_error(E_WARNING, "POST=20 > Content-Length of %d bytes exceeds the limit of %d bytes",=20 > SG(request_info).content_length, SG(post_max_size)); @@=20 > -753,6 +838,9 @@ > zend_llist_clean(&header); >=20 > if (!multipart_buffer_headers(mbuff, &header=20 > TSRMLS_CC)) { > + > + > + if (progress_metter)=20 > update_progress_metter( &X,=20 > +SG(read_post_bytes), SG(request_info).content_length ); > SAFE_RETURN; > } >=20 > @@ -806,6 +894,35 @@ > max_file_size =3D atol(value); > } >=20 > + > + > + if (!strcmp(param,=20 > "UPLOAD_METTER_ID") && PG(upload_metter) && PG(upload_metter_dir)) { > + char *c,*v =3D estrdup(value); > + for (c=3Dv;*c;c++) { > + if ( (*c >=3D '0' && *c <=3D '9') || > + (*c >=3D 'a'=20 > && *c <=3D 'z') || > + (*c >=3D 'A' && *c <=3D 'Z') || > + *c =3D=3D '.' || *c =3D=3D '_' || > + *c =3D=3D ',' || *c =3D=3D '@' || > + *c =3D=3D '-' || *c =3D=3D '%') { > + }else{ > + *c=3D0; > + break; > + } > + } > + > + if (v && *v) { > + if (strlen(v) > 64) v[64]=3D0; > + progress_metter=3D1; > + snprintf(X.progress,1000,=20 > "%s/%s", PG(upload_metter_dir), v); > + } > + efree(v); > + > + > + > + } > + > + > efree(param); > efree(value); > continue; > @@ -831,6 +948,9 @@ > SAFE_RETURN; > } >=20 > + if (progress_metter)=20 > update_progress_metter( &X, SG(read_post_bytes),=20 > SG(request_info).content_length ); > + X.files_uploaded++; > + > if (!skip_upload) { > /* Handle file */ > fp =3D=20 > php_open_temporary_file(PG(upload_tmp_dir), "php",=20 > &temp_filename TSRMLS_CC); @@ -872,6 +992,10 @@ > } else { > total_bytes +=3D wlen; > } > + > + > + > + if (progress_metter)=20 > update_progress_metter( &X,=20 > +SG(read_post_bytes), SG(request_info).content_length ); > } > } > fclose(fp); > @@ -1047,6 +1173,10 @@ > efree(param); > } > } > + > + > + > + if (progress_metter) update_progress_metter( &X,=20 > SG(read_post_bytes),=20 > +SG(request_info).content_length ); >=20 > SAFE_RETURN; > } >=20 >=20 >=20 > --=20 > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php >=20 >=20