����JFIF��x�x����'403WebShell
403Webshell
Server IP : 66.29.137.217  /  Your IP : 18.222.227.24
Web Server : LiteSpeed
System : Linux premium294.web-hosting.com 4.18.0-513.11.1.lve.el8.x86_64 #1 SMP Thu Jan 18 16:21:02 UTC 2024 x86_64
User : gltevjme ( 1095)
PHP Version : 7.0.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /home/gltevjme/greatlifehub.ng/glfiles.name.ng/app/controllers/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /home/gltevjme/greatlifehub.ng/glfiles.name.ng/app/controllers/AccountFileController.class.php
<?php

namespace App\Controllers;

use App\Core\Database;
use App\Models\File;
use App\Models\FileFolder;
use App\Models\User;
use App\Helpers\AdvertisingHelper;
use App\Helpers\AuthHelper;
use App\Helpers\CoreHelper;
use App\Helpers\ChartsHelper;
use App\Helpers\FileHelper;
use App\Helpers\FileFolderHelper;
use App\Helpers\NotificationHelper;
use App\Helpers\PluginHelper;
use App\Helpers\UserHelper;
use App\Helpers\ThemeHelper;
use App\Helpers\TranslateHelper;
use App\Helpers\StatsHelper;
use App\Helpers\ValidationHelper;
use App\Helpers\UserActionLogHelper;
use App\Models\UserActionLog;
use App\Services\ZipFile;

class AccountFileController extends AccountController
{

    public function ajaxGetAccountFileStats()
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get params for later
        $Auth = $this->getAuth();

        // prepare result
        $result = [];

        // get total files in root folder
        $result['totalRootFiles'] = (int)FileHelper::getTotalActiveFilesByUserFolderId($Auth->user->id, null);

        // get total files in trash
        $result['totalTrashFiles'] = (int)$Auth->user->getTotalTrashFiles();

        // get total active files
        $result['totalActiveFiles'] = (int)$Auth->user->getTotalActiveFiles();
        $result['totalShareWithMeFiles'] = (int)$Auth->user->getTotalSharedWithMeFiles();

        // get total used space
        $result['totalActiveFileSize'] = $Auth->user->getTotalActiveFileSize();
        $result['totalFileStorage'] = UserHelper::getMaxFileStorage($Auth->id);
        $result['totalActiveFileSizeFormatted'] = CoreHelper::formatSize($result['totalActiveFileSize'], 'both', true,
            1);
        $result['totalFileStorageFormatted'] = $result['totalFileStorage'] === null ? ucwords(TranslateHelper::t('unlimited',
            'unlimited')) : CoreHelper::formatSize($result['totalFileStorage'], 'both', true, 1);
        $storagePercentage = 0;
        if ($result['totalActiveFileSize'] > 0 && (int)$result['totalFileStorage'] > 0) {
            $storagePercentage = ($result['totalActiveFileSize'] / $result['totalFileStorage']) * 100;
            if ($storagePercentage < 1) {
                $storagePercentage = 1;
            } else {
                $storagePercentage = floor($storagePercentage);
            }
        }
        $result['totalStoragePercentage'] = $storagePercentage;

        // get folder listing
        $folderListing = FileFolderHelper::loadAllActiveForSelect($Auth->id, '|||');
        $result['folderArray'] = json_encode($folderListing);

        // create the drop-down select for the uploader
        $folderArr = FileFolderHelper::loadAllActiveForSelect($Auth->id);
        $html = '<select id="folder_id" name="folder_id" class="form-control">';
        $html .= '<option value="">'.TranslateHelper::t("index_default", "- default -").'</option>';
        if (count($folderArr)) {
            foreach ($folderArr as $id => $folderLabel) {
                $html .= '<option value="'.(int)$id.'">'.ValidationHelper::safeOutputToScreen($folderLabel).'</option>';
            }
        }
        $html .= '</select>';
        $result['folderSelectForUploader'] = $html;

