Admidio/admidio

View on GitHub
adm_program/modules/profile/profile_photo_edit.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php
/**
 ***********************************************************************************************
 * Upload and save new user photo
 *
 * @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:
 *
 * user_uuid        : Uuid of user whose photo should be changed
 * mode - choose    : default mode to choose the photo file you want to upload
 *        save      : save new photo in user recordset
 *        dont_save : delete photo in session and show message
 *        upload    : save new photo in session and show dialog with old and new photo
 *        review    : dialog shows current and new profile photo
 *        delete    : delete current photo in database
 ***********************************************************************************************
 */
use Admidio\Exception;
use Admidio\UserInterface\Form;

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

    // Initialize and check the parameters
    $getUserUuid = admFuncVariableIsValid($_GET, 'user_uuid', 'uuid', array('requireValue' => true));
    $getMode = admFuncVariableIsValid($_GET, 'mode', 'string', array('defaultValue' => 'choose', 'validValues' => array('choose', 'save', 'dont_save', 'upload', 'review', 'delete')));

    // checks if the server settings for file_upload are set to ON
    if (!PhpIniUtils::isFileUploadEnabled()) {
        throw new Exception('SYS_SERVER_NO_UPLOAD');
    }

    // read user data and show error if user doesn't exists
    $user = new User($gDb, $gProfileFields);
    $user->readDataByUuid($getUserUuid);

    // checks whether the user has the necessary rights to change the corresponding profile
    if (!$gCurrentUser->hasRightEditProfile($user)) {
        throw new Exception('SYS_NO_RIGHTS');
    }

    // when saving folders, check whether the subfolder in adm_my_files exists with the corresponding rights
    if ((int)$gSettingsManager->get('profile_photo_storage') === 1) {
        // Create folder for user photos in adm_my_files if necessary
        FileSystemUtils::createDirectoryIfNotExists(ADMIDIO_PATH . FOLDER_DATA . '/user_profile_photos');
    }

    if ((int)$user->getValue('usr_id') === 0) {
        throw new Exception('SYS_INVALID_PAGE_VIEW');
    }

    if ($getMode === 'save') {
        // Save photo

        if ((int)$gSettingsManager->get('profile_photo_storage') === 1) {
            // Save photo in the file system

            // Check if a photo was saved for the user
            $fileOld = ADMIDIO_PATH . FOLDER_DATA . '/user_profile_photos/' . $user->getValue('usr_id') . '_new.jpg';
            if (is_file($fileOld)) {
                $fileNew = ADMIDIO_PATH . FOLDER_DATA . '/user_profile_photos/' . $user->getValue('usr_id') . '.jpg';
                try {
                    FileSystemUtils::deleteFileIfExists($fileNew);

                    try {
                        FileSystemUtils::moveFile($fileOld, $fileNew);
                    } catch (\RuntimeException $exception) {
                        $gLogger->error('Could not move file!', array('from' => $fileOld, 'to' => $fileNew));
                        // TODO
                    }
                } catch (\RuntimeException $exception) {
                    $gLogger->error('Could not delete file!', array('filePath' => $fileNew));
                    // TODO
                }
            }
        } else {
            // Save photo in the database

            // Check if a photo was saved for the user
            if (strlen($gCurrentSession->getValue('ses_binary')) > 0) {
                $gDb->startTransaction();
                // Fotodaten in User-Tabelle schreiben
                $user->setValue('usr_photo', $gCurrentSession->getValue('ses_binary'));
                $user->save();

                // Foto aus Session entfernen und neues Einlesen des Users veranlassen
                $gCurrentSession->setValue('ses_binary', '');
                $gCurrentSession->save();
                $gCurrentSession->reload($user->getValue('usr_id'));
                $gDb->endTransaction();
            }
        }

        // back to the home page
        $gNavigation->deleteLastUrl();
        admRedirect(SecurityUtils::encodeUrl(ADMIDIO_URL . FOLDER_MODULES . '/profile/profile.php', array('user_uuid' => $getUserUuid)));
        // => EXIT
    } elseif ($getMode === 'dont_save') {
        // Do not save photo
        if ((int)$gSettingsManager->get('profile_photo_storage') === 1) {
            // Folder storage
            $file = ADMIDIO_PATH . FOLDER_DATA . '/user_profile_photos/' . $user->getValue('usr_id') . '_new.jpg';
            try {
                FileSystemUtils::deleteFileIfExists($file);
            } catch (\RuntimeException $exception) {
                $gLogger->error('Could not delete file!', array('filePath' => $file));
                // TODO
            }
        } else {
            // Database storage
            $gCurrentSession->setValue('ses_binary', '');
            $gCurrentSession->save();
        }
        // zur Ausgangsseite zurueck
        $gMessage->setForwardUrl(SecurityUtils::encodeUrl(ADMIDIO_URL . FOLDER_MODULES . '/profile/profile.php', array('user_id' => $getUserUuid)), 2000);
        $gMessage->show($gL10n->get('SYS_PROCESS_CANCELED'));
        // => EXIT
    } elseif ($getMode === 'delete') {
        // Delete photo

        // check the CSRF token of the form against the session token
        SecurityUtils::validateCsrfToken($_POST['admidio-csrf-token']);

        if ((int)$gSettingsManager->get('profile_photo_storage') === 1) {
            // Folder storage, delete file
            $filePath = ADMIDIO_PATH . FOLDER_DATA . '/user_profile_photos/' . $user->getValue('usr_id') . '.jpg';
            try {
                FileSystemUtils::deleteFileIfExists($filePath);
            } catch (\RuntimeException $exception) {
                $gLogger->error('Could not delete file!', array('filePath' => $filePath));
                // TODO
            }
        } else {
            // Database storage, remove data from session
            $user->setValue('usr_photo', '');
            $user->save();
            $gCurrentSession->reload($user->getValue('usr_id'));
        }

        echo 'done';
        exit();
    }

    // Upload photo
    if ($getMode === 'choose') {
        // set headline
        if ((int)$user->getValue('usr_id') === $gCurrentUserId) {
            $headline = $gL10n->get('SYS_EDIT_MY_PROFILE_PICTURE');
        } else {
            $headline = $gL10n->get('SYS_EDIT_PROFILE_PIC_FROM', array($user->getValue('FIRST_NAME'), $user->getValue('LAST_NAME')));
        }

        $gNavigation->addUrl(CURRENT_URL, $headline);

        // create html page object
        $page = new HtmlPage('admidio-profile-photo-edit', $headline);

        // show form
        $form = new Form(
            'admUploadPhotoForm',
            'modules/profile.new-photo.upload.tpl',
            SecurityUtils::encodeUrl(ADMIDIO_URL . FOLDER_MODULES . '/profile/profile_photo_edit.php', array('mode' => 'upload', 'user_uuid' => $getUserUuid)),
            $page,
            array('enableFileUpload' => true)
        );
        $form->addCustomContent(
            'admCurrentProfilePhoto',
            $gL10n->get('SYS_CURRENT_PROFILE_PICTURE'),
            '<img class="imageFrame" src="' . SecurityUtils::encodeUrl(ADMIDIO_URL . FOLDER_MODULES . '/profile/profile_photo_show.php', array('user_uuid' => $getUserUuid)) . '" alt="' . $gL10n->get('SYS_CURRENT_PROFILE_PICTURE') . '" />'
        );
        $form->addFileUpload(
            'admPhotoUploadFile',
            $gL10n->get('SYS_SELECT_PHOTO'),
            array(
                'property' => Form::FIELD_REQUIRED,
                'allowedMimeTypes' => array('image/jpeg', 'image/png'),
                'helpTextId' => array('SYS_PROFILE_PICTURE_RESTRICTIONS', array(round(SystemInfoUtils::getProcessableImageSize() / 1000000, 2), round(PhpIniUtils::getUploadMaxSize() / 1024 ** 2, 2)))
            )
        );
        $form->addSubmitButton(
            'admButtonUpload',
            $gL10n->get('SYS_UPLOAD_PROFILE_PICTURE'),
            array('icon' => 'bi-upload', 'class' => 'offset-sm-3')
        );

        // add form to html page and show page
        $form->addToHtmlPage();
        $gCurrentSession->addFormObject($form);
        $page->show();
    } elseif ($getMode === 'upload') {
        // Confirm cache photo

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

        // File size
        if ($_FILES['userfile']['error'][0] === UPLOAD_ERR_INI_SIZE) {
            throw new Exception('SYS_PHOTO_FILE_TO_LARGE', array(round(PhpIniUtils::getUploadMaxSize() / 1024 ** 2)));
        }

        // check if a file was really uploaded
        if (!file_exists($_FILES['userfile']['tmp_name'][0]) || !is_uploaded_file($_FILES['userfile']['tmp_name'][0])) {
            throw new Exception('SYS_NO_PICTURE_SELECTED');
        }

        // File ending
        $imageProperties = getimagesize($_FILES['userfile']['tmp_name'][0]);
        if ($imageProperties === false || !in_array($imageProperties['mime'], array('image/jpeg', 'image/png'), true)) {
            throw new Exception('SYS_PHOTO_FORMAT_INVALID');
        }

        // Resolution control
        $imageDimensions = $imageProperties[0] * $imageProperties[1];
        if ($imageDimensions > SystemInfoUtils::getProcessableImageSize()) {
            throw new Exception('SYS_PHOTO_RESOLUTION_TO_LARGE', array(round(SystemInfoUtils::getProcessableImageSize() / 1000000, 2)));
        }

        // Adjust photo to appropriate size
        $userImage = new Image($_FILES['userfile']['tmp_name'][0]);
        $userImage->setImageType('jpeg');
        $userImage->scale(130, 170);

        if ((int)$gSettingsManager->get('profile_photo_storage') === 1) {
            // Folder storage
            $userImage->copyToFile(null, ADMIDIO_PATH . FOLDER_DATA . '/user_profile_photos/' . $user->getValue('usr_id') . '_new.jpg');
        } else {
            // Database storage
            $userImage->copyToFile(null, $_FILES['userfile']['tmp_name'][0]);
            $userImageData = fread(fopen($_FILES['userfile']['tmp_name'][0], 'rb'), $_FILES['userfile']['size'][0]);

            $gCurrentSession->setValue('ses_binary', $userImageData);
            $gCurrentSession->save();
        }

        // delete image object
        $userImage->delete();

        echo json_encode(array(
            'status' => 'success',
            'url' => SecurityUtils::encodeUrl(ADMIDIO_URL . FOLDER_MODULES . '/profile/profile_photo_edit.php', array('mode' => 'review', 'user_uuid' => $getUserUuid))
        ));
        exit();
    } elseif ($getMode === 'review') {
        // show dialog with current and new profile photo for review

        if ((int)$user->getValue('usr_id') === $gCurrentUserId) {
            $headline = $gL10n->get('SYS_EDIT_MY_PROFILE_PICTURE');
        } else {
            $headline = $gL10n->get('SYS_EDIT_PROFILE_PIC_FROM', array($user->getValue('FIRST_NAME'), $user->getValue('LAST_NAME')));
        }

        // create html page object
        $page = new HtmlPage('admidio-profile-photo-edit', $headline);
        $page->addTemplateFile('modules/profile.new-photo.tpl');
        $page->assignSmartyVariable('urlCurrentProfilePhoto', SecurityUtils::encodeUrl(ADMIDIO_URL . FOLDER_MODULES . '/profile/profile_photo_show.php', array('user_uuid' => $getUserUuid)) );
        $page->assignSmartyVariable('urlNewProfilePhoto', SecurityUtils::encodeUrl(ADMIDIO_URL . FOLDER_MODULES . '/profile/profile_photo_show.php', array('user_uuid' => $getUserUuid, 'new_photo' => 1)));
        $page->assignSmartyVariable('urlNextPage', SecurityUtils::encodeUrl(ADMIDIO_URL . FOLDER_MODULES . '/profile/profile_photo_edit.php', array('mode' => 'save', 'user_uuid' => $getUserUuid)));
        $page->show();
    }
} catch (Exception|Exception|RuntimeException $e) {
    if (in_array($getMode, array('upload', 'delete'))) {
        echo json_encode(array('status' => 'error', 'message' => $e->getMessage()));
    } else {
        $gMessage->show($e->getMessage());
    }
}