PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 16.1-beta.2
Jetpack – WP Security, Backup, Speed, & Growth v16.1-beta.2
16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / vendor / wp-php-toolkit / filesystem / README.md
jetpack / vendor / wp-php-toolkit / filesystem Last commit date
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
README.md
262 lines
1 ---
2 slug: filesystem
3 title: Filesystem
4 install: wp-php-toolkit/filesystem
5
6 see_also:
7 - bytestream | ByteStream | Open files as readers and writers instead of loading full strings.
8 - zip | Zip | Mount archives and copy data between archive-backed and normal filesystems.
9 - git | Git | Expose repository trees through a filesystem-shaped API.
10 ---
11
12 One <code>Filesystem</code> interface across local disk, in-memory trees, SQLite databases, and ZIP archives. Forward-slash paths everywhere — even on Windows — so the same code runs in tests, in production, and inside read-only ZIP-backed trees.
13
14 ## Why this exists
15
16 <p>Code that touches the filesystem is hard to test, hard to port to Windows, and impossible to point at non-disk storage without rewriting it. Swap <code>LocalFilesystem</code> for <code>InMemoryFilesystem</code> in tests and your suite stops touching <code>/tmp</code>; swap it for <code>SQLiteFilesystem</code> when the <code>sqlite3</code> extension is available and your "files" become rows in a portable database; swap it for <code>ZipFilesystem</code> and you can read inside an archive with the same calls.</p>
17
18 <p>Every backend uses forward slashes regardless of host OS. No <code>DIRECTORY_SEPARATOR</code> juggling, no Windows-only test failures, no surprises when a path moves between backends.</p>
19
20 ## In-memory tree
21
22 <p>The fastest backend. No disk I/O, no cleanup, no test-isolation problems.</p>
23
24 <!-- snippet:
25 filename: teaser-memory.php
26 runnable: true
27 -->
28 ```php
29 <?php
30 require '/php-toolkit/vendor/autoload.php';
31
32 use WordPress\Filesystem\InMemoryFilesystem;
33
34 $fs = InMemoryFilesystem::create();
35 $fs->put_contents( '/hello.txt', 'Hello, world!' );
36 echo $fs->get_contents( '/hello.txt' );
37 ```
38
39 <!-- expected-output -->
40 ```
41 Hello, world!
42 ```
43
44 ## Test code without touching disk
45
46 <p>Code that takes a <code>Filesystem</code> parameter, instead of calling <code>file_get_contents()</code> directly, can be tested against an <code>InMemoryFilesystem</code>. The test sets up files in memory, exercises the function, and asserts on what got written — no temp directories, no cleanup.</p>
47
48 <!-- snippet:
49 filename: test-without-disk.php
50 runnable: true
51 -->
52 ```php
53 <?php
54 require '/php-toolkit/vendor/autoload.php';
55
56 use WordPress\Filesystem\Filesystem;
57 use WordPress\Filesystem\InMemoryFilesystem;
58
59 function bump_version( Filesystem $fs, $path ) {
60 $json = json_decode( $fs->get_contents( $path ), true );
61 list( $maj, $min, $patch ) = explode( '.', $json['version'] );
62 $json['version'] = $maj . '.' . $min . '.' . ( (int) $patch + 1 );
63 $fs->put_contents( $path, json_encode( $json ) );
64 }
65
66 $fs = InMemoryFilesystem::create();
67 $fs->put_contents( '/package.json', '{"version":"1.2.3"}' );
68 bump_version( $fs, '/package.json' );
69
70 echo $fs->get_contents( '/package.json' ) . "\n";
71 ```
72
73 <!-- expected-output -->
74 ```
75 {"version":"1.2.4"}
76 ```
77
78 ## Local disk with a chrooted root
79
80 <p><code>LocalFilesystem::create($root)</code> is implicitly chrooted: every path resolves relative to <code>$root</code> and a <code>../</code> cannot escape. Reach for it when a request path or CLI argument names a file inside one project directory.</p>
81
82 <!-- snippet:
83 filename: local-chroot.php
84 runnable: true
85 -->
86 ```php
87 <?php
88 require '/php-toolkit/vendor/autoload.php';
89
90 use WordPress\Filesystem\LocalFilesystem;
91
92 $root = sys_get_temp_dir() . '/toolkit-' . uniqid();
93 $fs = LocalFilesystem::create( $root );
94
95 $fs->mkdir( '/uploads', array( 'recursive' => true ) );
96 $fs->put_contents( '/uploads/note.txt', 'Hi from local disk.' );
97
98 echo $fs->get_contents( '/uploads/../uploads/note.txt' ) . "\n";
99
100 $fs->rmdir( '/', array( 'recursive' => true ) );
101 echo "exists after cleanup? " . ( is_dir( $root ) ? 'yes' : 'no' ) . "\n";
102 ```
103
104 <!-- expected-output -->
105 ```
106 Hi from local disk.
107 exists after cleanup? no
108 ```
109
110 ## SQLite as a portable file store
111
112 <p>The whole tree lives in one SQLite database file. Use it for self-contained scratch storage that survives process boundaries without leaving loose files behind. This backend requires PHP's <code>sqlite3</code> extension.</p>
113
114 <!-- snippet:
115 filename: sqlite.php
116 runnable: true
117 -->
118 ```php
119 <?php
120 require '/php-toolkit/vendor/autoload.php';
121
122 use WordPress\Filesystem\SQLiteFilesystem;
123
124 $fs = SQLiteFilesystem::create( ':memory:' );
125 $fs->mkdir( '/posts', array( 'recursive' => true ) );
126 for ( $i = 1; $i <= 3; $i++ ) {
127 $fs->put_contents( "/posts/post-{$i}.md", "# Post {$i}\n\nBody {$i}." );
128 }
129
130 foreach ( $fs->ls( '/posts' ) as $name ) {
131 $first = strtok( $fs->get_contents( '/posts/' . $name ), "\n" );
132 echo "{$name}: {$first}\n";
133 }
134 ```
135
136 <!-- expected-output -->
137 ```
138 post-1.md: # Post 1
139 post-2.md: # Post 2
140 post-3.md: # Post 3
141 ```
142
143 ## Copy a tree across backends
144
145 <p>The killer composability move: <code>copy_between_filesystems()</code> streams files chunk-by-chunk from any source to any target. Pull a ZIP into SQLite, snapshot SQLite to disk, mirror disk into RAM — all the same call, with the relevant backend extensions available.</p>
146
147 <!-- snippet:
148 filename: cross-backend-copy.php
149 runnable: true
150 -->
151 ```php
152 <?php
153 require '/php-toolkit/vendor/autoload.php';
154
155 use WordPress\Filesystem\InMemoryFilesystem;
156 use WordPress\Filesystem\LocalFilesystem;
157 use WordPress\Filesystem\SQLiteFilesystem;
158 use function WordPress\Filesystem\copy_between_filesystems;
159
160 $root = sys_get_temp_dir() . '/copytree-' . uniqid();
161 $local = LocalFilesystem::create( $root );
162 $local->mkdir( '/site/posts', array( 'recursive' => true ) );
163 $local->put_contents( '/site/posts/2024-01.md', '# Hello 2024' );
164 $local->put_contents( '/site/index.html', '<h1>Home</h1>' );
165
166 $sqlite = SQLiteFilesystem::create( ':memory:' );
167 copy_between_filesystems( array(
168 'source_filesystem' => $local,
169 'source_path' => '/site',
170 'target_filesystem' => $sqlite,
171 'target_path' => '/snapshot',
172 ) );
173
174 $mem = InMemoryFilesystem::create();
175 copy_between_filesystems( array(
176 'source_filesystem' => $sqlite,
177 'source_path' => '/snapshot',
178 'target_filesystem' => $mem,
179 'target_path' => '/copy',
180 ) );
181
182 echo "in memory after two copies:\n";
183 echo " posts: " . implode( ', ', $mem->ls( '/copy/posts' ) ) . "\n";
184 echo " index: " . $mem->get_contents( '/copy/index.html' ) . "\n";
185
186 $local->rmdir( '/', array( 'recursive' => true ) );
187 ```
188
189 <!-- expected-output -->
190 ```
191 in memory after two copies:
192 posts: 2024-01.md
193 index: <h1>Home</h1>
194 ```
195
196 ## Atomic write via tempfile rename
197
198 <p>Write to a sibling tempfile, then rename — that's how you avoid leaving a half-written file on crash. <code>rename()</code> is atomic within a single filesystem.</p>
199
200 <!-- snippet:
201 filename: atomic-write.php
202 runnable: true
203 -->
204 ```php
205 <?php
206 require '/php-toolkit/vendor/autoload.php';
207
208 use WordPress\Filesystem\Filesystem;
209 use WordPress\Filesystem\LocalFilesystem;
210
211 function atomic_put_contents( Filesystem $fs, $path, $bytes ) {
212 $tmp = $path . '.tmp.' . bin2hex( random_bytes( 4 ) );
213 $fs->put_contents( $tmp, $bytes );
214 $fs->rename( $tmp, $path );
215 }
216
217 $root = sys_get_temp_dir() . '/atomic-' . uniqid();
218 $fs = LocalFilesystem::create( $root );
219
220 $fs->put_contents( '/config.json', '{"v":1}' );
221 atomic_put_contents( $fs, '/config.json', '{"v":2}' );
222
223 echo "config: " . $fs->get_contents( '/config.json' ) . "\n";
224 echo "no .tmp leftovers: " . count( $fs->ls( '/' ) ) . " entries in root\n";
225
226 $fs->rmdir( '/', array( 'recursive' => true ) );
227 ```
228
229 <!-- expected-output -->
230 ```
231 config: {"v":2}
232 no .tmp leftovers: 1 entries in root
233 ```
234
235 ## Path helpers that behave the same on Windows
236
237 <p>Unix path semantics apply on every host OS. This matters for abstract paths such as a SQLite key or a ZIP entry name because those paths do not live on a real drive.</p>
238
239 <!-- snippet:
240 filename: path-helpers.php
241 runnable: true
242 -->
243 ```php
244 <?php
245 require '/php-toolkit/vendor/autoload.php';
246
247 use function WordPress\Filesystem\wp_join_unix_paths;
248 use function WordPress\Filesystem\wp_unix_dirname;
249 use function WordPress\Filesystem\wp_unix_path_resolve_dots;
250
251 echo wp_join_unix_paths( '/var/www', '/site/', '/index.php' ) . "\n";
252 echo wp_unix_dirname( '/a/b/c/d.txt', 2 ) . "\n";
253 echo wp_unix_path_resolve_dots( '/a/b/../c/./d/../e' ) . "\n";
254 ```
255
256 <!-- expected-output -->
257 ```
258 /var/www/site/index.php
259 /a/b
260 a/c/e
261 ```
262