Lines
54.23%
32 / 59
Methods
38.46%
5 / 13
Classes
0.00%
0 / 1
| Name | Lines | Methods | CRAP | ||||
|---|---|---|---|---|---|---|---|
| __construct | 70.00% | 7 / 10 | 0.00% | 0 / 1 | 4.43 | ||
| create | 87.50% | 7 / 8 | 0.00% | 0 / 1 | 4.03 | ||
| exists | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| setPermissions | 0.00% | 0 / 1 | 0.00% | 0 / 1 | 2 | ||
| delete | 66.66% | 2 / 3 | 0.00% | 0 / 1 | 2.15 | ||
| copy | 47.05% | 8 / 17 | 0.00% | 0 / 1 | 8.71 | ||
| write | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| getContents | 66.66% | 2 / 3 | 0.00% | 0 / 1 | 2.15 | ||
| getExtension | 100.00% | 2 / 2 | 100.00% | 1 / 1 | 2 | ||
| getMimeType | 0.00% | 0 / 3 | 0.00% | 0 / 1 | 12 | ||
| [Lucent\Filesystem\FileSystemObject] getDirectory | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [Lucent\Filesystem\FileSystemObject] getName | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | ||
| [Lucent\Filesystem\FileSystemObject] rename | 0.00% | 0 / 8 | 0.00% | 0 / 1 | 12 | ||
| 16 | class File extends FileSystemObject | |
| 17 | { | |
| 18 | /** | |
| 19 | * Creates a new File instance | |
| 20 | * | |
| 21 | * @param string $path The path to the file (relative or absolute) | |
| 22 | * @param mixed $content Optional content to write to the file | |
| 23 | * @param bool $absolute Whether the provided path is absolute (true) or relative to root (false) | |
| 24 | */ | |
| 25 | public function __construct(string $path, mixed $content = null, bool $absolute = false) | |
| 26 | { | |
| 27 | if (!$absolute) { | |
| 28 | $path = FileSystem::resolvePath($path); | |
| 29 | } | |
| 30 | ||
| 31 | // Normalize the path so `..`/`.` segments are resolved before the | |
| 32 | // containment guard runs. | |
| 33 | $path = FileSystem::normalizePath($path); | |
| 34 | ||
| 35 | // Containment guard: never allow a path to escape the configured root. | |
| 36 | if (!FileSystem::isWithinRoot($path)) { | |
| 37 | throw new \RuntimeException( | |
| 38 | "File path '{$path}' escapes the configured root path '" . FileSystem::rootPath() . "'" | |
| 39 | ); | |
| 40 | } | |
| 41 | ||
| 42 | $this->path = $path; | |
| 43 | ||
| 44 | if ($content !== null) { | |
| 45 | $this->create($content); | |
| 46 | } | |
| 47 | } | |
| 48 | ||
| 49 | /** | |
| 50 | * Creates the file with the given content | |
| 51 | * | |
| 52 | * Creates parent directories if they don't exist | |
| 53 | * | |
| 54 | * @param mixed $params Content to write to the file | |
| 55 | * @return bool True if successful, false otherwise | |
| 56 | */ | |
| 57 | public function create(mixed $params = null): bool | |
| 58 | { | |
| 59 | if (!file_exists($this->path)) { | |
| 60 | $directory = dirname($this->path); | |
| 61 | ||
| 62 | // Create directory if it doesn't exist | |
| 63 | if (!is_dir($directory)) { | |
| 64 | mkdir($directory, 0755, true); | |
| 65 | } | |
| 66 | ||
| 67 | if ($params !== null) { | |
| 68 | return $this->write($params); | |
| 69 | } else { | |
| 70 | return touch($this->path); | |
| 71 | } | |
| 72 | ||
| 73 | } | |
| 74 | ||
| 75 | return true; | |
| 76 | } | |
| 77 | ||
| 78 | /** | |
| 79 | * Checks if the file exists | |
| 80 | * | |
| 81 | * @return bool True if the file exists, false otherwise | |
| 82 | */ | |
| 83 | public function exists(): bool | |
| 84 | { | |
| 85 | return file_exists($this->path); | |
| 86 | } | |
| 87 | ||
| 88 | public function setPermissions(int $permissions): bool | |
| 89 | { | |
| 90 | return chmod($this->path, $permissions); | |
| 91 | } | |
| 92 | ||
| 93 | /** | |
| 94 | * Deletes the file | |
| 95 | * | |
| 96 | * @return bool True if successfully deleted, false otherwise | |
| 97 | */ | |
| 98 | public function delete(): bool | |
| 99 | { | |
| 100 | if (!$this->exists()) | |
| 101 | return false; | |
| 102 | ||
| 103 | return unlink($this->path); | |
| 104 | } | |
| 105 | ||
| 106 | /** | |
| 107 | * Copies the file to a new location | |
| 108 | * | |
| 109 | * @param string $name The name for the copied file | |
| 110 | * @param Folder $folder The destination folder | |
| 111 | * @param bool $absolute Whether the path is absolute | |
| 112 | * @return FileSystemObject|null The new file object if successful, null otherwise | |
| 113 | */ | |
| 114 | public function copy(string $name, Folder $folder, bool $absolute = false): ?FileSystemObject | |
| 115 | { | |
| 116 | // Construct destination path | |
| 117 | $destinationPath = $folder->path . DIRECTORY_SEPARATOR . $name; | |
| 118 | ||
| 119 | // Check source file | |
| 120 | if (!file_exists($this->path)) { | |
| 121 | Log::channel("lucent.filesystem")->error("[File] Copy error, source file does not exist:\n Path: {$this->path}"); | |
| 122 | return null; | |
| 123 | } | |
| 124 | ||
| 125 | // Check destination folder | |
| 126 | if (!is_dir($folder->path)) { | |
| 127 | Log::channel("lucent.filesystem")->error("[File] Copy error, destination folder does not exist:\n Path: {$folder->path}"); | |
| 128 | return null; | |
| 129 | } | |
| 130 | ||
| 131 | // Check write permissions | |
| 132 | if (!is_writable($folder->path)) { | |
| 133 | Log::channel("lucent.filesystem")->error("[File] Write error, destination folder is not writeable:\n Path: {$folder->path}"); | |
| 134 | return null; | |
| 135 | } | |
| 136 | ||
| 137 | // Create the new file object WITHOUT writing content - passing null | |
| 138 | // avoids creating an empty destination file before the copy runs. | |
| 139 | $copy = new File($destinationPath, null, true); | |
| 140 | ||
| 141 | // Perform copy operation | |
| 142 | $success = copy($this->path, $copy->path); | |
| 143 | ||
| 144 | // Check for PHP errors during copy | |
| 145 | if (!$success) { | |
| 146 | $error = error_get_last()['message'] ?? 'Unknown error'; | |
| 147 | Log::channel("lucent.filesystem")->critical("[File] PHP Error during copy: {$error}\n From: {$this->path}\n To: {$copy->path}"); | |
| 148 | return null; | |
| 149 | } | |
| 150 | ||
| 151 | return $copy; | |
| 152 | } | |
| 153 | ||
| 154 | /** | |
| 155 | * Writes content to the file | |
| 156 | * | |
| 157 | * @param mixed $content Content to write to the file | |
| 158 | * @return bool True if successful, false otherwise | |
| 159 | */ | |
| 160 | public function write(mixed $content = null): bool | |
| 161 | { | |
| 162 | return file_put_contents($this->path, $content) !== false; | |
| 163 | } | |
| 164 | ||
| 165 | /** | |
| 166 | * Gets the contents of the file | |
| 167 | * | |
| 168 | * @return string The file contents (empty string if the file doesn't exist) | |
| 169 | */ | |
| 170 | public function getContents(): string | |
| 171 | { | |
| 172 | if (!$this->exists()) { | |
| 173 | return ""; | |
| 174 | } | |
| 175 | ||
| 176 | return file_get_contents($this->path); | |
| 177 | } | |
| 178 | ||
| 179 | /** | |
| 180 | * Gets the file extension | |
| 181 | * | |
| 182 | * @return string The file extension | |
| 183 | */ | |
| 184 | public function getExtension(): string | |
| 185 | { | |
| 186 | $extension = pathinfo($this->path, PATHINFO_EXTENSION); | |
| 187 | return $extension ? '.' . $extension : ''; | |
| 188 | } | |
| 189 | ||
| 190 | /** | |
| 191 | * Gets the file mime-type | |
| 192 | * | |
| 193 | * @return string The file mime-type | |
| 194 | */ | |
| 195 | public function getMimeType(): string | |
| 196 | { | |
| 197 | if (!file_exists($this->path)) { | |
| 198 | return 'application/octet-stream'; | |
| 199 | } | |
| 200 | ||
| 201 | return mime_content_type($this->path) ?: 'application/octet-stream'; | |
| 202 | } | |
| 203 | } |
Inherited from Lucent\Filesystem\FileSystemObject
| 26 | public function getDirectory(): Folder | |
| 27 | { | |
| 28 | return new Folder(dirname($this->path), true); | |
| 29 | } |
| 36 | public function getName(): string | |
| 37 | { | |
| 38 | return basename($this->path); | |
| 39 | } |
| 70 | public function rename(string $newName): bool | |
| 71 | { | |
| 72 | // Get the directory path of the current object | |
| 73 | $directory = $this->getDirectory()->path; | |
| 74 | ||
| 75 | // Construct the new full path | |
| 76 | $newPath = $directory . DIRECTORY_SEPARATOR . $newName; | |
| 77 | ||
| 78 | // Check if the target already exists | |
| 79 | if (file_exists($newPath)) { | |
| 80 | throw new \RuntimeException("Cannot rename: target '{$newPath}' already exists"); | |
| 81 | } | |
| 82 | ||
| 83 | // Perform the rename operation | |
| 84 | if (rename($this->path, $newPath)) { | |
| 85 | // Update the path property to reflect the new path | |
| 86 | $this->path = $newPath; | |
| 87 | return true; | |
| 88 | } | |
| 89 | ||
| 90 | return false; | |
| 91 | } |