Having issues with incomplete images being passed along for image style generation. This seems to fix them.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

mikeytown2’s picture

Status: Active » Needs review
FileSize
4.24 KB
greggles’s picture

This looks pretty good to me. Sorry for the slow time to a response.

I noticed: "Preform" -> Perform.

I'm curious if there's a reason to use the php rename and unlink instead of file_unmanaged_copy and file_unmanaged_delete?

mikeytown2’s picture

#1377740: file_unmanaged_move() should issue rename() where possible instead of copy() & unlink()

This is a copy of what I use in AdvAgg in order to avoid multiple writes overwriting each other. If you don't do this then you can get corrupted files fairly easily in a high concurrent environment.

/**
 * Use write & rename instead of write.
 *
 * 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.
 *
 * @param string $destination
 *   A string containing the destination location.
 * @param string $data
 *   A string containing the contents of the file.
 *
 * @return bool
 *   True if write was successful. False if write or rename failed.
 */
function stage_file_proxy_write_file($destination, $data) {
  // Get a temporary filename in the destination directory.
  $dir = drupal_dirname($destination) . '/';
  $temporary_file = drupal_tempnam($dir, 'stage_file_proxy_');
  $temporary_file_copy = $temporary_file;

  // 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($destination);
  $extension = '.' . $parts['extension'];
  if ($extension === '.gz') {
    $parts = pathinfo($parts['filename']);
    $extension = '.' . $parts['extension'] . $extension;
  }
  // Move temp file into the destination dir if not in there.
  // Add the extension on as well.
  $temporary_file = str_replace(substr($temporary_file, 0, strpos($temporary_file, 'stage_file_proxy_')), $dir, $temporary_file) . $extension;

  // Preform the rename, adding the extension to the temp file.
  if (!@rename($temporary_file_copy, $temporary_file)) {
    // Remove if rename failed.
    @unlink($temporary_file_copy);
    return FALSE;
  }

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

  // Perform the rename operation if the write succeeded.
  if ($filepath) {
    if (!@rename($filepath, $destination)) {
      // Unlink and try again for windows. Rename on windows does not replace
      // the file if it already exists.
      @unlink($destination);
      if (!@rename($filepath, $destination)) {
        // Remove temporary_file if rename failed.
        @unlink($filepath);
      }
    }
  }

  // Final check; make sure file exists & is not empty.
  $result = FALSE;
  if (file_exists($destination) & filesize($destination) != 0 ) {
    $result = TRUE;
  }

  return $result;
}

I could use file_unmanaged_delete but that would fill the watchdog table up most likely.

greggles’s picture

I see, OK. I'm inclined to commit this but want to wait just a little more for anyone else to review.

asrob’s picture

Status: Needs review » Reviewed & tested by the community

It works, successfully applied patch in 7.x-1.x, that's why I changed its status.

markdorison’s picture

RTBC. Should this be ported to 8.x as well?

greggles’s picture

Yes, I think so. @markdorison, want to work on that port?

mikeytown2’s picture

Heads up that in advagg (which is where the write & rename code came from) I discovered that drupal_tempnam doesn't work as expected if the dir is a stream wrapper. The above patch already has a workaround:

+  // Move temp file into the destination dir if not in there.
+  // Add the extension on as well.
+  $temporary_file = str_replace(substr($temporary_file, 0, strpos($temporary_file, 'stage_file_proxy_')), $dir, $temporary_file) . $extension;

It works, we just might want to make it more clear in the code what is going on and why this is needed.

markdorison’s picture

Version: 7.x-1.x-dev » 8.x-1.x-dev
Status: Reviewed & tested by the community » Needs review
FileSize
6.71 KB

Ported patch to 8.x.

asrob’s picture

Status: Needs review » Reviewed & tested by the community

I successfully applied this patch and seems to work well. But this issue (#2795175: Handle guzzle client exceptions gracefully) does almost the same thing so we need to figure it out what we should do these issues.
However, I mark this as RTBC'ed because I prefer this patch!

geek-merlin’s picture

As i understand it, #2795175: Handle guzzle client exceptions gracefully touches the same code, but its change is completely orthogonal to this.
We should have both.
As this patch touches more code, i'd follow the suggestion to commit this and manually rebase the other patch onto this.

markdorison’s picture

Status: Reviewed & tested by the community » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.