Example #1
0
/**

 * Handle CopyFiles command

 *

 * @package CKFinder

 * @subpackage CommandHandlers

 * @copyright CKSource - Frederico Knabben

 */
class CKFinder_Connector_CommandHandler_CopyFiles extends CKFinder_Connector_CommandHandler_XmlCommandHandlerBase
{
    /**

     * Command name

     *

     * @access private

     * @var string

     */
    private $command = "CopyFiles";
    /**

     * handle request and build XML

     * @access protected

     *

     */
    protected function buildXml()
    {
        if (empty($_POST['CKFinderCommand']) || $_POST['CKFinderCommand'] != 'true') {
            $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST);
        }
        $clientPath = $this->_currentFolder->getClientPath();
        $sServerDir = $this->_currentFolder->getServerPath();
        $currentResourceTypeConfig = $this->_currentFolder->getResourceTypeConfig();
        $_config =& CKFinder_Connector_Core_Factory::getInstance("Core_Config");
        $_aclConfig = $_config->getAccessControlConfig();
        $aclMasks = array();
        $_resourceTypeConfig = array();
        if (!$this->_currentFolder->checkAcl(CKFINDER_CONNECTOR_ACL_FILE_RENAME | CKFINDER_CONNECTOR_ACL_FILE_UPLOAD | CKFINDER_CONNECTOR_ACL_FILE_DELETE)) {
            $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED);
        }
        // Create the "Errors" node.
        $oErrorsNode = new CKFinder_Connector_Utils_XmlNode("Errors");
        $errorCode = CKFINDER_CONNECTOR_ERROR_NONE;
        $copied = 0;
        $copiedAll = 0;
        if (!empty($_POST['copied'])) {
            $copiedAll = intval($_POST['copied']);
        }
        $checkedPaths = array();
        $oCopyFilesNode = new Ckfinder_Connector_Utils_XmlNode("CopyFiles");
        if (!empty($_POST['files']) && is_array($_POST['files'])) {
            foreach ($_POST['files'] as $index => $arr) {
                if (empty($arr['name'])) {
                    continue;
                }
                if (!isset($arr['name'], $arr['type'], $arr['folder'])) {
                    $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST);
                }
                // 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']);
                // options
                $options = !empty($arr['options']) ? $arr['options'] : '';
                $destinationFilePath = $sServerDir . $name;
                // check #1 (path)
                if (!CKFinder_Connector_Utils_FileSystem::checkFileName($name) || preg_match(CKFINDER_REGEX_INVALID_PATH, $path)) {
                    $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST);
                }
                // get resource type config for current file
                if (!isset($_resourceTypeConfig[$type])) {
                    $_resourceTypeConfig[$type] = $_config->getResourceTypeConfig($type);
                }
                // check #2 (resource type)
                if (is_null($_resourceTypeConfig[$type])) {
                    $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST);
                }
                // check #3 (extension)
                if (!$_resourceTypeConfig[$type]->checkExtension($name, false)) {
                    $errorCode = CKFINDER_CONNECTOR_ERROR_INVALID_EXTENSION;
                    $this->appendErrorNode($oErrorsNode, $errorCode, $name, $type, $path);
                    continue;
                }
                // check #4 (extension) - when moving to another resource type, double check extension
                if ($currentResourceTypeConfig->getName() != $type) {
                    if (!$currentResourceTypeConfig->checkExtension($name, false)) {
                        $errorCode = CKFINDER_CONNECTOR_ERROR_INVALID_EXTENSION;
                        $this->appendErrorNode($oErrorsNode, $errorCode, $name, $type, $path);
                        continue;
                    }
                }
                // check #5 (hidden folders)
                // cache results
                if (empty($checkedPaths[$path])) {
                    $checkedPaths[$path] = true;
                    if ($_resourceTypeConfig[$type]->checkIsHiddenPath($path)) {
                        $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST);
                    }
                }
                $sourceFilePath = $_resourceTypeConfig[$type]->getDirectory() . $path . $name;
                // check #6 (hidden file name)
                if ($currentResourceTypeConfig->checkIsHiddenFile($name)) {
                    $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST);
                }
                // 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) {
                    $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED);
                }
                // check #8 (invalid file name)
                if (!file_exists($sourceFilePath) || !is_file($sourceFilePath)) {
                    $errorCode = CKFINDER_CONNECTOR_ERROR_FILE_NOT_FOUND;
                    $this->appendErrorNode($oErrorsNode, $errorCode, $name, $type, $path);
                    continue;
                }
                // check #9 (max size)
                if ($currentResourceTypeConfig->getName() != $type) {
                    $maxSize = $currentResourceTypeConfig->getMaxSize();
                    $fileSize = filesize($sourceFilePath);
                    if ($maxSize && $fileSize > $maxSize) {
                        $errorCode = CKFINDER_CONNECTOR_ERROR_UPLOADED_TOO_BIG;
                        $this->appendErrorNode($oErrorsNode, $errorCode, $name, $type, $path);
                        continue;
                    }
                }
                //$overwrite
                // finally, no errors so far, we may attempt to copy a file
                // protection against copying files to itself
                if ($sourceFilePath == $destinationFilePath) {
                    $errorCode = CKFINDER_CONNECTOR_ERROR_SOURCE_AND_TARGET_PATH_EQUAL;
                    $this->appendErrorNode($oErrorsNode, $errorCode, $name, $type, $path);
                    continue;
                } else {
                    if (file_exists($destinationFilePath) && strpos($options, "overwrite") === false) {
                        if (strpos($options, "autorename") !== false) {
                            $fileName = CKFinder_Connector_Utils_FileSystem::autoRename($sServerDir, $name);
                            $destinationFilePath = $sServerDir . $fileName;
                            if (!@copy($sourceFilePath, $destinationFilePath)) {
                                $errorCode = CKFINDER_CONNECTOR_ERROR_ACCESS_DENIED;
                                $this->appendErrorNode($oErrorsNode, $errorCode, $name, $type, $path);
                                continue;
                            } else {
                                $copied++;
                            }
Example #2
0
 * Handle FileUpload command

 *

 * @package CKFinder

 * @subpackage CommandHandlers

 * @copyright CKSource - Frederico Knabben

 */
class CKFinder_Connector_CommandHandler_FileUpload extends CKFinder_Connector_CommandHandler_CommandHandlerBase
{
    /**

     * Command name

     *

     * @access protected

     * @var string

     */
    protected $command = "FileUpload";
    /**

     * send response (save uploaded file, resize if required)

     * @access public

     *

     */
    public function sendResponse()
    {
        $iErrorNumber = CKFINDER_CONNECTOR_ERROR_NONE;
        $_config =& CKFinder_Connector_Core_Factory::getInstance("Core_Config");
        $oRegistry =& CKFinder_Connector_Core_Factory::getInstance("Core_Registry");
        $oRegistry->set("FileUpload_fileName", "unknown file");
        $uploadedFile = array_shift($_FILES);
        if (!isset($uploadedFile['name'])) {
            $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UPLOADED_INVALID);
        }
        $sUnsafeFileName = CKFinder_Connector_Utils_FileSystem::convertToFilesystemEncoding(CKFinder_Connector_Utils_Misc::mbBasename($uploadedFile['name']));
        $sFileName = CKFinder_Connector_Utils_FileSystem::secureFileName($sUnsafeFileName);
        if ($sFileName != $sUnsafeFileName) {
            $iErrorNumber = CKFINDER_CONNECTOR_ERROR_UPLOADED_INVALID_NAME_RENAMED;
        }
        $oRegistry->set("FileUpload_fileName", $sFileName);
        $this->checkConnector();
        $this->checkRequest();
        if (!$this->_currentFolder->checkAcl(CKFINDER_CONNECTOR_ACL_FILE_UPLOAD)) {
            $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED);
        }
        $_resourceTypeConfig = $this->_currentFolder->getResourceTypeConfig();
        if (!CKFinder_Connector_Utils_FileSystem::checkFileName($sFileName) || $_resourceTypeConfig->checkIsHiddenFile($sFileName)) {
            $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_NAME);
        }
        $resourceTypeInfo = $this->_currentFolder->getResourceTypeConfig();
        if (!$resourceTypeInfo->checkExtension($sFileName)) {
            $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_EXTENSION);
        }
        $oRegistry->set("FileUpload_fileName", $sFileName);
        $oRegistry->set("FileUpload_url", $this->_currentFolder->getUrl());
        $maxSize = $resourceTypeInfo->getMaxSize();
        if (!$_config->checkSizeAfterScaling() && $maxSize && $uploadedFile['size'] > $maxSize) {
            $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UPLOADED_TOO_BIG);
        }
        $htmlExtensions = $_config->getHtmlExtensions();
        $sExtension = CKFinder_Connector_Utils_FileSystem::getExtension($sFileName);
        if ($htmlExtensions && !CKFinder_Connector_Utils_Misc::inArrayCaseInsensitive($sExtension, $htmlExtensions) && ($detectHtml = CKFinder_Connector_Utils_FileSystem::detectHtml($uploadedFile['tmp_name'])) === true) {
            $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UPLOADED_WRONG_HTML_FILE);
        }
        $secureImageUploads = $_config->getSecureImageUploads();
        if ($secureImageUploads && ($isImageValid = CKFinder_Connector_Utils_FileSystem::isImageValid($uploadedFile['tmp_name'], $sExtension)) === false) {
            $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UPLOADED_CORRUPT);
        }
        switch ($uploadedFile['error']) {
            case UPLOAD_ERR_OK:
                break;
            case UPLOAD_ERR_INI_SIZE:
            case UPLOAD_ERR_FORM_SIZE:
                $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UPLOADED_TOO_BIG);
                break;
            case UPLOAD_ERR_PARTIAL:
            case UPLOAD_ERR_NO_FILE:
                $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UPLOADED_CORRUPT);
                break;
            case UPLOAD_ERR_NO_TMP_DIR:
                $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UPLOADED_NO_TMP_DIR);
                break;
            case UPLOAD_ERR_CANT_WRITE:
                $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_ACCESS_DENIED);
                break;
            case UPLOAD_ERR_EXTENSION:
                $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_ACCESS_DENIED);
                break;
        }
        $sServerDir = $this->_currentFolder->getServerPath();
        while (true) {
            $sFilePath = CKFinder_Connector_Utils_FileSystem::combinePaths($sServerDir, $sFileName);
            if (file_exists($sFilePath)) {
                $sFileName = CKFinder_Connector_Utils_FileSystem::autoRename($sServerDir, $sFileName);
                $oRegistry->set("FileUpload_fileName", $sFileName);
                $iErrorNumber = CKFINDER_CONNECTOR_ERROR_UPLOADED_FILE_RENAMED;
            } else {
                if (false === move_uploaded_file($uploadedFile['tmp_name'], $sFilePath)) {
                    $iErrorNumber = CKFINDER_CONNECTOR_ERROR_ACCESS_DENIED;
                } else {
                    if (isset($detectHtml) && $detectHtml === -1 && CKFinder_Connector_Utils_FileSystem::detectHtml($sFilePath) === true) {
                        @unlink($sFilePath);
                        $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UPLOADED_WRONG_HTML_FILE);
                    } else {
                        if (isset($isImageValid) && $isImageValid === -1 && CKFinder_Connector_Utils_FileSystem::isImageValid($sFilePath, $sExtension) === false) {
                            @unlink($sFilePath);
                            $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UPLOADED_CORRUPT);
                        }
                    }
                }
Example #3
0
 /**
  * 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;
     } 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);
 }