Hi,

It appears that both the File module and Image module are only saving files as temporary files ($file->status == 0), as they are using file_save_upload() to save the files.

Cheers,
Deciphered.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

quicksketch’s picture

Priority: Normal » Critical

Yikes! That sounds like a terrible problem. We should be updating the status to FILE_STATUS_PERMANENT on file_field_update(). Unfortunately the file_set_status() function was removed entirely from Drupal 7, so we don't have any API to actually do this query.

Deciphered’s picture

Let me know how you go and I would be more than happy to test anything for you as I was hoping to use the status in the Drupal 7 FileField Paths port.

jim0203’s picture

#331013: Remove file_set_status() in favor of file_save() seems to suggest that $file->status should be set manually:

file_set_status() was added in Drupal 6 as a way of changing a temporary file to a permanent file back before file_save() was added. In it's current implementation the function has an annoying overlap with the functionality provided by file_save().

All file_set_status() does is changes the status field of a row in the {files} table and call hook_file_status. But there's nothing to stop you from assigning the file's status and then calling file_save() which would circumvent the call to hook_file_status.

It also diverges from the patterns established else where in core. We don't have a node_set_status() function, you just do a $node->status = 1; node_save($node); and I think the same should be true for files.

According to the docs for file_save_upload(),

The file will be added to the {file} table as a temporary file. Temporary files are periodically cleaned. To make the file a permanent file, assign the status and use file_save() to save the changes.

I think this means that we should call file_save_upload(), set the status of the returned $file object to 1, and then call file_save() when the node is actually submitted.

jim0203’s picture

FileSize
872 bytes

Patch attached which does a very rough version of what I've described in #3 - it imitates what is done in Drupal 6. This is rough and there must be a better way to do it, but it does work and might get the ball rolling towards a more elegant solution.

jim0203’s picture

Status: Active » Needs review

Status: Needs review » Needs work

The last submitted patch failed testing.

Anonymous’s picture

subscribe

Anonymous’s picture

Status: Needs work » Needs review
FileSize
1.12 KB

updated patch attached. not 100% sure its correct, but all file and file api tests pass.

i've tried to differentiate between the insert of a new object with a file field attached and a new revision of an existing object. lets see what the bot thinks.

Anonymous’s picture

Issue tags: +File API

tagging.

quicksketch’s picture

Thanks for your work on this justinrandell. From the patch in #8, it looks like this will only mark files as permanent on new nodes (when is_new is TRUE), not when updating existing nodes and adding additional files.

Anonymous’s picture

FileSize
1.09 KB

quicksketch: thanks for the review. yeah, i mixed up the containing object and the field. attached patch fixes that, so we always set the status to permanent regardless of the newness of the containing object.

i guess we also need a test, if my patch at #8 got the green light but was broken.

quicksketch’s picture

Now if a new revision is made, new files will not be made permanent. So if you upload a file, then make a new revision on that edit, your new file will not be made permanent. It looks like we don't need to modify the is_new or revision IF statement at all, we just need to put the new foreach loop in there before the existing IF.

Anonymous’s picture

Status: Needs review » Needs work

i'm really messing with stuff i don't quite grok here. seems what we really need is tests. no way this should keep coming back green if its broken in two different ways.

working on it...

yched’s picture

Crosslinking to #644338: file_field_update() triggers a full entity load durung entity_save(), since this patch seems to touch this exact area.

+ The discussion here is largely over my head, but if stuff needs to be done on both entity creation and entity update, maybe hook_field_presave() would be more appropriate ?
Sorry for the noise if this doesn't apply or has already been turned down ;-).

David_Rothstein’s picture

Title: Files saved as temporary files. » File and image fields are treated as temporary files and automatically deleted after six hours
Status: Needs work » Needs review
FileSize
1.77 KB

This is a nasty, horrible bug - giving it a better title :)

I'm pretty far out of my element here also, but after looking into it for a while, @yched's suggestion of using hook_field_presave() seems to make sense. If anyone has a reason why that's a bad idea, please explain!

The attached patch does this. I'm putting it at "needs review", but it definitely still needs tests. Hopefully I can work on those later.

aaron’s picture

subscribe

JacobSingh’s picture

