package.xml0000644000076500000240000003041314125450113012353 0ustar ramseystaff uploadprogress pecl.php.net An extension to track progress of a file upload. A PHP extension to track progress of a file upload, including details on the speed of the upload, estimated time remaining, and access to the contents of the file as it is being uploaded. The uploadprogress extension works on PHP 7.2+ and PHP 8. It works with Apache HTTP Server using mod_php, as well as Apache HTTP Server, nginx, and Caddy through PHP-FPM. It might work on other web servers; let us know where you're using it. See https://github.com/php/pecl-php-uploadprogress for documentation and examples. Christian Stocker chregu chregu@php.net yes Ben Ramsey ramsey ramsey@php.net yes 2021-10-01 2.0.2 1.0.0 stable stable PHP License - Update release package with latest examples and documentation 7.2.0 1.4.0 uploadprogress 2021-09-29 2.0.1 1.0.0 stable stable - Fix parameter and return type declarations for PHP 7 and PHP 8 2021-09-29 2.0.0 1.0.0 stable stable - Drop support for PHP < 7.2 2021-09-28 1.1.4 1.0.0 stable stable - Fix #79584: Segmentation fault in uploadprogress 1.1.0 and up - Add arginfo for functions to support PHP 8 and up 2020-01-28 1.1.3 1.0.0 stable stable - Improved documentation and examples included in the release package 2020-01-26 1.1.2 1.0.0 stable stable - PHP 8 compatibility; this now builds on PHP 5, PHP 7, and PHP 8 2020-01-26 1.1.1 1.0.0 stable stable - Mark maximum PHP version as 8.0.0; this will not build on PHP 8 2020-01-26 1.1.0 1.0.0 stable stable - PHP 7 compatibility 2011-08-15 1.0.3.1 1.0 stable stable - Wrong version number in .h file 2011-08-08 1.0.3 1.0 stable stable - Another make it work with PHP 5.4 2011-07-26 1.0.2 1.0 stable stable - Make it work with PHP 5.4 2009-06-16 1.0.1 1.0 stable stable - Default temporary directory is taken from system settings during compile time (guenter). - Fix a while loop error in removing preceding whitespace (terralith). - Example: Added a check, if the extension is installed at all. - Example: Added checks for a valid uploadprogress.file.filename_template setting. 2009-03-15 1.0.0 1.0 stable stable - Fixed a renaming issue with temporary files on Windows and PHP 5.2. 2009-01-22 0.9.2 0.9 beta beta - Fixed an issue with filenames containing spaces, see http://pecl.php.net/bugs/bug.php?id=14525 for details (by franck). - Extended the example to check for too large files. 2008-08-25 0.9.1 0.9 beta beta - Fixed version information in phpinfo() - Added php.ini options to phpinfo() 2008-07-08 0.9.0 0.9 beta beta - Added uploadprogress_get_contents(id, fieldname) to return the contents of that file (Ben Ramsey) - Added uploadprogress.get_contents INI option to enable above function (Ben Ramsey) - Added a simple example - Minor Fixes 2006-12-05 0.3.0 0.3 beta beta Initial release uploadprogress-2.0.2/examples/.docker/Dockerfile0000644000076500000240000000044014125450113021076 0ustar ramseystaffARG php_version FROM php:${php_version}-fpm ARG uploadprogress_version RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" COPY uploadprogress.ini $PHP_INI_DIR/conf.d/ RUN pecl install uploadprogress-${uploadprogress_version} \ && docker-php-ext-enable uploadprogress uploadprogress-2.0.2/examples/.docker/uploadprogress.ini0000644000076500000240000000047114125450113022662 0ustar ramseystaffmemory_limit = 20G file_uploads = On upload_tmp_dir = /tmp post_max_size = 13G upload_max_filesize = 12G max_execution_time = 120 ; extension = uploadprogress uploadprogress.get_contents = On uploadprogress.file.filename_template = /tmp/upt_%s.txt uploadprogress.file.contents_template = /tmp/upload_contents_%s uploadprogress-2.0.2/examples/.tmp/.gitkeep0000644000076500000240000000000014125450113020056 0ustar ramseystaffuploadprogress-2.0.2/examples/README.md0000644000076500000240000000245414125450113017045 0ustar ramseystaff# uploadprogress Example To run this example, you will need: * [Apache HTTP Server][] using [mod_php][], or [PHP-FPM][] used with [Apache HTTP Server][], [nginx][], or [Caddy][]. * PHP >= 7.2 with the [fileinfo][] extension The easiest way to run this example is by using [Docker][] with the provided `docker-compose.yml` file (which includes all the requirements). ## Using docker-compose To run the Docker image, open a terminal window, change to this examples directory (i.e. `cd /path/to/examples`), and enter the following command. It may take a few minutes the first time you enter this, since it will build the image for you and then run it. ``` docker-compose up ``` After it starts, open a web browser and go to to run the example. Follow the instructions on the page, and read the code in this directory for a better understanding of what's going on. To stop `docker-compose`, press `Ctrl`-`C` in your terminal window, and then enter `docker-compose rm` to remove the container that was created. [docker]: https://www.docker.com [Apache HTTP Server]: https://httpd.apache.org [mod_php]: https://www.php.net/manual/en/install.unix.apache2.php [php-fpm]: https://www.php.net/fpm [fileinfo]: https://www.php.net/fileinfo [nginx]: https://nginx.org [caddy]: https://caddyserver.com uploadprogress-2.0.2/examples/check-progress.php0000644000076500000240000000556114125450113021220 0ustar ramseystaff 'An error occurred.', 'messages' => $errors, ]); exit; } // Get the MIME type of the bytes uploaded, using the Fileinfo extension. $finfo = new finfo(FILEINFO_MIME_TYPE); $detectedMimeType = $finfo->buffer($contents); $info = array_merge($info, [ 'detectedMimeType' => $detectedMimeType, ]); // In our example, we respond with the uploadprogress information, as well as // the detected MIME type from the initial bytes uploaded (if we can detect it). header('HTTP/1.1 200 OK'); header('Content-Type: application/json'); echo json_encode($info); uploadprogress-2.0.2/examples/docker-compose.yml0000644000076500000240000000101514125450113021213 0ustar ramseystaffversion: "3.7" services: nginx: container_name: uploadprogress-web image: nginx:latest ports: - "8080:80" volumes: - "$PWD/nginx.conf:/etc/nginx/conf.d/default.conf" - ".:/var/www/html" depends_on: - php-fpm php-fpm: container_name: uploadprogress-php-fpm image: uploadprogress-example-php-fpm build: context: ./.docker args: php_version: 8.0 uploadprogress_version: 2.0.2 volumes: - "./.tmp:/tmp" - ".:/var/www/html" uploadprogress-2.0.2/examples/handle-upload.php0000644000076500000240000000425714125450113021017 0ustar ramseystaff 'ok']); uploadprogress-2.0.2/examples/index.html0000644000076500000240000002451314125450113017563 0ustar ramseystaff uploadprogress Example

