Files
DomFramework/src/File.php
2022-11-25 21:21:30 +01:00

1089 lines
38 KiB
PHP

<?php
/** DomFramework
* @package domframework
* @author Dominique Fournier <dominique@fournier38.fr>
* @license BSD
*/
namespace Domframework;
/** 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
* @param string $directory Go in the provided 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 string $filename The file/directory to change
* @param mixed $group 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 string $filename The file/directory to change
* @param integer $mode The mode to use for the filename
* @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 string $filename The file/directory to change
* @param mixed $user 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 string $directory The directory to chroot
* @return boolean 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;
}
/** Get the file contents in an array (like 'file' function, but can not
* have the same name as the class...)
* @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 fileArray($filename)
{
$this->debug(2, "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);
}
$contents = file($filename);
$this->debug(1, "file ($filename) => " . count($contents) . " rows");
return $contents;
}
/** 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|integer $data The data to write
* @param integer|null $flags The optional flags
* @return integer 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 integer|boolean 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);
}
/** Get the file size
* @param string $filename Path to the file
* @return integer|boolean the size of the file or FALSE on failure.
* @throws If parent directory not exists, is not writeable
*/
public function filesize($filename)
{
$this->debug(2, "filesize ($filename)");
$filename = $this->realpath($filename);
$this->checkPathRO(dirname($filename));
return filesize($filename);
}
/** Get the file info of the provided filename
* @param string $filename Path to the file
* @return string the mimetype of the file
* @throws If parent directory not exists, is not writeable
*/
public function fileinfoMimeType($filename)
{
$this->debug(2, "filesize ($filename)");
$filename = $this->realpath($filename);
$this->checkPathRO(dirname($filename));
$finfo = new \finfo(FILEINFO_MIME_TYPE);
return $finfo->file($filename);
}
/** Return the current working directory
* @return string the current working directory */
public function getcwd()
{
$this->debug(1, "getcwd $this->cwd");
return $this->cwd;
}
/** Find pathnames matching a pattern
* If there is some unreadable files, skip them quietly
* @param string $pattern The pattern to found
* @param integer|null $flags The additional flags
* @return array Return an array if there is an error
* @throws If parent directory not exists, or is not executable
* or if there is one file unreadable
*/
public function glob($pattern, $flags = 0)
{
$this->debug(2, "glob ($pattern, $flags)");
$this->checkPathRO($this->baseDir);
if (substr($pattern, 0, 1) === "/") {
$relative = 0;
} else {
$relative = 1;
}
$pattern = $this->realpath($pattern);
$files = glob($pattern, $flags);
if ($files === false) {
// FIXME : In the exception : how found the file which is not readable ?
throw new \Exception("Glob : can't read some files", 500);
}
foreach ($files as &$file) {
if (strlen($this->baseDir) > 1) {
if ($relative == 1) {
$file = substr($file, strlen($this->baseDir) + strlen($this->cwd) + 1);
} else {
$file = substr($file, strlen($this->baseDir));
}
} else {
if ($relative == 1) {
$file = substr($file, strlen($this->cwd) + 1);
}
}
}
return $files;
}
/** 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;
}
/** Tells whether a file exists and is executable
* @param string $filename The filename to test
* @return bool true if the $filename is a file exists and is writeable
* @throws If parent directory not exists, or is not executable
*/
public function is_executable($filename)
{
$this->debug(2, "is_executable ($filename)");
$filename = $this->realpath($filename);
$this->checkPathRO(dirname($filename));
if (file_exists($filename) && is_executable($filename)) {
return true;
}
return false;
}
/** Tells whether a file exists and is readable
* @param string $filename The filename to test
* @return bool true if the $filename is a file exists and is readable
* @throws If parent directory not exists, or is not executable
*/
public function is_readable($filename)
{
$this->debug(2, "is_readable ($filename)");
$filename = $this->realpath($filename);
$this->checkPathRO(dirname($filename));
if (file_exists($filename) && is_readable($filename)) {
return true;
}
return false;
}
/** Tells whether a file exists and is writeable
* @param string $filename The filename to test
* @return bool true if the $filename is a file exists and is writeable
* @throws If parent directory not exists, or is not executable
*/
public function is_writeable($filename)
{
$this->debug(2, "is_writeable ($filename)");
$filename = $this->realpath($filename);
$this->checkPathRO(dirname($filename));
if (file_exists($filename) && is_writeable($filename)) {
return true;
}
return false;
}
/** Lock a file exclusively
* @param string $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));
if (! file_exists($filename)) {
throw new \Exception(sprintf(
dgettext(
"domframework",
"File '%s' doesn't exists : could not be locked"
),
$filename
), 500);
}
if (! is_readable($filename)) {
throw new \Exception(sprintf(
dgettext(
"domframework",
"File '%s' is not readable : could not be locked"
),
$filename
), 500);
}
$this->locks[$filename] = fopen($filename, "rt");
return flock($this->locks[$filename], LOCK_EX);
}
/** Lock a file shared (allow multiple read)
* @param string $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));
if (! file_exists($filename)) {
throw new \Exception(sprintf(
dgettext(
"domframework",
"File '%s' doesn't exists : could not be locked"
),
$filename
), 500);
}
if (! is_readable($filename)) {
throw new \Exception(sprintf(
dgettext(
"domframework",
"File '%s' is not readable : could not be locked"
),
$filename
), 500);
}
$this->locks[$filename] = fopen($filename, "rt");
return flock($this->locks[$filename], LOCK_SH);
}
/** Unlock a file previously locked
* @param string $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]);
unset($this->locks[$filename]);
}
return $res;
}
/** Calculate the md5 sum of a file
* @param string $filename The file to hash
* @return string 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 string $pathname The directory to create
* @param integer $mode The mode to create (0777 by default)
* @param boolean $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 boolean $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 boolean $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 string $filename The file to hash
* @return string 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 integer|null $time the timestamp to use (actual timestamp if not
* defined)
* @param integer|null $atime the access 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 string $path The directory path to check
* @return boolean 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 string $path 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 integer $prio The message priority. Should be higher than
* $this->debug to save the message
* @param string $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;
}
}