file : add the filemtime function git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@3208 bf3deb0d-5f1a-0410-827f-c0cc1f45334c
773 lines
28 KiB
PHP
773 lines
28 KiB
PHP
<?php
|
|
/** DomFramework
|
|
@package domframework
|
|
@author Dominique Fournier <dominique@fournier38.fr> */
|
|
|
|
/** The file method allow to manage files like PHP with a working chroot on all
|
|
* plateforms, and a right management compatible with database
|
|
* Don't follow links !
|
|
*
|
|
* To allow an external authorization test in plus of the filesystem check, you
|
|
* must extends the class and overload checkExternalPathRO and
|
|
* checkExternalPathRW.
|
|
*/
|
|
class file
|
|
{
|
|
/** The virtual current working directory */
|
|
private $cwd = ".";
|
|
/** The real directory used as root in virtual chroot */
|
|
private $baseDir = "/";
|
|
|
|
/** The lock stack */
|
|
private $locks = array ();
|
|
|
|
/** Activate the debug and define the minimum priority to save */
|
|
public $debug = 0;
|
|
|
|
/** Change the current working directory
|
|
* @return bool true if the directory is changed
|
|
* @throws If directory not exists, or the directory is not executable
|
|
*/
|
|
public function chdir ($directory)
|
|
{
|
|
$this->debug (2, "chdir ($directory)");
|
|
$tmpdirectory = $this->realpath ($directory);
|
|
$this->checkPathRO ($tmpdirectory);
|
|
if ($this->baseDir === "/")
|
|
$this->cwd = $tmpdirectory;
|
|
else
|
|
$this->cwd = substr ($tmpdirectory, strlen ($this->baseDir));
|
|
$this->debug (1, "chdir $directory -> $this->cwd");
|
|
return true;
|
|
}
|
|
|
|
/** Change the group for a file/dir...
|
|
* @param $filename string The file/directory to change
|
|
* @param $group mixed The group name or group GID
|
|
* @throws If filename not exists, or the directory is not RW
|
|
*/
|
|
public function chgrp ($filename, $group)
|
|
{
|
|
$this->debug (2, "chgrp ($filename, $group)");
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRW (dirname ($filename));
|
|
if (! file_exists ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' to chmod doesn't exists"),
|
|
$filename), 404);
|
|
if (! is_writeable ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' to chmod is not writeable"),
|
|
$filename), 500);
|
|
$rc = chgrp ($filename, $group);
|
|
$this->debug (1, "chgrp ($filename, $group) => $rc");
|
|
return $rc;
|
|
}
|
|
|
|
/** Change the rights mode for a file/dir...
|
|
* @param $filename string The file/directory to change
|
|
* @throws If filename not exists, or the directory is not RW
|
|
*/
|
|
public function chmod ($filename, $mode)
|
|
{
|
|
$this->debug (2, "chmod ($filename, $mode)");
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRW (dirname ($filename));
|
|
if (! file_exists ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' to chmod doesn't exists"),
|
|
$filename), 404);
|
|
if (! is_writeable ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' to chmod is not writeable"),
|
|
$filename), 500);
|
|
$rc = chmod ($filename, $mode);
|
|
$this->debug (1, "chmod ($filename, $mode) => $rc");
|
|
return $rc;
|
|
}
|
|
|
|
/** Change the owner for a file/dir...
|
|
* @param $filename string The file/directory to change
|
|
* @param $user mixed The user name or user UID
|
|
* @throws If filename not exists, or the directory is not RW
|
|
*/
|
|
public function chown ($filename, $user)
|
|
{
|
|
$this->debug (2, "chown ($filename, $user)");
|
|
if (posix_getuid () !== 0 &&
|
|
posix_getuid () !== $user &&
|
|
posix_getpwuid (posix_getuid()) !== $user)
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"Only root user can change the file owner for '%s'"),
|
|
$filename), 500);
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRW (dirname ($filename));
|
|
if (! file_exists ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' to chmod doesn't exists"),
|
|
$filename), 404);
|
|
if (! is_writeable ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' to chmod is not writeable"),
|
|
$filename), 500);
|
|
$rc = chown ($filename, $user);
|
|
$this->debug (1, "chown ($filename, $user) => $rc");
|
|
return $rc;
|
|
}
|
|
|
|
/** Chroot in the provided directory
|
|
* @param $directory string The directory to chroot
|
|
* @return true if the chroot is done, false if there is a failure
|
|
* @throws If directory not exists, or the directory is not executable
|
|
*/
|
|
public function chroot ($directory)
|
|
{
|
|
// Use the checkPathRO (using the $this->baseDir) to not allow to go away of
|
|
// the chroot.
|
|
$this->debug (2, "chroot ($directory)");
|
|
$directory = $this->realpath ($directory);
|
|
$this->checkPathRO ($directory);
|
|
$this->baseDir = preg_replace ("#//+#", "/", $directory);
|
|
$this->cwd = "/";
|
|
$this->debug (1, "chroot $directory -> $this->baseDir");
|
|
return true;
|
|
}
|
|
|
|
/** Checks whether a file or directory exists
|
|
* @param string $filename The file or directory to verify
|
|
* @return bool true if the file exists, false otherwise
|
|
* @throws If parent directory not exists, or is not executable
|
|
*/
|
|
public function file_exists ($filename)
|
|
{
|
|
$this->debug (2, "file_exists ($filename)");
|
|
$filename = $this->realpath ($filename);
|
|
try
|
|
{
|
|
$this->checkPathRO (dirname ($filename));
|
|
}
|
|
catch (\Exception $e)
|
|
{
|
|
if ($e->getCode () !== 404)
|
|
throw new \Exception ($e->getMessage (), $e->getCode ());
|
|
}
|
|
if (file_exists ($filename) && ! is_link ($filename))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/** Get the file contents
|
|
* @param string $filename Name of the file to read
|
|
* @return string Content of the file
|
|
* @throws If parent directory not exists, is not readable, the file is not
|
|
* exists or is not readable
|
|
*/
|
|
public function file_get_contents ($filename)
|
|
{
|
|
$this->debug (2, "file_get_contents ($filename)");
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRO (dirname ($filename));
|
|
if (! is_file ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' is not a file"),
|
|
$filename), 500);
|
|
if (! is_readable ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' is not readable"),
|
|
$filename), 500);
|
|
$contents = file_get_contents ($filename);
|
|
$this->debug (1, "file_get_contents ($filename) => ".strlen ($contents).
|
|
" bytes");
|
|
return $contents;
|
|
}
|
|
|
|
/** Write a string to a file
|
|
* @param string $filename Path to the file where to write the data
|
|
* @param string $data The data to write
|
|
* @param int|null $flags The optional flags
|
|
* @return the length of the data stored
|
|
* @throws If parent directory not exists, is not writeable, or the file
|
|
* exists and is not writeable
|
|
*/
|
|
public function file_put_contents ($filename, $data, $flags=0)
|
|
{
|
|
$this->debug (2, "file_put_contents ($filename)");
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRW (dirname ($filename));
|
|
if (file_exists ($filename) && ! is_writeable ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' is not writeable"),
|
|
$filename), 500);
|
|
if (file_exists ($filename) && ! is_file ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' is not a file"),
|
|
$filename), 500);
|
|
$contents = file_put_contents ($filename, $data, $flags);
|
|
$this->debug (1, "file_put_contents ($filename, \$data) => ".
|
|
"$contents bytes");
|
|
return $contents;
|
|
|
|
}
|
|
|
|
/** Get the file modification time of a file
|
|
* @param string $filename Path to the file
|
|
* @return the time the file was last modified, or FALSE on failure. The
|
|
* time is returned as a Unix timestamp, which is suitable for the date()
|
|
* function.
|
|
* @throws If parent directory not exists, is not writeable
|
|
*/
|
|
public function filemtime ($filename)
|
|
{
|
|
$this->debug (2, "filemtime ($filename)");
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRO (dirname ($filename));
|
|
return filemtime ($filename);
|
|
}
|
|
|
|
/** Return the current working directory
|
|
* @return string the current working directory */
|
|
public function getcwd ()
|
|
{
|
|
$this->debug (1, "getcwd $this->cwd");
|
|
return $this->cwd;
|
|
}
|
|
|
|
/** Tells whether the given filename is a directory
|
|
* @param string $filename The filename to test
|
|
* @return bool true if the $filename is a directory and exists, false
|
|
* otherwise
|
|
* @throws If parent directory not exists, or is not executable
|
|
*/
|
|
public function is_dir ($filename)
|
|
{
|
|
$this->debug (2, "is_dir ($filename)");
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRO (dirname ($filename));
|
|
if (file_exists ($filename) && is_dir ($filename))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/** Tells whether the given filename is a valid file
|
|
* @param string $filename The filename to test
|
|
* @return bool true if the $filename is a file and exists, false otherwise
|
|
* @throws If parent directory not exists, or is not executable
|
|
*/
|
|
public function is_file ($filename)
|
|
{
|
|
$this->debug (2, "is_file ($filename)");
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRO (dirname ($filename));
|
|
if (file_exists ($filename) && is_file ($filename))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
|
|
/** Lock a file exclusively
|
|
* @param $filename The file to lock
|
|
* @return bool true if the lock is acquired, false otherwise
|
|
* @throws If parent directory not exists, or is not writeable
|
|
*/
|
|
public function lockEX ($filename)
|
|
{
|
|
$this->debug (2, "lockEX ($filename)");
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRW (dirname ($filename));
|
|
$this->locks[$filename] = fopen ($filename, "rt");
|
|
return flock ($this->locks[$filename], LOCK_EX);
|
|
}
|
|
|
|
/** Lock a file shared (allow multiple read)
|
|
* @param $filename The file to lock
|
|
* @return bool true if the lock is acquired, false otherwise
|
|
* @throws If parent directory not exists, or is not writeable
|
|
*/
|
|
public function lockSH ($filename)
|
|
{
|
|
$this->debug (2, "lockSH ($filename)");
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRW (dirname ($filename));
|
|
$this->locks[$filename] = fopen ($filename, "rt");
|
|
return flock ($this->locks[$filename], LOCK_SH);
|
|
}
|
|
|
|
/** Unlock a file previously locked
|
|
* @param $filename The file to lock
|
|
* @return bool true if the lock is acquired, false otherwise
|
|
* @throws If parent directory not exists, or is not writeable
|
|
*/
|
|
public function lockUN ($filename)
|
|
{
|
|
$this->debug (2, "lockUN ($filename)");
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRW (dirname ($filename));
|
|
$res = true;
|
|
if (isset ($this->locks[$filename]))
|
|
{
|
|
$res = flock ($this->locks[$filename], LOCK_UN);
|
|
fclose ($this->locks[$filename]);
|
|
}
|
|
return $res;
|
|
}
|
|
|
|
|
|
/** Calculate the md5 sum of a file
|
|
* @param $filename The file to hash
|
|
* @return the calulated hash
|
|
* @throws If the file doesn't exists
|
|
*/
|
|
public function md5_file ($filename)
|
|
{
|
|
$this->debug (2, "md5_file ($filename)");
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRO (dirname ($filename));
|
|
if (! is_file ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' is not a file"),
|
|
$filename), 500);
|
|
if (! is_readable ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' is not readable"),
|
|
$filename), 500);
|
|
return md5_file ($filename);
|
|
}
|
|
|
|
/** Create a new directory
|
|
* @param $pathname The directory to create
|
|
* @param $mode The mode to create (0777 by default)
|
|
* @param $recursive (false by default)
|
|
* @return bool true if the directory is correctely created, false if the
|
|
* directory already exists
|
|
* @throws If parent directory not exists, is not writeable
|
|
*/
|
|
public function mkdir ($pathname, $mode = 0777, $recursive = false)
|
|
{
|
|
$this->debug (2, "mkdir ($pathname, $mode, $recursive)");
|
|
$pathname = $this->realpath ($pathname);
|
|
if ($recursive)
|
|
{
|
|
$parents = explode ("/", $pathname);
|
|
array_pop ($parents);
|
|
$parent = "";
|
|
foreach ($parents as $p)
|
|
{
|
|
$parent = $parent.$p."/";
|
|
if (! file_exists ($parent))
|
|
{
|
|
if (is_writeable (dirname ($parent)))
|
|
break;
|
|
throw new \Exception (sprintf ("Last Directory '%s' is readonly",
|
|
dirname ($parent)), 500);
|
|
}
|
|
}
|
|
if ($parent === dirname ($pathname) && ! is_writeable (dirname ($parent)))
|
|
{
|
|
throw new \Exception (sprintf ("Parent directory '%s' is readonly",
|
|
dirname ($parent)), 500);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$this->checkPathRW (dirname ($pathname));
|
|
}
|
|
if (file_exists ($pathname))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"Directory '%s' already exists"),
|
|
$pathname), 500);
|
|
$rc = mkdir ($pathname, $mode, $recursive);
|
|
$this->debug (1, "mkdir ($pathname, $mode, $recursive) => $rc");
|
|
return $rc;
|
|
}
|
|
|
|
/** Copy a file or a directory
|
|
* @param string $oldname The file to copy
|
|
* @param string $newname The new name of the file. It will be
|
|
* overwrited if it already exists
|
|
* @return bool
|
|
*/
|
|
public function copy ($oldname, $newname)
|
|
{
|
|
$this->debug (2, "copy ($oldname, $newname)");
|
|
$oldname = $this->realpath ($oldname);
|
|
$newname = $this->realpath ($newname);
|
|
$this->checkPathRO (dirname ($oldname));
|
|
$this->checkPathRW (dirname ($newname));
|
|
if (is_dir ($oldname))
|
|
{
|
|
// Copy directory structure
|
|
if (! $this->file_exists ($newname))
|
|
$this->mkdir ($newname);
|
|
$files = $this->scandirNotSorted ($oldname);
|
|
foreach ($files as $file)
|
|
$this->copy ("$oldname/$file", "$newname/$file");
|
|
}
|
|
else
|
|
{
|
|
$rc = copy ($oldname, $newname);
|
|
}
|
|
$this->debug (1, "copy ($oldname, $newname) => $rc");
|
|
return $rc;
|
|
}
|
|
|
|
/** Renames a file or directory
|
|
* @param string $oldname The file or directory to rename
|
|
* @param string $newname The new name of the file or directory. It will be
|
|
* overwrited if it already exists
|
|
* @return bool
|
|
*/
|
|
public function rename ($oldname, $newname)
|
|
{
|
|
$this->debug (2, "rename ($oldname, $newname)");
|
|
$oldname = $this->realpath ($oldname);
|
|
$newname = $this->realpath ($newname);
|
|
$this->checkPathRO (dirname ($oldname));
|
|
$this->checkPathRW (dirname ($newname));
|
|
$rc = rename ($oldname, $newname);
|
|
$this->debug (1, "rename ($oldname, $newname) => $rc");
|
|
return $rc;
|
|
}
|
|
|
|
/** Return a ini file converted to an array
|
|
* @param string $filename The filename of the ini file being parsed.
|
|
* @param bool $process_sections Process the sections
|
|
* @return array
|
|
*/
|
|
public function parse_ini_file ($filename, $process_sections = false)
|
|
{
|
|
$this->debug (2, "parse_ini_file ($filename, $process_sections)");
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRO (dirname ($filename));
|
|
if (! is_file ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' is not a file"),
|
|
$filename), 500);
|
|
if (! is_readable ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' is not readable"),
|
|
$filename), 500);
|
|
return parse_ini_file ($filename, $process_sections);
|
|
}
|
|
|
|
/** Return the canonical absolute path. Do not check if the directory exists,
|
|
* if there is links. Just calculate the realpath based on the chroot value
|
|
* @param string $path the path to analyze
|
|
* @return string the canonical absolute path
|
|
*/
|
|
public function realpath ($path)
|
|
{
|
|
$oriPath = $path;
|
|
$this->debug (2, "realpath ($oriPath)");
|
|
$path = preg_replace ("#//+#", "/", $path);
|
|
if (substr ($path, -1) === "/")
|
|
$path = substr ($path, 0, -1);
|
|
$parts = explode ("/", $path);
|
|
$current = $this->cwd;
|
|
$tmp = explode ("/", $current);
|
|
foreach ($parts as $part)
|
|
{
|
|
if ($part === "")
|
|
$tmp = array();
|
|
elseif ($part === ".")
|
|
continue;
|
|
elseif ($part === "..")
|
|
{
|
|
array_pop ($tmp);
|
|
continue;
|
|
}
|
|
else
|
|
array_push ($tmp, $part);
|
|
}
|
|
if (reset ($tmp) === ".")
|
|
{
|
|
array_shift ($tmp);
|
|
$path = $current."/".implode ("/", $tmp);
|
|
}
|
|
else
|
|
$path = "/".implode ("/", $tmp);
|
|
if ($this->baseDir !== "/")
|
|
$path = $this->baseDir.$path;
|
|
$path = preg_replace ("#//+#", "/", $path);
|
|
if ($path !== "/" && substr ($path, -1) === "/")
|
|
$path = substr ($path, 0, -1);
|
|
$this->debug (1, "realpath ($oriPath) => $path");
|
|
return $path;
|
|
}
|
|
|
|
/** Remove the provided directory
|
|
* If the recurse flag is true, remove the content too (files and
|
|
* directories)
|
|
* @param string $dirname The directory to remove
|
|
* @param bool $recursive Remove recursively
|
|
* @return bool true if all is removed, false otherwise
|
|
* @throws If parent directory not exists, is not writeable or the current
|
|
* dir is not writeable
|
|
*/
|
|
public function rmdir ($dirname, $recursive=false)
|
|
{
|
|
$this->debug (2, "rmdir ($dirname, $recursive)");
|
|
$tmpdirname = $this->realpath ($dirname);
|
|
$this->checkPathRW (dirname ($tmpdirname));
|
|
$this->checkPathRW ($tmpdirname);
|
|
if ($recursive === false)
|
|
return @rmdir ($tmpdirname);
|
|
$files = array_diff (scandir ($tmpdirname), array('.','..'));
|
|
foreach ($files as $file)
|
|
{
|
|
if (is_dir ("$tmpdirname/$file"))
|
|
{
|
|
$this->rmdir("$dirname/$file", $recursive);
|
|
}
|
|
else
|
|
{
|
|
unlink ("$tmpdirname/$file");
|
|
}
|
|
}
|
|
return rmdir ($tmpdirname);
|
|
}
|
|
|
|
/** Return the list of files and directories in the directory.
|
|
* Do not return the . and .. virtual dirs.
|
|
* The result is sorted
|
|
* @param string $directory The directory to read
|
|
* @return array the list of files and dirs
|
|
* @throws If directory not exists, or is not executable
|
|
*/
|
|
public function scandir ($directory)
|
|
{
|
|
$this->debug (2, "scandir ($directory)");
|
|
$directory = $this->realpath ($directory);
|
|
$this->checkPathRO ($directory);
|
|
$res = array_values (array_diff (scandir ($directory), array('..', '.')));
|
|
natsort ($res);
|
|
return $res;
|
|
}
|
|
|
|
/** Return the list of files and directories in the directory.
|
|
* Do not return the . and .. virtual dirs.
|
|
* The result is NOT sorted
|
|
* @param string $directory The directory to read
|
|
* @return array the list of files and dirs
|
|
* @throws If directory not exists, or is not executable
|
|
*/
|
|
public function scandirNotSorted ($directory)
|
|
{
|
|
$this->debug (2, "scandirNotSorted ($directory)");
|
|
$directory = $this->realpath ($directory);
|
|
$this->checkPathRO ($directory);
|
|
$res = array_values (array_diff (scandir ($directory, SCANDIR_SORT_NONE),
|
|
array('..', '.')));
|
|
return $res;
|
|
}
|
|
|
|
/** Calculate the sha1 sum of a file
|
|
* @param $filename The file to hash
|
|
* @return the calulated hash
|
|
* @throws If the file doesn't exists
|
|
*/
|
|
public function sha1_file ($filename)
|
|
{
|
|
$this->debug (2, "sha1_file ($filename)");
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRO (dirname ($filename));
|
|
if (! is_file ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' is not a file"),
|
|
$filename), 500);
|
|
if (! is_readable ($filename))
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"File '%s' is not readable"),
|
|
$filename), 500);
|
|
return sha1_file ($filename);
|
|
}
|
|
|
|
/** Create a new file or update the timestamp if the file exists
|
|
* @param string $filename the filename
|
|
* @param int $time the timestamp to use (actual timestamp if not defined)
|
|
* @return bool true or false on failure
|
|
* @throws If parent directory not exists, is not writeable
|
|
*/
|
|
public function touch ($filename, $time = null, $atime = null)
|
|
{
|
|
$this->debug (2, "touch ($filename, $time, $atime)");
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRW (dirname ($filename));
|
|
if ($time === null)
|
|
$time = time ();
|
|
if ($atime === null)
|
|
$atime = time ();
|
|
$rc = touch ($filename, $time, $atime);
|
|
$this->debug (1, "touch ($filename, $time, $atime) => $rc");
|
|
return $rc;
|
|
}
|
|
|
|
/** Delete an existing file.
|
|
* @param string $filename The filename to remove
|
|
* @return bool true if the file si removed, false otherwise
|
|
* @throws If parent directory not exists, or is not executable
|
|
*/
|
|
public function unlink ($filename)
|
|
{
|
|
$this->debug (2, "unlink ($filename)");
|
|
$filename = $this->realpath ($filename);
|
|
$this->checkPathRW (dirname ($filename));
|
|
if (! file_exists ($filename) || ! is_writeable ($filename))
|
|
return false;
|
|
return unlink ($filename);
|
|
}
|
|
|
|
/** Check all the parents of the $directory if they are available, and
|
|
* executable. The path must exists.
|
|
* Must use the filesystem path (complete) and not the version in chroot.
|
|
* The last directoy must be executable and readable (no test for writeable)
|
|
* @param $path string The directory path to check
|
|
* @return true if the path is executable for all the parents and for the
|
|
* last directory
|
|
* @throws if there is a missing part, or a parent is not executable
|
|
*/
|
|
private function checkPathRO ($path)
|
|
{
|
|
$this->debug (2, "checkPathRO ($path)");
|
|
$path = preg_replace ("#//+#", "/", $path);
|
|
$parents = explode ("/", $path);
|
|
array_pop ($parents);
|
|
$parent = "";
|
|
foreach ($parents as $p)
|
|
{
|
|
$parent = $parent.$p."/";
|
|
if (! file_exists ($parent))
|
|
{
|
|
$this->debug (1,
|
|
"checkPathRO ($path) => Parent Path '$parent' not found");
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"Parent Path '%s' not found"),
|
|
$parent), 404);
|
|
}
|
|
if (! is_executable ($parent))
|
|
{
|
|
$this->debug (1, "checkPathRO ($path) => ".
|
|
"Parent Directory '$parent' not executable");
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"Parent Directory '%s' not executable"),
|
|
$parent), 500);
|
|
}
|
|
if ($this->checkExternalPathRO ($parent) !== true)
|
|
{
|
|
$this->debug (1, "checkPathRO ($path) => ".
|
|
"Parent Directory '$parent' not accessible by ".
|
|
"external check read-only");
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"Parent Directory '%s' not accessible ".
|
|
"by external check read-only"),
|
|
$parent), 500);
|
|
}
|
|
}
|
|
if (! file_exists ($path))
|
|
{
|
|
$this->debug (1, "checkPathRO ($path) => Path '$path' not found");
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"Path '%s' not found"),
|
|
$path), 404);
|
|
}
|
|
if (! is_dir ($path))
|
|
{
|
|
$this->debug (1, "checkPathRO ($path) => ".
|
|
"Path '$path' is not a directory");
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"Path '%s' is not a directory"),
|
|
$path),
|
|
500);
|
|
}
|
|
if (! is_executable ($path))
|
|
{
|
|
$this->debug (1, "checkPathRO ($path) => ".
|
|
"Directory '$path' is not executable");
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"Directory '%s' is not executable"),
|
|
$path), 500);
|
|
}
|
|
if (! is_readable ($path))
|
|
{
|
|
$this->debug (1, "checkPathRO ($path) => ".
|
|
"Directory '$path' is not readable");
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"Directory '%s' is not readable"),
|
|
$path), 500);
|
|
}
|
|
return $this->checkExternalPathRO ($path);
|
|
}
|
|
|
|
/** Check all the parents of the $directory if they are available, and
|
|
* executable. The path must exists.
|
|
* Must use the filesystem path (complete) and not the version in chroot.
|
|
* The last directoy must be executable and readable and writeable
|
|
* @param $path string The directory path to check
|
|
* @return true if the path is executable for all the parents and for the
|
|
* last directory
|
|
* @throws if there is a missing part, or a parent is not executable
|
|
*/
|
|
private function checkPathRW ($path)
|
|
{
|
|
$this->debug (2, "checkPathRW ($path)");
|
|
$this->checkPathRO ($path);
|
|
if (! is_writeable ($path))
|
|
{
|
|
$this->debug (1, "checkPathRW ($path) => ".
|
|
"Directory '$path' is not writeable");
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"Directory '%s' is not writeable"),
|
|
$path), 500);
|
|
}
|
|
if ($this->checkExternalPathRW ($path) !== true)
|
|
{
|
|
$this->debug (1, "checkPathRW ($path) => ".
|
|
"Directory '$path' not accessible by ".
|
|
"external check read-write");
|
|
throw new \Exception (sprintf (dgettext ("domframework",
|
|
"Directory '%s' not accessible ".
|
|
"by external check read-write"),
|
|
$path), 500);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/** Save a debug log
|
|
* @param $prio The message priority. Should be higher than $this->debug to
|
|
* save the message
|
|
* @param $message The message to save
|
|
* @return null;
|
|
*/
|
|
private function debug ($prio, $message)
|
|
{
|
|
if ($this->debug === false || $this->debug === 0)
|
|
return;
|
|
if ($prio <= $this->debug)
|
|
{
|
|
echo "[$prio] $message\n";
|
|
//file_put_contents ("/tmp/domframework.file.debug",
|
|
// date ("Y:m:d H:i:s")." [$prio] $message\n",
|
|
// FILE_APPEND);
|
|
}
|
|
}
|
|
|
|
/** External function allowed to be overloaded to test the RO access to a
|
|
* resource
|
|
* @param string $path The path to test in the filesystem
|
|
* @return boolean true if RO access, false if not
|
|
*/
|
|
public function checkExternalPathRO ($path)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/** External function allowed to be overloaded to test the RW access to a
|
|
* resource
|
|
* @param string $path The path to test in the filesystem
|
|
* @return boolean true if RW access, false if not
|
|
*/
|
|
public function checkExternalPathRW ($path)
|
|
{
|
|
return true;
|
|
}
|
|
}
|