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;
 }



-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to