1*04fd306cSNickeau<?php 2*04fd306cSNickeau 3*04fd306cSNickeau 4*04fd306cSNickeaunamespace ComboStrap; 5*04fd306cSNickeau 6*04fd306cSNickeau 7*04fd306cSNickeauuse DateTime; 8*04fd306cSNickeau 9*04fd306cSNickeauclass LocalFileSystem implements FileSystem 10*04fd306cSNickeau{ 11*04fd306cSNickeau 12*04fd306cSNickeau // same as the uri: ie local file os system 13*04fd306cSNickeau public const SCHEME = "file"; 14*04fd306cSNickeau 15*04fd306cSNickeau /** 16*04fd306cSNickeau * @var LocalFileSystem 17*04fd306cSNickeau */ 18*04fd306cSNickeau private static $localFs; 19*04fd306cSNickeau 20*04fd306cSNickeau public static function getOrCreate(): LocalFileSystem 21*04fd306cSNickeau { 22*04fd306cSNickeau if (self::$localFs === null) { 23*04fd306cSNickeau self::$localFs = new LocalFileSystem(); 24*04fd306cSNickeau } 25*04fd306cSNickeau return self::$localFs; 26*04fd306cSNickeau } 27*04fd306cSNickeau 28*04fd306cSNickeau function exists(Path $path): bool 29*04fd306cSNickeau { 30*04fd306cSNickeau return file_exists($path->toAbsolutePath()->toAbsoluteId()); 31*04fd306cSNickeau } 32*04fd306cSNickeau 33*04fd306cSNickeau /** 34*04fd306cSNickeau * @param $path 35*04fd306cSNickeau * @return string - textual content 36*04fd306cSNickeau * @throws ExceptionNotFound - if the file does not exist 37*04fd306cSNickeau */ 38*04fd306cSNickeau public function getContent($path): string 39*04fd306cSNickeau { 40*04fd306cSNickeau /** 41*04fd306cSNickeau * Mime check 42*04fd306cSNickeau */ 43*04fd306cSNickeau try { 44*04fd306cSNickeau $mime = FileSystems::getMime($path); 45*04fd306cSNickeau if (!$mime->isTextBased()) { 46*04fd306cSNickeau LogUtility::error("This mime content ($mime) is not text based (for the path $path). We can't return a text."); 47*04fd306cSNickeau return ""; 48*04fd306cSNickeau } 49*04fd306cSNickeau } catch (ExceptionNotFound $e) { 50*04fd306cSNickeau LogUtility::error("The mime is unknown for the path ($path). Trying to returning the content as text."); 51*04fd306cSNickeau } 52*04fd306cSNickeau $content = @file_get_contents($path->toAbsolutePath()->toAbsoluteId()); 53*04fd306cSNickeau if ($content === false) { 54*04fd306cSNickeau // file does not exists 55*04fd306cSNickeau throw new ExceptionNotFound("The file ($path) does not exists"); 56*04fd306cSNickeau } 57*04fd306cSNickeau return $content; 58*04fd306cSNickeau } 59*04fd306cSNickeau 60*04fd306cSNickeau /** 61*04fd306cSNickeau * @param LocalPath $path 62*04fd306cSNickeau * @return DateTime 63*04fd306cSNickeau * @throws ExceptionNotFound - if the file does not exist 64*04fd306cSNickeau */ 65*04fd306cSNickeau public function getModifiedTime($path): DateTime 66*04fd306cSNickeau { 67*04fd306cSNickeau if (!self::exists($path)) { 68*04fd306cSNickeau throw new ExceptionNotFound("Local File System Modified Time: The file ($path) does not exist"); 69*04fd306cSNickeau } 70*04fd306cSNickeau $timestamp = filemtime($path->toCanonicalAbsolutePath()->toAbsoluteId()); 71*04fd306cSNickeau return Iso8601Date::createFromTimestamp($timestamp)->getDateTime(); 72*04fd306cSNickeau } 73*04fd306cSNickeau 74*04fd306cSNickeau /** 75*04fd306cSNickeau * @throws ExceptionNotFound 76*04fd306cSNickeau */ 77*04fd306cSNickeau public function getCreationTime(Path $path) 78*04fd306cSNickeau { 79*04fd306cSNickeau if (!$this->exists($path)) { 80*04fd306cSNickeau throw new ExceptionNotFound("The path ($path) does not exists, no creation time"); 81*04fd306cSNickeau } 82*04fd306cSNickeau $filePath = $path->toAbsolutePath()->toAbsoluteId(); 83*04fd306cSNickeau $timestamp = filectime($filePath); 84*04fd306cSNickeau return Iso8601Date::createFromTimestamp($timestamp)->getDateTime(); 85*04fd306cSNickeau } 86*04fd306cSNickeau 87*04fd306cSNickeau /** 88*04fd306cSNickeau * @throws ExceptionFileSystem - if the action cannot be performed 89*04fd306cSNickeau */ 90*04fd306cSNickeau public function delete(Path $path) 91*04fd306cSNickeau { 92*04fd306cSNickeau $absolutePath = $path->toAbsolutePath()->toAbsoluteId(); 93*04fd306cSNickeau $success = unlink($absolutePath); 94*04fd306cSNickeau if(!$success){ 95*04fd306cSNickeau throw new ExceptionFileSystem("Unable to delete the file ($absolutePath)"); 96*04fd306cSNickeau } 97*04fd306cSNickeau } 98*04fd306cSNickeau 99*04fd306cSNickeau /** 100*04fd306cSNickeau * @return false|int 101*04fd306cSNickeau * @var LocalPath $path 102*04fd306cSNickeau */ 103*04fd306cSNickeau public function getSize(Path $path) 104*04fd306cSNickeau { 105*04fd306cSNickeau return filesize($path->toAbsolutePath()->toAbsoluteId()); 106*04fd306cSNickeau } 107*04fd306cSNickeau 108*04fd306cSNickeau /** 109*04fd306cSNickeau * @throws ExceptionCompile 110*04fd306cSNickeau */ 111*04fd306cSNickeau public function createDirectory(Path $dirPath): Path 112*04fd306cSNickeau { 113*04fd306cSNickeau $result = mkdir($dirPath->toAbsolutePath()->toAbsoluteId(), $mode = 0770, $recursive = true); 114*04fd306cSNickeau if ($result === false) { 115*04fd306cSNickeau throw new ExceptionCompile("Unable to create the directory path ($dirPath)"); 116*04fd306cSNickeau } 117*04fd306cSNickeau return $dirPath; 118*04fd306cSNickeau } 119*04fd306cSNickeau 120*04fd306cSNickeau public function isDirectory(Path $path): bool 121*04fd306cSNickeau { 122*04fd306cSNickeau return is_dir($path->toAbsolutePath()); 123*04fd306cSNickeau } 124*04fd306cSNickeau 125*04fd306cSNickeau /** 126*04fd306cSNickeau * @param LocalPath $path 127*04fd306cSNickeau * @param string|null $type container / leaf (ie directory / file or namespace/page) 128*04fd306cSNickeau * @return LocalPath[] 129*04fd306cSNickeau */ 130*04fd306cSNickeau public function getChildren(Path $path, string $type = null): array 131*04fd306cSNickeau { 132*04fd306cSNickeau 133*04fd306cSNickeau /** 134*04fd306cSNickeau * Same as {@link scandir()}, they output 135*04fd306cSNickeau * the current and parent relative directory (ie `.` and `..`) 136*04fd306cSNickeau */ 137*04fd306cSNickeau $directoryHandle = @opendir($path->toAbsolutePath()); 138*04fd306cSNickeau if (!$directoryHandle) return []; 139*04fd306cSNickeau try { 140*04fd306cSNickeau $localChildren = []; 141*04fd306cSNickeau while (($fileName = readdir($directoryHandle)) !== false) { 142*04fd306cSNickeau if (in_array($fileName, [LocalPath::RELATIVE_CURRENT, LocalPath::RELATIVE_PARENT])) { 143*04fd306cSNickeau continue; 144*04fd306cSNickeau } 145*04fd306cSNickeau $childPath = $path->resolve($fileName); 146*04fd306cSNickeau if ($type === null) { 147*04fd306cSNickeau $localChildren[] = $childPath; 148*04fd306cSNickeau continue; 149*04fd306cSNickeau } 150*04fd306cSNickeau /** 151*04fd306cSNickeau * Filter is not null, filter 152*04fd306cSNickeau */ 153*04fd306cSNickeau switch ($type) { 154*04fd306cSNickeau case FileSystems::CONTAINER: 155*04fd306cSNickeau if (FileSystems::isDirectory($childPath)) { 156*04fd306cSNickeau $localChildren[] = $childPath; 157*04fd306cSNickeau } 158*04fd306cSNickeau break; 159*04fd306cSNickeau case FileSystems::LEAF: 160*04fd306cSNickeau if (!FileSystems::isDirectory($childPath)) { 161*04fd306cSNickeau $localChildren[] = $childPath; 162*04fd306cSNickeau } 163*04fd306cSNickeau break; 164*04fd306cSNickeau default: 165*04fd306cSNickeau LogUtility::internalError("The type of file ($type) is unknown. It should be `" . FileSystems::CONTAINER . "` or `" . FileSystems::LEAF . "`"); 166*04fd306cSNickeau $localChildren[] = $childPath; 167*04fd306cSNickeau } 168*04fd306cSNickeau } 169*04fd306cSNickeau return $localChildren; 170*04fd306cSNickeau } finally { 171*04fd306cSNickeau closedir($directoryHandle); 172*04fd306cSNickeau } 173*04fd306cSNickeau 174*04fd306cSNickeau } 175*04fd306cSNickeau 176*04fd306cSNickeau /** 177*04fd306cSNickeau * @param LocalPath $path 178*04fd306cSNickeau * @param string $lastFullName 179*04fd306cSNickeau * @return Path 180*04fd306cSNickeau * @throws ExceptionNotFound 181*04fd306cSNickeau */ 182*04fd306cSNickeau public function closest(Path $path, string $lastFullName): Path 183*04fd306cSNickeau { 184*04fd306cSNickeau if (FileSystems::isDirectory($path)) { 185*04fd306cSNickeau $closest = $path->resolve($lastFullName); 186*04fd306cSNickeau if (FileSystems::exists($closest)) { 187*04fd306cSNickeau return $closest; 188*04fd306cSNickeau } 189*04fd306cSNickeau } 190*04fd306cSNickeau $parent = $path; 191*04fd306cSNickeau while (true) { 192*04fd306cSNickeau try { 193*04fd306cSNickeau $parent = $parent->getParent(); 194*04fd306cSNickeau } catch (ExceptionNotFound $e) { 195*04fd306cSNickeau break; 196*04fd306cSNickeau } 197*04fd306cSNickeau $closest = $parent->resolve($lastFullName); 198*04fd306cSNickeau if (FileSystems::exists($closest)) { 199*04fd306cSNickeau return $closest; 200*04fd306cSNickeau } 201*04fd306cSNickeau } 202*04fd306cSNickeau throw new ExceptionNotFound("No closest was found for the file name ($lastFullName) from the path ($path)"); 203*04fd306cSNickeau } 204*04fd306cSNickeau 205*04fd306cSNickeau /** 206*04fd306cSNickeau * @param LocalPath $path 207*04fd306cSNickeau * @return void 208*04fd306cSNickeau */ 209*04fd306cSNickeau public function createRegularFile(Path $path) 210*04fd306cSNickeau { 211*04fd306cSNickeau touch($path->toAbsoluteId()); 212*04fd306cSNickeau } 213*04fd306cSNickeau 214*04fd306cSNickeau public function setContent(Path $path, string $content) 215*04fd306cSNickeau { 216*04fd306cSNickeau 217*04fd306cSNickeau $file = $path->toAbsoluteId(); 218*04fd306cSNickeau /** 219*04fd306cSNickeau * the {@link io_saveFile()} dokuwiki function 220*04fd306cSNickeau * expects the path to be with unix separator 221*04fd306cSNickeau * It fails to calculate the parent because it just don't use 222*04fd306cSNickeau * {@link dirname()} but search for the last / 223*04fd306cSNickeau * in {@link io_mkdir_p()} 224*04fd306cSNickeau */ 225*04fd306cSNickeau $file = str_replace('\\','/',$file); 226*04fd306cSNickeau io_saveFile($file, $content, false); 227*04fd306cSNickeau } 228*04fd306cSNickeau 229*04fd306cSNickeau} 230