<?php
/**
* Manage main actions
*
* @category PHP
* @package VenoFileManager
* @author Nicola Franchini <info@veno.it>
* @license Exclusively sold on CodeCanyon
* @link http://filemanager.veno.it/
*/
if (!class_exists('Actions', false)) {
/**
* Class Actions
*
* @category PHP
* @package VenoFileManager
* @author Nicola Franchini <info@veno.it>
* @license Exclusively sold on CodeCanyon
* @link http://filemanager.veno.it/
*/
class Actions
{
/**
* The main function, checks if the user wants to perform any supported operations
*
* @param string $location to run
*
* @return checks if any action is required
*/
public function __construct($location = false)
{
if (!$location) {
return false;
}
global $gateKeeper;
$postnewdir = filter_input(INPUT_POST, 'userdir', FILTER_SANITIZE_SPECIAL_CHARS);
$renamedir = filter_input(INPUT_POST, 'newname', FILTER_SANITIZE_SPECIAL_CHARS);
$postoldname = filter_input(INPUT_POST, 'oldname', FILTER_SANITIZE_SPECIAL_CHARS);
$getdel = filter_input(INPUT_GET, 'del', FILTER_SANITIZE_SPECIAL_CHARS);
// delete files or folders
if ($getdel && $gateKeeper->isAllowed('delete_enable')) {
$decode_del = base64_decode($getdel, true);
if ($decode_del) {
$getdel = Utils::extraChars(urldecode($decode_del));
$this->setDel($getdel);
} else {
Utils::setError('<i class="bi bi-slash-circle"></i> Character encoding error, remove the file via FTP');
}
}
// add new folder
if ($postnewdir) {
$dirname = Utils::normalizeStr($postnewdir);
Actions::newFolder($location, $dirname);
}
// rename files or folders
if ($renamedir && $postoldname) {
$postoldname = base64_decode($postoldname, true); // Check also dir
$this->setRename($postoldname, Utils::normalizeStr($renamedir));
}
// Upload files in the old fashioned way ( IE <= 9 & Safari on Windows)
if (isset($_FILES['userfile']['name'])) {
Uploader::uploadMulti($_FILES['userfile']);
}
}
/**
* Check path to delete
*
* @param string $path to search
*
* @return true/false
*/
public static function checkDel($path)
{
global $gateKeeper;
global $setUp;
$startdir = $setUp->getConfig('starting_dir');
$cash = filter_input(INPUT_GET, 'h', FILTER_SANITIZE_SPECIAL_CHARS);
$del = filter_input(INPUT_GET, 'del', FILTER_SANITIZE_SPECIAL_CHARS);
$del = str_replace(' ', '+', $del);
if (md5($del.$setUp->getConfig('salt').$setUp->getConfig('session_name')) === $cash) {
if ($gateKeeper->getUserInfo('dir') != null) {
$userdirs = json_decode($gateKeeper->getUserInfo('dir'), true);
foreach ($userdirs as $value) {
$userpath = $startdir.$value;
$pos = strpos('./'.$path, $userpath);
if ($pos !== false) {
return true;
}
}
return false;
}
$pos = strpos('./'.$path, $startdir);
$filepathinfo = Utils::mbPathinfo($path);
$basepath = $filepathinfo['basename'];
$evil = array('', '/', '\\', '.');
$avoid = $setUp->getConfig('hidden_files');
if ($pos === false
|| in_array($path, $evil)
|| in_array($basepath, $avoid)
|| realpath($path) === realpath($startdir)
|| realpath($path) === realpath(dirname(__FILE__))
) {
return false;
}
return true;
}
return false;
}
/**
* Setup file to delete
*
* @param string $getdel path to delete
*
* @return call deleteFile()
*/
public function setDel($getdel)
{
global $gateKeeper;
global $setUp;
if (Actions::checkDel($getdel) == false) {
Utils::setError('<i class="bi bi-slash-circle"></i> '.$setUp->getString('not_allowed'));
return;
}
if (is_dir($getdel)) {
if ($gateKeeper->getUserSpace() !== false) {
$ritorno = Utils::getDirSize("./".$getdel);
$totalsize = $ritorno['size'];
if ($totalsize > 0) {
Actions::updateUserSpace(false, true, $totalsize);
}
}
Actions::deleteDir($getdel);
Utils::setWarning('<span><i class="bi bi-trash"></i> <strong>'.substr($getdel, strrpos($getdel, '/') + 1).'</strong></span>');
// Directory successfully deleted, sending log notification
Logger::logDeletion('./'.$getdel, true);
} elseif (is_file($getdel)) {
Actions::deleteFile($getdel);
}
}
/**
* Delete directory
*
* @param string $dir directory to delete
*
* @return deletes directory
*/
public static function deleteDir($dir)
{
if (is_dir($dir)) {
$objects = scandir($dir);
foreach ($objects as $object) {
if ($object != '.' && $object != '..') {
if (filetype($dir.'/'.$object) == 'dir') {
Actions::deleteDir($dir.'/'.$object);
} else {
$filetime = filemtime($dir.'/'.$object);
$filetime = $filetime ? $filetime : 'no-data';
unlink($dir.'/'.$object);
Actions::deleteThumb($dir.'/'.$object, $filetime);
}
}
}
reset($objects);
rmdir($dir);
}
}
/**
* Delete file
*
* @param string $file file to delete
* @param bool $multi delete multiple files
*
* @return deletes file
*/
public static function deleteFile($file, $multi = false)
{
if (is_file($file)) {
Actions::updateUserSpace($file, true);
$filepathinfo = Utils::mbPathinfo($file);
$basepath = $filepathinfo['basename'];
$filetime = filemtime($file);
$filetime = $filetime ? $filetime : 'no-data';
if ($multi) {
Actions::deleteThumb(substr($file, 6), $filetime, true);
Utils::setWarning('<span><i class="bi bi-trash"></i> <strong>'.$basepath.'</strong></span> ');
Logger::logDeletion(substr($file, 1), false, true);
} else {
$filetime = filemtime($file);
$filetime = $filetime ? $filetime : 'no-data';
Actions::deleteThumb($file, $filetime);
Utils::setWarning('<span><i class="bi bi-trash"></i> <strong>'.$basepath.'</strong></span>');
Logger::logDeletion('./'.$file, false);
}
unlink($file);
}
}
/**
* Setup file renaming
*
* @param string $postoldname original file or directory name
* @param string $postnewname new file or directory name
*
* @return call renameFile();
*/
public function setRename($postoldname, $postnewname)
{
global $gateKeeper;
if ($gateKeeper->isAccessAllowed() && $gateKeeper->isAllowed('rename_enable')) {
$postthisext = htmlspecialchars($_POST['thisext']);
$postthisdir = htmlspecialchars($_POST['thisdir']);
if ($postoldname && $postnewname) {
if ($postthisext) {
$oldname = $postthisdir.$postoldname.".".$postthisext;
$newname = $postthisdir.Utils::normalizeStr($postnewname).".".$postthisext;
} else {
$oldname = $postthisdir.$postoldname;
$newname = $postthisdir.Utils::normalizeStr($postnewname);
}
Actions::renameFile($oldname, $newname, $postnewname);
}
}
}
/**
* Rename files
*
* @param string $oldname original file path
* @param string $newname new file path
* @param string $thenewname new name
* @param bool $move move file
* @param bool $copy copy file
*
* @return boolean
*/
public static function renameFile($oldname, $newname, $thenewname, $move = false, $copy = false)
{
global $setUp;
$newname = Utils::extraChars($newname);
if (!Utils::fileExists($oldname)) {
Utils::setError('<span><i class="bi bi-exclamation-circle"></i> <strong>' .$oldname. '</strong> does not exist</span>');
return false;
}
if (Utils::fileExists($newname)) {
Utils::setWarning('<span><i class="bi bi-info-circle"></i> <strong>' .$thenewname. '</strong> '.$setUp->getString('file_exists').'</span>');
return false;
}
if ($copy) {
if (!copy($oldname, $newname)) {
Utils::setError('<span><i class="bi bi-exclamation-circle"></i> <strong>' .$thenewname. '</strong> can\'t be copied</span>');
return false;
} else {
Actions::updateUserSpace($oldname);
return true;
}
} else {
$filetime = filemtime($oldname);
$filetime = $filetime ? $filetime : 'no-data';
$delfilename = $move ? substr($oldname, 6) : substr($oldname, 3);
if (is_dir($oldname)) {
Actions::deleteThumbRecursive($oldname);
}
if (!rename($oldname, $newname)) {
Utils::setError('<span><i class="bi bi-exclamation-circle"></i> <strong>' .$thenewname. '</strong> can\'t be edited</span>');
return false;
} else {
if ($move) {
// Delete old thumbnail
Actions::deleteThumb($delfilename, $filetime, true);
} else {
// Simple name change
Utils::setSuccess('<span><strong>'.$thenewname. '</strong> '.$setUp->getString('updated').'</span>');
Actions::deleteThumb($oldname, $filetime);
}
return true;
}
}
}
/**
* Show available directories
*
* @param string $dir base path
* @param string $currentdir current directory browsing
* @param bool $link set link or data-dest
* @param string $relative relative path '../.' to be called from /vfm-admin/ajax/ instead of '' from index
*
* @return directories tree
*/
public static function walkDir($dir, $currentdir, $link = false, $relative = '', $checkbox = false, $userdirs = array(), $level = 0)
{
global $setUp;
$counter = 0;
$output = false;
$relativedir = $relative.$dir;
if (is_dir($relativedir)) {
$scandir = glob($relativedir.'*', GLOB_ONLYDIR);
natcasesort($scandir);
$cleandir = ltrim($dir, $setUp->getConfig('starting_dir'));
$level++;
$ulclass = $level > 1 ? ' class="sub-tree"' : '';
$output = '<ul'.$ulclass.'>';
foreach ($scandir as $folder) {
$filepathinfo = Utils::mbPathinfo($folder);
$file = $filepathinfo['basename'];
if ($relativedir.$file == $relative.'./vfm-admin' || substr($file, 0, 1) == '.') {
continue;
}
if (is_dir($relativedir.$file)) {
$counter++;
$output .= '<li class="level-'.$level.' level-'.$level.'-'.$counter.'">';
if ($level == 1) {
$output .= '<div class="highlight"></div>';
}
$dest = ltrim($dir.$file, './');
$cleandest = ltrim($cleandir.$file, './');
$checked = is_array($userdirs) && in_array($cleandest, $userdirs) ? ' checked' : '';
if ($checkbox) {
$box_id = md5($dest);
$output .= '<div class="form-check">
<input class="form-check-input setuserfolder" style="vertical-align: sub; float:none;" type="checkbox" value="'.$cleandest.'" id="'.$box_id.'"'.$checked.' data-target=".level-'.$level.'-'.$counter.'">
<label class="form-check-label" for="'.$box_id.'">'.$file.'</label>
</div>';
} else {
if ($relativedir.$file."/" == $relative.$currentdir) {
$output .= '<i class="bi bi-folder2-open"></i> <span class="search-highlight">'.$file.'</span>';
} else {
if ($link) {
$output .= '<a data href="?dir='.urlencode($dest).'">';
} else {
$output .= '<a href="#" data-dest="'.urlencode('./'.$dest).'" class="movelink">';
}
$output .= '<i class="bi bi-folder"></i> '.$file.'</a>';
}
}
// Break loop for checkboxes > 8 && foldertee > 30 levels
if (($checkbox && $level < 8) || (!$checkbox && $level < 30)) {
$scansub = glob($relativedir.$file.'/'.'*', GLOB_ONLYDIR);
if (count($scansub)) {
$output .= '<span class="toggle-tree"><i class="bi bi-dash-square tree-toggler bg-lighter"></i></span>';
$output .= Actions::walkDir($relativedir.$file.'/', $relative.$currentdir, $link, '', $checkbox, $userdirs, $level);
}
}
$output .= '</li>';
}
}
$output .= '</ul>';
}
return $output;
}
/**
* Create new folder
*
* @param string $location where to create new folder
* @param string $dirname new dir name
*
* @return adds new folder
*/
public static function newFolder($location, $dirname)
{
global $setUp;
global $gateKeeper;
if ($gateKeeper->isAllowed('newdir_enable')) {
if (strlen($dirname) > 0) {
if (!$location->editAllowed()) {
// The system configuration does not allow uploading here
Utils::setError($setUp->getString('upload_not_allowed'));
return false;
}
if (!$location->isWritable()) {
// The target directory is not writable
Utils::setError($setUp->getString('upload_dir_not_writable'));
return false;
}
if (Utils::fileExists($location->getDir(true, false, false, 0).$dirname)) {
Utils::setWarning(
'<span><i class="bi bi-folder"></i> <strong>'.$dirname.'</strong> '
.$setUp->getString('file_exists').'</span>'
);
return false;
}
if (!mkdir($location->getDir(true, false, false, 0).$dirname, 0755)) {
// Error creating a new directory
Utils::setError($setUp->getString('new_dir_failed'). ': <strong>'.$dirname.'</strong>');
return false;
}
Utils::setSuccess(
'<span><i class="bi bi-folder"></i> <strong>'.$dirname.'</strong> '
.$setUp->getString('created').'</span>'
);
// Directory successfully created, sending e-mail notification
Logger::logCreation($location->getDir(true, false, false, 0).$dirname, true);
// Redirect to the new folder.
// header('Location:'.$setUp->getConfig('script_url')."?dir=".$location->getDir(false, false, false, 0).$dirname);
return true;
}
Utils::setError($setUp->getString('new_dir_failed'). ': <strong>'.$dirname.'</strong>');
return false;
}
}
/**
* Delete directory
*
* @param string $dir directory to delete
*
* @return deletes directory
*/
public static function deleteThumbRecursive($dir)
{
if (is_dir($dir)) {
$objects = scandir($dir);
foreach ($objects as $object) {
if ($object != '.' && $object != '..') {
if (filetype($dir.'/'.$object) == 'dir') {
Actions::deleteThumbRecursive($dir.'/'.$object);
} else {
$filetime = filemtime($dir.'/'.$object);
$filetime = $filetime ? $filetime : 'no-data';
Actions::deleteThumb($dir.'/'.$object, $filetime);
}
}
}
reset($objects);
}
}
/**
* Delete thumbnail
*
* @param string $file file to delete
* @param string $filetime file time
* @param bool $multi called from vfm-del.php or vfm-move.php
*
* @return deletes thumb
*/
public static function deleteThumb($file, $filetime = 'no-data', $multi = false)
{
if ($multi == false) {
$relativepath = 'vfm-admin/';
} else {
$relativepath = '../';
}
$thumbdir = $relativepath.'_content/thumbs/';
$thumbname = md5($file.$filetime);
$thumb = $thumbdir.$thumbname.'.jpg';
$thumb_big = $thumbdir.$thumbname.'-big.jpg';
if (is_file($thumb)) {
unlink($thumb);
}
if (is_file($thumb_big)) {
unlink($thumb_big);
}
}
/**
* Check if user has space to upload
*
* @param string $file file to check
* @param int $thissize size to check
* @param bool $upload uploaded file
*
* @return true/false
*/
public static function checkUserSpace($file = false, $thissize = false, $upload = false)
{
global $setUp;
if ($upload) {
$max_upload_filesize = $setUp->getConfig('max_upload_filesize');
if ($max_upload_filesize > 0) {
$max_upload_filesize = ($max_upload_filesize*1024*1024);
if (!$thissize && $file) {
$thissize = Utils::getFileSize($file);
}
if ($thissize > $max_upload_filesize) {
return false;
}
}
}
if (isset($_SESSION['vfm_user_used'])
&& isset($_SESSION['vfm_user_space'])
) {
if (!$thissize && $file) {
$thissize = Utils::getFileSize($file);
}
$oldused = $_SESSION['vfm_user_used'];
$newused = $oldused + $thissize;
$freespace = $_SESSION['vfm_user_space'];
if ($newused > $freespace) {
return false;
}
}
return true;
}
/**
* Update user used space by file (add or subtract)
*
* @param string $file file to add/subtract
* @param boolean $add true/false add or subtract
* @param int $size size to add/subtract
*
* @return updates total used space
*/
public static function updateUserSpace($file = false, $add = false, $size = false)
{
if (isset($_SESSION['vfm_user_used'])) {
$thissize = ($size && !$file) ? $size : Utils::getFileSize($file);
$usedspace = $_SESSION['vfm_user_used'];
if ($add) {
$usedspace = (abs($usedspace) - abs($thissize));
} else {
$usedspace = (abs($usedspace) + abs($thissize));
}
$_SESSION['vfm_user_used'] = $usedspace;
}
}
}
}