You are here

function advagg_save_data in Advanced CSS/JS Aggregation 7.2

Save data to a file.

This will use the rename operation ensuring atomic file operations.

Parameters

string $uri: A string containing the destination location. This must be a stream wrapper URI.

string $data: A string containing the contents of the file.

bool $overwrite: (optional) Bool, set to TRUE to overwrite a file.

Return value

array Empty array if not errors happened, list of errors if the write had any issues.

5 calls to advagg_save_data()
advagg_create_subfile in ./advagg.inc
Write CSS parts to disk; used when CSS selectors in one file is > 4096.
advagg_htaccess_check_generate in ./advagg.missing.inc
Generate .htaccess rules and place them in advagg dir.
advagg_mod_init in advagg_mod/advagg_mod.module
Implements hook_init().
advagg_save_aggregate in ./advagg.missing.inc
Save an aggregate given a filename, the files included in it, and the type.
_advagg_relocate_save_remote_asset in advagg_relocate/advagg_relocate.advagg.inc
Parse the font family string into a structured array.

File

./advagg.missing.inc, line 1271
Advanced CSS/JS aggregation module.

Code

function advagg_save_data($uri, $data, $overwrite = FALSE) {
  $t = get_t();
  $errors = array();

  // Clear the stat cache.
  module_load_include('inc', 'advagg', 'advagg');
  advagg_clearstatcache($uri);

  // Prepare dir if needed.
  $dir = dirname($uri);
  $dir_good = file_prepare_directory($dir, FILE_CREATE_DIRECTORY);
  if (!$dir_good) {
    $errors[1] = $t('The directory for @file can not be created or is not writable.', array(
      '@file' => $uri,
    ));
    return $errors;
  }

  // File already exists.
  if (!$overwrite && file_exists($uri) && filesize($uri) > 0) {
    if (variable_get('advagg_debug', ADVAGG_DEBUG) >= 2) {
      watchdog('advagg-debug', 'File @uri exists and overwrite is false.', array(
        '@uri' => $uri,
      ), WATCHDOG_DEBUG);
    }
    $errors[2] = $t('File (@file) already exits.', array(
      '@file' => $uri,
    ));
    return $errors;
  }

  // If data is empty, write a space.
  if (empty($data)) {
    $data = ' ';
  }

  // Perform the replace operation. Since there could be multiple processes
  // writing to the same file, the best option is to create a temporary file in
  // the same directory and then rename it to the destination. A temporary file
  // is needed if the directory is mounted on a separate machine; thus ensuring
  // the rename command stays local and atomic.
  //
  // Get a temporary filename in the destination directory.
  $dir = $uri_dir = drupal_dirname($uri) . '/';

  // Corect the bug with drupal_tempnam where it doesn't pass subdirs to
  // tempnam() if the dir is a stream wrapper.
  $scheme = file_uri_scheme($uri_dir);
  if ($scheme && file_stream_wrapper_valid_scheme($scheme)) {
    $wrapper = file_stream_wrapper_get_instance_by_scheme($scheme);
    if ($wrapper && method_exists($wrapper, 'getDirectoryPath')) {
      $wrapper_dir_path = $wrapper
        ->getDirectoryPath();
      if (!empty($wrapper_dir_path)) {
        $dir = $wrapper_dir_path . '/' . substr($uri_dir, strlen($scheme . '://'));
        $uri = $dir . substr($uri, strlen($uri_dir));
      }
    }
  }

  // Get the extension of the original filename and append it to the temp file
  // name. Preserves the mime type in different stream wrapper implementations.
  $parts = pathinfo($uri);
  if (variable_get('advagg_debug', ADVAGG_DEBUG) >= 2) {
    $variables = array(
      '@uri' => $uri,
    );
    watchdog('advagg-debug', 'Creating URI @uri', $variables, WATCHDOG_DEBUG);
    $variables = array(
      '@parts' => print_r($parts, TRUE),
    );
    watchdog('advagg-debug', 'File Parts <pre>@parts</pre>', $variables, WATCHDOG_DEBUG);
  }
  $extension = '.' . $parts['extension'];
  if ($extension === '.gz' || $extension === '.br') {
    $parts = pathinfo($parts['filename']);
    $extension = '.' . $parts['extension'] . $extension;
  }

  // Create temp filename.
  $temporary_file = $dir . 'advagg_file_' . drupal_hash_base64(microtime(TRUE) . mt_rand()) . $extension;

  // Save to temporary filename in the destination directory.
  $filepath = file_unmanaged_save_data($data, $temporary_file, FILE_EXISTS_REPLACE);
  if ($filepath) {

    // Perform the rename operation.
    if (!advagg_rename($filepath, $uri)) {

      // Unlink and try again for windows. Rename on windows does not replace
      // the file if it already exists.
      if (variable_get('advagg_debug', ADVAGG_DEBUG) >= 2) {
        watchdog('advagg-debug', 'Rename failed. @to', array(
          '@to' => $uri,
        ), WATCHDOG_WARNING);
      }
      @unlink($uri);

      // Remove temporary_file if rename failed.
      if (!advagg_rename($filepath, $uri)) {
        $errors[20] = $t('Renaming the filename (@incorrect) to (@correct) failed.', array(
          '@incorrect' => $filepath,
          '@correct' => $uri,
        ));
        @unlink($filepath);
        if (file_exists($filepath)) {
          $errors[22] = $t('unlinking @file failed.', array(
            '@file' => $filepath,
          ));
        }
        watchdog('advagg', 'Rename 4 failed. Current: %current Target: %target', array(
          '%current' => $filepath,
          '%target' => $uri,
        ), WATCHDOG_ERROR);
      }
    }

    // Check the filesize.
    $file_size = @filesize($uri);
    $expected_size = _advagg_string_size_in_bytes($data);
    if ($file_size === 0) {

      // Zero byte file.
      $errors[26] = $t('Write successful, but the file is empty. @file', array(
        '@file' => $filepath,
      ));
      watchdog('advagg', 'Write successful, but the file is empty. Target: target.  The empty file has been removed.  If this error continues, performance will be greatly degraded.', array(
        '%target' => $uri,
      ), WATCHDOG_ERROR);

      // Better to serve straight from Drupal than have a broken file.
      @unlink($uri);
    }
    elseif ($file_size > 0 && $file_size != $expected_size) {

      // Data written to disk doesn't match.
      $errors[28] = $t('Write successful, but the file is the wrong size. @file Expected size is @expected_size, actual size is @file_size', array(
        '@file' => $uri,
        '@expected_size' => $expected_size,
        '@file_size' => $file_size,
      ));
      watchdog('advagg', 'Write successful, but the file is the wrong size. %file Expected size is %expected_size, actual size is %file_size. The broken file has been removed.  If this error continues, performance will be greatly degraded.', array(
        '%file' => $uri,
        '%expected_size' => $expected_size,
        '%file_size' => $file_size,
      ), WATCHDOG_ERROR);

      // Better to serve straight from Drupal than have a broken file.
      @unlink($uri);
    }
  }
  else {
    $errors[24] = $t('Write failed. @file', array(
      '@file' => $temporary_file,
    ));
    watchdog('advagg', 'Write failed. Target: %target', array(
      '%target' => $temporary_file,
    ), WATCHDOG_ERROR);
  }

  // Cleanup leftover files.
  if (file_exists($temporary_file)) {
    @unlink($temporary_file);
  }
  if (file_exists($filepath)) {
    @unlink($filepath);
  }
  return $errors;
}