self::FILE_TYPE_IMAGE, 'jpeg' => self::FILE_TYPE_IMAGE, 'jpe' => self::FILE_TYPE_IMAGE, 'png' => self::FILE_TYPE_IMAGE, 'gif' => self::FILE_TYPE_IMAGE, 'svg' => self::FILE_TYPE_IMAGE, 'svgz' => self::FILE_TYPE_IMAGE, 'js' => self::FILE_TYPE_TEXT, 'css' => self::FILE_TYPE_TEXT, 'txt' => self::FILE_TYPE_TEXT, 'html' => self::FILE_TYPE_TEXT, 'htm' => self::FILE_TYPE_TEXT, 'ini' => self::FILE_TYPE_TEXT, 'mp3' => self::FILE_TYPE_MEDIA, 'ogg' => self::FILE_TYPE_MEDIA, 'flac' => self::FILE_TYPE_MEDIA, 'webm' => self::FILE_TYPE_MEDIA, 'epub' => self::FILE_TYPE_BINARY, 'mobi' => self::FILE_TYPE_BINARY, 'pdf' => self::FILE_TYPE_BINARY, 'swf' => self::FILE_TYPE_BINARY, 'rtf' => self::FILE_TYPE_BINARY, 'ttf' => self::FILE_TYPE_BINARY, 'otf' => self::FILE_TYPE_BINARY, 'odt' => self::FILE_TYPE_BINARY, 'ods' => self::FILE_TYPE_BINARY, 'woff' => self::FILE_TYPE_BINARY, 'lencrier' => self::FILE_TYPE_BINARY, ); protected $journal_id = false; protected $journal_path = false; static public function getFileType($filename) { $ext = substr($filename, strrpos($filename, '.') + 1); $ext = strtolower($ext); if (isset(self::$allowed_files[$ext])) return self::$allowed_files[$ext]; else return false; } static public function getFileMimetype($filename) { $ext = substr($filename, strrpos($filename, '.') + 1); $ext = strtolower($ext); switch ($ext) { case 'ogg': case 'mp3': case 'flac': return 'audio/'.$ext; case 'webm': return 'video/'.$ext; case 'js': return 'text/javascript'; case 'txt': case 'ini': return 'text/plain'; case 'html': case 'htm': return 'text/html'; case 'css': return 'text/'.$ext; case 'jpe': case 'jpeg': case 'jpg': return 'image/jpeg'; case 'png': case 'gif': return 'image/'.$ext; case 'svg': case 'svgz': return 'image/svg+xml'; case 'epub': return 'application/epub+zip'; default: return 'application/octet-stream'; } } public function __construct($journal_id) { $this->journal_id = $journal_id; $this->journal_path = utils::getJournalDatasPath($this->journal_id, 'documents') . '/'; } public function getUsedQuota() { return utils::recurseFileSize($this->journal_path); } protected function _checkPath($path) { $path = realpath($this->journal_path . $path); if (!$path || strpos($path . '/', $this->journal_path) !== 0) return false; return $path; } public function getPath($path='') { $p = $this->_checkPath($path); if ($p !== false) { if (substr($p, -1) != '/' && is_dir($p)) $p .= '/'; $p = str_replace($this->journal_path, '', $p); if (substr($p, -1) == '/') { $p = substr($p, 0, -1); } return $p; } else { return false; } } public function getBreadcrumbs($path) { if ($path == '.') return false; $parts = explode('/', preg_replace('!^/|/$!', '', $path)); $crumbs = array(); $path = ''; foreach ($parts as $part) { $path .= $part . '/'; $crumbs[substr($path, 0, -1)] = $part; } return $crumbs; } public function getParent($path) { $parent = dirname($path); if ($parent == '.') $parent = ''; return $parent; } public function getList($path='') { $path = $this->getPath($path); if ($path === false) return false; $path = $this->journal_path . $path . '/'; $dir = dir($path); $files = $dirs = array(); while ($file = $dir->read()) { if ($file[0] == '.') continue; if (is_dir($path . $file)) { $dirs[$file] = array( 'filename' => $file, 'type' => self::FILE_TYPE_DIR, ); } else { $files[$file] = array( 'filename' => $file, 'size' => @filesize($path . $file), 'date' => @filemtime($path . $file), 'type' => self::getFileType($file), ); } } $dir->close(); ksort($files); ksort($dirs); return $dirs + $files; } public function createDir($path, $name) { if (!preg_match('!^[\d\w _-]+$!i', $name)) { return false; } $path = $this->getPath($path); if ($path === false) return false; if (trim($path)) $path .= '/' . $name; else $path = $name; if (file_exists($this->journal_path . $path)) return true; try { mkdir($this->journal_path . $path); return $path; } catch (ErrorException $e) { throw new technicalException('Unable to create dir ' . $this->journal_path . $path); } } public function deleteDir($path) { $path = $this->getPath($path); if ($path === false) return false; $list = $this->getList($path); if (count($list) > 0) return false; try { rmdir($this->journal_path . $path); $path = dirname($path); if ($path == '.') return ''; else return $path; } catch (ErrorException $e) { throw new technicalException('Unable to delete dir ' . $this->journal_path . $path); } } public function deleteFile($path, $name) { $path = $this->getPath($path); if ($path === false) return false; if ($path) $path .= '/'; $path .= $name; $path = $this->getPath($path); if ($path === false) return false; $r = @unlink($this->journal_path . $path); if ($r && preg_match('!^images!', $path) || $this instanceOf Journal_Files_Images) { @unlink(utils::getThumbPath($this->journal_id, preg_replace('!^images!', '', $path))); } return $r; } public function fileExists($file) { return $this->_checkPath($file); } public function getFileContent($file) { $file = $this->_checkPath($file); return file_get_contents($file); } public function saveFileContent($file, $content) { $file = $this->_checkPath($file); return file_put_contents($file, $content); } protected function _processEncodedUpload(&$file) { if (is_string($file)) { $file = array( 'content' => $file, 'name' => 'WHATEVER', ); } $file['error'] = $file['size'] = 0; if (empty($file['name']) || empty($file['content'])) { $file['error'] = UPLOAD_ERR_NO_FILE; return false; } if (!is_string($file['content'])) { $file['error'] = UPLOAD_ERR_NO_FILE; return false; } $file['content'] = base64_decode($file['content'], true); if (empty($file['content'])) { $file['error'] = UPLOAD_ERR_PARTIAL; return false; } $file['size'] = strlen($file['content']); if ($file['size'] == 0) { $file['error'] = UPLOAD_ERR_FORM_SIZE; return false; } $file['tmp_name'] = tempnam(ini_get('upload_tmp_dir') ?: sys_get_temp_dir(), 'lencrier'); if (!$file['tmp_name']) { $file['error'] = UPLOAD_ERR_NO_TMP_DIR; return false; } if (!file_put_contents($file['tmp_name'], $file['content'])) { $file['error'] = UPLOAD_ERR_CANT_WRITE; return false; } return true; } public function uploadFile($path, $file, $encoded = false) { if ($encoded) { $this->_processEncodedUpload($file); unset($file['content']); } if (!empty($file['error']) || empty($file['size'])) { switch ($file['error']) { case UPLOAD_ERR_INI_SIZE: $error = 'The uploaded file exceeds the allowed file size (ini).'; case UPLOAD_ERR_FORM_SIZE: $error = 'The uploaded file exceeds the allowed file size (html).'; case UPLOAD_ERR_PARTIAL: $error = 'The uploaded file was only partially uploaded.'; case UPLOAD_ERR_NO_FILE: $error = 'No file was uploaded.'; case UPLOAD_ERR_NO_TMP_DIR: $error = 'Missing a temporary folder.'; case UPLOAD_ERR_CANT_WRITE: $error = 'Failed to write file to disk.'; case UPLOAD_ERR_EXTENSION: $error = 'A server extension stopped the file upload.'; default: $error = 'Unknown error.'; } throw new userException($error); } if ($this->getUsedQuota() + $file['size'] > (LENCRIER_QUOTA_FILES * 1024 * 1024)) { throw new userException('Il ne reste pas assez de place sur les '.LENCRIER_QUOTA_FILES.' Mo autorisés pour copier ce fichier.'); } $path = $this->getPath($path); if ($path === false) return false; $name = preg_replace('![^\w\d_ .-]!i', '', $file['name']); $name = preg_replace('!^[._-]+!', '', $name); if (!self::getFileType($name)) { $types = array_keys(self::$allowed_files); $types = implode(', ', $types); $types = strtoupper($types); throw new userException('Type de fichier non autorisé (Autorisés : '.$types.')'); } if ($path) { $path .= '/'; } if (file_exists($this->journal_path . $path . $name)) { $name = date('Ymd_His-') . $name; } if ($encoded) { if (rename($file['tmp_name'], $this->journal_path . $path . $name)) { return $path . $name; } } else { if (move_uploaded_file($file['tmp_name'], $this->journal_path . $path . $name)) { return $path . $name; } } } } ?>