104fd306cSNickeau<?php 204fd306cSNickeau 304fd306cSNickeau 404fd306cSNickeaunamespace ComboStrap; 504fd306cSNickeau 604fd306cSNickeau 704fd306cSNickeauuse DateTime; 804fd306cSNickeau 904fd306cSNickeauclass LocalFileSystem implements FileSystem 1004fd306cSNickeau{ 1104fd306cSNickeau 1204fd306cSNickeau // same as the uri: ie local file os system 1304fd306cSNickeau public const SCHEME = "file"; 1404fd306cSNickeau 1504fd306cSNickeau /** 1604fd306cSNickeau * @var LocalFileSystem 1704fd306cSNickeau */ 1804fd306cSNickeau private static $localFs; 1904fd306cSNickeau 2004fd306cSNickeau public static function getOrCreate(): LocalFileSystem 2104fd306cSNickeau { 2204fd306cSNickeau if (self::$localFs === null) { 2304fd306cSNickeau self::$localFs = new LocalFileSystem(); 2404fd306cSNickeau } 2504fd306cSNickeau return self::$localFs; 2604fd306cSNickeau } 2704fd306cSNickeau 2804fd306cSNickeau function exists(Path $path): bool 2904fd306cSNickeau { 3004fd306cSNickeau return file_exists($path->toAbsolutePath()->toAbsoluteId()); 3104fd306cSNickeau } 3204fd306cSNickeau 3304fd306cSNickeau /** 3404fd306cSNickeau * @param $path 3504fd306cSNickeau * @return string - textual content 3604fd306cSNickeau * @throws ExceptionNotFound - if the file does not exist 3704fd306cSNickeau */ 3804fd306cSNickeau public function getContent($path): string 3904fd306cSNickeau { 4004fd306cSNickeau /** 4104fd306cSNickeau * Mime check 4204fd306cSNickeau */ 4304fd306cSNickeau try { 4404fd306cSNickeau $mime = FileSystems::getMime($path); 4504fd306cSNickeau if (!$mime->isTextBased()) { 4604fd306cSNickeau LogUtility::error("This mime content ($mime) is not text based (for the path $path). We can't return a text."); 4704fd306cSNickeau return ""; 4804fd306cSNickeau } 4904fd306cSNickeau } catch (ExceptionNotFound $e) { 5004fd306cSNickeau LogUtility::error("The mime is unknown for the path ($path). Trying to returning the content as text."); 5104fd306cSNickeau } 5204fd306cSNickeau $content = @file_get_contents($path->toAbsolutePath()->toAbsoluteId()); 5304fd306cSNickeau if ($content === false) { 5404fd306cSNickeau // file does not exists 5504fd306cSNickeau throw new ExceptionNotFound("The file ($path) does not exists"); 5604fd306cSNickeau } 5704fd306cSNickeau return $content; 5804fd306cSNickeau } 5904fd306cSNickeau 6004fd306cSNickeau /** 6104fd306cSNickeau * @param LocalPath $path 6204fd306cSNickeau * @return DateTime 6304fd306cSNickeau * @throws ExceptionNotFound - if the file does not exist 6404fd306cSNickeau */ 6504fd306cSNickeau public function getModifiedTime($path): DateTime 6604fd306cSNickeau { 6704fd306cSNickeau if (!self::exists($path)) { 6804fd306cSNickeau throw new ExceptionNotFound("Local File System Modified Time: The file ($path) does not exist"); 6904fd306cSNickeau } 7004fd306cSNickeau $timestamp = filemtime($path->toCanonicalAbsolutePath()->toAbsoluteId()); 7104fd306cSNickeau return Iso8601Date::createFromTimestamp($timestamp)->getDateTime(); 7204fd306cSNickeau } 7304fd306cSNickeau 7404fd306cSNickeau /** 7504fd306cSNickeau * @throws ExceptionNotFound 7604fd306cSNickeau */ 7704fd306cSNickeau public function getCreationTime(Path $path) 7804fd306cSNickeau { 7904fd306cSNickeau if (!$this->exists($path)) { 8004fd306cSNickeau throw new ExceptionNotFound("The path ($path) does not exists, no creation time"); 8104fd306cSNickeau } 8204fd306cSNickeau $filePath = $path->toAbsolutePath()->toAbsoluteId(); 8304fd306cSNickeau $timestamp = filectime($filePath); 8404fd306cSNickeau return Iso8601Date::createFromTimestamp($timestamp)->getDateTime(); 8504fd306cSNickeau } 8604fd306cSNickeau 8704fd306cSNickeau /** 8804fd306cSNickeau * @throws ExceptionFileSystem - if the action cannot be performed 8904fd306cSNickeau */ 9004fd306cSNickeau public function delete(Path $path) 9104fd306cSNickeau { 9204fd306cSNickeau $absolutePath = $path->toAbsolutePath()->toAbsoluteId(); 9304fd306cSNickeau $success = unlink($absolutePath); 9404fd306cSNickeau if(!$success){ 9504fd306cSNickeau throw new ExceptionFileSystem("Unable to delete the file ($absolutePath)"); 9604fd306cSNickeau } 9704fd306cSNickeau } 9804fd306cSNickeau 9904fd306cSNickeau /** 10004fd306cSNickeau * @return false|int 10104fd306cSNickeau * @var LocalPath $path 10204fd306cSNickeau */ 10304fd306cSNickeau public function getSize(Path $path) 10404fd306cSNickeau { 10504fd306cSNickeau return filesize($path->toAbsolutePath()->toAbsoluteId()); 10604fd306cSNickeau } 10704fd306cSNickeau 10804fd306cSNickeau /** 10904fd306cSNickeau * @throws ExceptionCompile 11004fd306cSNickeau */ 11104fd306cSNickeau public function createDirectory(Path $dirPath): Path 11204fd306cSNickeau { 11304fd306cSNickeau $result = mkdir($dirPath->toAbsolutePath()->toAbsoluteId(), $mode = 0770, $recursive = true); 11404fd306cSNickeau if ($result === false) { 11504fd306cSNickeau throw new ExceptionCompile("Unable to create the directory path ($dirPath)"); 11604fd306cSNickeau } 11704fd306cSNickeau return $dirPath; 11804fd306cSNickeau } 11904fd306cSNickeau 12004fd306cSNickeau public function isDirectory(Path $path): bool 12104fd306cSNickeau { 12204fd306cSNickeau return is_dir($path->toAbsolutePath()); 12304fd306cSNickeau } 12404fd306cSNickeau 12504fd306cSNickeau /** 12604fd306cSNickeau * @param LocalPath $path 12704fd306cSNickeau * @param string|null $type container / leaf (ie directory / file or namespace/page) 12804fd306cSNickeau * @return LocalPath[] 12904fd306cSNickeau */ 13004fd306cSNickeau public function getChildren(Path $path, string $type = null): array 13104fd306cSNickeau { 13204fd306cSNickeau 13304fd306cSNickeau /** 13404fd306cSNickeau * Same as {@link scandir()}, they output 13504fd306cSNickeau * the current and parent relative directory (ie `.` and `..`) 13604fd306cSNickeau */ 13704fd306cSNickeau $directoryHandle = @opendir($path->toAbsolutePath()); 13804fd306cSNickeau if (!$directoryHandle) return []; 13904fd306cSNickeau try { 14004fd306cSNickeau $localChildren = []; 14104fd306cSNickeau while (($fileName = readdir($directoryHandle)) !== false) { 14204fd306cSNickeau if (in_array($fileName, [LocalPath::RELATIVE_CURRENT, LocalPath::RELATIVE_PARENT])) { 14304fd306cSNickeau continue; 14404fd306cSNickeau } 14504fd306cSNickeau $childPath = $path->resolve($fileName); 14604fd306cSNickeau if ($type === null) { 14704fd306cSNickeau $localChildren[] = $childPath; 14804fd306cSNickeau continue; 14904fd306cSNickeau } 15004fd306cSNickeau /** 15104fd306cSNickeau * Filter is not null, filter 15204fd306cSNickeau */ 15304fd306cSNickeau switch ($type) { 15404fd306cSNickeau case FileSystems::CONTAINER: 15504fd306cSNickeau if (FileSystems::isDirectory($childPath)) { 15604fd306cSNickeau $localChildren[] = $childPath; 15704fd306cSNickeau } 15804fd306cSNickeau break; 15904fd306cSNickeau case FileSystems::LEAF: 16004fd306cSNickeau if (!FileSystems::isDirectory($childPath)) { 16104fd306cSNickeau $localChildren[] = $childPath; 16204fd306cSNickeau } 16304fd306cSNickeau break; 16404fd306cSNickeau default: 16504fd306cSNickeau LogUtility::internalError("The type of file ($type) is unknown. It should be `" . FileSystems::CONTAINER . "` or `" . FileSystems::LEAF . "`"); 16604fd306cSNickeau $localChildren[] = $childPath; 16704fd306cSNickeau } 16804fd306cSNickeau } 169*8a02de25Sgerardnico /** 170*8a02de25Sgerardnico * With the default, the file '10_....' is before the file '01....' 171*8a02de25Sgerardnico */ 172*8a02de25Sgerardnico sort($localChildren, SORT_NATURAL); 17304fd306cSNickeau return $localChildren; 17404fd306cSNickeau } finally { 17504fd306cSNickeau closedir($directoryHandle); 17604fd306cSNickeau } 17704fd306cSNickeau 17804fd306cSNickeau } 17904fd306cSNickeau 18004fd306cSNickeau /** 18104fd306cSNickeau * @param LocalPath $path 18204fd306cSNickeau * @param string $lastFullName 18304fd306cSNickeau * @return Path 18404fd306cSNickeau * @throws ExceptionNotFound 18504fd306cSNickeau */ 18604fd306cSNickeau public function closest(Path $path, string $lastFullName): Path 18704fd306cSNickeau { 18804fd306cSNickeau if (FileSystems::isDirectory($path)) { 18904fd306cSNickeau $closest = $path->resolve($lastFullName); 19004fd306cSNickeau if (FileSystems::exists($closest)) { 19104fd306cSNickeau return $closest; 19204fd306cSNickeau } 19304fd306cSNickeau } 19404fd306cSNickeau $parent = $path; 19504fd306cSNickeau while (true) { 19604fd306cSNickeau try { 19704fd306cSNickeau $parent = $parent->getParent(); 19804fd306cSNickeau } catch (ExceptionNotFound $e) { 19904fd306cSNickeau break; 20004fd306cSNickeau } 20104fd306cSNickeau $closest = $parent->resolve($lastFullName); 20204fd306cSNickeau if (FileSystems::exists($closest)) { 20304fd306cSNickeau return $closest; 20404fd306cSNickeau } 20504fd306cSNickeau } 20604fd306cSNickeau throw new ExceptionNotFound("No closest was found for the file name ($lastFullName) from the path ($path)"); 20704fd306cSNickeau } 20804fd306cSNickeau 20904fd306cSNickeau /** 21004fd306cSNickeau * @param LocalPath $path 21104fd306cSNickeau * @return void 21204fd306cSNickeau */ 21304fd306cSNickeau public function createRegularFile(Path $path) 21404fd306cSNickeau { 21504fd306cSNickeau touch($path->toAbsoluteId()); 21604fd306cSNickeau } 21704fd306cSNickeau 21804fd306cSNickeau public function setContent(Path $path, string $content) 21904fd306cSNickeau { 22004fd306cSNickeau 22104fd306cSNickeau $file = $path->toAbsoluteId(); 22204fd306cSNickeau /** 22304fd306cSNickeau * the {@link io_saveFile()} dokuwiki function 22404fd306cSNickeau * expects the path to be with unix separator 22504fd306cSNickeau * It fails to calculate the parent because it just don't use 22604fd306cSNickeau * {@link dirname()} but search for the last / 22704fd306cSNickeau * in {@link io_mkdir_p()} 22804fd306cSNickeau */ 22904fd306cSNickeau $file = str_replace('\\','/',$file); 23004fd306cSNickeau io_saveFile($file, $content, false); 23104fd306cSNickeau } 23204fd306cSNickeau 23304fd306cSNickeau} 234