This seems okay to me, but why don't we just clear anything with uri LIKE "temporary://%" every X hours where X is a variable defined by the administrator?

JacobSingh’s picture

Also, another thought: The default should be non-temporary, shouldn't it? Imagine people doing mass imports of files or grabbing them from URLs, etc

chx’s picture

Status: Needs review » Reviewed & tested by the community

I have created a node type, added an image field and then uploaded a file. Status was 0. Saved the node. Status is now 1. Seems like the patch is working. That's what the test would need to do. However, we survived without a file.test so far and this issue is so crippling that I daresay test is another issue (or this issue after the initial commit). I think the only upload test we had was the defunct upload.test.

Steven Merrill’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
5.41 KB

See attached with an updated "file field revisions test" to test permanence. The six new assertions fail without the rest of the patch, so this is a valid test.

C'mon testbot!

Steven Merrill’s picture

Better patch with a real description for the new method on FileFieldTestCase. (Duh.)

pwolanin’s picture

Status: Needs review » Reviewed & tested by the community

Code works as as intended. As a follow-up we should add more image field tests.

Steven Merrill’s picture

Some of that follow-up work is starting at #709904: Image field does not delete unused files where I'm looking at inconsistencies between file and image fields with regard to files that are no longer in use by a node.

webchick’s picture

Status: Reviewed & tested by the community » Needs review
Issue tags: +webchick's D7 alpha hit list

Well this is truly a horrifying bug, indeed. :) Couple of things:

1. Why on earth is the default behaviour of a function called file_save_upload() to delete the files after 6 hours? Shouldn't rather the default behaviour be to save them permanently, and a module have to do special back-flips to get them to be temporary instead?

2. How will we not have exactly this same bug cropping up constantly from video module, media module, emfield module, and any other module that deals with file uploads? Will they all have to add a hook_field_presave() to prevent massive data-loss, too? That seems like a huge, gaping flaw in our file API.

In other words, I would've expected to see file.inc hunks in this patch, not modules/file and modules/image hunks. What gives?

Steven Merrill’s picture