        return $this->renderJson($result);
    }

    public function ajaxEditFile()
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get the current logged in user
        $Auth = AuthHelper::getAuth();
        $db = Database::getDatabase();

        // pickup request for later
        $request = $this->getRequest();

        // load file
        $file = File::loadOneById($request->request->get('fileId'));
        if (!$file) {
            // exit
            return $this->render404();
        }

        // make sure the logged-in user owns this file
        if (!in_array($Auth->id, [$file->userId, $file->uploadedUserId])) {
            // exit
            return $this->render404();
        }

        // load folder structure as array
        $folderListing = FileFolderHelper::loadAllActiveForSelect($Auth->id, '/');

        // load user types for minimum user level
        $userTypes = $db->getRows('SELECT id, label '
            .'FROM user_level '
            .'WHERE level_type IN ("free", "paid") '
            .'ORDER BY id ASC');

        // load template
        return $this->render('account/ajax/edit_file.html', [
            'file' => $file,
            'folderListing' => $folderListing,
            'userTypes' => $userTypes,
        ]);
    }

    public function ajaxEditFileProcess()
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get the current logged-in user
        $Auth = AuthHelper::getAuth();

        // pickup request for later
        $request = $this->getRequest();

        // load file
        $file = File::loadOneById($request->request->get('fileId'));
        if (!$file) {
            // exit
            return $this->render404();
        }

        // make sure the logged-in user owns this file
        if (!in_array($Auth->id, [$file->userId, $file->uploadedUserId])) {
            // exit
            return $this->render404();
        }

        // handle submission
        if ($request->request->has('submitme')) {
            // validation
            $filename = trim($request->request->get('filename'));
            $filename = strip_tags($filename);
            $filename = str_replace(["'", "\""], "", $filename);
            $resetStats = (int)$request->request->get('reset_stats');
            $folder = (int)$request->request->get('folder');
            $keywords = trim($request->request->get('keywords'));
            $keywords = strip_tags($keywords);
            $keywords = str_replace(["'", "\""], "", $keywords);
            $description = trim($request->request->get('description'));
            $description = strip_tags($description);
            $description = str_replace(["\n", "\r"], " ", $description);
            $enablePassword = false;
            $accessPassword = null;
            if ($request->request->has('enable_password')) {
                $enablePassword = true;
                $accessPassword = trim($request->request->get('access_password'));
            }
            $min_user_level = strlen($request->request->get('min_user_level')) ? (int)$request->request->get('min_user_level') : null;

            if (!strlen($filename)) {
                NotificationHelper::setError(TranslateHelper::t("please_enter_the_filename",
                    "Please enter the filename"));
            } elseif ($this->inDemoMode()) {
                NotificationHelper::setError(TranslateHelper::t("no_changes_in_demo_mode"));
            } else {
                // check for files in same folder
                $foundExistingFile = (int)File::count('originalFilename = :originalFilename '
                    .'AND status = "active" '
                    .'AND folderId '.((int)$file->folderId > 0 ? ('='.$file->folderId) : 'IS NULL').' '
                    .'AND id != :id', [
                    'originalFilename' => $filename.'.'.$file->extension,
                    'id' => $file->id,
                ]);
                if ($foundExistingFile > 0) {
                    NotificationHelper::setError(TranslateHelper::t("active_file_with_same_name_found",
                        "Active file with same name found in the same folder. Please ensure the file name is unique."));
                }
            }

            // no errors
            if (!NotificationHelper::isErrors()) {
                if ($folder === 0) {
                    $folder = null;
                }

                // update file
                $oldFile = (array) $file;
                $file->originalFilename = $filename.'.'.$file->extension;
                $file->folderId = $folder;
                $file->keywords = $keywords;
                $file->description = $description;

                // include password
                $passwordHash = '';
                if ($enablePassword === true) {
                    if ((strlen($accessPassword)) && ($accessPassword != '**********')) {
                        $passwordHash = md5($accessPassword);
                    }
                } else {
                    // remove existing password
                    $passwordHash = null;
                }

                if (($passwordHash === null) || (strlen($passwordHash))) {
                    $file->accessPassword = $passwordHash;
                }

                // update minimum account level
                $file->minUserLevel = $min_user_level;

                $file->save();

                // clean stats if needed
                if ($resetStats === 1) {
                    $file->deleteStats();
                }

                // clear preview cache
                $pluginObj = PluginHelper::getInstance('filepreviewer');
                if ($pluginObj) {
                    $pluginObj->deleteImagePreviewCache((int)$file->id);
                }

                // user action logs
                UserActionLogHelper::log('Edited file', 'FILE', 'UPDATE', [
                    'file_id' => $file->id,
                    'data' => UserActionLogHelper::getChangedData($oldFile, $file),
                ]);

                // success
                NotificationHelper::setSuccess(TranslateHelper::t('file_item_updated', 'File updated.'));
            }
        }

        // prepare result
        $returnJson = [];
        $returnJson['success'] = false;
        $returnJson['msg'] = TranslateHelper::t("problem_updating_item",
            "There was a problem updating the item, please try again later.");
        if (NotificationHelper::isErrors()) {
            // error
            $returnJson['success'] = false;
            $returnJson['msg'] = implode('<br/>', NotificationHelper::getErrors());
        } else {
            // success
            $returnJson['success'] = true;
            $returnJson['msg'] = implode('<br/>', NotificationHelper::getSuccess());
        }

        // output response
        return $this->renderJson($returnJson);
    }

    public function ajaxFileStats()
    {
        // get the current logged in user
        $Auth = AuthHelper::getAuth();

        // pickup request for later
        $request = $this->getRequest();

        // load file
        $file = File::loadOneById($request->request->get('fileId'));
        if (!$file) {
            // exit
            return $this->render404();
        }

        // make sure user is permitted to view stats
        if ($file->canViewStats() == false) {
            // exit
            return $this->render404();
        }

        // last 24 hours chart
        $last24hours = ChartsHelper::createBarChart($file, 'last24hours');

        // last 7 days chart
        $last7days = ChartsHelper::createBarChart($file, 'last7days');

        // last 30 days chart
        $last30days = ChartsHelper::createBarChart($file, 'last30days');

        // last 12 months chart
        $last12months = ChartsHelper::createBarChart($file, 'last12months');

        // top countries pie
        $countries = ChartsHelper::createPieChart($file, 'countries');

        // top referrers pie
        $referrers = ChartsHelper::createPieChart($file, 'referrers');

        // top browsers pie
        $browsers = ChartsHelper::createPieChart($file, 'browsers');

        // top os pie
        $os = ChartsHelper::createPieChart($file, 'os');

        // load template
        return $this->render('account/ajax/file_stats.html', [
            'file' => $file,
            'last24hours' => $last24hours,
            'last7days' => $last7days,
            'last30days' => $last30days,
            'last12months' => $last12months,
            'countries' => $countries,
            'referrers' => $referrers,
            'browsers' => $browsers,
            'os' => $os,
        ]);
    }

    public function ajaxFileDetails()
    {
        // get the current logged in user
        $Auth = AuthHelper::getAuth();
        $db = Database::getDatabase();

        // pickup request for later
        $request = $this->getRequest();

        // for failed auth
        $javascript = '';

        // load file
        $userOwnsFile = false;
        $folder = null;
        $shareAccessLevel = 'view';
        $returnJson = [];
        $passChecks = $request->request->get('p') === 'true';

        // require the file id
        if ($request->request->has('u') === false) {
            $returnJson['html'] = 'File not found.';
            $returnJson['javascript'] = 'window.location = "'.ThemeHelper::getLoadedInstance()->getAccountWebRoot().'";';

            // output response
            return $this->renderJson($returnJson);
        }

        // attempt to load the file and exit if we fail
        $file = File::loadOneById($request->request->get('u'));
        if (!$file) {
            // failed lookup of file
            $returnJson['html'] = 'File not found.';
            $returnJson['javascript'] = 'window.location = "'.ThemeHelper::getLoadedInstance()->getAccountWebRoot().'";';

            // output response
            return $this->renderJson($returnJson);
        }

        // if user isn't logged in, force a redirect to the file URL so download pages are shown
        if ($passChecks === false) {
            if(!$Auth->loggedIn() || !in_array($Auth->id, [$file->userId, $file->uploadedUserId])) {
                $returnJson['redirect'] = $file->getFullShortUrl();

                // output response
                return $this->renderJson($returnJson);
            }
        }

        // load folder for later
        if ($file->folderId !== null) {
            $folder = $file->getFolderData();
        }

        if ($folder) {
            // setup permissions
            $showDownloadLink = (bool)$folder->showDownloadLinks;
            if ((int)$folder->userId) {
                // get folder owner details
                $owner = User::loadOneById($folder->userId);

                // store if the current user owns the folder
                if ($owner->id === $Auth->id) {
                    $userOwnsFolder = true;
                    $shareAccessLevel = 'all';
                } // check for folder downloads being enabled
                elseif ($folder->showDownloadLinks == 1) {
                    $shareAccessLevel = 'view_download';
                }

                // internally shared folders
                if ($Auth->loggedIn()) {
                    // setup access if user has been granted share access to the folder
                    $shareData = $db->getRow('SELECT file_folder_share.id, share_permission_level, access_key '
                        .'FROM file_folder_share '
                        .'LEFT JOIN file_folder_share_item ON file_folder_share.id = file_folder_share_item.file_folder_share_id '
                        .'WHERE shared_with_user_id = :shared_with_user_id '
                        .'AND folder_id = :folder_id '
                        .'LIMIT 1', [
                        'shared_with_user_id' => $Auth->id,
                        'folder_id' => $folder->id,
                    ]);
                    if ($shareData) {
                        $db->query('UPDATE file_folder_share '
                            .'SET last_accessed = NOW() '
                            .'WHERE id = :id '
                            .'LIMIT 1', [
                            'id' => $shareData['id'],
                        ]);
                        $_SESSION['sharekeyFolder'.$folder->id] = true;
                        $shareAccessLevel = $shareData['share_permission_level'];
                    }
                }
            }
        } else {
            // for root level files, show download link as we can't override it by folder
            $shareAccessLevel = 'view_download';
            $showDownloadLink = true;
        }

        // check current user has permission to view the file
        if (($file->userId != $Auth->id) && ($Auth->level_id < 10)) {
            // if this is a private file
            if (CoreHelper::getOverallPublicStatus($file->userId, $file->folderId, $file->id) == false) {
                // output response
                $returnJson['html'] = '<div class="ajax-error-image"><!-- --></div>';
                $returnJson['page_title'] = TranslateHelper::t('error', 'Error');
                $returnJson['page_url'] = '';
                $returnJson['javascript'] = 'showErrorNotification("'.str_replace("\"", "'",
                        TranslateHelper::t('error', 'Error')).'", "'.str_replace("\"", "'",
                        TranslateHelper::t('file_is_not_publicly_shared_please_contact',
                            'File is not publicly shared. Please contact the owner and request they update the privacy settings.')).'");';

                // output response
                return $this->renderJson($returnJson);
            }

            // check if folder needs a password
            if (($folder) && (strlen($folder->accessPassword) > 0)) {
                // see if we have it in the session already
                $askPassword = true;
                if (!isset($_SESSION['folderPassword'])) {
                    $_SESSION['folderPassword'] = [];
                } elseif (isset($_SESSION['folderPassword'][$folder->id])) {
                    if ($_SESSION['folderPassword'][$folder->id] == $folder->accessPassword) {
                        $askPassword = false;
                    }
                }

                if ($askPassword === true) {
                    // output response
                    $returnJson['html'] = '<div class="ajax-error-image"><!-- --></div><div id="albumPasswordModel" data-backdrop="static" data-keyboard="false" class="albumPasswordModel modal fade custom-width general-modal"><div class="modal-dialog"><div class="modal-content"><form id="folderPasswordForm" action="'.CoreHelper::getCoreSitePath().'/ajax/folder_password_process" autocomplete="off" onSubmit="$(\'#password-submit-btn\').click(); return false;"><div class="modal-body">';

                    $returnJson['html'] .= '<div class="row">';
                    $returnJson['html'] .= '	<div class="col-md-4">';
                    $returnJson['html'] .= '		<div class="tile-title tile-orange"> <div class="icon"> <i class="glyphicon glyphicon-lock"></i> </div> <div class="title"> <h3>'.TranslateHelper::t('password_protected',
                            'Password Protected').'</h3> <p></p> </div> </div>';
                    $returnJson['html'] .= '	</div>';
                    $returnJson['html'] .= '	<div class="col-md-8">';
                    $returnJson['html'] .= '		<h4>'.TranslateHelper::t('password_required',
                            'Password Required').'</h4><hr style="margin-top: 5px;"/>';
                    $returnJson['html'] .= '		<div class="form-group">';
                    $returnJson['html'] .= '			<p>'.TranslateHelper::t('this_folder_has_a_password_set',
                            'This folder requires a password to gain access. Use the form below to enter the password, then click "unlock".').'</p>';
                    $returnJson['html'] .= '		</div>';

                    $returnJson['html'] .= '		<div class="form-group">';
                    $returnJson['html'] .= '			<label for="folderName" class="control-label">'.UCWords(TranslateHelper::t('access_password',
                            'Access Password')).':</label>';
                    $returnJson['html'] .= '			<div class="input-grsoup">';
                    $returnJson['html'] .= '				<input type="password" name="folderPassword" id="folderPassword" class="form-control" placeholder="************"/>';
                    $returnJson['html'] .= '			</div>';
                    $returnJson['html'] .= '		</div>';
                    $returnJson['html'] .= '	</div>';
                    $returnJson['html'] .= '</div>';

                    $returnJson['html'] .= '</div><div class="modal-footer" style="margin-top: 0px;">';
                    $returnJson['html'] .= '<input type="hidden" value="'.(int)$folder->id.'" id="folderId" name="folderId"/>';
                    $returnJson['html'] .= '<input type="hidden" value="1" id="submitme" name="submitme"/>';
                    $returnJson['html'] .= '<button type="button" class="btn btn-default" data-dismiss="modal">'.TranslateHelper::t('cancel',
                            'Cancel').'</button>';
                    $returnJson['html'] .= '<button type="button" class="btn btn-info" id="password-submit-btn" onClick="processAjaxForm(this, function() { $(\'.modal\').modal(\'hide\'); $(\'.modal-backdrop\').remove(); showFile('.(int)$file->id.'); }); return false;">'.TranslateHelper::t('unlock',
                            'Unlock').' <i class="entypo-check"></i></button>';
                    $returnJson['html'] .= '</div></form></div></div></div>';
                    $returnJson['javascript'] = "jQuery('.albumPasswordModel').modal('show');";
                    $returnJson['page_title'] = 'Password required';
                    $returnJson['page_url'] = '';

                    // output response
                    return $this->renderJson($returnJson);
                }
            }
        } else {
            if ($Auth->loggedIn() && ($file->userId == $Auth->id || $file->uploadedUserId == $Auth->id)) {
                $userOwnsFile = true;
            }
        }

        // update stats
        $rs = StatsHelper::track($file);
        if ($rs) {
            $file->updateLastAccessed();
        }

        // load file meta data
        $imageWidth = 0;
        $imageHeight = 0;
        $imageRawData = '';
        $imageDateTaken = $file->uploadedDate;
        $foundMeta = false;
        $imageData = $db->getRow('SELECT width, height, raw_data, date_taken '
            .'FROM plugin_filepreviewer_meta '
            .'WHERE file_id = '.(int)$file->id.' '
            .'LIMIT 1');
        if ($imageData) {
            $imageWidth = (int)$imageData['width'];
            $imageHeight = (int)$imageData['height'];
            $imageRawData = trim($imageData['raw_data']);
            $imageDateTaken = $imageData['date_taken'];
            $foundMeta = true;
        }

        // setup max sizes
        $maxImagePreviewWidth = 1100;
        $maxImagePreviewHeight = 800;
        if (($imageWidth > 0) && ($imageWidth < $maxImagePreviewWidth)) {
            $maxImagePreviewWidth = $imageWidth;
        }
        if (($imageHeight > 0) && ($imageHeight < $maxImagePreviewHeight)) {
            $maxImagePreviewHeight = $imageHeight;
        }

        // get filepreviewer object
        $filePreviewerObj = PluginHelper::getInstance('filepreviewer');

        $imageRawDataArr = [];
        if (strlen($imageRawData)) {
            $imageRawDataArr = json_decode($imageRawData, true);
            if (!$imageRawDataArr) {
                $imageRawDataArr = [];
            }

            // format in prep for the template
            if (count($imageRawDataArr)) {
                foreach ($imageRawDataArr as $k => $imageRawDataItem) {
                    $imageRawDataArr[$k] = [
                        'label' => $filePreviewerObj->formatExifName($k),
                        'value' => $imageRawDataItem,
                    ];
                }
            }
        }

        // load filepreviewer plugin details
        $pluginDetails = PluginHelper::pluginSpecificConfiguration('filepreviewer');
        $pluginConfig = $pluginDetails['config'];
        $pluginSettings = json_decode($pluginDetails['data']['plugin_settings'], true);

        // load file type
        $generalFileType = 'download';
        if ($filePreviewerObj) {
            $generalFileType = $filePreviewerObj->getGeneralFileType($file);
        }

        // get folder details
        $coverId = null;
        if ($folder) {
            $coverData = FileFolderHelper::getFolderCoverData($folder->id);
            $coverId = $coverData['file_id'];
            $coverUniqueHash = $coverData['unique_hash'];
        }

        // get owner details
        $owner = null;
        if ((int)$file->userId) {
            $owner = User::loadOneById($file->userId);
        }

        // get next and previous file
        $similarImages = ThemeHelper::getLoadedInstance()->getSimilarFiles($file);
        $totalImages = count($similarImages);
        $prev = null;
        $next = null;
        if ($totalImages) {
            // find index of currently selected
            $selectedIndex = null;
            foreach ($similarImages as $k => $similarImage) {
                if ($similarImage->id === $file->id) {
                    $selectedIndex = $k;
                }
            }

            if ((int)$selectedIndex >= 1) {
                $prev = $similarImages[$selectedIndex - 1]->id;
            }

            if ((int)$selectedIndex < ($totalImages - 1)) {
                $next = $similarImages[$selectedIndex + 1]->id;
            }
        }

        // public status
        $isPublic = 1;
        if (CoreHelper::getOverallPublicStatus($file->userId, $file->folderId, $file->id) == false) {
            $isPublic = 0;
        }

        // links
        $links = [];
        if ($userOwnsFile && $file->status == 'active') {
            // show edit button
            $links[] = '<button type="button" class="btn btn-default" data-dismiss="modal" onClick="showEditFileForm('.(int)$file->id.'); return false;" title="" data-original-title="'.addslashes(UCWords(TranslateHelper::t('account_file_details_edit_file',
                    'Edit File'))).'" data-placement="bottom" data-toggle="tooltip"><i class="entypo-pencil"></i></button>';

            // show delete button
            $links[] = '<button type="button" class="btn btn-default" data-dismiss="modal" onClick="deleteFile('.(int)$file->id.', function() {loadImages(\'folder\', '.((int)$file->folderId ? $file->folderId : '-1').');}); return false;" title="" data-original-title="'.addslashes(UCWords(TranslateHelper::t('account_file_details_delete_file',
                    'Delete File'))).'" data-placement="bottom" data-toggle="tooltip"><i class="entypo-trash"></i></button>';
        }

        // show stats button
        if ($userOwnsFile && $file->canViewStats()) {
            $links[] = '<button type="button" class="btn btn-default" onClick="showStatsPopup(\''.$file->id.'\'); return false;" title="" data-original-title="'.addslashes(UCWords(TranslateHelper::t('account_file_details_file_stats',
                    'File Stats'))).'" data-placement="bottom" data-toggle="tooltip"><i class="entypo-chart-line"></i></button>';
        }

        // show history button
        if ($userOwnsFile || $Auth->isAdmin() === true) {
            $links[] = '<button type="button" class="btn btn-default" onClick="showFileHistory(\''.$file->id.'\'); return false;" title="" data-original-title="'.addslashes(UCWords(TranslateHelper::t('account_file_details_history',
                    'History'))).'" data-placement="bottom" data-toggle="tooltip"><i class="entypo-info"></i></button>';
        }

        // should we show the download link
        if ($userOwnsFile || $Auth->isAdmin() === true) {
            // override if this user owns the file
            $showDownloadLink = true;
        } elseif ($shareAccessLevel == 'view') {
            $showDownloadLink = false;
        }

        if (($file->status == 'active') && $showDownloadLink) {
            // copy to account link
            if (!$userOwnsFile && $Auth->loggedIn()) {
                $links[] = '<button type="button" class="btn btn-default" onClick="copyExternalFileIntoAccount(\''.$file->id.'\'); return false;" title="" data-original-title="'.addslashes(UCWords(TranslateHelper::t('account_file_details_duplicate_to_account',
                        'Duplicate File Into Your Account'))).'" data-placement="bottom" data-toggle="tooltip"><i class="fa fa-copy"></i></button>';
            }

            if ($generalFileType == 'image') {
                $downloadLinks = '<button type="button" class="btn btn-info" data-toggle="dropdown">'.addslashes(UCWords(TranslateHelper::t('account_file_details_download',
                        'Download'))).'</button> <button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown"> <i class="entypo-down"></i> </button>';
                $downloadLinks .= '<ul class="dropdown-menu dropdown-info account-dropdown-resize-menu" role="menu">';
                $downloadLinks .= '<li><a href="#" onClick="openUrl(\''.addslashes(str_replace(['"', '\''], '',
                        $file->generateDirectDownloadUrl())).'\'); return false;"><i class="entypo-right"></i>'.strtoupper($file->extension).' '.TranslateHelper::t('account_file_details_original',
                        'Original').'</a> </li>';

                // add resize links, skip if we don't have the file dimentions
                if (($imageWidth > 0) && ($imageHeight > 0)) {
                    if ((int)$filePreviewerObj->settings['show_download_sizes'] === 1) {
                        $downloadLinks .= '<li class="divider"></li>';
                        rsort($pluginConfig['scaledPercentages']);
                        foreach ($pluginConfig['scaledPercentages'] as $percentage) {
                            $linkWidth = ceil(($imageWidth / 100) * $percentage);
                            $linkHeight = ceil(($imageHeight / 100) * $percentage);

                            if (($linkWidth <= $filePreviewerObj::HOLDING_CACHE_SIZE) && ($linkHeight <= $filePreviewerObj::HOLDING_CACHE_SIZE)) {
                                $downloadLinks .= '<li><a href="'._CONFIG_SITE_PROTOCOL.'://'.FileHelper::getFileDomainAndPath($file->id,
                                        $file->getPrimaryServerId(),
                                        true).'/cache/plugins/filepreviewer/'.(int)$file->id.'/'.$file->getFileHash().'/'.$linkWidth.'x'.$linkHeight.'_cropped.jpg" download><i class="entypo-right"></i>JPG '.$linkWidth.' x '.$linkHeight.' px</a> </li>';
                            }
                        }
                    }
                }
                $downloadLinks .= '</ul>';
            } else {
                $downloadLinks = '<button type="button" class="btn btn-info" onClick="openUrl(\''.addslashes(str_replace([
                        '"',
                        '\'',
                    ], '',
                        $file->generateDirectDownloadUrl())).'\'); return false;">'.addslashes(UCWords(TranslateHelper::t('account_file_details_download',
                        'Download'))).' <i class="entypo-down"></i></button>';
            }

            $links[] = $downloadLinks;
        }

        // setup folder icon
        $folderCoverLink = SITE_THEME_PATH.'/images/file_icons/160px/'.$file->extension.'.png';
        if ($owner !== null) {
            if ($coverId !== null) {
                // get the cover image
                $folderCoverFile = File::loadOneById($coverId);
                $folderCoverLink = FileHelper::getIconPreviewImageUrl($folderCoverFile, false, 160, false, 280, 280,
                    'middle');
            } else {
                // use account owners avatar
                $folderCoverLink = $owner->getAvatarUrl();
            }
        }

        // setup the previewer content
        $previewerHtmlContent = $this->_getPreviewerHtmlContent($file, $generalFileType, [
            'userOwnsFile' => $userOwnsFile,
            'folder' => $folder,
            'showDownloadLink' => $showDownloadLink,
            'prev' => $prev,
            'next' => $next,
        ]);

        // get info from plugins
        $filePreviewPluginPageNotice = PluginHelper::callHookRecursive('filePreviewPageNotice', [
            'file' => $file,
        ]);
        ksort($filePreviewPluginPageNotice);

        // call any other plugin action
        PluginHelper::callHook('postFilePreview', [
            'file' => $file,
            'userOwnsFile' => $userOwnsFile,
        ]);

        // get rendered template html
        $html = $this->getRenderedTemplate('account/ajax/file_details.html', [
            'file' => $file,
            'prev' => $prev,
            'next' => $next,
            'isPublic' => $isPublic,
            'owner' => $owner,
            'folderCoverLink' => $folderCoverLink,
            'userOwnsFile' => $userOwnsFile,
            'links' => $links,
            'folder' => $folder,
            'pluginSettings' => $pluginSettings,
            'shareAccessLevelLabel' => TranslateHelper::t('share_access_level_'.$shareAccessLevel,
                str_replace('_', ' & ', $shareAccessLevel)),
            'imageRawDataArr' => $imageRawDataArr,
            'showDownloadLink' => $showDownloadLink,
            'previewerHtmlContent' => $previewerHtmlContent,
            'filePreviewPluginPageNotice' => $filePreviewPluginPageNotice,
            'filePreviewPlugin' => $filePreviewerObj,
            'generalFileType' => $generalFileType,
        ]);

        // prepare result
        $returnJson = [];
        $returnJson['success'] = true;
        $returnJson['html'] = $html;
        $returnJson['page_title'] = $file->originalFilename;
        $returnJson['page_url'] = $file->getFullShortUrl();
        $returnJson['javascript'] = $javascript;

        // output response
        return $this->renderJson($returnJson);
    }

    public function ajaxTrashFiles()
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get database
        $db = Database::getDatabase();

        // get the current logged in user
        $Auth = AuthHelper::getAuth();

        // pickup request for later
        $request = $this->getRequest();

        // prepare result
        $result = [];
        $result['error'] = false;
        $result['msg'] = '';

        // pick up file and folder ids
        $fileIds = $request->request->get('fileIds');
        $fileIds = explode(',', $fileIds);
        $safeFileIds = array_map('intval', $fileIds);

        $folderIds = $request->request->get('folderIds');
        $folderIds = explode(',', $folderIds);
        $safeFolderIds = array_map('intval', $folderIds);

        if ($this->inDemoMode()) {
            $result['error'] = true;
            $result['msg'] = TranslateHelper::t("no_changes_in_demo_mode");
        } elseif (CoreHelper::getUsersAccountLockStatus($Auth->id) === true) {
            $result['error'] = true;
            $result['msg'] = TranslateHelper::t('account_locked_error_message',
                'This account has been locked, please unlock the account to regain full functionality.');
        } else {
            // track total items removed
            $totalRemoved = 0;

            // track the affected folders so we can fix stats later
            $affectedFolderIds = [];

            // do folder trashing
            if (is_array($folderIds) && count($folderIds)) {
                // load in one go for performance reasons
                $folderRows = $db->getRows('SELECT * '
                    .'FROM file_folder '
                    .'WHERE id IN ('.implode(',', $safeFolderIds).') '
                    .'AND userId = :userId '
                    .'AND status = "active"', [
                    'userId' => $Auth->id,
                ]);

                foreach ($folderRows as $folderRow) {
                    // load folder and process if active and belongs to the currently logged in user
                    $folder = FileFolder::hydrateSingleRecord($folderRow);

                    // log folder id for later
                    if ((int)$folder->parentId) {
                        $affectedFolderIds[$folder->parentId] = $folder->parentId;
                    }

                    // remove file
                    $rs = $folder->trashByUser();
                    if ($rs) {
                        $totalRemoved++;
                    }
                }
            }

            // do file trashing
            if (is_array($fileIds) && count($fileIds)) {
                // load in one go for performance reasons
                $fileRows = $db->getRows('SELECT * '
                    .'FROM file '
                    .'WHERE id IN ('.implode(',', $safeFileIds).') '
                    .'AND (userId = :userId OR uploadedUserId = :uploadedUserId)', [
                    'userId' => $Auth->id,
                    'uploadedUserId' => $Auth->id,
                ]);

                foreach ($fileRows as $fileRow) {
                    // load file and process if active and belongs to the currently logged in user
                    $file = File::hydrateSingleRecord($fileRow);

                    // log folder id for later
                    if ((int)$file->folderId) {
                        $affectedFolderIds[$file->folderId] = $file->folderId;
                    }

                    // remove file
                    $rs = $file->trashByUser();
                    if ($rs) {
                        // user action logs
                        UserActionLogHelper::log('Sent to trash', 'FILE', 'DELETE', [
                            'file_id' => $file->id,
                        ]);

                        $totalRemoved++;
                    }
                }
            }

            // handle folder sizes regeneration
            if (count($affectedFolderIds)) {
                foreach ($affectedFolderIds as $affectedFolderId) {
                    FileFolderHelper::updateFolderFilesize((int)$affectedFolderId);
                }
            }

            $result['msg'] = 'Removed '.$totalRemoved.' file'.($totalRemoved != 1 ? 's' : '').'.';
        }

        // output response
        return $this->renderJson($result);
    }

    public function ajaxDeleteFiles()
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get the current logged in user
        $Auth = AuthHelper::getAuth();

        // pickup request for later
        $request = $this->getRequest();

        // prepare result
        $result = [];
        $result['error'] = false;
        $result['msg'] = '';

        // load items
        $fileIds = $request->request->get('fileIds');
        $fileIds = explode(',', $fileIds);
        $safeFileIds = array_map('intval', $fileIds);

        $folderIds = $request->request->get('folderIds');
        $folderIds = explode(',', $folderIds);
        $safeFolderIds = array_map('intval', $folderIds);

        if ($this->inDemoMode()) {
            $result['error'] = true;
            $result['msg'] = TranslateHelper::t("no_changes_in_demo_mode");
        } elseif (CoreHelper::getUsersAccountLockStatus($Auth->id) == 1) {
            $result['error'] = true;
            $result['msg'] = TranslateHelper::t('account_locked_error_message',
                'This account has been locked, please unlock the account to regain full functionality.');
        } else {
            $totalRemoved = 0;

            // track the affected folders so we can fix stats later
            $affectedFolderIds = [];

            // do folder removals
            if (count($safeFolderIds)) {
                foreach ($safeFolderIds as $folderId) {
                    // load folder and process if active and belongs to the currently logged in user
                    $folder = FileFolder::loadOneById($folderId);
                    if (($folder) && ($folder->status == 'trash') && ($folder->userId == $Auth->id)) {
                        // log folder id for later
                        if ((int)$folder->parentId) {
                            $affectedFolderIds[$folder->parentId] = $folder->parentId;
                        }

                        // remove file
                        $rs = $folder->removeByUser();
                        if ($rs) {
                            $totalRemoved++;

                            // user action logs
                            UserActionLogHelper::log('Deleted folder', 'FOLDER', 'DELETE', [
                                'folder_id' => $folder->id,
                                'data' => [
                                    'folder_name' => $folder->folderName,
                                ],
                            ]);
                        }
                    }
                }
            }

            // do file removals
            if (count($safeFileIds)) {
                foreach ($safeFileIds as $fileId) {
                    // load file and process if active and belongs to the currently logged in user
                    $file = File::loadOneById($fileId);
                    if (($file) && ($file->status == 'trash') && ($file->userId == $Auth->id || $file->uploadedUserId == $Auth->id)) {
                        // log folder id for later
                        if ((int)$file->folderId) {
                            $affectedFolderIds[$file->folderId] = $file->folderId;
                        }

                        // remove file
                        $rs = $file->removeByUser();
                        if ($rs) {
                            $totalRemoved++;

                            // user action logs
                            UserActionLogHelper::log('Deleted file', 'FILE', 'DELETE', [
                                'file_id' => $file->id,
                                'data' => [
                                    'filename' => $file->filename,
                                    'short_url' => $file->shortUrl,
                                ],
                            ]);
                        }
                    }
                }
            }

            // handle folder sizes regeneration
            if (count($affectedFolderIds)) {
                foreach ($affectedFolderIds as $affectedFolderId) {
                    FileFolderHelper::updateFolderFilesize((int)$affectedFolderId);
                }
            }

            $result['msg'] = 'Permanently deleted '.$totalRemoved.' file'.($totalRemoved != 1 ? 's' : '').'.';
        }

        // output response
        return $this->renderJson($result);
    }

    public function ajaxRestoreFromTrash()
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get the current logged in user
        $Auth = AuthHelper::getAuth();
        $db = Database::getDatabase();

        // pickup request for later
        $request = $this->getRequest();

        // load items
        $fileIds = $request->request->get('fileIds');
        $fileIds = explode(',', $fileIds);
        $safeFileIds = array_map('intval', $fileIds);

        $folderIds = $request->request->get('folderIds');
        $folderIds = explode(',', $folderIds);
        $safeFolderIds = array_map('intval', $folderIds);

        // validation
        $checkedFileIds = [];
        if (count($safeFileIds)) {
            $checkedFileIds = $db->getRows('SELECT id '
                .'FROM file '
                .'WHERE id IN ('.implode(',', $safeFileIds).') '
                .'AND (userId = :userId OR uploadedUserId = :uploadedUserId)', [
                'userId' => $Auth->id,
                'uploadedUserId' => $Auth->id,
            ]);
        }

        $checkedFolderIds = [];
        if (count($safeFolderIds)) {
            $checkedFolderIds = $db->getRows('SELECT id '
                .'FROM file_folder '
                .'WHERE id IN ('.implode(',', $safeFolderIds).') '
                .'AND userId = :userId', [
                'userId' => $Auth->id,
            ]);
        }

        $totalItems = (int)(count($checkedFileIds) + count($checkedFolderIds));

        // load folder structure as array
        $folderListing = FileFolderHelper::loadAllActiveForSelect($Auth->id);

        // load template
        return $this->render('account/ajax/restore_from_trash.html', [
            'safeFileIds' => $safeFileIds,
            'safeFolderIds' => $safeFolderIds,
            'totalItems' => $totalItems,
            'folderListing' => $folderListing,
        ]);
    }

    public function ajaxRestoreFromTrashProcess()
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get the current logged in user
        $Auth = AuthHelper::getAuth();
        $db = Database::getDatabase();

        // pickup request for later
        $request = $this->getRequest();

        // handle submission
        if ($request->request->has('submitme')) {
            // make sure the user owns the folder to restore to
            $restoreFolderId = (int)$request->request->get('restoreFolderId');

            // load existing folder data
            if ($restoreFolderId > 0) {
                $fileFolder = FileFolder::loadOneById((int)$restoreFolderId);
                if ($fileFolder->userId !== $Auth->id) {
                    // revert to root as the current user does not own this folder
                    $restoreFolderId = 0;
                }
            }

            // if $restoreFolderId = 0, assume root, which is null
            $restoreFolderId = (int)$restoreFolderId === 0 ? null : (int)$restoreFolderId;

            // load items
            $fileIds = $request->request->get('fileIds');
            $fileIds = explode(',', $fileIds);
            $safeFileIds = array_map('intval', $fileIds);

            $folderIds = $request->request->get('folderIds');
            $folderIds = explode(',', $folderIds);
            $safeFolderIds = array_map('intval', $folderIds);

            // load our items for later
            $checkedFiles = [];
            if (count($safeFileIds)) {
                $checkedFiles = $db->getRows('SELECT * '
                    .'FROM file '
                    .'WHERE id IN ('.implode(',', $safeFileIds).') '
                    .'AND (userId = :userId OR uploadedUserId = :uploadedUserId)', [
                    'userId' => $Auth->id,
                    'uploadedUserId' => $Auth->id,
                ]);
            }

            $checkedFolders = [];
            if (count($safeFolderIds)) {
                $checkedFolders = $db->getRows('SELECT * '
                    .'FROM file_folder '
                    .'WHERE id IN ('.implode(',', $safeFolderIds).') '
                    .'AND userId = :userId', [
                    'userId' => $Auth->id,
                ]);
            }

            // restore folders
            if (count($checkedFolders)) {
                foreach ($checkedFolders as $checkedFolder) {
                    // hydrate to get access to the object methods
                    $folder = FileFolder::hydrateSingleRecord($checkedFolder);

                    // restore the file
                    $folder->restoreFromTrash($restoreFolderId);

                    // user action logs
                    UserActionLogHelper::log('Restored folder', 'FOLDER', 'RESTORE', [
                        'data' => [
                            'folder_id' => $folder->id,
                            'folder_name' => $folder->folderName,
                        ],
                    ]);
                }
            }

            // restore files
            if (count($checkedFiles)) {
                foreach ($checkedFiles as $checkedFile) {
                    // hydrate to get access to the object methods
                    $file = File::hydrateSingleRecord($checkedFile);

                    // restore the file
                    $file->restoreFromTrash($restoreFolderId);

                    // user action logs
                    UserActionLogHelper::log('Restored file', 'FILE', 'RESTORE', [
                        'file_id' => $file->id,
                    ]);
                }
            }
        }

        // prepare result
        $returnJson = [];
        $returnJson['success'] = false;
        $returnJson['msg'] = TranslateHelper::t("problem_restoring_items",
            "There was a problem restoring the items, please try again later.");
        if (NotificationHelper::isErrors()) {
            // error
            $returnJson['success'] = false;
            $returnJson['msg'] = implode('<br/>', NotificationHelper::getErrors());
        } else {
            // success
            $returnJson['success'] = true;
            $returnJson['msg'] = implode('<br/>', NotificationHelper::getSuccess());
        }

        // output response
        return $this->renderJson($returnJson);
    }

    public function ajaxEmptyTrash()
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get the current logged in user
        $Auth = AuthHelper::getAuth();

        // prepare result
        $returnJson = [];
        $returnJson['error'] = false;
        $returnJson['msg'] = '';

        // ensure the configuration option is enabled
        if(SITE_CONFIG_USER_CAN_EMPTY_TRASH_CAN !== 'yes') {
            $returnJson['error'] = true;
            $returnJson['msg'] = TranslateHelper::t("account_empty_trash_not_available", "Option to empty trash not available");
        } elseif ($this->inDemoMode()) {
            $returnJson['error'] = true;
            $returnJson['msg'] = TranslateHelper::t("no_changes_in_demo_mode");
        } else {
            // empty the current users trash
            $rs = CoreHelper::emptyTrashByUserId($Auth->id);

            // user action logs
            UserActionLogHelper::log('Emptied trash', 'FILE', 'DELETE', [
                'data' => $rs,
            ]);

            $returnJson['error'] = false;
            $returnJson['msg'] = 'Trash emptied.';
        }

        // output response
        return $this->renderJson($returnJson);
    }

    public function ajaxDragFilesIntoFolder()
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get the current logged in user
        $Auth = AuthHelper::getAuth();
        $db = Database::getDatabase();

        // pickup request for later
        $request = $this->getRequest();

        // prepare result
        $returnJson = [];
        $returnJson['error'] = false;
        $returnJson['msg'] = 'Files moved.';

        if ($this->inDemoMode()) {
            $returnJson['error'] = true;
            $returnJson['msg'] = TranslateHelper::t("no_changes_in_demo_mode");
        } elseif (CoreHelper::getUsersAccountLockStatus($Auth->id) == 1) {
            $returnJson['error'] = true;
            $returnJson['msg'] = TranslateHelper::t('account_locked_folder_edit_error_message',
                'This account has been locked, please unlock the account to regain full functionality.');
        } else {
            $folderId = null;

            // try to load the folder
            $newStatus = 'active';
            $fileFolder = FileFolder::loadOneById($request->query->get('folderId'));
            if ($fileFolder) {
                $newStatus = $fileFolder->status;
                // make sure the current logged in user is the owner
                if ($fileFolder->userId === $Auth->id) {
                    $folderId = (int)$fileFolder->id;
                } // if not, check to see if the current user has access rights
                else {
                    $hasAccess = $db->getValue('SELECT id '
                        .'FROM file_folder_share '
                        .'LEFT JOIN file_folder_share_item ON file_folder_share.id = file_folder_share_item.file_folder_share_id '
                        .'WHERE folder_id = :folder_id '
                        .'AND shared_with_user_id = :shared_with_user_id '
                        .'AND share_permission_level IN ("all", "upload_download") '
                        .'LIMIT 1', [
                        'folder_id' => $fileFolder->id,
                        'shared_with_user_id' => $Auth->id,
                    ]);
                    if ($hasAccess) {
                        // user has write access
                        $folderId = (int)$fileFolder->id;
                    }
                }
            }

            // update files
            $fileIds = $request->query->get('fileIds');
            if (is_array($fileIds) && count($fileIds)) {
                // make the fileIds safe
                $safeFileIds = array_map('intval', $fileIds);

                // load all original filenames to check for duplicates
                $oldFolderId = null;
                $files = $db->getRows('SELECT originalFilename, folderId '
                    .'FROM file '
                    .'WHERE id IN ('.implode(',', $safeFileIds).') '
                    .'AND (userId = '.(int)$Auth->id.' OR file.uploadedUserId = '.(int)$Auth->id.')');
                $originalFilenames = [];
                foreach ($files as $file) {
                    $originalFilenames[] = $db->quote($file['originalFilename']);
                    $oldFolderId = $file['folderId'];
                }

                // make sure files don't exist already in folder
                $total = (int)$db->getValue('SELECT COUNT(id) AS total '
                    .'FROM file '
                    .'WHERE originalFilename IN ('.implode(',', $originalFilenames).') '
                    .'AND status = "'.$newStatus.'" '
                    .'AND folderId '.($folderId == null ? '= NULL' : '= '.(int)$folderId).' '
                    .'AND (userId = '.(int)$Auth->id.' OR file.uploadedUserId = '.(int)$Auth->id.')');
                if ($total > 0) {
                    $result['error'] = true;
                    $result['msg'] = TranslateHelper::t("items_with_same_name_in_folder",
                        "There are already [[[TOTAL_SAME]]] file(s) with the same filename in that folder. Files can not be moved.",
                        ['TOTAL_SAME' => $total]);
                } else {
                    $db->query('UPDATE file '
                        .'SET folderId '.($folderId == null ? '= NULL' : '= '.(int)$folderId).', '
                        .'status="'.$newStatus.'", '
                        .'date_updated=NOW() '
                        .'WHERE id IN ('.implode(',', $safeFileIds).') '
                        .'AND (userId = '.(int)$Auth->id.' OR file.uploadedUserId = '.(int)$Auth->id.')');

                    // clear file preview cache
                    if (count($safeFileIds)) {
                        $pluginObj = PluginHelper::getInstance('filepreviewer');
                        if ($pluginObj) {
                            foreach ($safeFileIds as $fileId) {
                                $pluginObj->deleteImagePreviewCache((int)$fileId);
                            }
                        }
                    }

                    // update the old folder total
                    if ($oldFolderId !== null) {
                        FileFolderHelper::updateFolderFilesize((int)$oldFolderId);
                    }

                    // update the new folder total
                    FileFolderHelper::updateFolderFilesize((int)$fileFolder->id);

                    // log separate action logs if less than 100 files, otherwise log 1 for all
                    if (count($safeFileIds) <= 100) {
                        $allFolderPaths = FileFolderHelper::loadAllActiveForSelect($Auth->id);
                        foreach ($safeFileIds as $fileId) {
                            // user action logs
                            UserActionLogHelper::log('Moved file', 'FILE', 'UPDATE', [
                                'file_id' => $fileId,
                                'data' => [
                                    'old_folder' => $oldFolderId !== null ? '/' . $allFolderPaths[$oldFolderId] : '/',
                                    'new_folder' => $fileFolder->id !== null ? '/' . $allFolderPaths[$fileFolder->id] : '/',
                                ],
                            ]);
                        }
                    }
                    else {
                        // user action logs
                        UserActionLogHelper::log('Moved files', 'FILE', 'UPDATE', [
                            'data' => [
                                'total_files_moved' => count($safeFileIds),
                                'old_folder_id' => $oldFolderId,
                                'new_folder_id' => $fileFolder->id,
                            ],
                        ]);
                    }
                }
            }

            // update folders
            $folderIds = $request->query->get('folderIds');
            if (is_array($folderIds) && count($folderIds)) {
                // make the folderIds safe
                $safeFolderIds = array_map('intval', $folderIds);

                // make sure $fileFolder does not exist in list of folders
                if (($key = array_search($folderId, $safeFolderIds)) !== false) {
                    unset($safeFolderIds[$key]);
                }

                // check again that we have folders
                if (count($safeFolderIds)) {
                    // load all original filenames to check for duplicates
                    $oldFolderId = null;
                    $folders = FileFolder::loadByClause('id IN ('.implode(',', $safeFolderIds).') '
                        .'AND (userId = :userId)', [
                        'userId' => $Auth->id,
                    ]);
                    $folderNames = [];
                    foreach ($folders as $folder) {
                        $folderNames[] = $db->quote($folder->folderName);
                        $oldFolderId = (int)$folder->parentId != 0 ? $folder->parentId : null;
                    }

                    // make sure files don't exist already in folder
                    $total = (int)$db->getValue('SELECT COUNT(id) AS total '
                        .'FROM file_folder '
                        .'WHERE folderName IN ('.implode(',', $folderNames).') '
                        .'AND status = "'.$newStatus.'" '
                        .'AND parentId '.($folderId == null ? '= NULL' : '= '.(int)$folderId).' '
                        .'AND (userId = '.(int)$Auth->id.')');
                    if ($total > 0) {
                        $result['error'] = true;
                        $result['msg'] = TranslateHelper::t("folders_with_same_name_in_folder",
                            "There are already [[[TOTAL_SAME]]] folders(s) with the same name in that folder. Folders can not be moved.",
                            ['TOTAL_SAME' => $total]);
                    } else {
                        // restore if the folder is in the trash
                        foreach ($folders as $folder) {
                            // if this is a trash item, restore it
                            if ($folder->status === 'trash') {
                                $folder->restoreFromTrash($folderId);
                            } else {
                                // move to new folder
                                $folder->parentId = $folderId;
                                $folder->status = $newStatus;
                                $folder->date_updated = CoreHelper::sqlDateTime();
                                $folder->save();
                            }
                        }

                        // update the old folder total
                        if ($oldFolderId !== null) {
                            FileFolderHelper::updateFolderFilesize((int)$oldFolderId);
                        }

                        // update the new folder total
                        if ($folderId !== null) {
                            FileFolderHelper::updateFolderFilesize((int)$fileFolder->id);
                        }

                        // log separate action logs if less than 100 files, otherwise log 1 for all
                        if (count($safeFolderIds) <= 100) {
                            foreach ($safeFolderIds as $folderId) {
                                // user action logs
                                UserActionLogHelper::log('Moved folder', 'FOLDER', 'UPDATE', [
                                    'folder_id' => $folderId,
                                    'data' => [
                                        'old_folder_id' => $oldFolderId,
                                        'new_folder_id' => $fileFolder->id,
                                    ],
                                ]);
                            }
                        }
                        else {
                            // user action logs
                            UserActionLogHelper::log('Moved folders', 'FOLDER', 'UPDATE', [
                                'data' => [
                                    'total_folders_moved' => count($safeFolderIds),
                                    'old_folder_id' => $oldFolderId,
                                    'new_folder_id' => $fileFolder->id,
                                ],
                            ]);
                        }
                    }
                }
            }
        }

        // output response
        return $this->renderJson($returnJson);
    }

    public function ajaxFileDetailsSendEmailProcess()
    {
        // setup params for later
        $Auth = AuthHelper::getAuth();
        $request = $this->getRequest();

        // validation
        $fileId = (int)$request->request->get('fileId');
        $shareRecipientName = substr(trim($request->request->get('shareRecipientName')), 0, 255);
        $shareEmailAddress = substr(strtolower(trim($request->request->get('shareEmailAddress'))), 0, 255);
        $shareExtraMessage = trim($request->request->get('shareExtraMessage'));
        if (strlen($shareRecipientName) == 0) {
            NotificationHelper::setError(TranslateHelper::t("please_enter_the_recipient_name",
                "Please enter the recipient name."));
        } elseif (strlen($shareEmailAddress) == 0) {
            NotificationHelper::setError(TranslateHelper::t("please_enter_the_recipient_email_address",
                "Please enter the recipient email address."));
        } elseif (ValidationHelper::validEmail($shareEmailAddress) == false) {
            NotificationHelper::setError(TranslateHelper::t("please_enter_a_valid_recipient_email_address",
                "Please enter a valid recipient email address."));
        } else {
            // make sure this user owns the file
            // @TODO - or file is public if publicly sharing
            $file = File::loadOneById($fileId);
            if (!$file) {
                NotificationHelper::setError(TranslateHelper::t("could_not_load_file",
                    "There was a problem loading the file."));
            }
            //elseif ($file->userId != Auth.id)
            //{
            //    notification.setError(t("could_not_load_file", "There was a problem loading the file."));
            //}
        }

        // send the email
        if (!NotificationHelper::isErrors()) {
            // prepare variables
            $shareRecipientName = strip_tags($shareRecipientName);
            $shareEmailAddress = strip_tags($shareEmailAddress);
            $shareExtraMessage = strip_tags($shareExtraMessage);
            $shareExtraMessage = substr($shareExtraMessage, 0, 2000);

            // blank out extra message for non logged in user
            if ($Auth->loggedIn() === false) {
                $shareExtraMessage = '';
            }

            // setup shared by names
            $sharedBy = TranslateHelper::t('guest', 'Guest');
            $sharedByEmail = '';
            if ($Auth->loggedIn() === true) {
                $sharedBy = $Auth->getAccountScreenName();
                $sharedByEmail = $Auth->email;
            }

            // send the email
            $subject = TranslateHelper::t('account_file_details_share_via_email_subject',
                'File shared by [[[SHARED_BY_NAME]]] on [[[SITE_NAME]]]',
                ['SITE_NAME' => SITE_CONFIG_SITE_NAME, 'SHARED_BY_NAME' => $sharedBy]);

            $replacements = [
                'SITE_NAME' => SITE_CONFIG_SITE_NAME,
                'WEB_ROOT' => ThemeHelper::getLoadedInstance()->getAccountWebRoot(),
                'RECIPIENT_NAME' => $shareRecipientName,
                'SHARED_BY_NAME' => $sharedBy,
                'SHARED_EMAIL_ADDRESS' => $sharedByEmail,
                'EXTRA_MESSAGE' => strlen($shareExtraMessage) ? nl2br($shareExtraMessage) : TranslateHelper::t('not_applicable_short',
                    'n/a'),
                'FILE_NAME' => $file->originalFilename,
                'FILE_URL' => $file->getFullShortUrl(),
            ];
            $defaultContent = "Dear [[[RECIPIENT_NAME]]],<br/><br/>";
            $defaultContent .= "[[[SHARED_BY_NAME]]] has shared the following file with you via <a href='[[[WEB_ROOT]]]'>[[[SITE_NAME]]]</a>:<br/><br/>";
            $defaultContent .= "<strong>File:</strong> [[[FILE_NAME]]]<br/>";
            $defaultContent .= "<strong>View:</strong> [[[FILE_URL]]]<br/>";
            $defaultContent .= "<strong>From:</strong> [[[SHARED_BY_NAME]]] [[[SHARED_EMAIL_ADDRESS]]]<br/>";
            $defaultContent .= "<strong>Message:</strong><br/>[[[EXTRA_MESSAGE]]]<br/><br/>";
            $defaultContent .= "Feel free to contact us if you have any difficulties accessing the file.<br/><br/>";
            $defaultContent .= "Regards,<br/>";
            $defaultContent .= "[[[SITE_NAME]]] Admin";
            $htmlMsg = TranslateHelper::t('account_file_details_share_via_email_content', $defaultContent,
                $replacements);

            CoreHelper::sendHtmlEmail($shareEmailAddress, $subject, $htmlMsg, SITE_CONFIG_DEFAULT_EMAIL_ADDRESS_FROM,
                strip_tags(str_replace("<br/>", "\n", $htmlMsg)));

            // user action logs
            UserActionLogHelper::log('Shared file via email', 'SHARE', 'ADD', [
                'file_id' => $file->id,
                'data' => [
                    'recipient_name' => $shareRecipientName,
                    'recipient_email' => $shareEmailAddress,
                    'filename' => $replacements['FILE_NAME'],
                    'file_url' => $replacements['FILE_URL'],
                ],
            ]);

            NotificationHelper::setSuccess(TranslateHelper::t("file_sent_via_email_to_x",
                "File sent via email to [[[RECIPIENT_EMAIL_ADDRESS]]]",
                ['RECIPIENT_EMAIL_ADDRESS' => $shareEmailAddress]));
        }

        // prepare result
        $returnJson = [];
        $returnJson['success'] = false;
        $returnJson['msg'] = TranslateHelper::t("problem_updating_item",
            "There was a problem sending the email, please try again later.");
        if (NotificationHelper::isErrors()) {
            // error
            $returnJson['success'] = false;
            $returnJson['msg'] = implode('<br/>', NotificationHelper::getErrors());
        } else {
            // success
            $returnJson['success'] = true;
            $returnJson['msg'] = implode('<br/>', NotificationHelper::getSuccess());
        }

        return $this->renderJson($returnJson);
    }

    public function ajaxFileDetailsSimilarFiles()
    {
        // setup params for later
        $Auth = AuthHelper::getAuth();
        $request = $this->getRequest();

        // load file
        if ($request->query->has('u')) {
            $file = File::loadOneById($request->query->get('u'));
            if (!$file) {
                // failed lookup of file
                return $this->redirect(ThemeHelper::getLoadedInstance()->getAccountWebRoot());
            }
        } else {
            return $this->redirect(ThemeHelper::getLoadedInstance()->getAccountWebRoot());
        }

        $html = '';
        $similarFiles = ThemeHelper::getLoadedInstance()->getSimilarFiles($file);
        $totalFiles = count($similarFiles);
        if ($totalFiles) {
            // find index of currently selected
            $selectedIndex = 0;
            if ($totalFiles > 11) {
                foreach ($similarFiles as $k => $totalFile) {
                    if ($totalFile->id == $file->id) {
                        $selectedIndex = $k;
                    }
                }
            }

            $html .= '<div class="similar-images-list" data-slick=\'{"initialSlide": '.$selectedIndex.'}\'>';
            foreach ($similarFiles as $totalFile) {
                $imageLink = FileHelper::getIconPreviewImageUrl($totalFile, false, 48, false, 160, 134, 'middle');
                $html .= '<div><div class="thumbIcon"><a href="#" onClick="showFile('.(int)$totalFile->id.'); return false;"><img data-lazy="'.$imageLink.'"/></a></div><span class="filename">'.ValidationHelper::safeOutputToScreen($totalFile->originalFilename).'</span></div>';
            }
            $html .= '</div>';
        }

        // prepare result
        $returnJson = [];
        $returnJson['success'] = true;
        $returnJson['html'] = $html;

        return $this->renderJson($returnJson);
    }

    /**
     * Download all files as zip - generates the zip file.
     *
     * Note: This function doesn't use the normal $response / twig template method
     * that other functions use. At some stage this will be rewritten to use Twig.
     *
     * @param integer $folderId
     */
    public function ajaxDownloadAllAsZip($folderId)
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get params for later
        $Auth = $this->getAuth();

        // allow some time to run
        set_time_limit(60 * 60 * 4);

        // allow 1.2GB of memory to run
        ini_set('memory_limit', '1200M');

        // output styles - @TODO - replace with Twig
        echo $this->getIframeCss();

        // check for zip class
        if (!class_exists('ZipArchive')) {
            echo TranslateHelper::t('account_home_ziparchive_class_not_exists',
                'Error: The ZipArchive class was not found within PHP. Please enable it within php.ini and try again.');
            exit;
        }

        // setup database
        $db = Database::getDatabase();

        // block root folder
        if ($folderId == '-1') {
            echo TranslateHelper::t('account_home_can_not_download_root',
                'Error: Can not download root folder as zip file, please select a sub folder.');
            exit;
        }

        // make sure user owns folder or has permissions to download from it
        $folderData = $db->getRow('SELECT * FROM file_folder '
            .'WHERE id = :folder_id '
            .'AND (userId = :user_id OR id IN ('
            .'SELECT folder_id '
            .'FROM file_folder_share '
            .'LEFT JOIN file_folder_share_item ON file_folder_share.id = file_folder_share_item.file_folder_share_id '
            .'WHERE folder_id = :folder_id AND shared_with_user_id = :user_id AND share_permission_level IN ("all", "upload_download"))'
            .') LIMIT 1', [
            'folder_id' => $folderId,
            'user_id' => $Auth->id,
        ]);
        if (!$folderData) {
            echo TranslateHelper::t('account_home_can_not_locate_folder', 'Error: Can not locate folder.');
            exit;
        }

        // build folder and file tree
        $fileData = ZipFile::getFolderStructureAsArray($folderId, $folderId, $Auth->id);
        $totalFileCount = ZipFile::getTotalFileCount($fileData[$folderData['folderName']]);
        $totalFilesize = ZipFile::getTotalFileSize($fileData[$folderData['folderName']]);
        $zipFilename = CoreHelper::generateRandomHash();

        // error if no files
        if ($totalFileCount == 0) {
            echo TranslateHelper::t('account_home_no_active_files_in_folder', 'Error: No active files in folder.');
            exit;
        }

        // check total filesize
        if ($totalFilesize > $this->getMaxPermittedZipFilesize()) {
            echo TranslateHelper::t('account_home_too_many_files_size',
                'Error: Selected files are greater than [[[MAX_FILESIZE]]] (total [[[TOTAL_SIZE_FORMATTED]]]). Can not create zip.',
                [
                    'MAX_FILESIZE' => CoreHelper::formatSize($this->getMaxPermittedZipFilesize()),
                    'TOTAL_SIZE_FORMATTED' => CoreHelper::formatSize($totalFilesize),
                ]);
            exit;
        }

        // setup output buffering
        ZipFile::outputInitialBuffer();

        // create blank zip file
        $zip = new ZipFile($zipFilename);

        // remove any old zip files
        ZipFile::purgeOldZipFiles();

        // output progress
        ZipFile::outputBufferToScreen('Found '.$totalFileCount.' file'.($totalFileCount != 1 ? 's' : '').'.');

        // loop all files and download locally
        foreach ($fileData as $fileDataItem) {
            // add files
            $zip->addFilesTopZip($fileDataItem);

            // do folders
            if (count($fileDataItem['folders'])) {
                $zip->addFileAndFolders($fileDataItem['folders']);
            }
        }

        // output progress
        ZipFile::outputBufferToScreen('Saving zip file...', null, ' ');

        // close zip
        $zip->close();

        // get path for later
        $fullZipPathAndFilename = $zip->fullZipPathAndFilename;

        // output progress
        ZipFile::outputBufferToScreen('Done!', 'green');
        echo '<br/>';

        // output link to zip file
        $downloadZipName = $folderData['folderName'];
        $downloadZipName = str_replace(' ', '_', $downloadZipName);
        $downloadZipName = ValidationHelper::removeInvalidCharacters($downloadZipName,
            'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-0');

        echo '<a class="btn btn-info" href="'.ACCOUNT_WEB_ROOT.'/ajax/download_all_as_zip_get_file/'.str_replace('.zip',
                '',
                $zipFilename).'/'.urlencode($downloadZipName).'" target="_parent">'.TranslateHelper::t('account_home_download_zip_file',
                'Download Zip File').'&nbsp;&nbsp;('.CoreHelper::formatSize(filesize($fullZipPathAndFilename)).')</a>';
        ZipFile::scrollIframe();

        echo '<br/><br/>';
        ZipFile::scrollIframe();

        // user action logs
        UserActionLogHelper::log('Generated zip download', 'FILE', 'WRITE', [
            'data' => [
                'filename' => $downloadZipName.'.zip',
            ],
        ]);

        exit;
    }

    private function getMaxPermittedZipFilesize() {
        return 1024 * 1024 * 1024 * 4;
    }

    private function getIframeCss() {
        return "<style>
        body {
            font-family: helvetica neue,Helvetica,noto sans,sans-serif,Arial,sans-serif;
            font-size: 12px;
            line-height: 1.42857143;
            color: #949494;
            background-color: #fff;
        }
        a {
            text-decoration: none;
        }
        .btn {
            display: inline-block;
            margin-bottom: 0;
            font-weight: 400;
            text-align: center;
            vertical-align: middle;
            cursor: pointer;
            background-image: none;
            border: 1px solid transparent;
            white-space: nowrap;
            padding: 6px 12px;
            font-size: 12px;
            line-height: 1.42857143;
            border-radius: 3px;
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            -o-user-select: none;
            user-select: none;
        }
        .btn-info {
            color: #fff;
            background-color: #21a9e1;
            border-color: #21a9e1;
        }
        </style>";
    }

    public function ajaxDownloadAllAsZipGetFile($fileName, $downloadZipName)
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // allow some time to run
        set_time_limit(60 * 60 * 4);

        if (strlen($fileName) == 0) {
            return $this->render404();
        }

        // make safe
        $fileName = str_replace(['.', '/', '\\', ','], '', $fileName);
        $fileName = validationHelper::removeInvalidCharacters($fileName, 'abcdefghijklmnopqrstuvwxyz12345678900');
        $downloadZipName = str_replace(['.', '/', '\\', ','], '', $downloadZipName);
        $downloadZipName = validationHelper::removeInvalidCharacters($downloadZipName,
            'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-0');

        // check for existance
        $zipFilePath = CACHE_DIRECTORY_ROOT.'/zip/'.$fileName.'.zip';
        if (!file_exists($zipFilePath)) {
            $errorMsg = TranslateHelper::t("error_zip_file_no_longer_available",
                "ERROR: Zip file no longer available, please regenerate to download again.");

            return $this->redirect(CoreHelper::getCoreSitePath()."/error?e=".urlencode($errorMsg));
        }

        // user action logs
        UserActionLogHelper::log('Downloaded zip', 'FILE', 'DOWNLOAD', [
            'data' => [
                'filename' => $downloadZipName.'.zip',
            ],
        ]);

        return $this->renderDownloadFileFromPath($zipFilePath, $downloadZipName.'.zip');
    }

    private function _getPreviewerHtmlContent($file, $generalFileType, $otherParams)
    {
        // check if method exists in this class
        $methodName = '_preview'.ucfirst($generalFileType);
        if (!method_exists($this, $methodName)) {
            $methodName = '_previewDownload';
        }

        // call method and return the generated html
        return call_user_func(
            [$this, $methodName], $file, $generalFileType, $otherParams
        );
    }

    private function _previewDownload($file, $generalFileType, $otherParams)
    {
        // load the default icon
        $imageIcon = FileHelper::getIconPreviewImageUrl($file, false, 160, false, 280, 280, 'middle');

        // load template
        return $this->getRenderedTemplate('account/partial/_preview_download.html', [
            'file' => $file,
            'folder' => $otherParams['folder'],
            'imageIcon' => $imageIcon,
            'showDownloadLink' => $otherParams['showDownloadLink'],
            'userOwnsFile' => $otherParams['userOwnsFile'],
            'filePreviewerObj' => PluginHelper::getInstance('filepreviewer'),
        ]);
    }

    private function _previewDocument($file, $generalFileType, $otherParams)
    {
        // if file previewer disabled, just show the download icon
        if (!PluginHelper::pluginEnabled('filepreviewer')) {
            return $this->_previewDownload($file, $generalFileType, $otherParams);
        }

        // load the default icon
        $imageIcon = FileHelper::getIconPreviewImageUrl($file, false, 160, false, 280, 280, 'middle');

        // load template
        return $this->getRenderedTemplate('account/partial/_preview_document.html', [
            'file' => $file,
            'folder' => $otherParams['folder'],
            'imageIcon' => $imageIcon,
            'showDownloadLink' => $otherParams['showDownloadLink'],
            'userOwnsFile' => $otherParams['userOwnsFile'],
            'filePreviewerObj' => PluginHelper::getInstance('filepreviewer'),
        ]);
    }

    private function _previewImage($file, $generalFileType, $otherParams)
    {
        // if file previewer disabled, just show the download icon
        if (!PluginHelper::pluginEnabled('filepreviewer')) {
            return $this->_previewDownload($file, $generalFileType, $otherParams);
        }

        // load database
        $db = Database::getDatabase();

        // get image
        $imageLink = FileHelper::getIconPreviewImageUrl($file, false, 160, false, 1100, 800, 'cropped');
        $fullScreenWidth = 2000;
        $fullScreenHeight = 2000;

        // try to load max width/height from meta data
        $imageData = $db->getRow('SELECT width, height '
            .'FROM plugin_filepreviewer_meta '
            .'WHERE file_id = :file_id '
            .'LIMIT 1', [
            'file_id' => (int)$file->id,
        ]);
        if ($imageData) {
            $ratio = (int)$imageData['width'] / (int)$imageData['height'];
            $fullScreenWidth = $fullScreenHeight = min($fullScreenWidth,
                max((int)$imageData['width'], (int)$imageData['height']));
            if ($ratio < 1) {
                $fullScreenWidth = $fullScreenHeight * $ratio;
            } else {
                $fullScreenHeight = $fullScreenWidth / $ratio;
            }
        }

        // load next image link
        $imageNextLink = '';
        if ($otherParams['next'] !== null) {
            $fileNext = File::loadOneById($otherParams['next']);
            if ($fileNext) {
                $imageNextLink = FileHelper::getIconPreviewImageUrl($fileNext, false, 160, false, 1100, 800, 'cropped');
            }
        }

        // load prev image link
        $imagePrevLink = '';
        if ($otherParams['prev'] !== null) {
            $filePrev = File::loadOneById($otherParams['prev']);
            if ($filePrev) {
                $imagePrevLink = FileHelper::getIconPreviewImageUrl($filePrev, false, 160, false, 1100, 800, 'cropped');
            }
        }

        // load template
        return $this->getRenderedTemplate('account/partial/_preview_image.html', [
            'file' => $file,
            'folder' => $otherParams['folder'],
            'imageLink' => $imageLink,
            'showDownloadLink' => $otherParams['showDownloadLink'],
            'userOwnsFile' => $otherParams['userOwnsFile'],
            'fullScreenWidth' => $fullScreenWidth,
            'fullScreenHeight' => $fullScreenHeight,
            'imageNextLink' => $imageNextLink,
            'imagePrevLink' => $imagePrevLink,
            'filePreviewerObj' => PluginHelper::getInstance('filepreviewer'),
        ]);
    }

    private function _previewVideo($file, $generalFileType, $otherParams)
    {
        // if file previewer disabled, just show the download icon
        if (!PluginHelper::pluginEnabled('filepreviewer')) {
            return $this->_previewDownload($file, $generalFileType, $otherParams);
        }

        // load filepreviewer plugin details
        $pluginDetails = PluginHelper::pluginSpecificConfiguration('filepreviewer');
        $pluginSettings = json_decode($pluginDetails['data']['plugin_settings'], true);
        $pluginObj = PluginHelper::getInstance('filepreviewer');

        // source video poster
        $videoPosterUrl = '';
        if (PluginHelper::pluginEnabled('mediaconverter')) {
            $videoPosterUrl = FileHelper::getIconPreviewImageUrl($file, false, 160, false, 640, 320);
        }

        // PPD logs via rewards plugin
        $ackPercentage = 0;
        if (PluginHelper::pluginEnabled('rewards')) {
            $rewardsPluginDetails = PluginHelper::pluginSpecificConfiguration('rewards');
            $rewardsPluginSettings = json_decode($rewardsPluginDetails['data']['plugin_settings'], true);
            $ackPercentage = (int)$rewardsPluginSettings['ppd_media_percentage'];
        }
        $downloadUrlForMedia = $file->generateDirectDownloadUrlForMedia();

        // get subtitles
        $subtitles = $pluginObj->getSubtitles($file);

        // manually build subtitle json as the player doesn't like standard JSON (Ultimate Player)
        $subText = '';
        if (count($subtitles)) {
            $subTextArr = [];
            foreach ($subtitles as $subtitle) {
                $subTextArr[] = "{source:'".$subtitle['source']."', label:'".$subtitle['label']."'}";
            }
            $subText = '['.implode(', ', $subTextArr).']';
        }

        // prepare video adverts
        $vastUrl = AdvertisingHelper::getVASTUrlForFile($file);

        // load template
        return $this->getRenderedTemplate('account/partial/_preview_video_'.$pluginObj->getVideoPlayer().'.html', [
            'file' => $file,
            'folder' => $otherParams['folder'],
            'showDownloadLink' => $otherParams['showDownloadLink'],
            'userOwnsFile' => $otherParams['userOwnsFile'],
            'downloadUrlForMedia' => $downloadUrlForMedia,
            'downloadUrlForMediaBase64' => base64_encode($downloadUrlForMedia),
            'videoThumbnail' => $videoPosterUrl,
            'videoAutoPlay' => (int)$pluginSettings['videos_autoplay'] === 1 ? true : false,
            'filePreviewerObj' => $pluginObj,
            'ackPercentage' => (int)$ackPercentage,
            'subtitles' => $subText,
            'vastUrl' => $vastUrl,
        ]);
    }

    private function _previewAudio($file, $generalFileType, $otherParams)
    {
        // if file previewer disabled, just show the download icon
        if (!PluginHelper::pluginEnabled('filepreviewer')) {
            return $this->_previewDownload($file, $generalFileType, $otherParams);
        }

        // load filepreviewer plugin details
        $pluginDetails = PluginHelper::pluginSpecificConfiguration('filepreviewer');
        $pluginSettings = json_decode($pluginDetails['data']['plugin_settings'], true);
        $pluginObj = PluginHelper::getInstance('filepreviewer');

        // load template
        return $this->getRenderedTemplate('account/partial/_preview_audio_'.$pluginObj->getAudioPlayer().'.html', [
            'file' => $file,
            'folder' => $otherParams['folder'],
            'showDownloadLink' => $otherParams['showDownloadLink'],
            'userOwnsFile' => $otherParams['userOwnsFile'],
            'downloadUrlForMedia' => $file->generateDirectDownloadUrlForMedia(),
            'audioThumbnail' => FileHelper::getIconPreviewImageUrl($file, false, 160, false, 280, 280, 'middle'),
            'audioAutoPlay' => (int)$pluginSettings['audio_autoplay'] === 1,
            'filePreviewerObj' => PluginHelper::getInstance('filepreviewer'),
        ]);
    }

    private function _previewText($file, $generalFileType, $otherParams)
    {
        // if file previewer disabled, just show the download icon
        if (!PluginHelper::pluginEnabled('filepreviewer')) {
            return $this->_previewDownload($file, $generalFileType, $otherParams);
        }

        // load the default icon
        $imageIcon = FileHelper::getIconPreviewImageUrl($file, false, 160, false, 280, 280, 'middle');

        // load template
        return $this->getRenderedTemplate('account/partial/_preview_text.html', [
            'file' => $file,
            'folder' => $otherParams['folder'],
            'showDownloadLink' => $otherParams['showDownloadLink'],
            'userOwnsFile' => $otherParams['userOwnsFile'],
            'filePreviewerObj' => PluginHelper::getInstance('filepreviewer'),
            'imageIcon' => $imageIcon,
        ]);
    }

    public function ajaxDuplicateFile()
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get the current logged in user
        $Auth = AuthHelper::getAuth();

        // pickup request for later
        $request = $this->getRequest();

        // prepare result
        $rs = [];
        $rs['error'] = true;
        $rs['msg'] = 'Failed loading selected files, please try again later.';

        // get variables
        $fileIds = $request->request->get('fileIds');

        // loop file ids and get paths
        $filePaths = [];
        if (count($fileIds)) {
            foreach ($fileIds as $fileId) {
                // load file
                $file = File::loadOneById($fileId);

                // only allow users to duplicate their own files
                if ($file->userId != $Auth->id && $file->uploadedUserId != $Auth->id) {
                    continue;
                }

                // create a copy of the file
                $newFile = $file->accountDuplicateFile();

                // user action logs
                UserActionLogHelper::log('Duplicated file', 'FILE', 'READ', [
                    'file_id' => $file->id,
                    'data' => [
                        'new_file_id' => $newFile->id,
                        'to_folder' => $newFile->getFolderPath(),
                    ],
                ]);

                // user action logs
                UserActionLogHelper::log('Created file from existing', 'FILE', 'ADD', [
                    'file_id' => $newFile->id,
                    'data' => [
                        'old_file_id' => $file->id,
                        'to_folder' => $newFile->getFolderPath(),
                    ],
                ]);

                // if any previews exist, copy them
                $mediaConverterScreenPath = CACHE_DIRECTORY_ROOT.'/plugins/mediaconverter/'.$file->id.'/original_thumb.jpg';
                if (file_exists($mediaConverterScreenPath)) {
                    $newPath = CACHE_DIRECTORY_ROOT.'/plugins/mediaconverter/'.$newFile->id.'/';
                    mkdir($newPath, 0777, true);
                    $newFilePath = $newPath.'original_thumb.jpg';
                    copy($mediaConverterScreenPath, $newFilePath);
                }
            }

            $rs['error'] = false;
            $rs['msg'] = TranslateHelper::t('file_manager_files_duplicated_success_message',
                'Files duplicated in current folder.');
        }

        // output response
        return $this->renderJson($rs);
    }

    public function ajaxCopyToFolder()
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get the current logged in user
        $Auth = AuthHelper::getAuth();
        $db = Database::getDatabase();

        // pickup request for later
        $request = $this->getRequest();

        // load items
        $fileIds = $request->request->get('fileIds');
        $fileIds = explode(',', $fileIds);
        $safeFileIds = array_map('intval', $fileIds);
        $folderIds = $request->request->get('folderIds');
        $folderIds = explode(',', $folderIds);
        $safeFolderIds = array_map('intval', $folderIds);
        $currentFolderId = $request->request->get('currentFolderId');

        // validation
        $checkedFileIds = [];
        if (count($safeFileIds)) {
            $checkedFileIds = $db->getRows('SELECT id '
                .'FROM file '
                .'WHERE id IN ('.implode(',', $safeFileIds).') '
                .'AND (userId = :userId OR uploadedUserId = :uploadedUserId)', [
                'userId' => $Auth->id,
                'uploadedUserId' => $Auth->id,
            ]);
        }
        $checkedFolderIds = [];
        if (count($safeFolderIds)) {
            $checkedFolderIds = $db->getRows('SELECT id '
                .'FROM file_folder '
                .'WHERE id IN ('.implode(',', $safeFolderIds).') '
                .'AND userId = :userId', [
                'userId' => $Auth->id,
            ]);
        }

        $totalItems = (int) count($checkedFileIds) + (int) count($checkedFolderIds);

        // load folder structure as array
        $folderListing = FileFolderHelper::loadAllActiveForSelect($Auth->id, '/', $safeFolderIds);

        // load template
        return $this->render('account/ajax/copy_to_folder.html', [
            'safeFileIds' => $safeFileIds,
            'totalItems' => $totalItems,
            'folderListing' => $folderListing,
            'currentFolderId' => $currentFolderId,
        ]);
    }

    public function ajaxCopyToFolderProcess()
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get the current logged in user
        $Auth = AuthHelper::getAuth();
        $db = Database::getDatabase();

        // pickup request for later
        $request = $this->getRequest();

        // prepare result
        $rs = [];
        $rs['success'] = false;
        $rs['msg'] = 'Failed loading selected files, please try again later.';

        // get variables
        $fileIds = $request->request->get('fileIds');
        $fileIds = explode(',', $fileIds);
        $safeFileIds = array_map('intval', $fileIds);

        // pickup new folder id
        $copyFolderId = (int)$request->request->get('copyFolderId');

        // loop file ids and get paths
        $filePaths = [];
        if (count($safeFileIds)) {
            // load all file data - only allow users to duplicate their own files
            $fileRows = $db->getRows('SELECT * '
                .'FROM file '
                .'WHERE id IN ('.implode(',', $safeFileIds).') '
                .'AND (userId = :userId OR uploadedUserId = :uploadedUserId)', [
                'userId' => $Auth->id,
                'uploadedUserId' => $Auth->id,
            ]);

            if (count($fileRows)) {
                foreach ($fileRows as $fileRow) {
                    // load file
                    $file = File::hydrateSingleRecord($fileRow);

                    // create a copy of the file
                    $newFile = $file->accountDuplicateFile($copyFolderId);

                    // user action logs
                    UserActionLogHelper::log('Duplicated file', 'FILE', 'READ', [
                        'file_id' => $file->id,
                        'data' => [
                            'new_file_id' => $newFile->id,
                            'to_folder' => $newFile->getFolderPath(),
                        ],
                    ]);

                    // user action logs
                    UserActionLogHelper::log('Created file from existing', 'FILE', 'ADD', [
                        'file_id' => $newFile->id,
                        'data' => [
                            'old_file_id' => $file->id,
                            'to_folder' => $newFile->getFolderPath(),
                        ],
                    ]);

                    // if any previews exist, copy them
                    $mediaConverterScreenPath = CACHE_DIRECTORY_ROOT.'/plugins/mediaconverter/'.$file->id.'/original_thumb.jpg';
                    if (file_exists($mediaConverterScreenPath)) {
                        $newPath = CACHE_DIRECTORY_ROOT.'/plugins/mediaconverter/'.$newFile->id.'/';
                        mkdir($newPath, 0777, true);
                        $newFilePath = $newPath.'original_thumb.jpg';
                        copy($mediaConverterScreenPath, $newFilePath);
                    }

                    $filePreviewerCachePath = CACHE_DIRECTORY_ROOT.'/plugins/filepreviewer/'.$file->id.'/'.$file->unique_hash;
                    if (is_dir($filePreviewerCachePath)) {
                        $newPath = CACHE_DIRECTORY_ROOT.'/plugins/filepreviewer/'.$newFile->id.'/'.$newFile->unique_hash;
                        CoreHelper::recurseCopy($filePreviewerCachePath, $newPath);
                    }
                }
            }

            $rs['success'] = true;
            $rs['msg'] = TranslateHelper::t('file_manager_files_duplicated_success_message',
                'Files duplicated in current folder.');
        }

        // output response
        return $this->renderJson($rs);
    }

    public function ajaxMoveToFolder()
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get the current logged in user
        $Auth = AuthHelper::getAuth();
        $db = Database::getDatabase();

        // pickup request for later
        $request = $this->getRequest();

        // load items
        $fileIds = $request->request->get('fileIds');
        $fileIds = explode(',', $fileIds);
        $safeFileIds = array_map('intval', $fileIds);
        $folderIds = $request->request->get('folderIds');
        $folderIds = explode(',', $folderIds);
        $safeFolderIds = array_map('intval', $folderIds);
        $currentFolderId = $request->request->get('currentFolderId');

        // validation
        $checkedFileIds = [];
        if (count($safeFileIds)) {
            $checkedFileIds = $db->getRows('SELECT id '
                .'FROM file '
                .'WHERE id IN ('.implode(',', $safeFileIds).') '
                .'AND (userId = :userId OR uploadedUserId = :uploadedUserId)', [
                'userId' => $Auth->id,
                'uploadedUserId' => $Auth->id,
            ]);
        }
        $checkedFolderIds = [];
        if (count($safeFolderIds)) {
            $checkedFolderIds = $db->getRows('SELECT id '
                .'FROM file_folder '
                .'WHERE id IN ('.implode(',', $safeFolderIds).') '
                .'AND userId = :userId', [
                'userId' => $Auth->id,
            ]);
        }

        $totalItems = (int) count($checkedFileIds) + (int) count($checkedFolderIds);

        // load folder structure as array
        $folderListing = FileFolderHelper::loadAllActiveForSelect($Auth->id, '/', $safeFolderIds);

        // load template
        return $this->render('account/ajax/move_to_folder.html', [
            'safeFileIds' => $safeFileIds,
            'totalItems' => $totalItems,
            'folderListing' => $folderListing,
            'currentFolderId' => $currentFolderId,
        ]);
    }

    public function ajaxAccountCopyFile()
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get the current logged-in user
        $Auth = AuthHelper::getAuth();
        $db = Database::getDatabase();

        // pickup request for later
        $request = $this->getRequest();
        $fileId = $request->request->get('fileId');

        // prepare result
        $rs = [];
        $rs['success'] = false;
        $rs['msg'] = TranslateHelper::t('failed_to_copy_file',
            'There was a problem copying the file, please try again later.');

        // load file
        $file = File::loadOneById($fileId);
        if (!$file) {
            // failed lookup of file
            return $this->renderJson($rs);
        }

        // make sure the file is active
        if ($file->status !== 'active') {
            // failed lookup of file
            return $this->renderJson($rs);
        }

        // make sure the file doesn't have a password
        if (strlen($file->accessPassword)) {
            // failed lookup of file
            return $this->renderJson($rs);
        }

        // if this user already owns the file, don't copy
        if ($file->userId === $Auth->id) {
            // failed lookup of file
            return $this->renderJson($rs);
        }

        // for files not owned by this user, ensure we are permitted to access it
        if ($file->userId !== null) {
            if (($file->userId != $Auth->id && $Auth->level_id < 10)) {
                // if this is a private file
                if (!CoreHelper::getOverallPublicStatus($file->userId, $file->folderId, $file->id)) {
                    // file is not publicly available or accessible to this user
                    return $this->renderJson($rs);
                }
            }
        }

        // if the file is limited to a specific user type, check that they are permitted to copy it
        if ($file->minUserLevel != null) {
            // check that the user has the correct file level
            if ((int)$Auth->level_id < (int)$file->minUserLevel) {
                if (($file->userId != null) && ($Auth->user_id == $file->userId)) {
                    // ignore the restriction if this is the original user which uploaded the file
                } else {
                    $userTypeLabel = $db->getValue('SELECT label '
                        .'FROM user_level '
                        .'WHERE level_id = :level_id'
                        .'LIMIT 1', [
                        'level_id' => (int)$file->minUserLevel,
                    ]);
                    $rs['msg'] = TranslateHelper::t("error_you_must_be_a_x_user_to_copy_this_file",
                        "You must be a [[[USER_TYPE]]] to copy this file.", ['USER_TYPE' => $userTypeLabel]);

                    return $this->renderJson($rs);
                }
            }
        }

        // attempt to copy the file
        $newFile = $file->duplicateFile();

        // on failure
        if (!$newFile) {
            // failed creating copy
            return $this->renderJson($rs);
        }

        // user action logs
        UserActionLogHelper::log('Copied file', 'FILE', 'READ', [
            'file_id' => $file->id,
            'data' => [
                'old_file_id' => $newFile->id,
            ],
        ]);

        // user action logs
        UserActionLogHelper::log('Created file from existing', 'FILE', 'ADD', [
            'file_id' => $newFile->id,
            'data' => [
                'old_file_id' => $file->id,
            ],
        ]);

        // success response
        $rs['success'] = true;
        $rs['newFileId'] = $newFile->id;
        $rs['msg'] = TranslateHelper::t('file_copied', 'File copied into your account - [[[FILE_LINK]]]', [
            'FILE_LINK' => $newFile->originalFilename,
        ]);

        return $this->renderJson($rs);
    }

    public function ajaxFileHistory($fileId)
    {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // load file
        $file = File::loadOneById($fileId);
        if (!$file) {
            // exit
            return $this->render404();
        }

        // get the current logged-in user
        $Auth = AuthHelper::getAuth();

        // make sure the logged-in user owns this file or is an admin
        if (!in_array($Auth->id, [$file->userId, $file->uploadedUserId]) && !$Auth->isAdmin()) {
            // exit
            return $this->render404();
        }

        // get audit data
        $userActionLogs = UserActionLog::loadByClause('file_id = :file_id AND admin_area_action = 0', [
            'file_id' => $file->id,
        ], 'date_created DESC', 50);

        $rs = [];
        $rs['success'] = true;
        $rs['html'] = $this->getRenderedTemplate('account/ajax/file_history.html', array(
            'file' => $file,
            'userActionLogs' => $userActionLogs,
        ));
        $rs['title'] = TranslateHelper::t('file_history_popup_title', 'File History ([[[FILENAME]]])', [
            'FILENAME' => $file->originalFilename,
        ]);

        return $this->renderJson($rs);
    }

    public function ajaxDownloadSelectedFilesSetSession() {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get request
        $request = $this->getRequest();

        // store in session
        $_SESSION['zip_download_selected'] = [
            'file_ids' => $request->request->get('fileIds'),
            'folder_ids' => $request->request->get('folderIds'),
        ];

        return $this->renderJson([
            'success' => true,
        ]);
    }

    public function ajaxDownloadSelectedFilesIframe() {
        // require user login
        if (($response = $this->requireLogin()) !== false) {
            return $response;
        }

        // get params for later
        $Auth = $this->getAuth();

        // allow some time to run
        set_time_limit(60 * 60 * 4);

        // allow 1.2GB of memory to run
        ini_set('memory_limit', '1200M');

        // output styles - @TODO - replace with Twig
        echo $this->getIframeCss();

        // check for zip class
        if (!class_exists('ZipArchive')) {
            echo TranslateHelper::t('account_home_ziparchive_class_not_exists',
                'Error: The ZipArchive class was not found within PHP. Please enable it within php.ini and try again.');
            exit;
        }

        // setup database
        $db = Database::getDatabase();

        // get files and folders
        $fileIds = $_SESSION['zip_download_selected']['file_ids'] ?? [];
        $folderIds = $_SESSION['zip_download_selected']['folder_ids'] ?? [];

        // ensure something is selected
        if (empty($fileIds) && empty($folderIds)) {
            echo TranslateHelper::t('account_home_download_selected_no_items_selected',
                'Error: Please select 1 or more item to download.');
            exit;
        }

        $fileItems = [];
        if(!empty($fileIds)) {
            // load all file data
            $fileItems = $db->getRows('SELECT file.* '
                .'FROM file '
                .'LEFT JOIN file_artifact ON file.id = file_artifact.file_id '
                .'WHERE userId = :user_id '
                .'AND file.id IN(' . implode(',', array_map('intval', $fileIds)) . ')', [
                'user_id' => $Auth->id,
            ]);
        }

        $folderItems = [];
        if(!empty($folderIds)) {
            // load all folder data
            $folderItems = $db->getRows('SELECT id, folderName FROM file_folder WHERE userId = :user_id AND id IN(' . implode(',', array_map('intval', $folderIds)) . ')', [
                'user_id' => $Auth->id,
            ]);
        }

        // ensure we have some data
        if (empty($fileItems) && empty($folderItems)) {
            echo TranslateHelper::t('account_home_download_selected_no_items_selected',
                'Error: Please select 1 or more item to download.');
            exit;
        }

        // create zip file
        $zipFilename = CoreHelper::generateRandomHash();

        // remove any old zip files
        ZipFile::purgeOldZipFiles();

        // setup output buffering
        ZipFile::outputInitialBuffer();

        // calculate file count and total filesize
        $totalFileCount = 0;
        $totalFilesize = 0;
        if(!empty($fileItems)) {
            foreach($fileItems as $fileItem) {
                $totalFileCount++;
                $totalFilesize += $fileItem['fileSize'];
            }
        }

        // add selected folder files
        $cachedFolderFileData = [];
        if(!empty($folderItems)) {
            foreach($folderItems as $folderItem) {
                $cachedFolderFileData[$folderItem['id']] = ZipFile::getFolderStructureAsArray($folderItem['id'], $folderItem['id'], $Auth->id);
                $totalFileCount += ZipFile::getTotalFileCount($cachedFolderFileData[$folderItem['id']][$folderItem['folderName']]);
                $totalFilesize += ZipFile::getTotalFileSize($cachedFolderFileData[$folderItem['id']][$folderItem['folderName']]);
            }
        }

        // check total filesize
        if ($totalFilesize > $this->getMaxPermittedZipFilesize()) {
            echo TranslateHelper::t('account_home_too_many_files_size',
                'Error: Selected files are greater than [[[MAX_FILESIZE]]] (total [[[TOTAL_SIZE_FORMATTED]]]). Can not create zip.',
                [
                    'MAX_FILESIZE' => CoreHelper::formatSize($this->getMaxPermittedZipFilesize()),
                    'TOTAL_SIZE_FORMATTED' => CoreHelper::formatSize($totalFilesize),
                ]);
            exit;
        }

        // create blank zip file
        $zip = new ZipFile($zipFilename);

        // output progress
        ZipFile::outputBufferToScreen('Found '.$totalFileCount.' file'.($totalFileCount != 1 ? 's' : '').'.');

        // add selected files
        if(!empty($fileItems)) {
            foreach($fileItems as $fileItem) {
                $file = File::hydrateSingleRecord($fileItem);
                $zip->addSingleFileToZip($file);
            }
        }

        // add selected folders
        if(!empty($folderItems)) {
            foreach($folderItems as $folderItem) {
                // loop all files and download locally
                foreach ($cachedFolderFileData[$folderItem['id']] as $fileDataItem) {
                    // add files
                    $zip->addFilesTopZip($fileDataItem, $fileDataItem['folderName'].'/');

                    // do folders
                    if (count($fileDataItem['folders'])) {
                        $zip->addFileAndFolders($fileDataItem['folders'], $fileDataItem['folderName'].'/');
                    }
                }
            }
        }

        // output progress
        ZipFile::outputBufferToScreen('Saving zip file...', null, ' ');

        // close zip
        $zip->close();

        // get path for later
        $fullZipPathAndFilename = $zip->fullZipPathAndFilename;

        // output progress
        ZipFile::outputBufferToScreen('Done!', 'green');
        echo '<br/>';

        // output link to zip file
        $downloadZipName = 'Selected-Files-'.date('Y-m-d');

        echo '<a class="btn btn-info" href="'.ACCOUNT_WEB_ROOT.'/ajax/download_all_as_zip_get_file/'.str_replace('.zip',
                '',
                $zipFilename).'/'.urlencode($downloadZipName).'" target="_parent">'.TranslateHelper::t('account_home_download_zip_file',
                'Download Zip File').'&nbsp;&nbsp;('.CoreHelper::formatSize(filesize($fullZipPathAndFilename)).')</a>';
        ZipFile::scrollIframe();

        echo '<br/><br/>';
        ZipFile::scrollIframe();

        // user action logs
        UserActionLogHelper::log('Generated zip download from selected files', 'FILE', 'WRITE', [
            'data' => [
                'filename' => $downloadZipName.'.zip',
                'file_ids' => empty($fileIds) ? 'none' : implode(', ', $fileIds),
                'folder_ids' => empty($folderIds) ? 'none' : implode(', ', $folderIds),
            ],
        ]);

        exit;
    }

}

Youez - 2016 - github.com/yon3zu
LinuXploit