You are here

function _s3fs_image_style_deliver in S3 File System 7

Same name and namespace in other branches
  1. 7.3 s3fs.module \_s3fs_image_style_deliver()
  2. 7.2 s3fs.module \_s3fs_image_style_deliver()

Generates an image derivative in S3.

This is a re-write of the core Image module's image_style_deliver() function. It exists to improve the performance of serving newly-created image derivatives from S3.

Note to future maintainers: this function is variatic. It accepts two fixed arguments: $style and $scheme, and any number of further arguments, which represent the path to the file in S3 (split on the slahses).

1 string reference to '_s3fs_image_style_deliver'
s3fs_menu in ./s3fs.module
Implements hook_menu().

File

./s3fs.module, line 138
Sets up the S3fsStreamWrapper class to be used as a Drupal file system.

Code

function _s3fs_image_style_deliver() {

  // Drupal's black magic calls this function with the image style as arg0,
  // the scheme as arg1, and the full path to the filename split across arg2+.
  // So we need to use PHP's version of variatic functions to get the complete
  // filename.
  $args = func_get_args();
  $style = array_shift($args);
  $scheme = array_shift($args);
  $filename = implode('/', $args);
  $valid = !empty($style);
  if (!variable_get('image_allow_insecure_derivatives', FALSE) || strpos(ltrim($filename, '\\/'), 'styles/') === 0) {
    $valid = $valid && isset($_GET[IMAGE_DERIVATIVE_TOKEN]) && $_GET[IMAGE_DERIVATIVE_TOKEN] === image_style_path_token($style['name'], "{$scheme}://{$filename}");
  }
  if (!$valid) {
    return MENU_ACCESS_DENIED;
  }
  $image_uri = "{$scheme}://{$filename}";
  $derivative_uri = image_style_path($style['name'], $image_uri);

  // Confirm that the original source image exists before trying to process it.
  if (!is_file($image_uri)) {
    watchdog('s3fs', 'Source image at %source_image_path not found while trying to generate derivative image at %derivative_path.', array(
      '%source_image_path' => $image_uri,
      '%derivative_path' => $derivative_uri,
    ));
    return MENU_NOT_FOUND;
  }

  // Don't start generating the image if the derivative already exists or if
  // generation is in progress in another thread.
  $lock_name = '_s3fs_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('Content-Type', 'text/html; charset=utf-8');
      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);
  if (!$success) {

    // If we successfully generate the derivative, wait until S3 acknolowedges
    // its existence. Otherwise, redirecting to it may cause a 403 error.
    $success = image_style_create_derivative($style, $image_uri, $derivative_uri) && file_stream_wrapper_get_instance_by_scheme('s3')
      ->waitUntilFileExists($derivative_uri);
  }
  if (!empty($lock_acquired)) {
    lock_release($lock_name);
  }
  if ($success) {

    // Perform a 302 Redirect to the new image derivative in S3.
    drupal_goto(file_create_url($derivative_uri));
  }
  else {
    watchdog('S3 File System', 'Unable to generate an image derivative at %path.', array(
      '%path' => $derivative_uri,
    ));
    drupal_add_http_header('Status', '500 Internal Server Error');
    drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
    print t('Error generating image.');
    drupal_exit();
  }
}