You are here

function s3fs_cors_sign_request in S3 File System CORS Upload 7

AJAX callback to create paramaters necessary for submitting a CORS request.

Use the filename, filesize, and filemime properies in $_POST in conjunction with the AWS key/secret in order to create the required parameters for sending a file to S3 via a CORS request.

The heavy lifting here is handled by the AWSSDK.

See also

s3fs_cors.js

1 string reference to 's3fs_cors_sign_request'
s3fs_cors_menu in ./s3fs_cors.module
Implements hook_menu().

File

./s3fs_cors.module, line 525
Allow uploading of files directly to AmazonS3 via the browser using CORS.

Code

function s3fs_cors_sign_request() {

  // Be careful with these, as they are user input.
  $filename = $_POST['filename'];
  if (module_exists('transliteration') && variable_get('transliteration_file_uploads', 1)) {
    $filename = transliteration_clean_filename($filename);
  }
  $filemime = $_POST['filemime'];
  $form_build_id = $_POST['form_build_id'];
  $field_name = $_POST['field_name'];
  $library = _s3fs_load_awssdk2_library();
  if (!$library['loaded']) {
    $error = t('Unable to load the AWS SDK for PHP. Please check you have the library installed correctly and have your S3 credentials configured.');
    header('HTTP/1.1 500 Internal Server Error');
    drupal_add_http_header('Content-Type', 'application/json; charset=utf-8');
    print json_encode(array(
      'error' => $error,
    ));
    drupal_exit();
  }

  // Retrieve the form from which this request is being made, so we can get some much-needed context.
  $form_state = form_state_defaults();
  $form = form_get_cache($form_build_id, $form_state);
  if (!$form) {

    // If $form cannot be loaded from the cache, the form_build_id in $_POST
    // must be invalid, which means that someone performed a POST request onto
    // system/ajax without actually viewing the concerned form in the browser.
    // This is likely a hacking attempt as it never happens under normal
    // circumstances, so we just do nothing.
    watchdog('ajax', 'Invalid form POST data.', array(), WATCHDOG_WARNING);
    drupal_exit();
  }

  // Get the "File directory" setting for this field, as a URI.
  $instance_info = field_info_instance($form['#entity_type'], $field_name, $form['#bundle']);
  $field_info = field_info_field($field_name);

  // "File directory" supports tokens, so we have to do the replacement ourselves.
  $file_directory = token_replace($instance_info['settings']['file_directory']);
  $file_scheme = $field_info['settings']['uri_scheme'];

  // S3 config and client initialization.
  $config = _s3fs_get_config();
  $key = $file_scheme . '_folder';
  $config['root_folder'] = isset($config[$key]) ? $config[$key] : '';
  $client = _s3fs_get_amazons3_client($config);

  // Use file_create_filename() to avoid overwriting an existing file.
  $file_directory_uri = "{$file_scheme}://{$file_directory}";
  $uri = file_create_filename($filename, $file_directory_uri);
  $acl = strpos($uri, 'private://') === FALSE ? 'public-read' : 'private';
  $s3_scheme_prefix = !empty($config['root_folder']) ? $config['root_folder'] . '/' : '';
  $s3_key = $s3_scheme_prefix . file_uri_target($uri);
  $formInputs = array(
    'acl' => $acl,
    'Content-Type' => $filemime,
    // The root folder is not part of a file's URI, so we don't add it until
    // we're setting up the final s3 parameters.
    'key' => $s3_key,
    'X-Amz-Expires' => '21600',
    'success_action_status' => '201',
  );
  $options = [
    [
      'bucket' => $config['bucket'],
    ],
    [
      'acl' => $acl,
    ],
    [
      'starts-with',
      '$key',
      $s3_key,
    ],
    [
      'starts-with',
      '$Content-Type',
      '',
    ],
    [
      'success_action_status' => '201',
    ],
    [
      'X-Amz-Expires' => '21600',
    ],
  ];

  // Allow other modules to change the options.
  drupal_alter('s3fs_cors_sign_request_options', $options);
  if (!empty($config['cache_control_header'])) {
    $options['Cache-Control'] = $config['cache_control_header'];
  }
  module_load_include('inc', 's3fs_cors', 's3fs_cors.post_object_v4.class');
  $post_object = new S3fsCorsPostObjectV4($client, $config['bucket'], $formInputs, $options);

  // Use next code with AWS SDK v3.
  // $post_object = new Aws\S3\PostObjectV4($client, $config['bucket'], $formInputs, $options);
  $data = array(
    'inputs' => $post_object
      ->getFormInputs(),
    'form' => $post_object
      ->getFormAttributes(),
    // Tell our javascript the filename that Drupal ended up giving us.
    'file_real' => drupal_basename($s3_key),
  );

  // Prepare to send JSON text to the browser.
  if (ob_get_level()) {
    ob_end_clean();
  }
  drupal_add_http_header('Content-Type', 'application/json; charset=utf-8');
  print json_encode($data);
  drupal_exit();
}