I'm out of time for tonight on this one. Here's as far as I got (keep in mind that I'm still a D7 n00b.)

I had added a bit of logic in file_save_upload() to do the following before its call to file_save():

  // Save the file as permanent if it's not being moved to the temporary://
  // scheme.
  if (file_uri_scheme($file->uri) != 'temporary') {
    $file->status |= FILE_STATUS_PERMANENT;
  }

It seems innocuous enough, yet it causes plenty of fails in the file tests. One major area where it clearly falls over is file_managed_file_validate(), since the validator expects a file to not yet be permament when validated, or if it is permament, to have more than 0 references to it, lest you trigger the "Referencing to the file used in the image field is not allowed." The offending validation code is

/**
 * An #element_validate callback for the managed_file element.
 */
function file_managed_file_validate(&$element, &$form_state) {
  // If referencing an existing file, only allow if there are existing
  // references. This prevents unmanaged files from being deleted if this
  // item were to be deleted.
  $clicked_button = end($form_state['clicked_button']['#parents']);
  if ($clicked_button != 'remove_button' && !empty($element['fid']['#value'])) {
    if ($file = file_load($element['fid']['#value'])) {
      if ($file->status == FILE_STATUS_PERMANENT) {
        $reference_count = 0;
        foreach (module_invoke_all('file_references', $file) as $module => $references) {
          $reference_count += $references;
        }
        if ($reference_count == 0) {
          form_error($element, t('Referencing to the file used in the !name field is not allowed.', array('!name' => $element['#title'])));
        }
      }
    }
  // SNIPPED
  }
}
Steven Merrill’s picture

Status: Needs review » Needs work
FileSize
512 bytes

Here's the change above as a patch if you really want it. It won't pass tests.

Jon Nunan’s picture

@webchick
1. I think its this way, so if you ajax upload an image or hit preview on a form with a filefield, but never fully submit it, those files that are ultimately never used get cleaned up automatically. Not sure how you'd stop that if it wasn't this way, or are you just suggesting a name change to make it less confusing?

pwolanin’s picture

@webchick - that behavior is directly ported from D6

pwolanin’s picture

Status: Needs work » Reviewed & tested by the community

#22 should be committed asap. Yes, the logic is stupid, but it matches what's in Drupal 6 and we need at least to avoid a total #fail in core before further debating API changes.

Status: Reviewed & tested by the community » Needs work
Issue tags: -File API, -webchick's D7 alpha hit list

The last submitted patch, 618654-patch-work-26.patch, failed testing.

pwolanin’s picture

Status: Needs work » Needs review
Issue tags: +File API, +webchick's D7 alpha hit list

#21: file-save-temp-618654-21.patch queued for re-testing.

Steven Merrill’s picture

If #21 doesn't pass, I can easily bzr up and re-roll.

chx’s picture

Status: Needs review » Reviewed & tested by the community

#21 is RTBC. This is how Drupal 6 worked and until we find something better which I bet we can't within the confines of Drupal 7 we need to fix this horror now.

webchick’s picture

Status: Reviewed & tested by the community » Needs review

I'd like to get quicksketch to eyeball this first. He's the maintainer of filefield and also worked a lot on Drupal 7's file API, and was advocating a more "central" fix earlier, which makes a lot more sense to me.

But yes, agreed on the nastiness and that we urgently need a fix. I've sent him a mail about it.

David_Rothstein’s picture

I believe he was mainly advocating that the file_set_status() API function be added back to Drupal 7, which sounds like a good idea... the code involving the & and |= operators in the patch is a little crazy to expect people to copy around correctly all over the place. I thought it was a bit out of scope for this bugfix, but maybe not.

+function file_field_presave($obj_type, $object, $field, $instance, $langcode, &$items) {
+  // Make sure that each file which will be saved with this object has a
+  // permanent status, so that it will not be removed when temporary files are
+  // cleaned up.

There is obviously a lot of confusion around this, so we should probably expand the code comment to explain why we are saving things in a "presave" hook - Dries was confused about that when looking at this patch although he did not comment here :)

Basically, @meatsack's explanation in #27 is correct; in common use cases, the file itself needs to be saved before the filefield that points to it, so we only make that file permanent when the filefield itself is ready to save.

quicksketch’s picture

Status: Needs review » Reviewed & tested by the community

Everything looks good to me. #21 is exactly the implementation I'd pursue to fix this same problem. While I don't necessary think the *default* behavior should be to delete files after 6 hours, it makes a good amount of sense in the use-cases we use within file and image modules. For example:

- User goes to node/add/article.
- User uploads new file.
- User closes window and never saves the node.

In this situation we definitely want the file to marked as temporary so it will be removed after 6 hours. At the same time we also want the file to be uploaded to the final location because if the user wants to insert it into a WYSIWYG or have it on preview, the image should be in the final location so we don't have to do any ridiculous URL rewriting or pass-throughs like we had in Drupal 5 (which never worked well).

In the alternative situation, where the file is saved to a temporary directory initially when it's not needed/wanted immediately (such as if you're replacing the site logo), then temporary also makes sense. The file is moved to it's final location and marked permanent upon submission of the form.

webchick’s picture

Priority: Critical » Normal
Status: Reviewed & tested by the community » Needs work

Well, then. :) #21 it is.

Committed to HEAD. Can I get a follow-up patch for the comment clarifications?

quicksketch’s picture

Priority: Normal » Critical
Status: Needs work » Reviewed & tested by the community

I believe he was mainly advocating that the file_set_status() API function be added back to Drupal 7, which sounds like a good idea...

Right, at the time I was wondering what had happened to the function, but since it only requires the same number of queries as file_save() (minus hook_* queries added by other modules), it makes sense to drop the function. I just didn't see a direct equivalent initially.

we should probably expand the code comment to explain why we are saving things in a "presave" hook

Just picking up this issue tonight, it took me a second to think of what I'd do to fix the problem, but I quickly settled on presave even before I looked at the patch in #21. It makes sense to me. It's easy and direct. Oddly though we'll mark a file "permanent" in presave then delete it in "update" if the file is marked for deletion. To prevent this we could add one more check to not save a file as permanent if $item['delete'] is TRUE.

quicksketch’s picture

Priority: Critical » Normal
Status: Reviewed & tested by the community » Needs work

