_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST); } if (!extension_loaded('zip')) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_COMMAND); } $this->checkConnector(); $this->checkRequest(); if ( !$this->_currentFolder->checkAcl(CKFINDER_CONNECTOR_ACL_FILE_UPLOAD)) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED); } if (!isset($_POST["fileName"])) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_NAME); } $fileName = CKFinder_Connector_Utils_FileSystem::convertToFilesystemEncoding($_POST["fileName"]); $resourceTypeInfo = $this->_currentFolder->getResourceTypeConfig(); if (!$resourceTypeInfo->checkExtension($fileName)) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_EXTENSION); } if (!CKFinder_Connector_Utils_FileSystem::checkFileName($fileName) || $resourceTypeInfo->checkIsHiddenFile($fileName)) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST); } $filePath = CKFinder_Connector_Utils_FileSystem::combinePaths($this->_currentFolder->getServerPath(), $fileName); if (!file_exists($filePath) || !is_file($filePath)) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_FILE_NOT_FOUND); } if (!is_writable(dirname($filePath))) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_ACCESS_DENIED); } if ( strtolower(pathinfo($fileName, PATHINFO_EXTENSION)) !== 'zip'){ $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_EXTENSION); } $zip = new ZipArchive(); $result = $zip->open($filePath); if ($result !== TRUE) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNKNOWN); } $this->zip = $zip; $this->filePath = $filePath; $this->_config =& CKFinder_Connector_Core_Factory::getInstance("Core_Config"); // list of unzipped nodes $this->unzippedNodes = new CKFinder_Connector_Utils_XmlNode("UnzippedFiles"); // list of files which could not be unzipped $this->skippedFilesNode = new CKFinder_Connector_Utils_XmlNode("Errors"); $this->errorCode = CKFINDER_CONNECTOR_ERROR_NONE; } /** * Check one file for security reasons * * @param object $filePathInfo * @param string $originalFileName * @return mixed bool(false) - if security checks fails. Otherwise string - ralative zip archive path with secured filename. */ protected function checkOneFile($filePathInfo, $originalFileName ) { $resourceTypeInfo = $this->_currentFolder->getResourceTypeConfig(); // checked if it is a folder $fileStat = $this->zip->statName($originalFileName); if ( empty($filePathInfo['extension']) && empty($fileStat['size']) ){ $sNewFolderName = CKFinder_Connector_Utils_FileSystem::convertToFilesystemEncoding(rtrim($fileStat['name'],'/')); if ($this->_config->forceAscii()) { $sNewFolderName = CKFinder_Connector_Utils_FileSystem::convertToAscii($sNewFolderName); } if (!CKFinder_Connector_Utils_FileSystem::checkFolderPath($sNewFolderName) || $resourceTypeInfo->checkIsHiddenFolder($sNewFolderName)) { $this->errorCode = CKFINDER_CONNECTOR_ERROR_INVALID_NAME; $this->appendErrorNode($this->skippedFilesNode, $this->errorCode, $originalFileName); return false; } if (!is_writeable($this->_currentFolder->getServerPath())) { $this->errorCode = CKFINDER_CONNECTOR_ERROR_ACCESS_DENIED; $this->appendErrorNode($this->skippedFilesNode, $this->errorCode, $originalFileName); return false; } return $originalFileName; } $fileName = CKFinder_Connector_Utils_FileSystem::convertToFilesystemEncoding($filePathInfo['basename']); $sFileName = CKFinder_Connector_Utils_FileSystem::secureFileName($fileName); // max file size $maxSize = $resourceTypeInfo->getMaxSize(); if ( $maxSize && $fileStat['size'] > $maxSize ) { $this->errorCode = CKFINDER_CONNECTOR_ERROR_UPLOADED_TOO_BIG; $this->appendErrorNode($this->skippedFilesNode, $this->errorCode, $originalFileName); return false; } // extension if ( !$resourceTypeInfo->checkExtension($sFileName) ) { $this->errorCode = CKFINDER_CONNECTOR_ERROR_INVALID_EXTENSION; $this->appendErrorNode($this->skippedFilesNode, $this->errorCode, $originalFileName); return false; } // hidden file if ( !CKFinder_Connector_Utils_FileSystem::checkFileName($sFileName) || $resourceTypeInfo->checkIsHiddenFile($sFileName) ){ $this->errorCode = CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST; $this->appendErrorNode($this->skippedFilesNode, $this->errorCode, $originalFileName); return false; } // unpack file to tmp dir for detecting html and valid image $dir = CKFinder_Connector_Utils_FileSystem::getTmpDir().'/'; if ( file_exists($dir.$sFileName) && !CKFinder_Connector_Utils_FileSystem::unlink($dir.$sFileName) ){ $this->errorCode = CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST; $this->appendErrorNode($this->skippedFilesNode, $this->errorCode, $originalFileName); return false; } if ( copy('zip://'.$this->filePath.'#'.$originalFileName, $dir.$sFileName) ) { // html extensions $htmlExtensions = $this->_config->getHtmlExtensions(); $sExtension = CKFinder_Connector_Utils_FileSystem::getExtension( $dir.$sFileName ); if ( $htmlExtensions && !CKFinder_Connector_Utils_Misc::inArrayCaseInsensitive( $sExtension, $htmlExtensions ) && CKFinder_Connector_Utils_FileSystem::detectHtml($dir.$sFileName) === true ) { $this->errorCode = CKFINDER_CONNECTOR_ERROR_UPLOADED_INVALID; $this->appendErrorNode($this->skippedFilesNode, $this->errorCode, $originalFileName); return false; } // proper image $secureImageUploads = $this->_config->getSecureImageUploads(); if ( $secureImageUploads && ( $isImageValid = CKFinder_Connector_Utils_FileSystem::isImageValid($dir.$sFileName, $sExtension) ) === false ) { $this->errorCode = CKFINDER_CONNECTOR_ERROR_UPLOADED_INVALID; $this->appendErrorNode($this->skippedFilesNode, $this->errorCode, $originalFileName); return false; } } $sDirName = ($filePathInfo['dirname'] != '.')? $filePathInfo['dirname'].'/' : ''; return $sDirName.$sFileName; } /** * Add error node to the list * @param obj $oErrorsNode * @param int $errorCode * @param string $name * @param string $type * @param string $path */ protected function appendErrorNode($oErrorsNode, $errorCode=0, $name, $type=null, $path=null) { $oErrorNode = new CKFinder_Connector_Utils_XmlNode("Error"); $oErrorNode->addAttribute("code", $errorCode); $oErrorNode->addAttribute("name", CKFinder_Connector_Utils_FileSystem::convertToConnectorEncoding($name)); if ( $type ){ $oErrorNode->addAttribute("type", $type); } if ( $path ){ $oErrorNode->addAttribute("folder", $path); } $oErrorsNode->addChild($oErrorNode); } /** * Add unzipped node to the list * @param obj $oUnzippedNodes * @param string $name * @param string $action */ protected function appendUnzippedNode($oUnzippedNodes, $name, $action='ok') { $oUnzippedNode = new CKFinder_Connector_Utils_XmlNode("File"); $oUnzippedNode->addAttribute("name", CKFinder_Connector_Utils_FileSystem::convertToConnectorEncoding($name)); $oUnzippedNode->addAttribute("action", $action ); $oUnzippedNodes->addChild($oUnzippedNode); } /** * Extract one file from zip archive * * @param string $extractPath * @param string $extractClientPath * @param array $filePathInfo * @param string $sFileName * @param string $originalFileName */ protected function extractTo($extractPath, $extractClientPath, $filePathInfo, $sFileName, $originalFileName) { $sfilePathInfo = pathinfo($extractPath.$sFileName); $extractClientPathDir = $filePathInfo['dirname']; if ( $filePathInfo['dirname'] == '.' ){ $extractClientPathDir = ''; } $folderPath = CKFinder_Connector_Utils_FileSystem::combinePaths($extractClientPath,$extractClientPathDir); $_aclConfig = $this->_config->getAccessControlConfig(); $aclMask = $_aclConfig->getComputedMask($this->_currentFolder->getResourceTypeName(),$folderPath); $canCreateFolder = (($aclMask & CKFINDER_CONNECTOR_ACL_FOLDER_CREATE ) == CKFINDER_CONNECTOR_ACL_FOLDER_CREATE ); // create sub-directory of zip archive if ( empty($sfilePathInfo['extension']) ) { $fileStat = $this->zip->statName($originalFileName); $isDir = false; if ( $fileStat && empty($fileStat['size']) ){ $isDir = true; } if( !empty($sfilePathInfo['dirname']) && !empty($sfilePathInfo['basename']) && !file_exists($sfilePathInfo['dirname'].'/'.$sfilePathInfo['basename']) ) { if ( !$canCreateFolder ){ return; } if ( $isDir ) { CKFinder_Connector_Utils_FileSystem::createDirectoryRecursively( $sfilePathInfo['dirname'].'/'.$sfilePathInfo['basename'] ); return; } else { CKFinder_Connector_Utils_FileSystem::createDirectoryRecursively( $sfilePathInfo['dirname']); } } else { return; } } // extract file if ( !file_exists($sfilePathInfo['dirname']) ){ if ( !$canCreateFolder ){ $this->errorCode = CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED; $this->appendErrorNode($this->skippedFilesNode, $this->errorCode, $originalFileName ); return; } CKFinder_Connector_Utils_FileSystem::createDirectoryRecursively($sfilePathInfo['dirname']); } $isAuthorized = (($aclMask & CKFINDER_CONNECTOR_ACL_FILE_UPLOAD ) == CKFINDER_CONNECTOR_ACL_FILE_UPLOAD ); if ( !$isAuthorized ){ $this->errorCode = CKFINDER_CONNECTOR_ERROR_COPY_FAILED; $this->appendErrorNode($this->skippedFilesNode, $this->errorCode, $originalFileName); return; } if ( copy('zip://'.$this->filePath.'#'.$originalFileName, $extractPath.$sFileName) ) { $this->appendUnzippedNode($this->unzippedNodes,$originalFileName); // chmod extracted file if ( is_file($extractPath.$sFileName) && ( $perms = $this->_config->getChmodFiles()) ) { $oldumask = umask(0); chmod( $extractPath.$sFileName, $perms ); umask( $oldumask ); } } // file extraction failed, add to skipped else { $this->errorCode = CKFINDER_CONNECTOR_ERROR_COPY_FAILED; $this->appendErrorNode($this->skippedFilesNode, $this->errorCode, $originalFileName); } } } // end of CKFinder_Connector_CommandHandler_Unzip class class CKFinder_Connector_CommandHandler_UnzipHere extends CKFinder_Connector_CommandHandler_Unzip { /** * Handle request and build XML */ protected function buildXml() { parent::buildXml(); $checkedFiles = array(); if ( !empty($_POST['files']) && is_array($_POST['files']) ){ foreach ( $_POST['files'] as $file){ $checkedFiles[$file['name']] = $file; } } for ($i = 0; $i < $this->zip->numFiles; $i++) { $fileName = $this->zip->getNameIndex($i); if ( !empty($checkedFiles[$fileName]) && $checkedFiles[$fileName]['options'] == 'ok' ) { // file was sucessfully unzipped before $this->appendUnzippedNode($this->unzippedNodes,$fileName); continue; } $filePathInfo = pathinfo($fileName); $fileType = 'File'; $fileStat = $this->zip->statName($i); if ( empty($filePathInfo['extension']) && empty($fileStat['size']) ){ $fileType = 'Folder'; // check if we can create subfolder if ( !$this->_currentFolder->checkAcl( CKFINDER_CONNECTOR_ACL_FOLDER_CREATE ) ){ $this->errorCode = CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED; $this->appendErrorNode($this->skippedFilesNode, $this->errorCode, $fileName, $fileType); continue; } } $extractPath = $this->_currentFolder->getServerPath(); $extractClientPath = $this->_currentFolder->getClientPath(); $sFileName = $this->checkOneFile( $filePathInfo, $fileName ); // security test failed, add to skipped if ( false !== $sFileName ) { if ( file_exists($extractPath.$sFileName) ) { if ( !is_dir($extractPath.$sFileName) ) { // file was checked before if ( !empty($checkedFiles[$fileName]['options']) ) { if ( $checkedFiles[$fileName]['options'] == 'autorename') { $sFileName = CKFinder_Connector_Utils_FileSystem::autoRename($extractPath,$sFileName); $this->extractTo($extractPath,$extractClientPath,$filePathInfo,$sFileName,$fileName); } elseif ( $checkedFiles[$fileName]['options'] == 'overwrite') { if ( !$this->_currentFolder->checkAcl( CKFINDER_CONNECTOR_ACL_FILE_DELETE ) ){ $this->errorCode = CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED; $this->appendErrorNode($this->skippedFilesNode, $this->errorCode, $fileName, $fileType); continue; } if (!CKFinder_Connector_Utils_FileSystem::unlink($extractPath.$sFileName)) { $this->errorCode = CKFINDER_CONNECTOR_ERROR_ACCESS_DENIED; $this->appendErrorNode($this->skippedFilesNode, $this->errorCode, $fileName, $fileType); } else { $this->extractTo($extractPath,$extractClientPath,$filePathInfo,$sFileName,$fileName); } } else { // add to skipped files $this->appendUnzippedNode($this->unzippedNodes,$fileName,'skip'); } } else { $this->errorCode = CKFINDER_CONNECTOR_ERROR_ALREADY_EXIST; $this->appendErrorNode($this->skippedFilesNode, $this->errorCode, $fileName, $fileType); } } } // file doesn't exist yet else { $this->extractTo($extractPath,$extractClientPath,$filePathInfo,$sFileName,$fileName); } } } $this->zip->close(); $this->_connectorNode->addChild($this->unzippedNodes); if ($this->errorCode != CKFINDER_CONNECTOR_ERROR_NONE) { $this->_connectorNode->addChild($this->skippedFilesNode); $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_ZIP_FAILED); } } public function onBeforeExecuteCommand( &$command ) { if ( $command == 'ExtractHere' ) { $this->sendResponse(); return false; } return true ; } } // end of CKFinder_Connector_CommandHandler_UnzipHere class class CKFinder_Connector_CommandHandler_UnzipTo extends CKFinder_Connector_CommandHandler_Unzip { /** * Handle request and build XML */ protected function buildXml() { parent::buildXml(); $extractDir = ( !empty($_POST['extractDir']) ) ? ltrim($_POST['extractDir'],'/') : ''; $extractDir = CKFinder_Connector_Utils_FileSystem::convertToFilesystemEncoding($extractDir); if ( preg_match(CKFINDER_REGEX_INVALID_PATH, $extractDir) ){ $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST); } $extractPath = CKFinder_Connector_Utils_FileSystem::combinePaths($this->_currentFolder->getServerPath(), $extractDir.'/'); $extractClientPath = CKFinder_Connector_Utils_FileSystem::combinePaths($this->_currentFolder->getClientPath(),$extractDir); // acl for upload dir $_aclConfig = $this->_config->getAccessControlConfig(); $aclMask = $_aclConfig->getComputedMask($this->_currentFolder->getResourceTypeName(),$extractDir); if ( !(($aclMask & CKFINDER_CONNECTOR_ACL_FOLDER_CREATE ) == CKFINDER_CONNECTOR_ACL_FOLDER_CREATE ) ){ $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED); } if ( empty( $_POST['force']) && file_exists($extractPath) && is_dir($extractPath) && !CKFinder_Connector_Utils_FileSystem::isEmptyDir($extractPath) ) { $dirExists = new CKFinder_Connector_Utils_XmlNode("FolderExists"); $oErrorNode = new CKFinder_Connector_Utils_XmlNode("Folder"); $oErrorNode->addAttribute("name", $extractDir); $dirExists->addChild($oErrorNode); $this->_connectorNode->addChild($dirExists); return; } elseif ( !empty( $_POST['force']) && $_POST['force'] =='overwrite' ) { if ( !(($aclMask & CKFINDER_CONNECTOR_ACL_FILE_UPLOAD | CKFINDER_CONNECTOR_ACL_FILE_DELETE ) == CKFINDER_CONNECTOR_ACL_FILE_UPLOAD | CKFINDER_CONNECTOR_ACL_FILE_DELETE ) ){ $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED); } if ( $extractDir && file_exists($extractPath) && is_dir($extractPath) ) { if ( !(($aclMask & CKFINDER_CONNECTOR_ACL_FOLDER_CREATE | CKFINDER_CONNECTOR_ACL_FOLDER_DELETE ) == CKFINDER_CONNECTOR_ACL_FOLDER_CREATE | CKFINDER_CONNECTOR_ACL_FOLDER_DELETE ) ){ $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED); } if (!CKFinder_Connector_Utils_FileSystem::unlink($extractPath)) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_ACCESS_DENIED); } } } else if ( !empty( $_POST['force']) && $_POST['force'] !== 'merge' ) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST); } for ($i = 0; $i < $this->zip->numFiles; $i++) { $fileName = $this->zip->getNameIndex($i); $filePathInfo = pathinfo($fileName); $sFileName = $this->checkOneFile( $filePathInfo, $fileName ); // security test failed, add to skipped if ( $sFileName ) { $this->extractTo($extractPath,$extractClientPath,$filePathInfo,$sFileName,$fileName); } } $this->zip->close(); $this->_connectorNode->addChild($this->unzippedNodes); if ($this->errorCode != CKFINDER_CONNECTOR_ERROR_NONE) { $this->_connectorNode->addChild($this->skippedFilesNode); $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_ZIP_FAILED); } } public function onBeforeExecuteCommand( &$command ) { if ( $command == 'ExtractTo'){ $this->sendResponse(); return false; } return true ; } } // end of CKFinder_Connector_CommandHandler_UnzipTo class class CKFinder_Connector_CommandHandler_CreateZip extends CKFinder_Connector_CommandHandler_XmlCommandHandlerBase { protected $_config; /** * Get private zip plugin config * * @access protected * @return array */ protected function getConfig(){ $config = array(); $config['zipMaxSize'] = 'default'; if (isset($GLOBALS['config']['ZipMaxSize']) && (string)$GLOBALS['config']['ZipMaxSize']!='default' ){ $config['zipMaxSize'] = CKFinder_Connector_Utils_Misc::returnBytes((string)$GLOBALS['config']['ZipMaxSize']); } return $config; } /** * Checks given file for security * * @param SplFileInfo $file * @access protected * @return bool */ protected function checkOneFile($file) { $resourceTypeInfo = $this->_currentFolder->getResourceTypeConfig(); $_aclConfig = $this->_config->getAccessControlConfig(); $directory = str_replace('\\','/', $resourceTypeInfo->getDirectory()); $fileName = CKFinder_Connector_Utils_FileSystem::convertToFilesystemEncoding($file->getFilename()); if ($this->_config->forceAscii()) { $fileName = CKFinder_Connector_Utils_FileSystem::convertToAscii($fileName); } $pathName = str_replace('\\','/', pathinfo($file->getPathname(), PATHINFO_DIRNAME) ); $pathName = CKFinder_Connector_Utils_FileSystem::convertToFilesystemEncoding($pathName); // acl $aclMask = $_aclConfig->getComputedMask($this->_currentFolder->getResourceTypeName(), str_ireplace($directory,'',$pathName)); $isAuthorized = (($aclMask & CKFINDER_CONNECTOR_ACL_FILE_VIEW) == CKFINDER_CONNECTOR_ACL_FILE_VIEW); if ( !$isAuthorized ){ return false; } // if it is a folder fileName represents the dir if ( $file->isDir() && ( !CKFinder_Connector_Utils_FileSystem::checkFolderPath($fileName) || $resourceTypeInfo->checkIsHiddenPath($fileName) ) ){ return false; } // folder name if ( !CKFinder_Connector_Utils_FileSystem::checkFolderPath($pathName) ){ return false; } // is hidden if ( $resourceTypeInfo->checkIsHiddenPath($pathName) || $resourceTypeInfo->checkIsHiddenFile($fileName) ){ return false; } // extension if ( !$resourceTypeInfo->checkExtension($fileName) || !CKFinder_Connector_Utils_FileSystem::checkFileName($fileName) ){ return false; } return true; } /** * Get list of all files in given directory, including sub-directories * * @param string $directory * @param int $zipMaxSize Maximum zip file size * @return array $allFiles */ protected function getFilesRecursively( $directory, $zipMaxSize ) { $allFiles = array(); $_zipFilesSize = 0; $serverPath = str_replace('\\','/',$directory); foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory), RecursiveIteratorIterator::CHILD_FIRST) as $file ) { if ( !$this->checkOneFile($file) ){ continue; } if ( !empty($zipMaxSize) ){ clearstatcache(); $_zipFilesSize += $file->getSize(); if ( $_zipFilesSize > $zipMaxSize ) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_CREATED_FILE_TOO_BIG); } } $pathName = str_replace('\\','/',$file->getPathname()); if ( $file->isDir() ){ // skip dot folders on unix systems ( do not try to use isDot() as $file is not a DirectoryIterator obj ) if ( in_array($file->getFilename(),array('..','.')) ){ continue; } if ($pathName != rtrim($serverPath,'/')){ $allFiles[ ltrim(str_ireplace(rtrim($serverPath,'/'),'',$pathName),'/') ] = ''; } } else { $allFiles[$pathName] = str_ireplace($serverPath,'',$pathName); } } return $allFiles; } /** * Handle request and build XML */ public function buildXml() { if (!extension_loaded('zip')) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_COMMAND); } $this->checkConnector(); $this->checkRequest(); if ( !$this->_currentFolder->checkAcl(CKFINDER_CONNECTOR_ACL_FILE_UPLOAD)) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED); } $this->_config =& CKFinder_Connector_Core_Factory::getInstance("Core_Config"); $currentResourceTypeConfig = $this->_currentFolder->getResourceTypeConfig(); $_sServerDir = $this->_currentFolder->getServerPath(); $files = array(); $_zipFilesSize = 0; $config = $this->getConfig(); $zipMaxSize = $config['zipMaxSize']; if ( !empty($zipMaxSize) && $zipMaxSize == 'default' ){ $zipMaxSize = $currentResourceTypeConfig->getMaxSize(); } $_isBasket = ( isset($_POST['basket']) && $_POST['basket'] == 'true' )? true : false; if ( !empty($_POST['files'])) { $_aclConfig = $this->_config->getAccessControlConfig(); $aclMasks = array(); $_resourceTypeConfig = array(); foreach ( $_POST['files'] as $arr ){ if ( empty($arr['name']) || empty($arr['type']) || empty($arr['folder']) ) { continue; } // file name $name = CKFinder_Connector_Utils_FileSystem::convertToFilesystemEncoding($arr['name']); // resource type $type = $arr['type']; // client path $path = CKFinder_Connector_Utils_FileSystem::convertToFilesystemEncoding($arr['folder']); // check #1 (path) if (!CKFinder_Connector_Utils_FileSystem::checkFileName($name) || preg_match(CKFINDER_REGEX_INVALID_PATH, $path)) { continue; } // get resource type config for current file if (!isset($_resourceTypeConfig[$type])) { $_resourceTypeConfig[$type] = $this->_config->getResourceTypeConfig($type); } // check #2 (resource type) if (is_null($_resourceTypeConfig[$type])) { continue; } // check #3 (extension) if (!$_resourceTypeConfig[$type]->checkExtension($name, false)) { continue; } // check #4 (extension) - when moving to another resource type, double check extension if ($currentResourceTypeConfig->getName() != $type && !$currentResourceTypeConfig->checkExtension($name, false)) { continue; } // check #5 (hidden folders) // cache results if (empty($checkedPaths[$path])) { $checkedPaths[$path] = true; if ($_resourceTypeConfig[$type]->checkIsHiddenPath($path)) { continue; } } // check #6 (hidden file name) if ($currentResourceTypeConfig->checkIsHiddenFile($name)) { continue; } // check #7 (Access Control, need file view permission to source files) if (!isset($aclMasks[$type."@".$path])) { $aclMasks[$type."@".$path] = $_aclConfig->getComputedMask($type, $path); } $isAuthorized = (($aclMasks[$type."@".$path] & CKFINDER_CONNECTOR_ACL_FILE_VIEW) == CKFINDER_CONNECTOR_ACL_FILE_VIEW); if (!$isAuthorized) { continue; } $sourceFilePath = CKFinder_Connector_Utils_FileSystem::combinePaths($_resourceTypeConfig[$type]->getDirectory().$path,$name); // check #8 (invalid file name) if (!file_exists($sourceFilePath) || !is_file($sourceFilePath)) { continue; } // check #9 - max file size if ( !empty($zipMaxSize) ){ clearstatcache(); $_zipFilesSize += filesize($sourceFilePath); if ( $_zipFilesSize > $zipMaxSize ) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_CREATED_FILE_TOO_BIG); } } $zipPathPart = ( $_isBasket ) ? CKFinder_Connector_Utils_FileSystem::combinePaths($type,$path) : ''; $files[$sourceFilePath] = $zipPathPart.pathinfo($sourceFilePath,PATHINFO_BASENAME); } } else { if (!is_dir($_sServerDir)) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_FOLDER_NOT_FOUND); } $files = $this->getFilesRecursively($_sServerDir,$zipMaxSize); } if ( sizeof($files)<1) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_FILE_NOT_FOUND); } // default destination dir - temp $dest_dir = CKFinder_Connector_Utils_FileSystem::getTmpDir(); $resourceTypeInfo = $this->_currentFolder->getResourceTypeConfig(); // default file name - hash $zip_filename = substr(md5(serialize($files)), 0, 16).$resourceTypeInfo->getHash().'.zip'; // compress files - do not download them // change destination and name if ( isset($_POST['download']) && $_POST['download'] == 'false'){ $dest_dir = $_sServerDir; if ( isset($_POST['zipName']) && !empty($_POST['zipName'])){ $zip_filename = CKFinder_Connector_Utils_FileSystem::convertToFilesystemEncoding($_POST['zipName']); if (!$resourceTypeInfo->checkExtension($zip_filename)) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_EXTENSION); } } } if (!CKFinder_Connector_Utils_FileSystem::checkFileName($zip_filename) || $resourceTypeInfo->checkIsHiddenFile($zip_filename)) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_NAME); } if ($this->_config->forceAscii()) { $zip_filename = CKFinder_Connector_Utils_FileSystem::convertToAscii($zip_filename); } $zipFilePath = CKFinder_Connector_Utils_FileSystem::combinePaths($dest_dir, $zip_filename); if (!is_writable(dirname($zipFilePath))) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_ACCESS_DENIED); } // usually we would need to create zip? $createZip = true; // only if file already exists and we want download it // do not create new one - because hash of previously created is the same - existing archive is ok if ( file_exists($zipFilePath) && isset($_POST['download']) && $_POST['download'] == 'true' ){ $createZip = false; } // if we only want to create archive else { if ( file_exists($zipFilePath) && ( !isset($_POST['fileExistsAction']) || !in_array($_POST['fileExistsAction'], array('autorename','overwrite')) ) ){ $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_ALREADY_EXIST); } if ( !$this->_currentFolder->checkAcl( CKFINDER_CONNECTOR_ACL_FILE_UPLOAD )) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED); } // check how to deal with existing file if ( isset($_POST['fileExistsAction']) && $_POST['fileExistsAction'] == 'autorename' ) { if ( !$this->_currentFolder->checkAcl(CKFINDER_CONNECTOR_ACL_FILE_UPLOAD | CKFINDER_CONNECTOR_ACL_FILE_RENAME )) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED); } $zip_filename = CKFinder_Connector_Utils_FileSystem::autoRename($dest_dir, $zip_filename); $zipFilePath = CKFinder_Connector_Utils_FileSystem::combinePaths($dest_dir, $zip_filename); } elseif ( isset($_POST['fileExistsAction']) && $_POST['fileExistsAction'] == 'overwrite' ) { if ( !$this->_currentFolder->checkAcl(CKFINDER_CONNECTOR_ACL_FILE_RENAME | CKFINDER_CONNECTOR_ACL_FILE_DELETE)) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED); } if (!CKFinder_Connector_Utils_FileSystem::unlink($zipFilePath)){ $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_ACCESS_DENIED); } } } if ( $createZip ){ $zip = new ZipArchive(); $result = $zip->open( $zipFilePath, ZIPARCHIVE::CREATE); if ( $result !== TRUE ) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNKNOWN); } foreach ( $files as $pathname => $filename ){ if ( !empty($filename) ){ if ( file_exists($pathname) && is_readable($pathname) ){ $zip->addFile( $pathname, $filename ); } } else { $zip->addEmptyDir( $pathname ); } } $zip->close(); } $file = new CKFinder_Connector_Utils_XmlNode("ZipFile"); $file->addAttribute("name", $zip_filename); $this->_connectorNode->addChild($file); } public function onBeforeExecuteCommand( &$command ) { if ( $command == 'CreateZip'){ $this->sendResponse(); return false; } return true ; } } // end of CKFinder_Connector_CommandHandler_DownloadZip class class CKFinder_Connector_CommandHandler_DownloadZip extends CKFinder_Connector_CommandHandler_CreateZip { /** * Sends generated zip file to the user */ protected function sendZipFile() { if (!function_exists('ob_list_handlers') || ob_list_handlers()) { @ob_end_clean(); } header("Content-Encoding: none"); $this->checkConnector(); $this->checkRequest(); // empty wystarczy if ( empty($_GET['FileName']) ){ $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_FILE_NOT_FOUND); } $resourceTypeInfo = $this->_currentFolder->getResourceTypeConfig(); $hash = $resourceTypeInfo->getHash(); if ( $hash !== $_GET['hash'] || $hash !== substr($_GET['FileName'],16,16) ){ $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST); } if (!$this->_currentFolder->checkAcl(CKFINDER_CONNECTOR_ACL_FILE_VIEW)) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED); } $fileName = CKFinder_Connector_Utils_FileSystem::convertToFilesystemEncoding(trim($_GET['FileName'])); if (!CKFinder_Connector_Utils_FileSystem::checkFileName($fileName)) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST); } if ( strtolower(pathinfo($fileName, PATHINFO_EXTENSION)) !== 'zip'){ $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_EXTENSION); } $dest_dir = CKFinder_Connector_Utils_FileSystem::getTmpDir(); $filePath = CKFinder_Connector_Utils_FileSystem::combinePaths($dest_dir,$fileName); if ( !file_exists($filePath) || !is_file($filePath)) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_FILE_NOT_FOUND); } if (!is_readable($filePath)) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_ACCESS_DENIED); } $zipFileName = CKFinder_Connector_Utils_FileSystem::convertToFilesystemEncoding(trim($_GET['ZipName'])); if (!CKFinder_Connector_Utils_FileSystem::checkFileName($zipFileName)) { $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST); } $fileFilename = pathinfo($zipFileName,PATHINFO_BASENAME ); header("Content-Encoding: none"); header("Cache-Control: cache, must-revalidate"); header("Pragma: public"); header("Expires: 0"); $user_agent = !empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ""; $encodedName = str_replace("\"", "\\\"", $fileFilename); if (strpos($user_agent, "MSIE") !== false) { $encodedName = str_replace(array("+", "%2E"), array(" ", "."), urlencode($encodedName)); } header("Content-type: application/octet-stream; name=\"" . $fileFilename . "\""); header("Content-Disposition: attachment; filename=\"" . $encodedName. "\""); header("Content-Length: " . filesize($filePath)); CKFinder_Connector_Utils_FileSystem::sendFile($filePath); exit; } public function onBeforeExecuteCommand( &$command ) { if ( $command == 'DownloadZip'){ $this->sendZipFile(); return false; } return true ; } } // end of CKFinder_Connector_CommandHandler_DownloadZip if (extension_loaded('zip')) { $CommandHandler_UnzipHere = new CKFinder_Connector_CommandHandler_UnzipHere(); $CommandHandler_UnzipTo = new CKFinder_Connector_CommandHandler_UnzipTo(); $CommandHandler_CreateZip = new CKFinder_Connector_CommandHandler_CreateZip(); $CommandHandler_DownloadZip = new CKFinder_Connector_CommandHandler_DownloadZip(); $config['Hooks']['BeforeExecuteCommand'][] = array($CommandHandler_UnzipHere, "onBeforeExecuteCommand"); $config['Hooks']['BeforeExecuteCommand'][] = array($CommandHandler_UnzipTo, "onBeforeExecuteCommand"); $config['Hooks']['BeforeExecuteCommand'][] = array($CommandHandler_CreateZip, "onBeforeExecuteCommand"); $config['Hooks']['BeforeExecuteCommand'][] = array($CommandHandler_DownloadZip, "onBeforeExecuteCommand"); $config['Plugins'][] = 'zip'; }