Admidio/admidio

View on GitHub
adm_program/modules/documents-files/documents_files_function.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php
/**
 ***********************************************************************************************
 * Various functions for documents & files module
 *
 * @copyright The Admidio Team
 * @see https://www.admidio.org/
 * @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License v2.0 only
 ***********************************************************************************************
 * Parameters:
 *
 * mode   :  create_folder - Create folder
 *           delete_folder - Delete folder
 *           delete_file   - Delete file
 *           permissions   - Save permissions of folder
 *           add    - Add file/folder to database
 *           rename - Rename file/folder
 *           move   - Move file / folder
 * folder_uuid : UUID of the folder in the database
 * file_uuid   : UUID of the file in the database
 * name        : Name of the file/folder that should be added to the database
 ***********************************************************************************************/
use Admidio\Exception;

require_once(__DIR__ . '/../../system/common.php');
require(__DIR__ . '/../../system/login_valid.php');

try {
    // Initialize and check the parameters
    $getMode       = admFuncVariableIsValid($_GET, 'mode', 'string', array('requireValue' => true, 'validValues' => array('create_folder', 'delete_folder', 'delete_file', 'add', 'rename', 'move', 'permissions')));
    $getFolderUuid = admFuncVariableIsValid($_GET, 'folder_uuid', 'uuid');
    $getFileUuid   = admFuncVariableIsValid($_GET, 'file_uuid', 'uuid');
    $getName       = admFuncVariableIsValid($_GET, 'name', 'file');

    // check if the module is enabled and disallow access if it's disabled
    if (!$gSettingsManager->getBool('documents_files_module_enabled')) {
        throw new Exception('SYS_MODULE_DISABLED');
    }

    // Check path in adm_my_files and create if necessary
    FileSystemUtils::createDirectoryIfNotExists(ADMIDIO_PATH . FOLDER_DATA . '/' . TableFolder::getRootFolderName());

    // check the rights of the current folder
    // user must be administrator or must have the right to upload files
    $folder = new TableFolder($gDb);
    $folder->getFolderForDownload($getFolderUuid);

    if (!$folder->hasUploadRight()) {
        throw new Exception('SYS_NO_RIGHTS');
    }

    // check the CSRF token of the form against the session token
    if (in_array($getMode, array('delete_folder', 'delete_file'))) {
        SecurityUtils::validateCsrfToken($_POST['admidio-csrf-token']);
    }

    // Delete file
    if ($getMode === 'delete_file') {
        if ($getFileUuid !== '') {
            // get recordset of current file from database
            $file = new TableFile($gDb);
            $file->getFileForDownload($getFileUuid);

            $file->delete();
            echo json_encode(array('status' => 'success'));
            exit();
        } else {
            // if no file id was set then show error
            throw new Exception('SYS_INVALID_PAGE_VIEW');
        }
    }

    // create folder
    elseif ($getMode === 'create_folder') {
        if ($getFolderUuid === '') {
            // Folder UUID is required to create a sub-folder
            throw new Exception('SYS_INVALID_PAGE_VIEW');
        }

        try {
            $newFolderName = admFuncVariableIsValid($_POST, 'new_folder', 'file', array('requireValue' => true));
            $newFolderDescription = admFuncVariableIsValid($_POST, 'new_description', 'string');

            // check form field input and sanitized it from malicious content
            $documentsFilesFolderNewForm = $gCurrentSession->getFormObject($_POST['admidio-csrf-token']);
            $formValues = $documentsFilesFolderNewForm->validate($_POST);

            // Test if the folder already exists in the file system
            if (is_dir($folder->getFullFolderPath() . '/' . $newFolderName)) {
                throw new Exception('SYS_FOLDER_EXISTS', array($newFolderName));
            } else {
                // create folder
                $error = $folder->createFolder($newFolderName);

                if ($error === null) {
                    $folId = (int) $folder->getValue('fol_id');

                    // add folder to database
                    $newFolder = new TableFolder($gDb);

                    $newFolder->setValue('fol_fol_id_parent', $folId);
                    $newFolder->setValue('fol_type', 'DOCUMENTS');
                    $newFolder->setValue('fol_name', $newFolderName);
                    $newFolder->setValue('fol_description', $newFolderDescription);
                    $newFolder->setValue('fol_path', $folder->getFolderPath());
                    $newFolder->setValue('fol_locked', $folder->getValue('fol_locked'));
                    $newFolder->setValue('fol_public', $folder->getValue('fol_public'));
                    $newFolder->save();

                    // get roles rights of parent folder
                    $rightParentFolderView = new RolesRights($gDb, 'folder_view', $folId);
                    $newFolder->addRolesOnFolder('folder_view', $rightParentFolderView->getRolesIds());
                    $rightParentFolderUpload = new RolesRights($gDb, 'folder_upload', $folId);
                    $newFolder->addRolesOnFolder('folder_upload', $rightParentFolderUpload->getRolesIds());
                } else {
                    // the corresponding folder could not be created
                    throw new Exception($gL10n->get($error['text'], array($error['path'], '<a href="mailto:'.$gSettingsManager->getString('email_administrator').'">', '</a>')));
                }

                $gNavigation->deleteLastUrl();
                echo json_encode(array('status' => 'success', 'url' => $gNavigation->getUrl()));
                exit();
            }
        } catch (Exception $e) {
            if ($e->getMessage() === 'SYS_FILENAME_EMPTY') {
                throw new Exception('SYS_FIELD_EMPTY', array($gL10n->get('SYS_NAME')));
            }
            if ($e->getMessage() === 'SYS_FILENAME_INVALID') {
                throw new Exception('SYS_FOLDER_NAME_INVALID');
            }
            throw new Exception($e->getMessage());
        }
    }

    // rename folder or file
    elseif ($getMode === 'rename') {
        if (!$getFileUuid && !$getFolderUuid) {
            // file UUID and/or folder UUID must be set
            throw new Exception('SYS_INVALID_PAGE_VIEW');
        }

        try {
            $newName = admFuncVariableIsValid($_POST, 'new_name', 'file', array('requireValue' => true));
            $newDescription = admFuncVariableIsValid($_POST, 'new_description', 'string');

            // check form field input and sanitized it from malicious content
            $documentsFilesRenameForm = $gCurrentSession->getFormObject($_POST['admidio-csrf-token']);
            $formValues = $documentsFilesRenameForm->validate($_POST);

            if ($getFileUuid !== '') {
                // get recordset of current file from database and throw exception if necessary
                $file = new TableFile($gDb);
                $file->getFileForDownload($getFileUuid);

                $oldFile = $file->getFullFilePath();
                $newPath = $file->getFullFolderPath() . '/';
                $newFile = $newName . '.' . pathinfo($oldFile, PATHINFO_EXTENSION);

                // check if file already exists in filesystem
                if ($newFile !== $file->getValue('fil_name') && is_file($newPath . $newFile)) {
                    throw new Exception('SYS_FILE_EXIST', array($newFile));
                } else {
                    $oldName = $file->getValue('fil_name');

                    if ($newFile !== $file->getValue('fil_name')) {
                        // rename file in filesystem and database
                        try {
                            FileSystemUtils::moveFile($oldFile, $newPath . $newFile);
                        } catch (RuntimeException $exception) {
                            throw new Exception('SYS_FILE_RENAME_ERROR', array($oldName));
                        }
                    }

                    $file->setValue('fil_name', $newFile);
                    $file->setValue('fil_description', $newDescription);
                    $file->save();

                    $gNavigation->deleteLastUrl();
                    echo json_encode(array('status' => 'success', 'url' => $gNavigation->getUrl()));
                    exit();
                }
            } elseif ($getFolderUuid !== '') {
                // main folder could not be renamed
                if ($folder->getValue('fol_fol_id_parent') === '') {
                    throw new Exception('SYS_INVALID_PAGE_VIEW');
                }

                $oldFolder = $folder->getFullFolderPath();
                $newFolder = $newName;

                // check if folder already exists in filesystem
                if ($newFolder !== $folder->getValue('fol_name')
                && is_dir(ADMIDIO_PATH. $folder->getValue('fol_path'). '/'.$newFolder)) {
                    throw new Exception('SYS_FOLDER_EXISTS', array($newFolder));
                } else {
                    $oldName = $folder->getValue('fol_name');

                    if ($newFolder !== $folder->getValue('fol_name')) {
                        // rename folder in filesystem and database
                        try {
                            FileSystemUtils::moveDirectory($oldFolder, ADMIDIO_PATH. $folder->getValue('fol_path'). '/'.$newFolder);

                            $folder->rename($newFolder, $folder->getValue('fol_path'));
                        } catch (RuntimeException $exception) {
                            throw new Exception('SYS_FOLDER_RENAME_ERROR', array($oldName));
                        }
                    }

                    $folder->setValue('fol_description', $newDescription);
                    $folder->save();

                    $gNavigation->deleteLastUrl();
                    echo json_encode(array('status' => 'success', 'url' => $gNavigation->getUrl()));
                    exit();
                }
            }
        }
        // exception handling; replace some exception strings with better descriptions
        catch (Exception $e) {
            if ($e->getMessage() === 'SYS_FILENAME_EMPTY') {
                throw new Exception('SYS_FIELD_EMPTY', array($gL10n->get('SYS_NEW_NAME')));
            }
            if ($e->getMessage() === 'SYS_FILENAME_INVALID' && $getFolderUuid !== '') {
                throw new Exception('SYS_FOLDER_NAME_INVALID');
            }
            throw new Exception($e->getMessage());
        }
    }

    // delete folder
    elseif ($getMode === 'delete_folder') {
        if ($getFolderUuid === '') {
            // the uuid of the current folder must be set
            throw new Exception('SYS_INVALID_PAGE_VIEW');
        } else {
            $folder->delete();
            echo json_encode(array('status' => 'success'));
            exit();
        }
    }

    // add file / folder to database
    elseif ($getMode === 'add') {
        if ($getFolderUuid === '') {
            // the uuid of the current folder must be set
            throw new Exception('SYS_INVALID_PAGE_VIEW');
        }

        // only users with download administration rights should set new roles rights
        if (!$gCurrentUser->adminDocumentsFiles()) {
            throw new Exception('SYS_NO_RIGHTS');
        }

        // add the file or folder recursively to the database
        $folder->addFolderOrFileToDatabase($getName);

        // back to previous page
        $gNavigation->addUrl(CURRENT_URL);
        admRedirect(ADMIDIO_URL . '/adm_program/system/back.php');
        // => EXIT
    }

    // save view or upload rights for a folder
    elseif ($getMode === 'permissions') {
        if (!isset($_POST['adm_roles_view_right'])) {
            throw new Exception('SYS_FIELD_EMPTY', array('SYS_VISIBLE_FOR'));
        }
        if (!isset($_POST['adm_roles_upload_right'])) {
            // upload right does not need to be set because documents & files module administrators still
            // have the right, so initialize the parameter
            $_POST['adm_roles_upload_right'] = array();
        }

        if ($getFolderUuid === '' || !is_array($_POST['adm_roles_view_right']) || !is_array($_POST['adm_roles_upload_right'])) {
            // the uuid of the current folder must be set
            throw new Exception('SYS_INVALID_PAGE_VIEW');
        }

        // only users with documents & files administration rights should set new roles rights
        if (!$gCurrentUser->adminDocumentsFiles()) {
            throw new Exception('SYS_NO_RIGHTS');
        }

        // check form field input and sanitized it from malicious content
        $documentsFilesFolderPermissionsForm = $gCurrentSession->getFormObject($_POST['admidio-csrf-token']);
        $formValues = $documentsFilesFolderPermissionsForm->validate($_POST);

        $postIntRolesViewRight   = array_map('intval', $_POST['adm_roles_view_right']);
        $postIntRolesUploadRight = array_map('intval', $_POST['adm_roles_upload_right']);

        // Read current view roles rights of the folder
        $rightFolderView = new RolesRights($gDb, 'folder_view', $folder->getValue('fol_id'));
        $rolesFolderView = $rightFolderView->getRolesIds();

        // Read current upload roles rights of the folder
        $rightFolderUpload = new RolesRights($gDb, 'folder_upload', $folder->getValue('fol_id'));
        $rolesFolderUpload = $rightFolderUpload->getRolesIds();

        // get new roles and removed roles
        $addUploadRoles = array_diff($postIntRolesUploadRight, $rolesFolderUpload);
        $removeUploadRoles = array_diff($rolesFolderUpload, $postIntRolesUploadRight);

        if (in_array(0, $postIntRolesViewRight, true)) {
            // set flag public for this folder and all child folders
            $folder->editPublicFlagOnFolder(true);
            // if all users have access then delete all existing roles
            $folder->removeRolesOnFolder('folder_view', $rolesFolderView);
        } else {
            // set flag public for this folder and all child folders
            $folder->editPublicFlagOnFolder(false);

            // get new roles and removed roles
            $addViewRoles = array_unique(array_merge(array_diff($postIntRolesViewRight, $rolesFolderView), $postIntRolesUploadRight, $rolesFolderUpload));
            $removeViewRoles = array_diff($rolesFolderView, $postIntRolesViewRight);

            $folder->addRolesOnFolder('folder_view', $addViewRoles);
            $folder->removeRolesOnFolder('folder_view', $removeViewRoles);

            // upload right should not contain removed view roles
            $removeUploadRoles = array_merge($removeUploadRoles, $removeViewRoles);
        }

        $folder->addRolesOnFolder('folder_upload', $addUploadRoles);
        $folder->removeRolesOnFolder('folder_upload', $removeUploadRoles);
        $folder->save();

        $gNavigation->deleteLastUrl();
        echo json_encode(array('status' => 'success', 'url' => $gNavigation->getUrl()));
        exit();
    }
    // move file to another folder
    elseif ($getMode === 'move') {
        $destFolderUUID = admFuncVariableIsValid($_POST, 'dest_folder_uuid', 'string', array('requireValue' => true));

        // check form field input and sanitized it from malicious content
        $documentsFilesMoveForm = $gCurrentSession->getFormObject($_POST['admidio-csrf-token']);
        $formValues = $documentsFilesMoveForm->validate($_POST);

        if ($getFileUuid !== '') {
            $file = new TableFile($gDb);
            $file->readDataByUuid($getFileUuid);
            $file->moveToFolder($destFolderUUID);
        } else {
            $folder = new TableFolder($gDb);
            $folder->readDataByUuid($getFolderUuid);
            $folder->moveToFolder($destFolderUUID);
        }

        $gNavigation->deleteLastUrl();
        echo json_encode(array('status' => 'success', 'url' => $gNavigation->getUrl()));
        exit();
    }
} catch (Exception | Exception | RuntimeException | UnexpectedValueException $e) {
    echo json_encode(array('status' => 'error', 'message' => $e->getMessage()));
}