Crosspost. Maybe we can add the $item['delete'] check in the followup too then. ;-)

YesCT’s picture

did anyone make a follow up?

thepeterstone’s picture

Status: Needs work » Needs review
FileSize
940 bytes

There's a remaining reference to $form_state['clicked_button'] (file.module:536), so here's a patch that replaces it with $form_state['triggering_element']. This cleans up a warning ("end() expects parameter 1 to be array, null given") I'm seeing with AJAX updates.

Status: Needs review » Needs work
Issue tags: -File API, -webchick's D7 alpha hit list

The last submitted patch, 681654.triggering_element.patch, failed testing.

thepeterstone’s picture

Status: Needs work » Needs review
Issue tags: +File API, +webchick's D7 alpha hit list

#42: 681654.triggering_element.patch queued for re-testing.

AgaPe’s picture

subscribe

jtwalters’s picture

Still an issue for me in Drupal core 7.x-dev as of February 2011.

Jon Betts’s picture

Status: Needs review » Active

This is still an issue for me too using Drupal Core 7.0.

1. Create a CT
2. Add image field
3. Upload default image
4. Save CT
5. Add content to CT
6. Sleep
7. Wake up
8. Repeat steps 3-8.

bfroehle’s picture

Status: Active » Needs review

glowsinthedark: That's not surprising -- the issue was fixed after 7.0 was released. You'll need to use a 7.x-dev version or wait for 7.1.

Edit: I've forgotten we are in the year 2011 now... Sorry! Regardless, there is a patch in #42 so the status should be needs review.

David_Rothstein’s picture

Title: File and image fields are treated as temporary files and automatically deleted after six hours » (Fixed, but needs cleanup) File and image fields are treated as temporary files and automatically deleted after six hours

@glowsinthedark: The bug you're describing is already being addressed at #1028092: Default image is not set to permanent and saved to the wrong schema. This issue was for user-uploaded files (not default ones) and was fixed a long time ago.

As far as I know, this is just open for the residual cleanups listed above... and needs review for the patch in #42, although I'm not quite sure I understand how that patch is related?

Jon Betts’s picture

@bfroehle, @David_Rothstein, thanks and sorry for the status change! I'll look into the issue mentioned in #49. Thanks again!

bryancasler’s picture

subscribe

geerlingguy’s picture

Subscribe. I really, really wish issue summaries worked now :-)

Is one of the above patches able to be applied to 7.0 so I can just get the default images to not be deleted after six hours? That's all I'm really hoping for, for now at least. I'd rather not switch to 7.x-dev for one of my sites.

js’s picture

following #52 question

I am not using .dev

I lost the "default image" for an image field a couple of times. After reading this thread I see that the status in "file_managed" was 0.

I have set this to 1, hoping it will stick around awhile.

Jon Nunan’s picture

@52 & 53, check comment 49, sounds like issue #1028092: Default image is not set to permanent and saved to the wrong schema is what you're both experiencing.

mherchel’s picture

subscribe. Still an issue in 7.2.

beatnykk’s picture

subscribed, got it here too in 7.2

jbrown’s picture

Status: Needs review » Closed (duplicate)

You need to use 7.x-dev until 7.3 comes out.

jbrown’s picture

Status: Closed (duplicate) » Needs review

#42: 681654.triggering_element.patch queued for re-testing.

Tor Arne Thune’s picture

Version: 7.x-dev » 8.x-dev
Issue tags: +Needs backport to D7
marcoscano’s picture

subscribe

plastikkposen’s picture

subscribe

JTxt’s picture

subscribe Thanks!

plastikkposen’s picture

This is now fixed in the new D7.4 - yay!

Tor Arne Thune’s picture

See comment #49 :)

jmones’s picture

subscribe

jbrown’s picture

#42: 681654.triggering_element.patch queued for re-testing.

Status: Needs review » Needs work
Issue tags: +File API, +Needs backport to D7

The last submitted patch, 681654.triggering_element.patch, failed testing.

langworthy’s picture

Title: (Fixed, but needs cleanup) File and image fields are treated as temporary files and automatically deleted after six hours » File and image fields are treated as temporary files and automatically deleted after six hours

