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
is_writable
(PHP 4, PHP 5)
is_writable — Indica si un archivo existe y es escribible
Descripción
$filename
)
Devuelve TRUE si filename existe y es
escribible. El argumento nombre_archivo puede ser el nombre de un directorio, permitiendo así
comprobar si el directorio es escribible.
Tenga en cuenta que PHP puede estar accediendo al archivo bajo el id de ususario por el que se está ejecutando el servidor web (a menudo 'nobody'). Las limitaciones del modo seguro no se toman en cuenta.
Parámetros
-
filename -
El nombre de archivo que va a ser comprobado.
Valores devueltos
Devuelve TRUE si el parámetro filename existe y es
escribible.
Ejemplos
Ejemplo #1 Ejemplo de is_writable()
<?php
$nombre_archivo = 'prueba.txt';
if (is_writable($nombre_archivo)) {
echo 'El archivo es escribible';
} else {
echo 'El archivo no es escribible';
}
?>
Errores/Excepciones
En caso de fallo, se emite un E_WARNING.
Notas
Nota: Los resultados de esta función son guardados en caché. Para más información ver clearstatcache().
Desde PHP 5.0.0, esta función también puede usarse con algunos URL wrappers. Consultar Protocolos y Envolturas soportados para deter4minar qué envolturas soportan la familia de funcionalidad de stat().
Ver también
- is_readable() - Indica si un fichero existe y es legible
- file_exists() - Comprueba si existe un fichero o directorio
- fwrite() - Escritura de un archivo en modo binario seguro
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.
<?php
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;
}
}
?>
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
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
<?php
chmod($s_pathFichier, 0400);
echo'<pre>';var_dump(is_writable($s_pathFichier));echo'</pre>';
chmod($s_pathFichier, 04600);
echo'<pre>';var_dump(is_writable($s_pathFichier));echo'</pre>';
exit;
?>
I was trying to create a new file using fwrite, and i had the following error. Any idea?
Warning: fwrite(): supplied argument is not a valid stream resource in
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.
<?php
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:
<?php
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
In response to Darek:
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.'
Under Windows, it only returns the read-only attribute status, not the actual permissions (ACL).
See http://bugs.php.net/bug.php?id=27609
Ooooops, sorry! My mistake. is__writable should be:
<?php
function is__writable($path)
{
if ($path{strlen($path)-1}=='/') //Start function again with tmp file...
return is__writable($path.uniqid(mt_rand()).'.tmp');
elseif (ereg('.tmp', $path))
{ //Check tmp file for read/write capabilities
if (!($f = @fopen($path, 'w+')))
return false;
fclose($f);
unlink($path);
return true;
}
else //We have a path error.
return 0; // Or return error - invalid path...
}
?>
The original could've deleted a folder if the path was invalid to start with (no trailing slash..) and the folder was writable to begin with...
Be careful of legolas558 dot sourceforge comma net's example, try this instead:
<?php
function is__writable($path)
{
if ($path{strlen($path)-1}=='/')
return is__writable($path.uniqid(mt_rand()).'.tmp');
elseif (file_exists($path) && ereg('.tmp', $path))
{
if (!($f = @fopen($path, 'w+')))
return false;
fclose($f);
unlink($path);
return true;
}
else
return 0; // Or return error - invalid path...
}
?>
this one recursivly checks if a folder and all its contents are writeable
<?php
function is_removeable($dir)
{
$folder = opendir($dir);
while($file = readdir( $folder ))
if($file != '.' && $file != '..' &&
( !is_writable( $dir."/".$file ) ||
( is_dir( $dir."/".$file ) && !is_removeable( $dir."/".$file ) ) ))
{
closedir($dir);
return false;
}
closedir($dir);
return true;
}
?>
