Skip to content

File Mode / Permissions Interface #49

@tristanlins

Description

@tristanlins

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions