session = Session::getInstance($phpUnit); $this->store = Store::getInstance('', $phpUnit); $this->uploadErrMsg = [ UPLOAD_ERR_INI_SIZE => "The uploaded file exceeds the upload_max_filesize directive in php.ini", UPLOAD_ERR_FORM_SIZE => "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form", UPLOAD_ERR_PARTIAL => "The uploaded file was only partially uploaded", UPLOAD_ERR_NO_FILE => "No file was uploaded", UPLOAD_ERR_NO_TMP_DIR => "Missing a temporary folder", UPLOAD_ERR_CANT_WRITE => "Failed to write file to disk", UPLOAD_ERR_EXTENSION => "File upload stopped by extension", ]; } /** * @throws UserFormException */ public function process() { $sipUpload = $this->store->getVar(SIP_SIP, STORE_SIP); if ($sipUpload === false) { throw new UserFormException('SIP invalid: ' . $sipUpload, ERROR_SIP_INVALID); } $statusUpload = $this->store->getVar($sipUpload, STORE_EXTRA, SANITIZE_ALLOW_ALL); if ($statusUpload === false) { $statusUpload = array(); } $action = $this->store->getVar(FILE_ACTION, STORE_CLIENT, SANITIZE_ALLOW_ALNUMX); switch ($action) { case FILE_ACTION_UPLOAD: $this->doUpload($sipUpload, $statusUpload); break; case FILE_ACTION_DELETE: $this->doDelete($sipUpload, $statusUpload); break; default: throw new UserFormException("Unknown FILE_ACTION: $action", ERROR_UPLOAD_UNKNOWN_ACTION); } } /** * @param string $sipUpload * @param array $statusUpload * * @throws CodeException * @throws UserFormException */ private function doUpload($sipUpload, array $statusUpload) { list($dummy, $newArr) = each($_FILES); $statusUpload = array_merge($statusUpload, $newArr); if ($statusUpload[FILES_ERROR] !== UPLOAD_ERR_OK) { throw new UserFormException($this->uploadErrMsg[$newArr[FILES_ERROR]], ERROR_UPLOAD); } $maxFileSize = $this->store->getVar(FE_FILE_MAX_FILE_SIZE, STORE_SIP); if ($statusUpload['size'] >= $maxFileSize) { throw new UserFormException('File to big. Max size allowed: ' . $maxFileSize, ERROR_UPLOAD_TOO_BIG); } $accept = $this->store->getVar(FE_FILE_MIME_TYPE_ACCEPT, STORE_SIP); if (!$this->checkFileType($statusUpload['tmp_name'], $statusUpload['name'], $accept)) { throw new UserFormException('Filetype not allowed. Allowed: ' . $accept, ERROR_UPLOAD_FILE_TYPE); } // rename uploaded file: ?.cached $filenameCached = Support::extendFilename($statusUpload[FILES_TMP_NAME], UPLOAD_CACHED); move_uploaded_file($newArr[FILES_TMP_NAME], $filenameCached); $this->store->setVar($sipUpload, $statusUpload, STORE_EXTRA); } /** * Checks the file filetype against the allowed mimetype definition. Return true as soon as one match is found. * Types recognized: * * 'mime type' as delivered by `file` which matches a definition on * http://www.iana.org/assignments/media-types/media-types.xhtml * * Joker based: audio/*, video/*, image/* * * Filename extension based: .pdf,.doc,.. * * @param string $tmp_name * @param string $name * @param string $accept * * @return bool * @throws UserFormException */ private function checkFileType($tmp_name, $name, $accept) { $return_var = 0; // E.g.: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=binary' $fileMimeType = exec('file --brief --mime ' . $tmp_name, $output, $return_var); if ($return_var != 0) { throw new UserFormException('Error get mime type of upload.', ERROR_UPLOAD_GET_MIME_TYPE); } // Strip optional '; charset=binary' $arr = explode(';', $fileMimeType, 2); $fileMimeType = $arr[0]; // Split between 'Media Type' and 'Media Subtype' $fileMimeTypeSplitted = explode('/', $arr[0], 2); $path_parts = pathinfo($name); // to extract the filename extension of the uploaded file. // Process all listed mimetypes (incl. filename extension and joker) // $accept e.g.: 'image/*,application/pdf,.pdf' $arr = explode(',', $accept); // Split multiple defined mimetypes/extensions in single chunks. foreach ($arr as $listElementMimeType) { $listElementMimeType = trim($listElementMimeType); if ($listElementMimeType == '') { continue; // will be skipped } elseif ($listElementMimeType[0] == '.') { // Check for definition 'filename extension' if ('.' . $path_parts['extension'] == $listElementMimeType) { return true; } } else { // Check for Joker, e.g.: 'image/*' $splitted = explode('/', $listElementMimeType, 2); if ($splitted[1] == '*') { if ($splitted[0] == $fileMimeTypeSplitted[0]) { return true; } } elseif ($fileMimeType == $listElementMimeType) { return true; } } } return false; } /** * @param $sipUpload * @param $statusUpload * * @throws CodeException * @throws UserFormException * @internal param string $keyStoreExtra */ private function doDelete($sipUpload, $statusUpload) { if (isset($statusUpload[FILES_TMP_NAME]) && $statusUpload[FILES_TMP_NAME] != '') { $file = Support::extendFilename($statusUpload[FILES_TMP_NAME], UPLOAD_CACHED); if (file_exists($file)) { if (!unlink($file)) { throw new UserFormException('unlink file: ' . $file, ERROR_IO_UNLINK); } } $statusUpload[FILES_TMP_NAME] = ''; } $statusUpload[FILES_FLAG_DELETE] = '1'; $this->store->setVar($sipUpload, $statusUpload, STORE_EXTRA); } }