diff --git a/ais.htaccess.example b/ais.htaccess.example index 346b45a..1926de0 100644 --- a/ais.htaccess.example +++ b/ais.htaccess.example @@ -108,7 +108,7 @@ DirectoryIndex index.php index.html index.htm RewriteCond %{REQUEST_URI} ^(.+)/files/styles/adaptive/(.+)$ RewriteCond %{REQUEST_URI} !/modules/image/sample.png RewriteCond %{HTTP_COOKIE} ais=([a-z0-9-_]+) - RewriteRule ^(.+)/files/styles/adaptive/(.+)$ $1/files/styles/%1/$2 [R=302,L] + RewriteRule ^(.+)/files/styles/adaptive/(.+)$ /images/adaptive/%1/$2 [R=302,L] # Pass all requests not referring directly to files in the filesystem to # index.php. Clean URLs are handled in drupal_environment_initialize(). diff --git a/ais.htaccess.patch b/ais.htaccess.patch index 70e4134..bd8a4ec 100644 --- a/ais.htaccess.patch +++ b/ais.htaccess.patch @@ -9,7 +9,7 @@ + RewriteCond %{REQUEST_URI} ^(.+)/files/styles/adaptive/(.+)$ + RewriteCond %{REQUEST_URI} !/modules/image/sample.png + RewriteCond %{HTTP_COOKIE} ais=([a-z0-9-_]+) -+ RewriteRule ^(.+)/files/styles/adaptive/(.+)$ $1/files/styles/%1/$2 [R=302,L] ++ RewriteRule ^(.+)/files/styles/adaptive/(.+)$ /images/adaptive/%1/$2 [R=302,L] + # Pass all requests not referring directly to files in the filesystem to # index.php. Clean URLs are handled in drupal_environment_initialize(). diff --git a/ais.module b/ais.module index 5b409aa..13a1e85 100644 --- a/ais.module +++ b/ais.module @@ -69,12 +69,112 @@ function ais_menu() { 'page arguments' => array('ais_admin_settings'), 'access arguments' => array('administer ais'), 'file' => 'ais.admin.inc', + 'type' => MENU_CALLBACK, + ); + + $items['images/adaptive/%image_style'] = array( + 'title' => "Adaptive Image", + 'page callback' => 'ais_image_style_deliver', + 'page arguments' => array(2), + 'access arguments' => array('View published content'), + 'type' => MENU_CALLBACK, ); return $items; } /** + * Menu callback; Given a style and image path, generate a derivative. + * + * After generating an image, transfer it to the requesting agent. + * Modified from image_style_deliver + * + * @param array $style + * The image style + * @param string $scheme + * File delivery scheme (public or private) + * @see image_style_deliver + */ +function ais_image_style_deliver($style, $scheme) { + $args = func_get_args(); + array_shift($args); + array_shift($args); + $target = implode('/', $args); + + $uri = variable_get('file_public_path', conf_path() . '/files') . "/" . $target; + $token = image_style_path_token($style['name'], $scheme . '://' . $target); + + // Check that the style is defined, the scheme is valid, and the image + // derivative token is valid. (Sites which require image derivatives to be + // generated without a token can set the 'image_allow_insecure_derivatives' + // variable to TRUE to bypass the latter check, but this will increase the + // site's vulnerability to denial-of-service attacks.) + $valid = !empty($style) && file_stream_wrapper_valid_scheme($scheme); + if (!variable_get('image_allow_insecure_derivatives', FALSE)) { + $valid = $valid && isset($_GET[IMAGE_DERIVATIVE_TOKEN]) && $_GET[IMAGE_DERIVATIVE_TOKEN] === image_style_path_token("adaptive", $scheme . '://' . $target); + } + if (!$valid) { + return MENU_ACCESS_DENIED; + } + + $image_uri = $scheme . '://' . $target; + $derivative_uri = image_style_path($style['name'], $image_uri); + // If using the private scheme, let other modules provide headers and + // control access to the file. + if ($scheme == 'private') { + if (file_exists($derivative_uri)) { + file_download($scheme, file_uri_target($derivative_uri)); + } + else { + $headers = module_invoke_all('file_download', $image_uri); + if (in_array(-1, $headers) || empty($headers)) { + return drupal_access_denied(); + } + if (count($headers)) { + foreach ($headers as $name => $value) { + drupal_add_http_header($name, $value); + } + } + } + } + + // Don't start generating the image if the derivative already exists or if + // generation is in progress in another thread. + $lock_name = 'ais_image_style_deliver:' . $style['name'] . ':' . drupal_hash_base64($image_uri); + if (!file_exists($derivative_uri)) { + $lock_acquired = lock_acquire($lock_name); + if (!$lock_acquired) { + // Tell client to retry again in 3 seconds. Currently no browsers are known + // to support Retry-After. + drupal_add_http_header('Status', '503 Service Unavailable'); + drupal_add_http_header('Retry-After', 3); + print t('Image generation in progress. Try again shortly.'); + drupal_exit(); + } + } + + // Try to generate the image, unless another thread just did it while we were + // acquiring the lock. + $success = file_exists($derivative_uri) || image_style_create_derivative($style, $image_uri, $derivative_uri); + + if (!empty($lock_acquired)) { + lock_release($lock_name); + } + + if ($success) { + $image = image_load($derivative_uri); + file_transfer($image->source, array('Content-Type' => $image->info['mime_type'], 'Content-Length' => $image->info['file_size'])); + } + else { + watchdog('image', 'Unable to generate the derived image located at %path.', array('%path' => $derivative_uri)); + drupal_add_http_header('Status', '500 Internal Server Error'); + print t('Error generating image.'); + drupal_exit(); + } +} + + +/** * Implements hook_image_default_styles(). */ function ais_image_default_styles() {