This is still a problem for me with Drupal 7 HEAD.

Steps to reproduce:

1 - Install standard profile
2 - Create/config private files directory
3 - Add an Image field to the page content type. Use all default options except set to use Private files.
4 - Upload a default image after completely saving the field.

In the files_managed table the default image will have a status of 0 (temporary). Changing it to 1 results in 403 error when viewing default image.

A similar error happens when adding the default image at the first opportunity:

Steps 1, 2 same as above

3 - Add an Image field to the page content type. On the overlay (field settings), select private files and upload a default image. Click 'save field settings'.

The default image is now has a record in the files_managed table and it's status is set to 1 (permanent). But viewing the image results in a 403 error.

langworthy’s picture

I just tested the first "Steps to reproduce: in #68 in D8 HEAD.

The only difference is that the default image file is saved with a permanent status but attempts to view the image from the field settings result in a 403. Changing the status to temporary allows the file to be viewed.

I wonder if I'm missing something when it comes to files settings?

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

  • webchick committed 00319d8 on 8.3.x
    #618654 by Steven Merrill, justinrandell, jim0203, quicksketch, and...

  • webchick committed 00319d8 on 8.3.x
    #618654 by Steven Merrill, justinrandell, jim0203, quicksketch, and...

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

  • webchick committed 00319d8 on 8.4.x
    #618654 by Steven Merrill, justinrandell, jim0203, quicksketch, and...

  • webchick committed 00319d8 on 8.4.x
    #618654 by Steven Merrill, justinrandell, jim0203, quicksketch, and...

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

sic’s picture

Issue summary: View changes

i cant believe this issue just lies here for 6 years. d8 keeps deleting random images - wtf :o

cilefen’s picture

Are you seeing exactly this problem? What version of Drupal are you working with?

catch’s picture

Status: Needs work » Fixed

@sic this issue got lost, it looks like the patch got committed here but the issue never actually got marked fixed.

However, there have been literally dozens of issues dealing with this and numerous fixes, while we eventually realised we need to overhaul how to deal with unused files altogether. The one that actually stops deletion is #2801777: Give users the option to prevent drupal from automatically marking unused files as temporary and it'll be released in 8.4.0. There are a number of other issues from the meta that cilefen linked to which will need follow-up. Going to mark this one as fixed because the specific aspect of the bug reported here was fixed, even though the wider problem has indeed continued for years - but it's well covered by the other issues mentioned.

sic’s picture

thanks guys.

were using 8.3. i'll have a look into the linked issue. thanks!

donaldp’s picture

I've taken over the development of a site that is using Drupal 8.3.7 and I'm having a number of issues with File fields that may all be related to what I've noticed. I'm getting duplicate entries in the file usage table with the same file marked as both permanent and temporary.

I'm not sure if this is a common problem but what I've found is that when you upload a file using a node edit form, ajax is used to upload the file. Whilst this is going on, the node save button is still enabled. If the node is saved before the file is fully uploaded, you can end up with duplicate entries in the file usage table. One marked as permanent with a usage count of 1 and the other as temporary with a usage count of 0.
When the "temporary" file is deleted of course the permanent file disappears although the file is still referenced.

There seems to be a possible fixes for this in that the node save button could be disabled until the file upload is complete.

Can anyone duplicate this behaviour?

I'm also getting possibly related issues such as links to the files (which are stored in private storage) returning access denied even to user 1 and the browser sometimes trying to open the files (spreadsheets) rather then downloading them. I'm guessing that these issues could also be caused by broken file storage values.

Edit: Just found this thread, so it seems that this could be a long running issue: https://www.drupal.org/node/610462

Status: Fixed » Closed (fixed)

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

David_Rothstein’s picture

Version: 8.4.x-dev » 7.x-dev

Note that the change in #42 already got added somewhere else along the way, and the other followups discussed above (code comments, etc) are probably not earth-shatteringly important enough that they are worth a followup issue for... so closing this issue is correct.

However, the patch was committed to Drupal 7 in February 2010 (!) so it was already part of the codebase before Drupal 8 was ever branched; therefore, for posterity, this should be a Drupal 7 issue rather than Drupal 8.