how to know if file is still open for writing
i have a function that writes to a file , how can i using another script check if the file is being used for writing or it is closed ? Edit : this file might be opened for writing by other script/application/system . thank you .
3 Answers 3
You should use flock in both scripts. This puts a flag on the file so that other scripts are informed that the file is in use. The flag is turned off either intentionally using fclose or implicitly by the end of the script.
While flock is the answer (or dio_fcntl ), flock only provides an advisory lock. You have to coordinate everywhere with flock. Any other script not using flock can manipulate the file at any time.
@jasonbar Hence by «in both scripts». After your first comment, I had updated my answer to reflect your excellent point.
@Rohan, this covers cross script / application cases. What do you mean by «system»? Another physical (or virtual) machine?
If you’re on Unix, your system might have the lsof («LiSt Open Files») command installed. The «FD» column in the output indicates whether the file was opened for reading, writing, or both.
I’d like to point out that any process of the form «check to see if file X is open for writing, if so do something. » is subject to a race condition. Some other process could open the file after you’ve checked, but before the action was started.
@Ronan: In Windows, it’s easier — the LockFile function allows guaranteed exclusive access to a file (or even part of a file). Most Unix filesystems only provide advisory locks, which aren’t necessarily respected by other processes beyond your control, so file locking is not a good design choice for that environment. lsof or flock() may get you part of the way there.
I’d say just use the file open function, if it returns false, then the file’s obviously still open.
This question is in a collective: a subcommunity defined by tags with relevant content and experts.
is_writable
Returns true if the filename exists and is writable. The filename argument may be a directory name allowing you to check if a directory is writable.
Keep in mind that PHP may be accessing the file as the user id that the web server runs as (often ‘nobody’).
Parameters
The filename being checked.
Return Values
Returns true if the filename exists and is writable.
Errors/Exceptions
Upon failure, an E_WARNING is emitted.
Examples
Example #1 is_writable() example
$filename = ‘test.txt’ ;
if ( is_writable ( $filename )) echo ‘The file is writable’ ;
> else echo ‘The file is not writable’ ;
>
?>?php
Notes
Note: The results of this function are cached. See clearstatcache() for more details.
As of PHP 5.0.0, this function can also be used with some URL wrappers. Refer to Supported Protocols and Wrappers to determine which wrappers support stat() family of functionality.
See Also
- is_readable() — Tells whether a file exists and is readable
- file_exists() — Checks whether a file or directory exists
- fwrite() — Binary-safe file write
User Contributed Notes 15 notes
Be warned, that is_writable returns false for non-existent files, although they can be written to the queried path.
To Darek and F Dot: About group permissions, there is this note in the php.ini file:
; By default, Safe Mode does a UID compare check when
; opening files. If you want to relax this to a GID compare,
; then turn on safe_mode_gid.
safe_mode_gid = Off
It appears that is_writable() does not check full permissions of a file to determine whether the current user can write to it. For example, with Apache running as user ‘www’, and a member of the group ‘wheel’, is_writable() returns false on a file like
-rwxrwxr-x root wheel /etc/some.file
Check director is writable recursively. to return true, all of directory contents must be writable
function is_writable_r ( $dir ) if ( is_dir ( $dir )) if( is_writable ( $dir )) $objects = scandir ( $dir );
foreach ( $objects as $object ) if ( $object != «.» && $object != «..» ) if (! is_writable_r ( $dir . «/» . $object )) return false ;
else continue;
>
>
return true ;
>else return false ;
>
>else if( file_exists ( $dir )) return ( is_writable ( $dir ));
This file_write() function will give $filename the write permission before writing $content to it.
Note that many servers do not allow file permissions to be changed by the PHP user.
function file_write ( $filename , & $content ) <
if (! is_writable ( $filename )) if (! chmod ( $filename , 0666 )) echo «Cannot change the mode of file ( $filename )» ;
exit;
>;
>
if (! $fp = @ fopen ( $filename , «w» )) echo «Cannot open file ( $filename )» ;
exit;
>
if ( fwrite ( $fp , $content ) === FALSE ) echo «Cannot write to file ( $filename )» ;
exit;
>
if (! fclose ( $fp )) echo «Cannot close file ( $filename )» ;
exit;
>
>
?>
Regarding you might recognize your files on your web contructed by your PHP-scripts are grouped as NOBODY you can avoid this problem by setting up an FTP-Connection («ftp_connect», «ftp_raw», etc.) and use methods like «ftp_fput» to create these [instead of giving out rights so you can use the usual «unsecure» way]. This will give the files created not the GROUP NOBODY — it will give out the GROUP your FTP-Connection via your FTP-Program uses, too.
Furthermore you might want to hash the password for the FTP-Connection — then check out:
http://dev.mysql.com/doc/mysql/en/Password_hashing.html
The results of this function seems to be not cached :
Tested on linux and windows
chmod ( $s_pathFichier , 0400 );
echo ‘
' ; var_dump ( is_writable ( $s_pathFichier ));echo '
‘ ;
chmod ( $s_pathFichier , 04600 );
echo ‘
' ; var_dump ( is_writable ( $s_pathFichier ));echo '
‘ ;
exit;
?>
This function returns always false on windows, when you check an network drive.
We have two servers: one running PHP 5.0.4 and Apache 1.3.33, the other running PHP 4.3.5 and Apache 1.3.27. The PHP 4 server exhibits the behavior you are describing, with is_writable() returning ‘false’ even though the www user is in the group that owns the file, but the PHP 5 server is returning ‘true.’
This is the latest version of is__writable() I could come up with.
It can accept files or folders, but folders should end with a trailing slash! The function attempts to actually write a file, so it will correctly return true when a file/folder can be written to when the user has ACL write access to it.
function is__writable ( $path ) //will work in despite of Windows ACLs bug
//NOTE: use a trailing slash for folders.
//see http://bugs.php.net/bug.php?id=27609
//see http://bugs.php.net/bug.php?id=30931
if ( $path < strlen ( $path )- 1 >== ‘/’ ) // recursively return a temporary file path
return is__writable ( $path . uniqid ( mt_rand ()). ‘.tmp’ );
else if ( is_dir ( $path ))
return is__writable ( $path . ‘/’ . uniqid ( mt_rand ()). ‘.tmp’ );
// check tmp file for read/write capabilities
$rm = file_exists ( $path );
$f = @ fopen ( $path , ‘a’ );
if ( $f === false )
return false ;
fclose ( $f );
if (! $rm )
unlink ( $path );
return true ;
>
?>
Since looks like the Windows ACLs bug «wont fix» (see http://bugs.php.net/bug.php?id=27609) I propose this alternative function:
function is__writable ( $path )
if ( $path < strlen ( $path )- 1 >== ‘/’ )
return is__writable ( $path . uniqid ( mt_rand ()). ‘.tmp’ );
if ( file_exists ( $path )) if (!( $f = @ fopen ( $path , ‘r+’ )))
return false ;
fclose ( $f );
return true ;
>
if (!( $f = @ fopen ( $path , ‘w’ )))
return false ;
fclose ( $f );
unlink ( $path );
return true ;
>
?>
It should work both on *nix and Windows
NOTE: you must use a trailing slash to identify a directory
function is_writable(‘ftp://user. ‘) always return false. I can create/delete files, but can check is writable. Is this bug or php feature :)?
I’d like to also clarify a point on this. Even if you see 777 permissions for the directly, you may need to check your ACL, since your server’s group might not have write permissions there.
Check if a directory is writable. Work also on mounted SMB shares:
How to check if a PHP stream resource is readable or writable?
In PHP, how do I check if a stream resource (or file pointer, handle, or whatever you want to call them) is either readable or writable? For example, if you’re faced with a situation where you know nothing about how the resource was opened or created, how do you check if it’s readable? And how do you check if it’s writable? Based on the testing that I’ve done (just with regular text files using PHP 5.3.3), fread() does not throw any errors at any level when the resource is not readable. It just returns an empty string, but it also does that for an empty file. And ideally, it would be better to have a check that doesn’t modify the resource itself. Testing if a resource is readable by trying to read from it will change the position of the pointer. Conversely, fwrite() does not throw any errors at any level when the resource is not writable. It just returns zero. This is slightly more useful, because if you were trying to write a certain number of bytes to a file and fwrite() returns zero, you know something went wrong. But still, this is not an ideal method, because it would be much better to know if it’s writable before I need to write to it rather than trying to write to it and see if it fails. Also, ideally, the check should work on any sort of stream resource, not just files. Is this possible? Does anything like this exist? I have been unable to find anything useful. Thanks in advance for your answers.
Of course, both fread() and fwrite() return bool(false) on failure according to their respective documentation page. But that doesn’t happen in PHP 5.3.5.
PHP: How to check if a file is currently being written to
Lets say I have a PHP script that is going to serve a big file and I am currently uploading this big file through for example FTP. Is there a way I can check in my PHP script if the upload is complete? Is there for example a way I can check if a file is currently being written to or something like that? Update: Should have mentioned this before, but I’m not talking about uploading through an upload script I’m talking about for example uploading big pdf files or such through other means like FTP or SFTP.
If the file gets locked during the upload, trying to flock it from PHP should return FALSE and then you know the file is used by something else atm.
@Gordon: If the script was run two times in parallell that means even if one succeeded the other would fail? Or?
if the upload is currently running and FTP has a lock on the file, both scripts whould return false. In the case where there is no upload and one script flocks the file, then yes, the other would return false.
2 Answers 2
You can in upload script use a temportantly file (in temportantly directory) and if upload was finished you can simple move file to your final location with good filename.
This is a common solution for this problem.
For get temportantly file (enviroment independent) use PHP function:
Documemtation for it you can find at http://pl.php.net/manual/en/function.tmpfile.php This function returning handle to your new clean tempfile.
But if your using this function you must copy file before you close handle to it because this file was removed when you call fclose(handle) . To get assurance of file buffer is clean you can at end call fflush(handle) .
Or if you don’t want use tmpfile(void) function you can do this manualy.
string tempnam ( string $dir, string $prefix )
Prefix is a prefix to your files to easly group her to delete or something. Call this function to get unique file in typed directory, as directory get you temp directory in your enviroment, you can get this by calling:
string sys_get_temp_dir ( void )
Then when you have self tempfile, write to it upload data and close. Copy this file to your final location using:
bool copy ( string $source, string $dest [, resource $context ] )
And delete your tempfile to get clean in your enviroment calling:
bool unlink ( string $filename [, resource $context ] )