PHP fwrite always returns the number of bytes to be written even if the file doesn't exist, is this expected behaviour?
I have the following example code
<?php
`echo test > /tmp/test.txt`;
$f=fopen("/tmp/test.txt","w+");
`rm /tmp/test.txt`;
var_dump(fwrite($f,"test"));
fclose($f);
file_get_contents("/tmp/test.txt");
Which creates a file, opens a pointer to it, removes the file then attempts to write to it. Now I would expect the fwrite to return false or 0 since no data will be written, however it produces the following output
int(4)
Warning: file_get_contents(/tmp/test.txt): failed to open stream: No such file or directory in /Stuff/tmp/test3 on line 7
So the fwrite apparently succeeds but the file_get_contents fails as expected.
Is it expec开发者_如何学运维ted behaviour for the fwrite to return the number of bytes to be written? If so how can I test if the write was really successful?
This is with php 5.3.3
The reason it's returning false
is that the file pointer is at the end of the file after fwrite
... That's what fgets
is supposed to do when it reaches the end of the file (it returns false
since there is no more data to get)...
What you need to do is add a fseek
call before you call fgets
:
var_dump(fwrite($f,"test"));
fseek($f, 0);
var_dump(fgets($f));
Edit: Now that I understand your question (and have looked at it):
Alright, so here's what's happening. To understand, you must first know how Linux filesystems work. The file's name is meaningless to the operating system. All it does is point to the INODE
for the file. The inode stores the data, etc. It also stores a reference number to the number of hard-links to that file. The file is only deleted when the reference number falls to 0. I'm suspecting that opening a pointer to the file (using fopen
, or other system calls) increases the reference count.
So basically, what that means is that when you ran rm
on the file, it deleted the hard-link. But since the file was still open, you could still access the inode through fwrite
(hence why the write succeeded). You couldn't access /tmp/test.txt
since the hard link to that filename no longer existed. So the file became a phantom file that is only accessible by the inode. But as soon as you closed the file handle for that file (fclose
, or by ending the script) the reference count fell to 0 and the inode was freed...
So the file does exist, it's just not accessible from the filename after you call rm
...
That's just what I'm gathering by knowing what I know about the filesystems. I'm not saying it's 100% accurate, but it should be a decent hypothesis...
If this is on a Linux (and possible other unix-like OSes) system, the reference to the file in the filesystem is deleted by rm
, but the file itself still exists until all programs reading from/writing to it are closed.
This is due to how hard links work; all entries in the filesystem are hard links, soft links, or devices.
I believe you first must save the file
fclose($f);
The following code should allow you to check whether it was a successful write.
if (fwrite($handle, $somecontent) === FALSE) {
echo "Cannot write to file ($filename)";
exit;
}
Your code needs some conditions, error handling e.g.
- check whether the file exists
- whether the file is writable
- whether the data was written to the file
- whether the data are readable
精彩评论