Currently we do not work around different permission systems.
How about to introduce an interface and some classes to handle this problem.
interface FileMode // or FilePermissions
{
const TYPE = 'unknown';
/**
* Check if file modes are supported by the fs.
*
* @return bool
*/
public function isSupported();
/**
* Test if file is readable for the current user.
* Which "user" is referenced, depends on the implementation
* and have to be automatically detected.
*
* @return bool
*/
public function isReadable();
/**
* Test if file is writeable for the current user.
* Which "user" is referenced, depends on the implementation
* and have to be automatically detected.
*
* @return bool
*/
public function isWriteable();
/**
* Test if file is executeable for the current user.
* Which "user" is referenced, depends on the implementation
* and have to be automatically detected.
*
* @return bool
*/
public function isExecuteable();
/**
* For stacked file permission systems, get the next hop.
*
* @return FileMode
*/
public function nextFileMode();
}
Then we have multiple classes with specific methods.
The UnsupportedFileMode
class that indicate that file permissions are not supported.
class UnsupportedFileMode implements FileMode
{
const TYPE = 'unsupported';
public function isSupported()
{
return false;
}
}
The PrimitiveFileMode
only know read, write, executeable. It does not know owner, groups or complex acl rules.
class PrimitiveFileMode implements FileMode
{
const TYPE = 'primitive';
public function isSupported()
{
return true;
}
public function isReadable();
public function isWriteable();
public function isExecuteable();
}
The UnixFileMode
only know read, write, executeable for owner, groups and others.
class UnixFileMode implements FileMode
{
const TYPE = 'unix';
public function isSupported()
{
return true;
}
public function isOwnerReadable();
public function isOwnerWriteable();
public function isOwnerExecuteable();
public function isGroupReadable();
public function isGroupWriteable();
public function isGroupExecuteable();
public function isOthersReadable();
public function isOthersWriteable();
public function isOthersExecuteable();
public function isSticky();
// maybe more
}
As you expected, the ACLFileMode will allow access to acl rules.
An interface system like this allow us to respect the different permission system.
The FileMode::isSupported
is mandatory, because in mounted or merged filesystem I don't have access to the underlaying filesystem to check the "file permissions" ability. The UnsupportedFileMode
prevents File::getMode
from returning null
.
Also other systems are allowed to implement there own permission system. For example Contao could implement it's own ContaoPermissionsFileMode
for example.
class ContaoPermissionsFileMode implements FileMode
{
const TYPE = 'contao';
public function isSupported()
{
return true;
}
public function isUserReadable($backendUserId);
public function isUserWriteable($backendUserId);
public function isMemberReadable($memberId);
public function isMemberWriteable($memberId);
}
To allow access to different permission systems, for example the ContaoPermissionsFileMode
is just an overlay over UnixFileMode
, the File::getMode
should be extended with a type parameter:
interface File
{
/**
* Get permission access object for this file.
*
* @param string $type The permission system to access.
* If null the filesystem default permission system will be returned.
*
* @throw UnsupportedPermissionSystemException will be thrown if the requested permission system is not available.
*/
public function getMode($type = null);
}
To access different permission systems just use the TYPE
constant:
/** @var ContaoFilesystem $fs */
$file = $fs->getFile('foo');
/** @var ContaoPermissionsFileMode $contaoPerms */
$contaoPerms = $file->getMode();
// forcing a permission system (not good)
try {
/** @var UnixFileMode $unixPerms */
$unixPerms = $file->getMode(UnixFileMode::TYPE);
} catch (UnsupportedPermissionSystemException $e) {
// unix unsupported, maybe it is a linked in remote share like dropbox or amazon S3
}
// get the next permission system (good way)
/** @var UnixFileMode|DropboxFileMode|AmazonS3FileMode|... $nextPerms */
$nextPerms = $contaoPerms->nextFileMode();
This allow us to transparent add file permission systems, nobody knows about it, but it will protect the files. The File::isReadable
, File::isWriteable
and File::isExecuteable
should be shortcuts to the FileMode::isReadable
, FileMode::isWriteable
, FileMode::isExecuteable
methods.