php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #68935 fwrite won't recreate deleted file or emit warning
Submitted: 2015-01-28 15:27 UTC Modified: 2015-01-30 01:08 UTC
From: mattsch at gmail dot com Assigned:
Status: Not a bug Package: Filesystem function related
PHP Version: 5.6.5 OS: Gentoo Linux 13.0
Private report: No CVE-ID: None
 [2015-01-28 15:27 UTC] mattsch at gmail dot com
Description:
------------
Open/create a file with fopen. Then delete the file with unlink.  Finally, write to that already opened resource with fwrite.  fwrite reports the number of bytes written without any errors but the file no longer exists so nothing is actually written to a file.  One of two options should happen:

1. fwrite should emit a warning and report bytes written as false

or

2. fwrite should recreate the deleted file and write to it and report the bytes written.

Test script:
---------------
<?php
$resource = fopen('foo', 'w');
unlink('foo');
$bytesWritten = @fwrite($file, 'bar');
$error = error_get_last();
var_dump($error);
var_dump($bytesWritten);
var_dump(file_exists('foo'));

Expected result:
----------------
array(4) {
  ["type"]=>
  int(2)
  ["message"]=>
  string(58) "fwrite(): cannot write to file because file no longer exists"
  ["file"]=>
  string(27) "/home/foo/foo.php"
  ["line"]=>
  int(4)
}
bool(false)
bool(false)

--or--

NULL
int(3)
bool(true)

Actual result:
--------------
NULL
int(3)
bool(false)

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-01-28 15:29 UTC] mattsch at gmail dot com
-Summary: fwrite won't recreate deleted file to write to +Summary: fwrite won't recreate deleted file or emit warning
 [2015-01-28 15:29 UTC] mattsch at gmail dot com
Changed the summary to include the other potential expected result.
 [2015-01-28 20:56 UTC] cmbecker69 at gmx dot de
The manual[1] states that unlink is similar to the Unix unlink()
function.  man unlink(3) states[2]:

| The unlink() function shall remove a link to a file.
| [...]
| When the file's link count becomes 0 and no process has the file
| open, the space occupied by the file shall be freed and the file
| shall no longer be accessible. If one or more processes have the
| file open when the last link is removed, the link shall be removed
| before unlink() returns, but the removal of the file contents
| shall be postponed until all references to the file are closed.

This would explain the reported behavior. Maybe all this is just
a documentation issue.

FWIW: on Windows it is not possible to unlink a file with an open
handle.

[1] <http://php.net/manual/en/function.unlink.php>
[2] <http://linux.die.net/man/3/unlink>
 [2015-01-29 05:12 UTC] phpmpan at mpan dot pl
I believe this is just a misunderstanding around a difference between a file not existing and a file not having an entry within a filesystem.

The behaviour is fine. While it may not be the case for PHP web applications, in general it is not a very uncommon scenario to change/delete filename while a file associated with it is still open. See IPC based on temporary named pipes as an example.

However, documentation for `unlink` should notify the reader about the behaviour. Indeed it may be a bit surprising for Windows users.
 [2015-01-29 15:02 UTC] mattsch at gmail dot com
So if this a documentation fix, then in order to ensure a link in the filesystem, I will have to check if the file exists before calling fwrite and if not, null the resource and open a new one and write to the new one.
 [2015-01-29 22:43 UTC] danack@php.net
-Status: Open +Status: Not a bug
 [2015-01-29 22:43 UTC] danack@php.net
mattsch that is correct. If something on your machine is unlinking files that you are currently writing to, then you need to check to see if that has happened.

I would suggest merely renaming the file instead of deleting it, to allow a new file to be created in it's place, and for any writes to existing handles proceed to the renamed file.
 [2015-01-30 01:08 UTC] yohgaki@php.net
> I would suggest merely renaming the file instead of deleting it, to allow a new file to be created in it's place, and for any writes to existing handles proceed to the renamed file.

Then, we have issue with garbages.
BTW, is it possible to rename opened files under windows?
 [2015-01-30 02:09 UTC] cmbecker69 at gmx dot de
> BTW, is it possible to rename opened files under windows?

No:

  $f = fopen('foo', 'w');
  rename('foo', 'bar');
  
Warning: rename(foo,bar): Der Prozess kann nicht auf die Datei
zugreifen, da sie von einem anderen Prozess verwendet wird.

[The process can't access the file, because it's used by another
process.]

It seems to me that several file operations work quite differently
on *nix and Windows, and that these differences deserve better
documentation in the PHP manual.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Mar 29 01:01:28 2024 UTC