* @package tao */ class tao_models_classes_service_FileStorage extends ConfigurableService implements ServiceFileStorage { const OPTION_PUBLIC_FS = 'public'; const OPTION_PRIVATE_FS = 'private'; const OPTION_ACCESS_PROVIDER = 'provider'; /** * @return tao_models_classes_service_FileStorage */ public static function singleton() { return ServiceManager::getServiceManager()->get(self::SERVICE_ID); } private $accessProvider; /** * @return string */ protected function getFsId($public) { return $public ? $this->getOption(self::OPTION_PUBLIC_FS) : $this->getOption(self::OPTION_PRIVATE_FS); } /** * @return Websource * @throws \oat\tao\model\websource\WebsourceNotFound */ protected function getAccessProvider() { if (is_null($this->accessProvider)) { $this->accessProvider = $this->getServiceLocator() ->get(WebsourceManager::class) ->getWebsource($this->getOption(self::OPTION_ACCESS_PROVIDER)); } return $this->accessProvider; } /** * @param boolean $public * @return tao_models_classes_service_StorageDirectory */ public function spawnDirectory($public = false) { $id = common_Utils::getNewUri() . ($public ? '+' : '-'); $directory = $this->getDirectoryById($id); return $directory; } /** * @param string $id * @return tao_models_classes_service_StorageDirectory */ public function getDirectoryById($id) { $public = $id[strlen($id) - 1] == '+'; $path = $this->id2path($id); $dir = new tao_models_classes_service_StorageDirectory( $id, $this->getFsId($public), $path, $public ? $this->getAccessProvider() : null ); $dir->setServiceLocator($this->getServiceLocator()); return $dir; } /** * Delete directory represented by the $id * * @param $id * @return mixed */ public function deleteDirectoryById($id) { $public = $id[strlen($id) - 1] == '+'; $path = $this->id2path($id); return $this->getServiceLocator()->get(FileSystemService::SERVICE_ID)->getFileSystem($this->getFsId($public))->deleteDir($path); } /** * @param string $id * @param string $directoryPath * @throws common_Exception */ public function import($id, $directoryPath) { $directory = $this->getDirectoryById($id); if (is_dir($directoryPath) && is_readable($directoryPath)) { foreach ( $iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($directoryPath, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST ) as $item ) { if (!$item->isDir()) { $file = $directory->getFile($iterator->getSubPathName()); $fh = fopen($item, 'rb'); if ($file->exists()) { if (0 !== strcmp($this->getStreamHash($fh), $this->getStreamHash($file->readStream()))) { fclose($fh); throw new common_Exception('Different file content'); } } else { $file->put($fh); fclose($fh); } } } } else { common_Logger::w('Missing directory ' . $directoryPath); } } private function id2path($id) { $encoded = md5($id); $returnValue = ""; $len = strlen($encoded); for ($i = 0; $i < $len; $i++) { if ($i < 3) { $returnValue .= $encoded[$i] . DIRECTORY_SEPARATOR; } else { $returnValue .= $encoded[$i]; } } return $returnValue . DIRECTORY_SEPARATOR; } /** * Calculates hash for given stream * @param $stream * @param string $hash * @return string */ private function getStreamHash($stream, $hash = 'md5') { $hc = hash_init($hash); hash_update_stream($hc, $stream); return hash_final($hc); } }