Skip to content
Browse files

* New working version. Now using an HTTP header to recover the upload

  progress info.
  • Loading branch information...
1 parent c160f3a commit 62e59c7392a1b1533c3d20dcba427f8f3d7b0341 @perusio committed Oct 21, 2012
Showing with 170 additions and 161 deletions.
  1. +7 −12 README.md
  2. +10 −10 filefield_nginx_progress.info
  3. +8 −11 filefield_nginx_progress.install
  4. +145 −128 filefield_nginx_progress.module
View
19 README.md
@@ -76,8 +76,8 @@ The configuration consists in three parts:
## that it report the progress of the upload through a GET
## request. But the drupal form element makes use of clean
## URLs in the POST.
- location ~ (.*)/x-progress-id:(\w*) {
- rewrite ^(.*)/x-progress-id:(\w*) $1?X-Progress-ID=$2;
+ location ~ (?<upload_form_uri>.*)/x-progress-id:(?<upload_id>\d*) {
+ rewrite ^ $upload_form_uri?X-Progress-ID=$upload_id;
}
## Now the above rewrite must be matched by a location that
@@ -89,7 +89,10 @@ The configuration consists in three parts:
3. Now on **each** location where you want the upload progress bar
to work you must enable it like on this example.
-
+
+ N.B. The `track_uploads` directive must be the **last** in a given
+ location.
+
location = /index.php {
include fastcgi.conf;
fastcgi_pass phpcgi;
@@ -103,18 +106,10 @@ The configuration consists in three parts:
service nginx reload
5. Done.
-
## TODO
- 1. Use the `X-Progress-ID` header instead of issuing a GET request
- and relying on the above rewrite. It will make the configuration
- easier to understand and faster. This development occurs in the
- 7.x-2.x branch. This implies a divergence from the way the
- progress bar support is implemented in the file module (core).
-
- 2. Make the 7.x version work correctly. Currently there are some
- problems with it as can be seen on the issue queue.
+ 1. Suggest a configuration and verify it using a `hook_requirements()`.
## Credits & Acknowledgments
View
20 filefield_nginx_progress.info
@@ -1,13 +1,13 @@
-; $Id;
-name = FileField Nginx Progress
-description = Adds upload progress functionality for Nginx webservers
-
-files[] = filefield_nginx_progress.install
-files[] = filefield_nginx_progress.module
-
-dependencies[] = file
-package = CCK
-core = 7.x
+; $Id;
+name = FileField Nginx Progress
+description = Adds upload progress functionality for Nginx
+
+files[] = filefield_nginx_progress.install
+files[] = filefield_nginx_progress.module
+
+dependencies[] = file
+package = CCK
+core = 7.x
; Information added by drupal.org packaging script on 2011-02-25
version = "7.x-1.x-dev"
View
19 filefield_nginx_progress.install
@@ -1,16 +1,15 @@
<?php
/**
- * @file filefield_nginx_progress.install
- *
+ * @file filefield_nginx_progress.install
+ *
* @brief Install file for the filefield_nginx_progress module. The module
* implements a upload progress bar for filefield.
- *
+ *
*/
-
-/**
- * Implementation of hook_install().
+/**
+ * Implementation of hook_install().
*
*/
function filefield_nginx_progress_install() {
@@ -59,12 +58,10 @@ function filefield_nginx_progress_requirements($phase) {
return $requirements;
} // filefield_nginx_progress_requirements
-
-
-/**
- *
+/**
+ *
* Set the upload progress in the status report page.
- *
+ *
*/
function filefield_nginx_progress_update_7100() {
db_update('system')
View
273 filefield_nginx_progress.module
@@ -1,128 +1,145 @@
-<?php
-
-/**
- * @file
- * Adds upload progress functionality to FileFields on the nginx webserver.
- */
-
-/**
- * Implementation of hook_menu().
- */
-function filefield_nginx_progress_menu() {
- $items = array();
-
- $items['filefield_nginx_progress'] = array(
- 'page callback' => 'filefield_nginx_progress_ajax',
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
-
- return $items;
-}
-
-/**
- * Menu callback for nginx upload progress.
- */
-function filefield_nginx_progress_ajax($key) {
- $progress = array(
- 'message' => t('Starting upload...'),
- 'percentage' => -1,
- );
-
- $status = nginx_progress_fetch($key);
- if ($status['state'] == 'uploading') {
- $progress['message'] = t('Uploading... (@current of @total)', array('@current' => format_size($status['received']), '@total' => format_size($status['size'])));
- $progress['percentage'] = round(100 * $status['received'] / $status['size']);
- }
-
- drupal_json_output($progress);
-}
-
-/**
- * Implementation of hook_element_info().
- */
-function filefield_nginx_progress_element_info() {
- $elements = array();
-
- foreach (module_invoke_all('filefield_nginx_progress_widgets') as $widget) {
- $elements[$widget]['#process'] = array('filefield_nginx_progress_element_process');
- }
- return $elements;
-}
-
-/**
- * Implementation of hook_filefield_nginx_progress_widgets().
- *
- * This returns a list of widgets that are compatible with FileField Nginx Progress.
- */
-function filefield_nginx_progress_filefield_nginx_progress_widgets() {
- return array('managed_file');
-}
-
-/**
- * A #process callback to extend the file_widget element type.
- *
- * To get the field working with nginx upload progress, we need to enable the progress bar
- * and modify the ahah paths to work with the nginx redirection.
- */
-function filefield_nginx_progress_element_process($element, &$form_state, $form) {
- // Generate upload progress key
- $upload_progress_key = mt_rand();
-
- // Nginx really wants us to send a get value, but form_expand_ahah doesn't
- // allow query strings in paths. The work around is to add the progress id
- // into the path and to rewrite at the nginx level to the required url.
- $element['upload_button']['#ajax']['path'] .= '/x-progress-id:' . $upload_progress_key;
-
- // Add the upload key to the form, in a manner compatible with the existing
- // javascript
- $element['UPLOAD_IDENTIFIER'] = array(
- '#type' => 'hidden',
- '#value' => $upload_progress_key,
- '#attributes' => array('class' => array('file-progress')),
- );
-
- // Unset this as a precaution in the unlikely event that apc upload progress
- // is enabled in php.ini
- unset($element['APC_UPLOAD_PROGRESS']);
-
- // Enable the progress bar
- $element['upload_button']['#ajax']['progress']['type'] = 'bar';
-
- // Modify the upload progress callback to use our own menu callback.
- $element['upload_button']['#ajax']['progress']['path'] = 'filefield_nginx_progress/' . $upload_progress_key;
-
- return $element;
-}
-
-/**
- * Fetch the upload progress from nginx using the X-Progress-ID parameter
- *
- * Since the javascript returned by the progress tracking in nginx is not
- * compatible with the ahah progress bar, we need to get drupal to issue an
- * http request and then parse the response.
- *
- */
-function nginx_progress_fetch($key) {
- // Find root url of server
- $domain = $_SERVER['HTTP_HOST'];
- $proto = !empty($_SERVER['HTTPS']) ? 'https://' : 'http://';
- $base_url = $proto . $domain;
-
- $url = url($base_url . '/progress', array('query' => array('X-Progress-ID' => $key), 'absolute' => TRUE, 'external' => TRUE));
-
- $response = drupal_http_request($url);
- $status = array();
- // strip the extraneous parts out leaving a comma delimited list.
- if (preg_match("/\{(.*)\}/", $response->data, $matches) ) {
- $items = explode(',', $matches[1]);
- foreach ($items as $item) {
- $array = explode(':', $item);
- // strip quotes and spaces from key & value pair
- $key = trim($array[0], "' ");
- $value = trim($array[1], "' ");
- $status[$key] = $value;
- }
- }
- return $status;
-}
+<?php
+/**
+ * @file filefield_nginx_progress.module
+ * @author Ben Osman <dev@smoothify.com>
+ * António P. P. Almeida <appa@perusio.net>
+ * @date Sun Oct 21 14:31:03 2012
+ *
+ * @brief Adds upload progress bar support for Nginx based on the
+ * 3rd party Nginx Upload Progress module.
+ * https://github.com/masterzen/nginx-upload-progress-module.
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function filefield_nginx_progress_menu() {
+ $items = array();
+
+ $items['filefield_nginx_progress'] = array(
+ 'page callback' => 'filefield_nginx_progress_ajax',
+ 'access arguments' => array('access content'),
+ 'type' => MENU_CALLBACK,
+ );
+
+ return $items;
+} // filefield_nginx_progress_menu
+
+/**
+ * Menu callback for nginx upload progress.
+ *
+ * @param integer $key
+ * The upload element ID to be used by the nginx progress upload module to
+ * identify a particular upload.
+ *
+ * @return string
+ * The response given by the Nginx module in JSON.
+ *
+ */
+function filefield_nginx_progress_ajax($key) {
+ $progress = array(
+ 'message' => t('Starting upload...'),
+ 'percentage' => -1,
+ );
+ // Get the status.
+ $status = nginx_progress_fetch($key);
+ if ($status['state'] == 'uploading') {
+ // We set a message only when the upload is in progress.
+ $progress['message'] = t('Uploading... (@current of @total)', array('@current' => format_size($status['received']), '@total' => format_size($status['size'])));
+ $progress['percentage'] = round(100 * $status['received'] / $status['size']);
+ }
+ // Output as JSON so that the JS progress bar can use it.
+ drupal_json_output($progress);
+} // filefield_nginx_progress_ajax
+
+/**
+ * Implements hook_element_info().
+ */
+function filefield_nginx_progress_element_info() {
+ $elements = array();
+
+ foreach (module_invoke_all('filefield_nginx_progress_widgets') as $widget) {
+ $elements[$widget]['#process'] = array('filefield_nginx_progress_element_process');
+ }
+ return $elements;
+} // filefield_nginx_progress_element_info
+
+/**
+ * Implements hook_filefield_nginx_progress_widgets().
+ *
+ * This returns a list of widgets that are compatible with FileField Nginx Progress.
+ */
+function filefield_nginx_progress_filefield_nginx_progress_widgets() {
+ return array('managed_file');
+}
+
+/**
+ * A #process callback to extend the file_widget element type.
+ *
+ * To get the field working with nginx upload progress, we need to enable the
+ * progress bar and modify the ahah paths to work with the nginx redirection.
+ *
+ */
+function filefield_nginx_progress_element_process($element, &$form_state, $form) {
+ // Generate a random upload progress key.
+ $upload_progress_key = mt_rand();
+
+ // Nginx really wants us to send a get value, but form_expand_ahah doesn't
+ // allow query strings in paths. The work around is to add the progress id
+ // into the path and to rewrite at the nginx level to the required url.
+ $element['upload_button']['#ajax']['path'] .= '/x-progress-id:' . $upload_progress_key;
+
+ // Add the upload key to the form, in a manner compatible with the existing
+ // javascript
+ $element['UPLOAD_IDENTIFIER'] = array(
+ '#type' => 'hidden',
+ '#value' => $upload_progress_key,
+ '#attributes' => array('class' => array('file-progress')),
+ );
+
+ // Unset this as a precaution in the unlikely event that apc upload progress
+ // is enabled in php.ini.
+ if (isset($element['APC_UPLOAD_PROGRESS'])) {
+ unset($element['APC_UPLOAD_PROGRESS']);
+ }
+
+ // Enable the progress bar.
+ $element['upload_button']['#ajax']['progress']['type'] = 'bar';
+
+ // Modify the upload progress callback to use our own menu callback.
+ $element['upload_button']['#ajax']['progress']['path'] = 'filefield_nginx_progress/' . $upload_progress_key;
+
+ return $element;
+} // filefield_nginx_progress_element_process
+
+/**
+ *
+ * Fetch the upload progress from nginx using the X-Progress-ID header.
+ *
+ * @param integer $key
+ * The key generated when processing the upload button element.
+ * @return array
+ * An array with the status information for the progress bar.
+ */
+function nginx_progress_fetch($key) {
+ global $base_url, $base_path;
+
+ $url = url($base_url . $base_path. 'progress', array('absolute' => TRUE, 'external' => TRUE));
+ // We get the response using an header instead of a query string. This
+ // mimics what is given as example on the module README.
+ $response = drupal_http_request($url, array('headers' => array('X-Progress-ID' => $key)));
+
+ $status = array();
+ // Strip the extraneous parts out leaving a comma delimited list.
+ if (preg_match("/\{(.*)\}/", $response->data, $matches) ) {
+ $items = explode(',', $matches[1]);
+ foreach ($items as $item) {
+ $response_array = explode(':', $item);
+ // Strip quotes and spaces from key-value pair.
+ $key = trim($response_array[0], "' ");
+ $value = trim($response_array[1], "' ");
+ $status[$key] = $value;
+ }
+ }
+ return $status;
+} // nginx_progress_fetch

0 comments on commit 62e59c7

Please sign in to comment.
Something went wrong with that request. Please try again.