# [PATCH] upload progress metter

- Thread: https://externals.io/message/2191
- Original archive: https://news-web.php.net/php.internals/2191
- Started by David Enderson on 2003-06-05T22:29:38+00:00
- Messages: 1
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #2191 — David Enderson — 2003-06-05T22:29:38+00:00

URL: https://externals.io/message/2191#2191

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

-----=+=-----
David Enderson
Programmer
Digital IMS
402.437.0137
denderson@digitalims.com


> 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
> 
> 
> 
> 
> --------------------------------------------------------------
> ---------------------
> 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",			
> "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	Thu Jun  5 22:56:57 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	Thu Jun  5 22:59:45 2003
> @@ -676,6 +678,81 @@
>  	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 = 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 +770,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 +838,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 +894,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 +948,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 +992,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 +1173,10 @@
>  			efree(param);
>  		}
>  	}
> +
> +
> +
> +	if (progress_metter) update_progress_metter( &X, 
> SG(read_post_bytes), 
> +SG(request_info).content_length );
> 
>  	SAFE_RETURN;
>  }
