ByteStream
6 days ago
Layer
6 days ago
Mixin
6 days ago
Path
6 days ago
Visitor
6 days ago
LICENSE.md
6 days ago
README.md
6 days ago
class-filesystemexception.php
6 days ago
class-inmemoryfilesystem.php
6 days ago
class-localfilesystem.php
6 days ago
class-sqlitefilesystem.php
6 days ago
class-uploadedfilesystem.php
6 days ago
composer.json
6 days ago
functions.php
6 days ago
interface-filesystem.php
6 days ago
class-localfilesystem.php
198 lines
| 1 | <?php |
| 2 | |
| 3 | namespace WordPress\Filesystem; |
| 4 | |
| 5 | use WordPress\ByteStream\ReadStream\ByteReadStream; |
| 6 | use WordPress\ByteStream\ReadStream\FileReadStream; |
| 7 | use WordPress\ByteStream\WriteStream\ByteWriteStream; |
| 8 | use WordPress\ByteStream\WriteStream\FileWriteStream; |
| 9 | use WordPress\Filesystem\Layer\ChrootLayer; |
| 10 | |
| 11 | /** |
| 12 | * Represents the currently available filesystem. |
| 13 | */ |
| 14 | class LocalFilesystem implements Filesystem { |
| 15 | |
| 16 | use Mixin\PutContentsViaWriteStream; |
| 17 | use Mixin\GetContentsViaReadStream; |
| 18 | use Mixin\RmdirRecursive; |
| 19 | use Mixin\MkdirRecursive; |
| 20 | use Mixin\CopyDirectoryRecursive; |
| 21 | |
| 22 | private $root; |
| 23 | |
| 24 | public static function create( $root = null ) { |
| 25 | // Make sure the root path uses forward slashes on Windows. |
| 26 | // This allows us to use all wp_unix_* functions across the board. |
| 27 | if ( null === $root ) { |
| 28 | if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) ) { |
| 29 | $system_drive = getenv( 'SystemDrive' ); |
| 30 | $root = $system_drive ? $system_drive . '\\' : 'C:\\'; |
| 31 | } else { |
| 32 | $root = '/'; |
| 33 | } |
| 34 | } elseif ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) ) { |
| 35 | $root = self::normalize_path( $root ); |
| 36 | } |
| 37 | |
| 38 | if ( ! is_dir( $root ) ) { |
| 39 | if ( false === mkdir( $root, 0755, true ) ) { |
| 40 | throw new FilesystemException( sprintf( 'Root directory did not exist and could not be created: %s', var_export( $root, true ) ) ); |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | return new ChrootLayer( |
| 45 | new LocalFilesystem( $root ), |
| 46 | $root |
| 47 | ); |
| 48 | } |
| 49 | |
| 50 | /** |
| 51 | * Use LocalFilesystem::create() to ensure the correct filesystem layers are applied. |
| 52 | */ |
| 53 | private function __construct( $root ) { |
| 54 | $this->root = $root; |
| 55 | } |
| 56 | |
| 57 | /** |
| 58 | * For mkdir_recursive(). |
| 59 | */ |
| 60 | public function get_root(): string { |
| 61 | return $this->root; |
| 62 | } |
| 63 | |
| 64 | public function get_meta(): array { |
| 65 | return array( |
| 66 | 'root' => $this->root, |
| 67 | ); |
| 68 | } |
| 69 | |
| 70 | public function ls( $path = '/' ) { |
| 71 | $dh = @opendir( $path ); |
| 72 | if ( false === $dh ) { |
| 73 | throw new FilesystemException( |
| 74 | sprintf( 'Failed to open directory: %s', $path ) |
| 75 | ); |
| 76 | } |
| 77 | |
| 78 | $children = array(); |
| 79 | while ( true ) { |
| 80 | $filename = readdir( $dh ); |
| 81 | if ( false === $filename ) { |
| 82 | break; |
| 83 | } |
| 84 | if ( '.' === $filename || '..' === $filename ) { |
| 85 | continue; |
| 86 | } |
| 87 | $children[] = $filename; |
| 88 | } |
| 89 | closedir( $dh ); |
| 90 | |
| 91 | return $children; |
| 92 | } |
| 93 | |
| 94 | public function is_dir( $path ) { |
| 95 | return is_dir( $path ); |
| 96 | } |
| 97 | |
| 98 | public function is_file( $path ) { |
| 99 | return is_file( $path ); |
| 100 | } |
| 101 | |
| 102 | public function exists( $path ) { |
| 103 | return file_exists( $path ); |
| 104 | } |
| 105 | |
| 106 | public function rename( $old_path, $new_path, $options = array() ) { |
| 107 | if ( false === @rename( $old_path, $new_path ) ) { |
| 108 | throw new FilesystemException( |
| 109 | sprintf( 'Failed to rename: %s to %s', $old_path, $new_path ) |
| 110 | ); |
| 111 | } |
| 112 | |
| 113 | return true; |
| 114 | } |
| 115 | |
| 116 | public function copy_file( $from_path, $to_path, $options ) { |
| 117 | // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged |
| 118 | if ( false === @copy( $from_path, $to_path ) ) { |
| 119 | throw new FilesystemException( |
| 120 | sprintf( 'Failed to copy file: %s to %s', $from_path, $to_path ) |
| 121 | ); |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | protected function mkdir_single( $path, $options = array() ) { |
| 126 | $resolved_path = $this->normalize_path( $path ); |
| 127 | if ( $this->exists( $path ) ) { |
| 128 | throw new FilesystemException( |
| 129 | sprintf( 'Path already exists: %s', $path ) |
| 130 | ); |
| 131 | } |
| 132 | if ( false === @mkdir( $resolved_path ) ) { |
| 133 | throw new FilesystemException( |
| 134 | sprintf( 'Failed to create directory: %s', $resolved_path ) |
| 135 | ); |
| 136 | } |
| 137 | if ( isset( $options['chmod'] ) ) { |
| 138 | // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged |
| 139 | if ( false === @chmod( $path, $options['chmod'] ) ) { |
| 140 | throw new FilesystemException( |
| 141 | sprintf( 'Failed to chmod directory: %s', $path ) |
| 142 | ); |
| 143 | } |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | public function rm( $path ) { |
| 148 | if ( false === @unlink( $path ) ) { |
| 149 | throw new FilesystemException( |
| 150 | sprintf( 'Failed to remove file: %s', $path ) |
| 151 | ); |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | protected function rmdir_single( $path, $options = array() ) { |
| 156 | if ( false === @rmdir( $path ) ) { |
| 157 | throw new FilesystemException( |
| 158 | sprintf( 'Failed to remove directory: %s', $path ) |
| 159 | ); |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | public function put_contents( $path, $data, $options = array() ) { |
| 164 | // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged |
| 165 | if ( false === @file_put_contents( |
| 166 | $path, |
| 167 | $data |
| 168 | ) ) { |
| 169 | throw new FilesystemException( |
| 170 | sprintf( 'Failed to write to file: %s', $path ) |
| 171 | ); |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | public function open_write_stream( $path ): ByteWriteStream { |
| 176 | return FileWriteStream::from_path( $path, 'truncate' ); |
| 177 | } |
| 178 | |
| 179 | public function open_read_stream( $path ): ByteReadStream { |
| 180 | return FileReadStream::from_path( $path ); |
| 181 | } |
| 182 | |
| 183 | /** |
| 184 | * Turns a linux path into an OS-specific path. |
| 185 | * |
| 186 | * This is necessary because Filesystem-related classes use |
| 187 | * forward slashes to separate paths. They must. LocalFilesystem |
| 188 | * is just one of the available Filesystem implementations. |
| 189 | * |
| 190 | * Therefore, the problem of converting forward slashes to |
| 191 | * OS-specific path separators is specific to the LocalFilesystem |
| 192 | * class |
| 193 | */ |
| 194 | private static function normalize_path( $path ) { |
| 195 | return str_replace( DIRECTORY_SEPARATOR, '/', $path ); |
| 196 | } |
| 197 | } |
| 198 |