uploadprogress Example

Welcome to the uploadprogress extension example!

Click on the file field below or the "Browse" button to select a file, and then click the "Upload" button. For best results, select a large file — something over 10 MB. As the file uploads, you will see the progress bar fill up. You should also see a guess about the file's type. This uses the fileinfo extension to examine the bytes as they're being uploaded to guess the file type.

To learn more about what's going on in this example, read the code.

0%
It looks like you're uploading .
uploadprogress-2.0.2/examples/nginx.conf0000644000076500000240000000122414125450113017552 0ustar ramseystaffserver { listen 80; root /var/www/html; index index.html index.php; client_max_body_size 13G; location / { try_files $uri $uri/ /index.php?$args; } location ~ [^/]\.php(/|$) { fastcgi_split_path_info ^(.+?\.php)(/.*)$; if (!-f $document_root$fastcgi_script_name) { return 404; } include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; fastcgi_pass php-fpm:9000; fastcgi_index index.php; } }uploadprogress-2.0.2/tests/mocks/get_contents/upload_contents_basic-formFieldId0000644000076500000240000000124214125450113027363 0ustar ramseystaffLorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse placerat risus ac augue lacinia, sed aliquam sapien ullamcorper. Nulla ipsum diam, condimentum nec vulputate sodales, convallis vel neque. Morbi at rutrum arcu, sit amet ullamcorper velit. In erat risus, blandit sit amet imperdiet eget, auctor a turpis. Nulla vel augue elit. Pellentesque vestibulum dui nisl, a auctor leo accumsan in. Etiam eget varius metus. Donec eu pulvinar metus, ac vulputate erat. Integer viverra augue quis mauris vestibulum, vel rutrum ante dapibus. Donec venenatis viverra mollis. Pellentesque id magna sit amet leo lobortis faucibus. Nam eu tellus vel nibh lobortis tincidunt. uploadprogress-2.0.2/tests/mocks/get_contents/upload_contents_variation003-formFieldId0000644000076500000240000000124214125450113030521 0ustar ramseystaffLorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse placerat risus ac augue lacinia, sed aliquam sapien ullamcorper. Nulla ipsum diam, condimentum nec vulputate sodales, convallis vel neque. Morbi at rutrum arcu, sit amet ullamcorper velit. In erat risus, blandit sit amet imperdiet eget, auctor a turpis. Nulla vel augue elit. Pellentesque vestibulum dui nisl, a auctor leo accumsan in. Etiam eget varius metus. Donec eu pulvinar metus, ac vulputate erat. Integer viverra augue quis mauris vestibulum, vel rutrum ante dapibus. Donec venenatis viverra mollis. Pellentesque id magna sit amet leo lobortis faucibus. Nam eu tellus vel nibh lobortis tincidunt. uploadprogress-2.0.2/tests/mocks/get_contents/upload_contents_variation004-aFieldId0000644000076500000240000000000014125450113027766 0ustar ramseystaffuploadprogress-2.0.2/tests/mocks/get_contents/upload_contents_variation006-field0000644000076500000240000000007114125450113027422 0ustar ramseystaffLorem ipsum dolor sit amet, consectetur adipiscing elit. uploadprogress-2.0.2/tests/mocks/get_contents/variation005-fieldName0000644000076500000240000000007114125450113024741 0ustar ramseystaffLorem ipsum dolor sit amet, consectetur adipiscing elit. uploadprogress-2.0.2/tests/mocks/get_info/upt_basic.txt0000644000076500000240000000030714125450113022525 0ustar ramseystaffupload_id=file001 fieldname=uploadFile filename=example.txt time_start=1579893044 time_last=30 speed_average=300 speed_last=300 bytes_uploaded=1592342 bytes_total=3000000 files_uploaded=1 est_sec=45 uploadprogress-2.0.2/tests/mocks/get_info/upt_bug58318.txt0000644000076500000240000000042614125450113022634 0ustar ramseystaffupload_id=974489 fieldname=fichier_video filename=C:\Documents and Settings\franck\Bureau\taf\tevasia\1and1\video\Kumar.flv time_start=1219105999 time_last=1219106351 speed_average=49492 speed_last=51190 bytes_uploaded=17421484 bytes_total=28610177 files_uploaded=0 est_sec=226 uploadprogress-2.0.2/tests/mocks/get_info/upt_variation003.txt0000644000076500000240000000030714125450113023663 0ustar ramseystaffupload_id=file004 fieldname=uploadFile filename=example.txt time_start=1579893044 time_last=30 speed_average=300 speed_last=300 bytes_uploaded=1592342 bytes_total=3000000 files_uploaded=1 est_sec=45 uploadprogress-2.0.2/tests/mocks/get_info/upt_variation004.txt0000644000076500000240000000037514125450113023671 0ustar ramseystaffupload_id=file005 fieldname=uploadFile filename = a value with spaces in it time_start=1579893044 time_last = 30 speed_average = 300 speed_last=300 bytes_uploaded =1592342 bytes_total=3000000 files_uploaded= 1 est_sec= 45 uploadprogress-2.0.2/tests/mocks/get_info/variation0010000644000076500000240000000032514125450113022153 0ustar ramseystaffupload_id=file003 fieldname=uploadFile filename=/path/to/tmp/filename.txt time_start=1579893044 time_last=30 speed_average=300 speed_last=300 bytes_uploaded=1592342 bytes_total=3000000 files_uploaded=1 est_sec=45 uploadprogress-2.0.2/tests/bug58318.phpt0000644000076500000240000000067214125450113017175 0ustar ramseystaff--TEST-- uploadprogress_get_info - Filename containing spaces (bug #58318) --SKIPIF-- = 8) exit('skip test not valid on PHP 8'); --INI-- uploadprogress.get_contents = On --FILE-- 'file001', 'fieldname' => 'uploadFile', 'filename' => 'example.txt', 'time_start' => '1579893044', 'time_last' => '30', 'speed_average' => '300', 'speed_last' => '300', 'bytes_uploaded' => '1592342', 'bytes_total' => '3000000', 'files_uploaded' => '1', 'est_sec' => '45', ) uploadprogress-2.0.2/tests/uploadprogress_get_info_error001.phpt0000644000076500000240000000066314125450113024364 0ustar ramseystaff--TEST-- uploadprogress_get_info - Warns when too few arguments --SKIPIF-- = 8) exit('skip test not valid on PHP 8'); --FILE-- 'file003', 'fieldname' => 'uploadFile', 'filename' => '/path/to/tmp/filename.txt', 'time_start' => '1579893044', 'time_last' => '30', 'speed_average' => '300', 'speed_last' => '300', 'bytes_uploaded' => '1592342', 'bytes_total' => '3000000', 'files_uploaded' => '1', 'est_sec' => '45', ) uploadprogress-2.0.2/tests/uploadprogress_get_info_variation002.phpt0000644000076500000240000000046514125450113025230 0ustar ramseystaff--TEST-- uploadprogress_get_info - When empty template and identifier --SKIPIF-- 'file005', 'fieldname' => 'uploadFile', 'filename' => 'a value with spaces in it', 'time_start' => '1579893044', 'time_last' => '30', 'speed_average' => '300', 'speed_last' => '300', 'bytes_uploaded' => '1592342', 'bytes_total' => '3000000', 'files_uploaded' => '1', 'est_sec' => '45', ) uploadprogress-2.0.2/config.m40000644000076500000240000000065014125450113015453 0ustar ramseystaffPHP_ARG_ENABLE([uploadprogress], [whether to enable uploadprogress functions], [AS_HELP_STRING([--enable-uploadprogress], [Enable uploadprogress support [default=yes]])]) if test "$PHP_UPLOADPROGRESS" != "no"; then PHP_SUBST(UPLOADPROGRESS_SHARED_LIBADD) AC_DEFINE(HAVE_UPLOADPROGRESS, 1, [Whether the uploadprogress extension is enabled]) PHP_NEW_EXTENSION(uploadprogress, uploadprogress.c , $ext_shared) fi uploadprogress-2.0.2/config.w320000644000076500000240000000037214125450113015547 0ustar ramseystaff// vim:ft=javascript ARG_ENABLE('uploadprogress' , 'The Upload Progress extension', 'no'); if (PHP_UPLOADPROGRESS != "no") { EXTENSION("uploadprogress", "uploadprogress.c"); AC_DEFINE('HAVE_UPLOADPROGRESS', 1, 'The Upload Progress extension'); } uploadprogress-2.0.2/php_uploadprogress.h0000644000076500000240000000642414125450113020042 0ustar ramseystaff/* +----------------------------------------------------------------------+ | Uploadprogress extension | +----------------------------------------------------------------------+ | Copyright (c) The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Christian Stocker (chregu@liip.ch) | | Derived from: Doru Petrescu (pdoru-php-upm@kappa.ro)    | | http://pdoru.from.ro/upload-progress-meter/ | +----------------------------------------------------------------------+ */ #ifndef PHP_UPLOADPROGRESS_H #define PHP_UPLOADPROGRESS_H #ifdef __cplusplus extern "C" { #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #ifdef HAVE_UPLOADPROGRESS #include #include #include #include #ifdef __cplusplus } // extern "C" #endif #ifdef __cplusplus extern "C" { #endif extern zend_module_entry uploadprogress_module_entry; #define phpext_uploadprogress_ptr &uploadprogress_module_entry #define PHP_UPLOADPROGRESS_VERSION "2.0.2" #ifdef PHP_WIN32 #define PHP_UPLOADPROGRESS_API __declspec(dllexport) #else #define PHP_UPLOADPROGRESS_API #endif typedef struct _uploadprogress_data { /* Full filename, or just the identifier, depending on method */ char *identifier; /* Full filename, or just the identifier, depending on method */ char *identifier_tmp; /* Raw string of the UPLOAD_IDENTIFIER */ char *upload_id; /* Full filename of temporary data file */ char *data_filename; /* Name of form field for current file being uploaded */ char *fieldname; /* Filename of the uploaded file */ char *filename; time_t time_start; time_t time_last; unsigned int speed_average; unsigned int speed_last; unsigned long bytes_uploaded; unsigned long bytes_total; unsigned int files_uploaded; int est_sec; } uploadprogress_data; static char *uploadprogress_mk_filename(char *identifier, char *template); static void uploadprogress_file_php_get_info(char *, zval *); static void uploadprogress_file_php_get_contents(char *, char *, long, zval *); PHP_MINIT_FUNCTION(uploadprogress); PHP_MSHUTDOWN_FUNCTION(uploadprogress); PHP_RINIT_FUNCTION(uploadprogress); PHP_RSHUTDOWN_FUNCTION(uploadprogress); PHP_MINFO_FUNCTION(uploadprogress); #ifdef ZTS #include "TSRM.h" #endif PHP_FUNCTION(uploadprogress_get_info); PHP_FUNCTION(uploadprogress_get_contents); #ifdef __cplusplus } // extern "C" #endif #endif /* PHP_HAVE_UPLOADPROGRESS */ #endif /* PHP_UPLOADPROGRESS_H */ uploadprogress-2.0.2/uploadprogress.c0000644000076500000240000003573014125450113017170 0ustar ramseystaff/* +----------------------------------------------------------------------+ | Uploadprogress extension | +----------------------------------------------------------------------+ | Copyright (c) The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Christian Stocker (chregu@liip.ch) | | Derived from: Doru Petrescu (pdoru-php-upm@kappa.ro)    | | http://pdoru.from.ro/upload-progress-meter/ | +----------------------------------------------------------------------+ */ #include "php_uploadprogress.h" #include "rfc1867.h" #if HAVE_UPLOADPROGRESS #ifdef P_tmpdir #define TMPDIR P_tmpdir #else #define TMPDIR "/tmp" #endif /* {{{ argument information */ #if PHP_VERSION_ID < 80000 #include "uploadprogress_legacy_arginfo.h" #else #include "uploadprogress_arginfo.h" #endif PHP_INI_BEGIN() PHP_INI_ENTRY("uploadprogress.file.filename_template", TMPDIR"/upt_%s.txt", PHP_INI_ALL, NULL) PHP_INI_ENTRY("uploadprogress.file.contents_template", TMPDIR"/upload_contents_%s", PHP_INI_ALL, NULL) PHP_INI_ENTRY("uploadprogress.get_contents", "0", PHP_INI_ALL, NULL) PHP_INI_END() /* {{{ uploadprogress_module_entry */ zend_module_entry uploadprogress_module_entry = { STANDARD_MODULE_HEADER, "uploadprogress", ext_functions, PHP_MINIT(uploadprogress), PHP_MSHUTDOWN(uploadprogress), PHP_RINIT(uploadprogress), PHP_RSHUTDOWN(uploadprogress), PHP_MINFO(uploadprogress), PHP_UPLOADPROGRESS_VERSION, STANDARD_MODULE_PROPERTIES }; /* }}} */ #ifdef COMPILE_DL_UPLOADPROGRESS ZEND_GET_MODULE(uploadprogress) #endif PHPAPI extern int (*php_rfc1867_callback)(unsigned int , void *, void **); /* {{{ uploadprogress_php_rfc1867_file */ static int uploadprogress_php_rfc1867_file(unsigned int event, void *event_data, void **data) { uploadprogress_data *progress; int read_bytes; zend_bool get_contents = INI_BOOL("uploadprogress.get_contents"); progress = *data; if (event == MULTIPART_EVENT_START) { multipart_event_start *e_data; e_data = (multipart_event_start*) event_data; progress = emalloc(sizeof(uploadprogress_data)); progress->upload_id = NULL; progress->fieldname = NULL; progress->data_filename = NULL; progress->bytes_total = e_data->content_length; progress->identifier = NULL; progress->identifier_tmp = NULL; progress->time_start = time(NULL); *data = progress; } else if (event == MULTIPART_EVENT_FORMDATA) { multipart_event_formdata *e_data; e_data = (multipart_event_formdata*) event_data; read_bytes = e_data->post_bytes_processed; if (e_data->newlength) { *e_data->newlength = e_data->length; } if (strcmp(e_data->name, "UPLOAD_IDENTIFIER") == 0) { char *template = INI_STR("uploadprogress.file.filename_template"); if (strcmp(template, "") == 0) { return FAILURE; } progress->upload_id = emalloc(strlen(*e_data->value) + 1); strcpy(progress->upload_id, *e_data->value); progress->time_last = time(NULL); progress->speed_average = 0; progress->speed_last = 0; progress->bytes_uploaded = read_bytes; progress->files_uploaded = 0; progress->est_sec = 0; progress->identifier = uploadprogress_mk_filename(progress->upload_id, template); progress->identifier_tmp = emalloc(strlen( progress->identifier) + 4); sprintf(progress->identifier_tmp, "%s.wr", progress->identifier); } } if (progress->identifier) { time_t crtime = time(NULL); int d, dt, ds; if (event == MULTIPART_EVENT_FILE_START) { char *data_identifier; multipart_event_file_start *e_data; e_data = (multipart_event_file_start*) event_data; read_bytes = e_data->post_bytes_processed; progress->fieldname = e_data->name; progress->filename = *e_data->filename; data_identifier = emalloc(strlen(progress->upload_id) + strlen(progress->fieldname) + 2); sprintf(data_identifier, "%s-%s", progress->upload_id, progress->fieldname); if (get_contents) { char *data_template = INI_STR("uploadprogress.file.contents_template"); if (strcmp(data_template, "") == 0) { return FAILURE; } progress->data_filename = uploadprogress_mk_filename(data_identifier, data_template); } if (data_identifier) { efree(data_identifier); } } else if (event == MULTIPART_EVENT_FILE_DATA) { multipart_event_file_data *e_data; e_data = (multipart_event_file_data*) event_data; read_bytes = e_data->post_bytes_processed; if (get_contents) { php_stream *stream; int options = 0; stream = php_stream_open_wrapper(progress->data_filename, "ab", options, NULL); if (stream) { php_stream_write(stream, e_data->data, e_data->length); } php_stream_close(stream); } } else if (event == MULTIPART_EVENT_FILE_END) { multipart_event_file_end *e_data; e_data = (multipart_event_file_end*) event_data; read_bytes = e_data->post_bytes_processed; progress->files_uploaded++; if (get_contents) { VCWD_UNLINK(progress->data_filename); efree(progress->data_filename); } } else if (event == MULTIPART_EVENT_END) { VCWD_UNLINK(progress->identifier); efree(progress->upload_id); efree(progress->identifier); efree(progress->identifier_tmp); efree(progress); return SUCCESS; } /* Just in case we encounter a fracture in time. */ if (progress->time_last > crtime) { progress->time_last = crtime; } dt = crtime - progress->time_last; ds = crtime - progress->time_start; d = read_bytes - progress->bytes_uploaded; if (dt) { progress->speed_last = d/dt; progress->time_last = crtime; progress->bytes_uploaded = read_bytes; progress->speed_average = ds ? read_bytes / ds : 0; progress->est_sec = progress->speed_average ? (progress->bytes_total - read_bytes) / progress->speed_average : -1; } if (dt || event >= MULTIPART_EVENT_FILE_END) { FILE *F; F = VCWD_FOPEN(progress->identifier_tmp, "wb"); if (F) { fprintf(F, "upload_id=%s\nfieldname=%s\nfilename=%s\ntime_start=%ld\n" "time_last=%ld\nspeed_average=%u\nspeed_last=%u\n" "bytes_uploaded=%lu\nbytes_total=%lu\n" "files_uploaded=%u\nest_sec=%d\n", progress->upload_id, progress->fieldname, progress->filename, progress->time_start, progress->time_last, progress->speed_average, progress->speed_last, progress->bytes_uploaded, progress->bytes_total, progress->files_uploaded, progress->est_sec); fclose(F); VCWD_RENAME(progress->identifier_tmp, progress->identifier); } } } if (event == MULTIPART_EVENT_END ) { if (progress->identifier) { efree(progress->identifier); } if (progress->upload_id) { efree(progress->upload_id); } if (progress->identifier_tmp) { efree(progress->identifier_tmp); } if (get_contents && progress->data_filename) { efree(progress->data_filename); } efree(progress); } return SUCCESS; } /* }}} */ /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(uploadprogress) { REGISTER_INI_ENTRIES(); php_rfc1867_callback = uploadprogress_php_rfc1867_file; return SUCCESS; } /* }}} */ /* {{{ PHP_MSHUTDOWN_FUNCTION */ PHP_MSHUTDOWN_FUNCTION(uploadprogress) { UNREGISTER_INI_ENTRIES(); php_rfc1867_callback = NULL; return SUCCESS; } /* }}} */ /* {{{ PHP_RINIT_FUNCTION */ PHP_RINIT_FUNCTION(uploadprogress) { return SUCCESS; } /* }}} */ /* {{{ PHP_RSHUTDOWN_FUNCTION */ PHP_RSHUTDOWN_FUNCTION(uploadprogress) { return SUCCESS; } /* }}} */ /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION(uploadprogress) { php_info_print_table_start(); php_info_print_table_header(2, "uploadprogress support", "enabled"); php_info_print_table_row(2, "Version", PHP_UPLOADPROGRESS_VERSION); php_info_print_table_end(); DISPLAY_INI_ENTRIES(); } /* }}} */ /* {{{ proto array uploadprogress_get_info(string identifier) */ PHP_FUNCTION(uploadprogress_get_info) { char *id; size_t id_lg; if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &id, &id_lg) == FAILURE) { return; } uploadprogress_file_php_get_info(id, return_value); return; } /* }}} */ /* {{{ proto string uploadprogress_get_contents(string identifier, string fieldname[, int maxlen]) */ PHP_FUNCTION(uploadprogress_get_contents) { char *id, *fieldname; size_t id_len, fieldname_len; long maxlen = PHP_STREAM_COPY_ALL; zend_bool get_contents = INI_BOOL("uploadprogress.get_contents"); if (!get_contents) { php_error_docref(NULL, E_WARNING, "this function is disabled; set uploadprogress.get_contents = On to enable it"); RETURN_FALSE; return; } if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|l", &id, &id_len, &fieldname, &fieldname_len, &maxlen) == FAILURE) { return; } if (ZEND_NUM_ARGS() == 3 && maxlen < 0) { php_error_docref(NULL, E_WARNING, "length must be greater than or equal to zero"); RETURN_FALSE; } uploadprogress_file_php_get_contents(id, fieldname, maxlen, return_value); return; } /* }}} */ /* {{{ uploadprogress_mk_filename */ static char *uploadprogress_mk_filename(char *identifier, char *template) { char *x; char *filename; filename = emalloc(strlen(template) + strlen(identifier) + 3); x = strstr(template, "%s"); if (x == NULL) { sprintf(filename, "%s/%s", template, identifier); } else { strcpy(filename, template); strcpy(filename + (x - template), identifier); strcat(filename, x + 2); } return filename; } /* }}} */ /* {{{ uploadprogress_file_php_get_info */ static void uploadprogress_file_php_get_info(char *id, zval *return_value) { char s[1024]; char *filename; char *template; FILE *F; template = INI_STR("uploadprogress.file.filename_template"); if (strcmp(template, "") == 0) { return; } else { filename = uploadprogress_mk_filename(id, template); if (!filename) { return; } F = VCWD_FOPEN(filename, "rb"); if (F) { array_init(return_value); while (fgets(s, 1000, F)) { char *k, *v, *e; int index = 0; e = strchr(s, '='); if (!e) { continue; } /* Break the line into 2 parts. */ *e = 0; v = e + 1; k = s; /* Trim spaces in front of the name/value. */ while (*k && *k <= 32) { k++; } while (*v && *v <= 32) { v++; } /* Trim spaces everywhere in the name. */ for (e = k; *e; e++) { if (*e <= 32) { *e = 0; break; } } /* Trim spaces only at the end of the value. */ if (v != NULL) { for (index = strlen(v); index > 0; index--) { if (v[index] > 32) { break; } v[index] = 0; } } add_assoc_string(return_value, k, v); } fclose(F); } if (filename) { efree(filename); } return; } } /* }}} */ /* {{{ uploadprogress_file_php_get_contents */ static void uploadprogress_file_php_get_contents(char *id, char *fieldname, long maxlen, zval *return_value) { char *filename, *template, *data_identifier; zend_string *contents; int options = 0; size_t len; php_stream *stream; template = INI_STR("uploadprogress.file.contents_template"); if (strcmp(template, "") == 0) { return; } else { data_identifier = emalloc(strlen(id) + strlen(fieldname) + 2); sprintf(data_identifier, "%s-%s", id, fieldname); filename = uploadprogress_mk_filename(data_identifier, template); if (!filename) { if (data_identifier) { efree(data_identifier); } return; } stream = php_stream_open_wrapper(filename, "rb", options, NULL); if (!stream) { if (data_identifier) { efree(data_identifier); } if (filename) { efree(filename); } RETURN_FALSE; } /* Uses mmap if possible. */ contents = php_stream_copy_to_mem(stream, maxlen, 0); if (contents) { len = contents->len; } if (contents && len > 0) { RETVAL_STR(contents); } else { RETVAL_EMPTY_STRING(); } php_stream_close(stream); if (data_identifier) { efree(data_identifier); } if (filename) { efree(filename); } return; } } /* }}} */ #endif /* HAVE_UPLOADPROGRESS */ uploadprogress-2.0.2/uploadprogress.stub.php0000644000076500000240000000036614125450113020506 0ustar ramseystaff". THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------- This software consists of voluntary contributions made by many individuals on behalf of the PHP Group. The PHP Group can be contacted via Email at group@php.net. For more information on the PHP Group and the PHP project, please see . PHP includes the Zend Engine, freely available at . uploadprogress-2.0.2/README.md0000644000076500000240000001520214125450113015222 0ustar ramseystaff# uploadprogress A PHP extension to track progress of a file upload, including details on the speed of the upload, estimated time remaining, and access to the contents of the file as it is being uploaded. ## Requirements The uploadprogress extension works on PHP 7.2+ and PHP 8. It works with [Apache HTTP Server][] using [mod_php][], as well as [Apache HTTP Server][], [nginx][], and [Caddy][] through [PHP-FPM][]. It might work on other web servers; let us know where you're using it. ## Example Check out the [examples][] directory for a working example that you can run on your local machine. ## Installation Install uploadprogress with `pecl`: ``` pecl install uploadprogress ``` If it is not automatically added to your `php.ini` file by the `pecl` command, you will need to update `php.ini` by adding the following line: ``` ini extension=uploadprogress ``` ## Documentation In forms for which you wish to track a file upload using uploadprogress, you must include a field named `UPLOAD_IDENTIFIER`. The value of the `UPLOAD_IDENTIFIER` field may be any string. We recommend a random, unique string per upload. This extension will use this value to keep track of the upload, and you may query the extension using this identifier to check the progress of the upload. For example, you might choose to define the `UPLOAD_IDENTIFIER` field as such: ``` html ``` The uploadprogress extension provides two functions: `uploadprogress_get_info()` and `uploadprogress_get_contents()`. While a file is uploading, you may call these functions from a different script to check on the progress of the uploading file, providing the same identifier used as the `UPLOAD_IDENTIFIER`. For example, you might make an HTTP `GET` request to `/check-progress.php?identifier=some_identifier&fieldName=the_file_upload_form_field_name`. The contents of `check-progress.php` might contain code like this: ``` php $identifier = filter_input(INPUT_GET, 'identifier', FILTER_SANITIZE_STRING); $fieldName = filter_input(INPUT_GET, 'fieldName', FILTER_SANITIZE_STRING); $info = uploadprogress_get_info($identifier); $contents = uploadprogress_get_contents($identifier, $fieldName); ``` ### php.ini Settings * `uploadprogress.file.filename_template`: Set the path and pattern to which the *info* file should be written. This is where we will store the data about the uploaded file, while it is being uploaded. You may set it to a directory, or you may optionally use a filename pattern. It defaults to `sys_get_temp_dir() . '/upt_%s.txt'`. The `%s` is replaced with the value of `UPLOAD_IDENTIFIER`. * `uploadprogress.file.contents_template`: Set the path and pattern to which the *contents* of the uploaded file should be written. This allows us to read the contents of the file, while it is still being uploaded. You may set it to a directory, or you may optionally use a filename pattern. It defaults to `sys_get_temp_dir() . '/upload_contents_%s'`. The `%s` is replaced with the value of `UPLOAD_IDENTIFIER` combined with the name of the file upload form field. * `uploadprogress.get_contents`: Set to "On" to enable the ability to read a file's contents while it is still uploading. Defaults to "Off." **NOTE:** The paths for these INI settings must be *absolute* paths. Relative paths will not work. #### Example php.ini ``` ini extension=uploadprogress uploadprogress.get_contents=On uploadprogress.file.filename_template=/tmp/upt_%s.txt uploadprogress.file.contents_template=/tmp/upload_contents_%s ``` ### uploadprogress_get_info ``` php uploadprogress_get_info ( string $identifier ) : array ``` The `$identifier` is the value of the form field named `UPLOAD_IDENTIFIER`. This returns an associative array with the following keys: * `upload_id` - The value of `UPLOAD_IDENTIFIER`. * `fieldname` - The name of the file upload form field for this file upload. * `filename` - The original name of the file being uploaded. * `time_start` - The Unix timestamp at which the upload began. * `time_last` - The Unix timestamp at which this information was last updated. * `speed_average` - The average upload speed, in bytes. * `speed_last` - The last speed calculation, in bytes. * `bytes_uploaded` - The number of bytes uploaded so far. * `bytes_total` - The total number of bytes to be upload. * `files_uploaded` - The total number of files uploaded so far. * `est_sec` - The estimated number of seconds remaining until the upload is complete. ### uploadprogress_get_contents ``` php uploadprogress_get_contents ( string $identifier , string $fieldName [, int $maxLength ] ) : string ``` The `$identifier` is the value of the form field named `UPLOAD_IDENTIFIER`. The `$fieldName` is the value of the file upload form field name. The `$maxLength` is an optional number of bytes to read, if you wish to read only the first `$maxLength` bytes of the uploading file. Otherwise, all bytes currently uploaded will be read. This returns a string of all the bytes currently uploaded for the uploading file. ## Contributing Your contributions and bug reports are highly appreciated. To contribute, fork and create a pull request. To report a bug use the [PHP Bug Tracking System](https://bugs.php.net/report.php?package=uploadprogress). ### Building on *nix systems To compile this extension, execute the following steps: ```shell phpize ./configure --enable-uploadprogress make ``` ### Building on Windows The extension provides the VisualStudio V6 project file: uploadprogress.dsp To compile the extension you open this file using VisualStudio, select the apropriate configuration for your installation (either "Release_TS" or "Debug_TS") and create `php_uploadprogress.dll`. After successfull compilation you have to copy the newly created `php_uploadprogress.dll` to the PHP extension directory (default: `C:\PHP\extensions`). ### Testing You may now run the tests with the following (on Windows, use `nmake`): ```shell make test TESTS="-n --show-diff tests" ``` For application testing, you can now load the extension using a php.ini directive ``` ini extension=uploadprogress ``` The extension should now be available, which you can test using the `extension_loaded()` function: ``` php if (extension_loaded('uploadprogress')) { echo "uploadprogress loaded :)"; } else { echo "something is wrong :("; } ``` The extension will also add its own block to the output of `phpinfo();`. [Apache HTTP Server]: https://httpd.apache.org [mod_php]: https://www.php.net/manual/en/install.unix.apache2.php [php-fpm]: https://www.php.net/fpm [examples]: ./examples [nginx]: https://nginx.org [caddy]: https://caddyserver.com