author | ymh <ymh.work@gmail.com> |
Mon, 08 Sep 2025 19:44:41 +0200 | |
changeset 23 | 417f20492bf7 |
parent 21 | 48c4eec2b7e6 |
permissions | -rw-r--r-- |
0 | 1 |
<?php |
2 |
/** |
|
3 |
* WordPress FTP Filesystem. |
|
4 |
* |
|
5 |
* @package WordPress |
|
6 |
* @subpackage Filesystem |
|
7 |
*/ |
|
8 |
||
9 |
/** |
|
10 |
* WordPress Filesystem Class for implementing FTP. |
|
11 |
* |
|
5 | 12 |
* @since 2.5.0 |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
13 |
* |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
14 |
* @see WP_Filesystem_Base |
0 | 15 |
*/ |
16 |
class WP_Filesystem_FTPext extends WP_Filesystem_Base { |
|
9 | 17 |
|
18 |
/** |
|
19 |
* @since 2.5.0 |
|
20 |
* @var resource |
|
21 |
*/ |
|
5 | 22 |
public $link; |
0 | 23 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
24 |
/** |
9 | 25 |
* Constructor. |
26 |
* |
|
27 |
* @since 2.5.0 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
28 |
* |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
29 |
* @param array $opt |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
30 |
*/ |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
31 |
public function __construct( $opt = '' ) { |
0 | 32 |
$this->method = 'ftpext'; |
33 |
$this->errors = new WP_Error(); |
|
34 |
||
35 |
// Check if possible to use ftp functions. |
|
9 | 36 |
if ( ! extension_loaded( 'ftp' ) ) { |
37 |
$this->errors->add( 'no_ftp_ext', __( 'The ftp PHP extension is not available' ) ); |
|
5 | 38 |
return; |
0 | 39 |
} |
40 |
||
16 | 41 |
// This class uses the timeout on a per-connection basis, others use it on a per-action basis. |
9 | 42 |
if ( ! defined( 'FS_TIMEOUT' ) ) { |
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
43 |
define( 'FS_TIMEOUT', 4 * MINUTE_IN_SECONDS ); |
9 | 44 |
} |
0 | 45 |
|
9 | 46 |
if ( empty( $opt['port'] ) ) { |
0 | 47 |
$this->options['port'] = 21; |
9 | 48 |
} else { |
0 | 49 |
$this->options['port'] = $opt['port']; |
9 | 50 |
} |
0 | 51 |
|
9 | 52 |
if ( empty( $opt['hostname'] ) ) { |
53 |
$this->errors->add( 'empty_hostname', __( 'FTP hostname is required' ) ); |
|
54 |
} else { |
|
0 | 55 |
$this->options['hostname'] = $opt['hostname']; |
9 | 56 |
} |
0 | 57 |
|
58 |
// Check if the options provided are OK. |
|
9 | 59 |
if ( empty( $opt['username'] ) ) { |
60 |
$this->errors->add( 'empty_username', __( 'FTP username is required' ) ); |
|
61 |
} else { |
|
0 | 62 |
$this->options['username'] = $opt['username']; |
9 | 63 |
} |
0 | 64 |
|
9 | 65 |
if ( empty( $opt['password'] ) ) { |
66 |
$this->errors->add( 'empty_password', __( 'FTP password is required' ) ); |
|
67 |
} else { |
|
0 | 68 |
$this->options['password'] = $opt['password']; |
9 | 69 |
} |
0 | 70 |
|
71 |
$this->options['ssl'] = false; |
|
16 | 72 |
|
73 |
if ( isset( $opt['connection_type'] ) && 'ftps' === $opt['connection_type'] ) { |
|
0 | 74 |
$this->options['ssl'] = true; |
9 | 75 |
} |
0 | 76 |
} |
77 |
||
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
78 |
/** |
9 | 79 |
* Connects filesystem. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
80 |
* |
9 | 81 |
* @since 2.5.0 |
82 |
* |
|
83 |
* @return bool True on success, false on failure. |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
84 |
*/ |
5 | 85 |
public function connect() { |
9 | 86 |
if ( isset( $this->options['ssl'] ) && $this->options['ssl'] && function_exists( 'ftp_ssl_connect' ) ) { |
87 |
$this->link = @ftp_ssl_connect( $this->options['hostname'], $this->options['port'], FS_CONNECT_TIMEOUT ); |
|
88 |
} else { |
|
89 |
$this->link = @ftp_connect( $this->options['hostname'], $this->options['port'], FS_CONNECT_TIMEOUT ); |
|
90 |
} |
|
0 | 91 |
|
92 |
if ( ! $this->link ) { |
|
9 | 93 |
$this->errors->add( |
94 |
'connect', |
|
95 |
sprintf( |
|
16 | 96 |
/* translators: %s: hostname:port */ |
9 | 97 |
__( 'Failed to connect to FTP Server %s' ), |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
98 |
$this->options['hostname'] . ':' . $this->options['port'] |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
99 |
) |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
100 |
); |
16 | 101 |
|
0 | 102 |
return false; |
103 |
} |
|
104 |
||
9 | 105 |
if ( ! @ftp_login( $this->link, $this->options['username'], $this->options['password'] ) ) { |
106 |
$this->errors->add( |
|
107 |
'auth', |
|
108 |
sprintf( |
|
16 | 109 |
/* translators: %s: Username. */ |
9 | 110 |
__( 'Username/Password incorrect for %s' ), |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
111 |
$this->options['username'] |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
112 |
) |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
113 |
); |
16 | 114 |
|
0 | 115 |
return false; |
116 |
} |
|
117 |
||
16 | 118 |
// Set the connection to use Passive FTP. |
119 |
ftp_pasv( $this->link, true ); |
|
120 |
||
9 | 121 |
if ( @ftp_get_option( $this->link, FTP_TIMEOUT_SEC ) < FS_TIMEOUT ) { |
122 |
@ftp_set_option( $this->link, FTP_TIMEOUT_SEC, FS_TIMEOUT ); |
|
123 |
} |
|
0 | 124 |
|
125 |
return true; |
|
126 |
} |
|
127 |
||
5 | 128 |
/** |
9 | 129 |
* Reads entire file into a string. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
130 |
* |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
131 |
* @since 2.5.0 |
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
132 |
* |
9 | 133 |
* @param string $file Name of the file to read. |
134 |
* @return string|false Read data on success, false if no temporary file could be opened, |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
135 |
* or if the file couldn't be retrieved. |
5 | 136 |
*/ |
137 |
public function get_contents( $file ) { |
|
16 | 138 |
$tempfile = wp_tempnam( $file ); |
139 |
$temphandle = fopen( $tempfile, 'w+' ); |
|
0 | 140 |
|
16 | 141 |
if ( ! $temphandle ) { |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
142 |
unlink( $tempfile ); |
0 | 143 |
return false; |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
144 |
} |
0 | 145 |
|
16 | 146 |
if ( ! ftp_fget( $this->link, $temphandle, $file, FTP_BINARY ) ) { |
147 |
fclose( $temphandle ); |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
148 |
unlink( $tempfile ); |
0 | 149 |
return false; |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
150 |
} |
0 | 151 |
|
16 | 152 |
fseek( $temphandle, 0 ); // Skip back to the start of the file being written to. |
0 | 153 |
$contents = ''; |
154 |
||
16 | 155 |
while ( ! feof( $temphandle ) ) { |
156 |
$contents .= fread( $temphandle, 8 * KB_IN_BYTES ); |
|
9 | 157 |
} |
0 | 158 |
|
16 | 159 |
fclose( $temphandle ); |
9 | 160 |
unlink( $tempfile ); |
16 | 161 |
|
0 | 162 |
return $contents; |
163 |
} |
|
164 |
||
5 | 165 |
/** |
9 | 166 |
* Reads entire file into an array. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
167 |
* |
9 | 168 |
* @since 2.5.0 |
169 |
* |
|
170 |
* @param string $file Path to the file. |
|
171 |
* @return array|false File contents in an array on success, false on failure. |
|
5 | 172 |
*/ |
9 | 173 |
public function get_contents_array( $file ) { |
174 |
return explode( "\n", $this->get_contents( $file ) ); |
|
0 | 175 |
} |
176 |
||
5 | 177 |
/** |
9 | 178 |
* Writes a string to a file. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
179 |
* |
9 | 180 |
* @since 2.5.0 |
181 |
* |
|
182 |
* @param string $file Remote path to the file where to write the data. |
|
183 |
* @param string $contents The data to write. |
|
184 |
* @param int|false $mode Optional. The file permissions as octal number, usually 0644. |
|
185 |
* Default false. |
|
186 |
* @return bool True on success, false on failure. |
|
5 | 187 |
*/ |
9 | 188 |
public function put_contents( $file, $contents, $mode = false ) { |
16 | 189 |
$tempfile = wp_tempnam( $file ); |
190 |
$temphandle = fopen( $tempfile, 'wb+' ); |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
191 |
|
16 | 192 |
if ( ! $temphandle ) { |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
193 |
unlink( $tempfile ); |
0 | 194 |
return false; |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
195 |
} |
0 | 196 |
|
197 |
mbstring_binary_safe_encoding(); |
|
198 |
||
9 | 199 |
$data_length = strlen( $contents ); |
16 | 200 |
$bytes_written = fwrite( $temphandle, $contents ); |
0 | 201 |
|
202 |
reset_mbstring_encoding(); |
|
203 |
||
204 |
if ( $data_length !== $bytes_written ) { |
|
16 | 205 |
fclose( $temphandle ); |
0 | 206 |
unlink( $tempfile ); |
207 |
return false; |
|
208 |
} |
|
209 |
||
16 | 210 |
fseek( $temphandle, 0 ); // Skip back to the start of the file being written to. |
0 | 211 |
|
16 | 212 |
$ret = ftp_fput( $this->link, $file, $temphandle, FTP_BINARY ); |
0 | 213 |
|
16 | 214 |
fclose( $temphandle ); |
9 | 215 |
unlink( $tempfile ); |
0 | 216 |
|
9 | 217 |
$this->chmod( $file, $mode ); |
0 | 218 |
|
219 |
return $ret; |
|
220 |
} |
|
221 |
||
5 | 222 |
/** |
9 | 223 |
* Gets the current working directory. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
224 |
* |
9 | 225 |
* @since 2.5.0 |
226 |
* |
|
227 |
* @return string|false The current working directory on success, false on failure. |
|
5 | 228 |
*/ |
229 |
public function cwd() { |
|
16 | 230 |
$cwd = ftp_pwd( $this->link ); |
231 |
||
9 | 232 |
if ( $cwd ) { |
233 |
$cwd = trailingslashit( $cwd ); |
|
234 |
} |
|
16 | 235 |
|
0 | 236 |
return $cwd; |
237 |
} |
|
238 |
||
5 | 239 |
/** |
9 | 240 |
* Changes current directory. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
241 |
* |
9 | 242 |
* @since 2.5.0 |
243 |
* |
|
244 |
* @param string $dir The new current directory. |
|
245 |
* @return bool True on success, false on failure. |
|
5 | 246 |
*/ |
9 | 247 |
public function chdir( $dir ) { |
248 |
return @ftp_chdir( $this->link, $dir ); |
|
0 | 249 |
} |
250 |
||
5 | 251 |
/** |
9 | 252 |
* Changes filesystem permissions. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
253 |
* |
9 | 254 |
* @since 2.5.0 |
255 |
* |
|
256 |
* @param string $file Path to the file. |
|
257 |
* @param int|false $mode Optional. The permissions as octal number, usually 0644 for files, |
|
258 |
* 0755 for directories. Default false. |
|
16 | 259 |
* @param bool $recursive Optional. If set to true, changes file permissions recursively. |
9 | 260 |
* Default false. |
261 |
* @return bool True on success, false on failure. |
|
5 | 262 |
*/ |
9 | 263 |
public function chmod( $file, $mode = false, $recursive = false ) { |
0 | 264 |
if ( ! $mode ) { |
9 | 265 |
if ( $this->is_file( $file ) ) { |
0 | 266 |
$mode = FS_CHMOD_FILE; |
9 | 267 |
} elseif ( $this->is_dir( $file ) ) { |
0 | 268 |
$mode = FS_CHMOD_DIR; |
9 | 269 |
} else { |
0 | 270 |
return false; |
9 | 271 |
} |
0 | 272 |
} |
273 |
||
274 |
// chmod any sub-objects if recursive. |
|
9 | 275 |
if ( $recursive && $this->is_dir( $file ) ) { |
276 |
$filelist = $this->dirlist( $file ); |
|
16 | 277 |
|
9 | 278 |
foreach ( (array) $filelist as $filename => $filemeta ) { |
279 |
$this->chmod( $file . '/' . $filename, $mode, $recursive ); |
|
280 |
} |
|
0 | 281 |
} |
282 |
||
16 | 283 |
// chmod the file or directory. |
9 | 284 |
if ( ! function_exists( 'ftp_chmod' ) ) { |
16 | 285 |
return (bool) ftp_site( $this->link, sprintf( 'CHMOD %o %s', $mode, $file ) ); |
9 | 286 |
} |
16 | 287 |
|
288 |
return (bool) ftp_chmod( $this->link, $mode, $file ); |
|
0 | 289 |
} |
290 |
||
5 | 291 |
/** |
9 | 292 |
* Gets the file owner. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
293 |
* |
9 | 294 |
* @since 2.5.0 |
295 |
* |
|
296 |
* @param string $file Path to the file. |
|
297 |
* @return string|false Username of the owner on success, false on failure. |
|
5 | 298 |
*/ |
9 | 299 |
public function owner( $file ) { |
300 |
$dir = $this->dirlist( $file ); |
|
16 | 301 |
|
9 | 302 |
return $dir[ $file ]['owner']; |
0 | 303 |
} |
9 | 304 |
|
5 | 305 |
/** |
9 | 306 |
* Gets the permissions of the specified file or filepath in their octal format. |
307 |
* |
|
308 |
* @since 2.5.0 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
309 |
* |
9 | 310 |
* @param string $file Path to the file. |
311 |
* @return string Mode of the file (the last 3 digits). |
|
5 | 312 |
*/ |
9 | 313 |
public function getchmod( $file ) { |
314 |
$dir = $this->dirlist( $file ); |
|
16 | 315 |
|
9 | 316 |
return $dir[ $file ]['permsn']; |
0 | 317 |
} |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
318 |
|
5 | 319 |
/** |
9 | 320 |
* Gets the file's group. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
321 |
* |
9 | 322 |
* @since 2.5.0 |
323 |
* |
|
324 |
* @param string $file Path to the file. |
|
325 |
* @return string|false The group on success, false on failure. |
|
5 | 326 |
*/ |
9 | 327 |
public function group( $file ) { |
328 |
$dir = $this->dirlist( $file ); |
|
16 | 329 |
|
9 | 330 |
return $dir[ $file ]['group']; |
0 | 331 |
} |
332 |
||
5 | 333 |
/** |
9 | 334 |
* Copies a file. |
5 | 335 |
* |
9 | 336 |
* @since 2.5.0 |
337 |
* |
|
338 |
* @param string $source Path to the source file. |
|
339 |
* @param string $destination Path to the destination file. |
|
340 |
* @param bool $overwrite Optional. Whether to overwrite the destination file if it exists. |
|
341 |
* Default false. |
|
342 |
* @param int|false $mode Optional. The permissions as octal number, usually 0644 for files, |
|
343 |
* 0755 for dirs. Default false. |
|
344 |
* @return bool True on success, false on failure. |
|
5 | 345 |
*/ |
9 | 346 |
public function copy( $source, $destination, $overwrite = false, $mode = false ) { |
347 |
if ( ! $overwrite && $this->exists( $destination ) ) { |
|
0 | 348 |
return false; |
9 | 349 |
} |
16 | 350 |
|
9 | 351 |
$content = $this->get_contents( $source ); |
16 | 352 |
|
9 | 353 |
if ( false === $content ) { |
0 | 354 |
return false; |
9 | 355 |
} |
16 | 356 |
|
9 | 357 |
return $this->put_contents( $destination, $content, $mode ); |
0 | 358 |
} |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
359 |
|
5 | 360 |
/** |
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
361 |
* Moves a file or directory. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
362 |
* |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
363 |
* After moving files or directories, OPcache will need to be invalidated. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
364 |
* |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
365 |
* If moving a directory fails, `copy_dir()` can be used for a recursive copy. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
366 |
* |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
367 |
* Use `move_dir()` for moving directories with OPcache invalidation and a |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
368 |
* fallback to `copy_dir()`. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
369 |
* |
9 | 370 |
* @since 2.5.0 |
371 |
* |
|
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
372 |
* @param string $source Path to the source file or directory. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
373 |
* @param string $destination Path to the destination file or directory. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
374 |
* @param bool $overwrite Optional. Whether to overwrite the destination if it exists. |
9 | 375 |
* Default false. |
376 |
* @return bool True on success, false on failure. |
|
5 | 377 |
*/ |
9 | 378 |
public function move( $source, $destination, $overwrite = false ) { |
379 |
return ftp_rename( $this->link, $source, $destination ); |
|
0 | 380 |
} |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
381 |
|
5 | 382 |
/** |
9 | 383 |
* Deletes a file or directory. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
384 |
* |
9 | 385 |
* @since 2.5.0 |
386 |
* |
|
387 |
* @param string $file Path to the file or directory. |
|
16 | 388 |
* @param bool $recursive Optional. If set to true, deletes files and folders recursively. |
9 | 389 |
* Default false. |
390 |
* @param string|false $type Type of resource. 'f' for file, 'd' for directory. |
|
391 |
* Default false. |
|
392 |
* @return bool True on success, false on failure. |
|
5 | 393 |
*/ |
9 | 394 |
public function delete( $file, $recursive = false, $type = false ) { |
395 |
if ( empty( $file ) ) { |
|
0 | 396 |
return false; |
9 | 397 |
} |
16 | 398 |
|
399 |
if ( 'f' === $type || $this->is_file( $file ) ) { |
|
400 |
return ftp_delete( $this->link, $file ); |
|
9 | 401 |
} |
16 | 402 |
|
9 | 403 |
if ( ! $recursive ) { |
16 | 404 |
return ftp_rmdir( $this->link, $file ); |
9 | 405 |
} |
0 | 406 |
|
9 | 407 |
$filelist = $this->dirlist( trailingslashit( $file ) ); |
16 | 408 |
|
9 | 409 |
if ( ! empty( $filelist ) ) { |
410 |
foreach ( $filelist as $delete_file ) { |
|
411 |
$this->delete( trailingslashit( $file ) . $delete_file['name'], $recursive, $delete_file['type'] ); |
|
412 |
} |
|
413 |
} |
|
16 | 414 |
|
415 |
return ftp_rmdir( $this->link, $file ); |
|
0 | 416 |
} |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
417 |
|
5 | 418 |
/** |
9 | 419 |
* Checks if a file or directory exists. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
420 |
* |
9 | 421 |
* @since 2.5.0 |
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
422 |
* @since 6.3.0 Returns false for an empty path. |
9 | 423 |
* |
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
424 |
* @param string $path Path to file or directory. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
425 |
* @return bool Whether $path exists or not. |
5 | 426 |
*/ |
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
427 |
public function exists( $path ) { |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
428 |
/* |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
429 |
* Check for empty path. If ftp_nlist() receives an empty path, |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
430 |
* it checks the current working directory and may return true. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
431 |
* |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
432 |
* See https://core.trac.wordpress.org/ticket/33058. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
433 |
*/ |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
434 |
if ( '' === $path ) { |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
435 |
return false; |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
436 |
} |
0 | 437 |
|
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
438 |
$list = ftp_nlist( $this->link, $path ); |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
439 |
|
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
440 |
if ( empty( $list ) && $this->is_dir( $path ) ) { |
5 | 441 |
return true; // File is an empty directory. |
442 |
} |
|
443 |
||
16 | 444 |
return ! empty( $list ); // Empty list = no file, so invert. |
0 | 445 |
} |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
446 |
|
5 | 447 |
/** |
9 | 448 |
* Checks if resource is a file. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
449 |
* |
9 | 450 |
* @since 2.5.0 |
451 |
* |
|
452 |
* @param string $file File path. |
|
453 |
* @return bool Whether $file is a file. |
|
5 | 454 |
*/ |
9 | 455 |
public function is_file( $file ) { |
456 |
return $this->exists( $file ) && ! $this->is_dir( $file ); |
|
0 | 457 |
} |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
458 |
|
5 | 459 |
/** |
9 | 460 |
* Checks if resource is a directory. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
461 |
* |
9 | 462 |
* @since 2.5.0 |
463 |
* |
|
464 |
* @param string $path Directory path. |
|
465 |
* @return bool Whether $path is a directory. |
|
5 | 466 |
*/ |
9 | 467 |
public function is_dir( $path ) { |
468 |
$cwd = $this->cwd(); |
|
469 |
$result = @ftp_chdir( $this->link, trailingslashit( $path ) ); |
|
16 | 470 |
|
18 | 471 |
if ( $result && $path === $this->cwd() || $this->cwd() !== $cwd ) { |
9 | 472 |
@ftp_chdir( $this->link, $cwd ); |
0 | 473 |
return true; |
474 |
} |
|
16 | 475 |
|
0 | 476 |
return false; |
477 |
} |
|
478 |
||
5 | 479 |
/** |
9 | 480 |
* Checks if a file is readable. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
481 |
* |
9 | 482 |
* @since 2.5.0 |
483 |
* |
|
484 |
* @param string $file Path to file. |
|
485 |
* @return bool Whether $file is readable. |
|
5 | 486 |
*/ |
9 | 487 |
public function is_readable( $file ) { |
0 | 488 |
return true; |
489 |
} |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
490 |
|
5 | 491 |
/** |
9 | 492 |
* Checks if a file or directory is writable. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
493 |
* |
9 | 494 |
* @since 2.5.0 |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
495 |
* |
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
496 |
* @param string $path Path to file or directory. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
497 |
* @return bool Whether $path is writable. |
5 | 498 |
*/ |
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
499 |
public function is_writable( $path ) { |
0 | 500 |
return true; |
501 |
} |
|
502 |
||
5 | 503 |
/** |
9 | 504 |
* Gets the file's last access time. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
505 |
* |
9 | 506 |
* @since 2.5.0 |
507 |
* |
|
508 |
* @param string $file Path to file. |
|
509 |
* @return int|false Unix timestamp representing last access time, false on failure. |
|
5 | 510 |
*/ |
9 | 511 |
public function atime( $file ) { |
512 |
return false; |
|
513 |
} |
|
514 |
||
515 |
/** |
|
516 |
* Gets the file modification time. |
|
517 |
* |
|
518 |
* @since 2.5.0 |
|
519 |
* |
|
520 |
* @param string $file Path to file. |
|
521 |
* @return int|false Unix timestamp representing modification time, false on failure. |
|
522 |
*/ |
|
523 |
public function mtime( $file ) { |
|
524 |
return ftp_mdtm( $this->link, $file ); |
|
525 |
} |
|
526 |
||
527 |
/** |
|
528 |
* Gets the file size (in bytes). |
|
529 |
* |
|
530 |
* @since 2.5.0 |
|
531 |
* |
|
532 |
* @param string $file Path to file. |
|
533 |
* @return int|false Size of the file in bytes on success, false on failure. |
|
534 |
*/ |
|
535 |
public function size( $file ) { |
|
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
536 |
$size = ftp_size( $this->link, $file ); |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
537 |
|
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
538 |
return ( $size > -1 ) ? $size : false; |
0 | 539 |
} |
540 |
||
5 | 541 |
/** |
9 | 542 |
* Sets the access and modification times of a file. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
543 |
* |
9 | 544 |
* Note: If $file doesn't exist, it will be created. |
545 |
* |
|
546 |
* @since 2.5.0 |
|
547 |
* |
|
548 |
* @param string $file Path to file. |
|
549 |
* @param int $time Optional. Modified time to set for file. |
|
550 |
* Default 0. |
|
551 |
* @param int $atime Optional. Access time to set for file. |
|
552 |
* Default 0. |
|
553 |
* @return bool True on success, false on failure. |
|
554 |
*/ |
|
555 |
public function touch( $file, $time = 0, $atime = 0 ) { |
|
556 |
return false; |
|
557 |
} |
|
558 |
||
559 |
/** |
|
560 |
* Creates a directory. |
|
561 |
* |
|
562 |
* @since 2.5.0 |
|
563 |
* |
|
18 | 564 |
* @param string $path Path for new directory. |
565 |
* @param int|false $chmod Optional. The permissions as octal number (or false to skip chmod). |
|
566 |
* Default false. |
|
567 |
* @param string|int|false $chown Optional. A user name or number (or false to skip chown). |
|
568 |
* Default false. |
|
569 |
* @param string|int|false $chgrp Optional. A group name or number (or false to skip chgrp). |
|
570 |
* Default false. |
|
9 | 571 |
* @return bool True on success, false on failure. |
572 |
*/ |
|
573 |
public function mkdir( $path, $chmod = false, $chown = false, $chgrp = false ) { |
|
574 |
$path = untrailingslashit( $path ); |
|
16 | 575 |
|
9 | 576 |
if ( empty( $path ) ) { |
577 |
return false; |
|
578 |
} |
|
579 |
||
16 | 580 |
if ( ! ftp_mkdir( $this->link, $path ) ) { |
9 | 581 |
return false; |
582 |
} |
|
16 | 583 |
|
9 | 584 |
$this->chmod( $path, $chmod ); |
16 | 585 |
|
9 | 586 |
return true; |
587 |
} |
|
588 |
||
589 |
/** |
|
590 |
* Deletes a directory. |
|
591 |
* |
|
592 |
* @since 2.5.0 |
|
593 |
* |
|
594 |
* @param string $path Path to directory. |
|
595 |
* @param bool $recursive Optional. Whether to recursively remove files/directories. |
|
596 |
* Default false. |
|
597 |
* @return bool True on success, false on failure. |
|
598 |
*/ |
|
599 |
public function rmdir( $path, $recursive = false ) { |
|
600 |
return $this->delete( $path, $recursive ); |
|
601 |
} |
|
602 |
||
603 |
/** |
|
5 | 604 |
* @param string $line |
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
605 |
* @return array { |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
606 |
* Array of file information. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
607 |
* |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
608 |
* @type string $name Name of the file or directory. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
609 |
* @type string $perms *nix representation of permissions. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
610 |
* @type string $permsn Octal representation of permissions. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
611 |
* @type string|false $number File number as a string, or false if not available. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
612 |
* @type string|false $owner Owner name or ID, or false if not available. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
613 |
* @type string|false $group File permissions group, or false if not available. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
614 |
* @type string|false $size Size of file in bytes as a string, or false if not available. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
615 |
* @type string|false $lastmodunix Last modified unix timestamp as a string, or false if not available. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
616 |
* @type string|false $lastmod Last modified month (3 letters) and day (without leading 0), or |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
617 |
* false if not available. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
618 |
* @type string|false $time Last modified time, or false if not available. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
619 |
* @type string $type Type of resource. 'f' for file, 'd' for directory, 'l' for link. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
620 |
* @type array|false $files If a directory and `$recursive` is true, contains another array of files. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
621 |
* False if unable to list directory contents. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
622 |
* } |
5 | 623 |
*/ |
9 | 624 |
public function parselisting( $line ) { |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
625 |
static $is_windows = null; |
16 | 626 |
|
9 | 627 |
if ( is_null( $is_windows ) ) { |
628 |
$is_windows = stripos( ftp_systype( $this->link ), 'win' ) !== false; |
|
629 |
} |
|
0 | 630 |
|
9 | 631 |
if ( $is_windows && preg_match( '/([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|<DIR>) +(.+)/', $line, $lucifer ) ) { |
0 | 632 |
$b = array(); |
16 | 633 |
|
9 | 634 |
if ( $lucifer[3] < 70 ) { |
635 |
$lucifer[3] += 2000; |
|
636 |
} else { |
|
16 | 637 |
$lucifer[3] += 1900; // 4-digit year fix. |
9 | 638 |
} |
16 | 639 |
|
640 |
$b['isdir'] = ( '<DIR>' === $lucifer[7] ); |
|
641 |
||
9 | 642 |
if ( $b['isdir'] ) { |
0 | 643 |
$b['type'] = 'd'; |
9 | 644 |
} else { |
0 | 645 |
$b['type'] = 'f'; |
9 | 646 |
} |
16 | 647 |
|
9 | 648 |
$b['size'] = $lucifer[7]; |
649 |
$b['month'] = $lucifer[1]; |
|
650 |
$b['day'] = $lucifer[2]; |
|
651 |
$b['year'] = $lucifer[3]; |
|
652 |
$b['hour'] = $lucifer[4]; |
|
0 | 653 |
$b['minute'] = $lucifer[5]; |
18 | 654 |
$b['time'] = mktime( $lucifer[4] + ( strcasecmp( $lucifer[6], 'PM' ) === 0 ? 12 : 0 ), $lucifer[5], 0, $lucifer[1], $lucifer[2], $lucifer[3] ); |
9 | 655 |
$b['am/pm'] = $lucifer[6]; |
656 |
$b['name'] = $lucifer[8]; |
|
16 | 657 |
} elseif ( ! $is_windows ) { |
658 |
$lucifer = preg_split( '/[ ]/', $line, 9, PREG_SPLIT_NO_EMPTY ); |
|
659 |
||
660 |
if ( $lucifer ) { |
|
661 |
// echo $line."\n"; |
|
662 |
$lcount = count( $lucifer ); |
|
663 |
||
664 |
if ( $lcount < 8 ) { |
|
665 |
return ''; |
|
666 |
} |
|
667 |
||
668 |
$b = array(); |
|
669 |
$b['isdir'] = 'd' === $lucifer[0][0]; |
|
670 |
$b['islink'] = 'l' === $lucifer[0][0]; |
|
671 |
||
672 |
if ( $b['isdir'] ) { |
|
673 |
$b['type'] = 'd'; |
|
674 |
} elseif ( $b['islink'] ) { |
|
675 |
$b['type'] = 'l'; |
|
0 | 676 |
} else { |
16 | 677 |
$b['type'] = 'f'; |
0 | 678 |
} |
16 | 679 |
|
680 |
$b['perms'] = $lucifer[0]; |
|
681 |
$b['permsn'] = $this->getnumchmodfromh( $b['perms'] ); |
|
682 |
$b['number'] = $lucifer[1]; |
|
683 |
$b['owner'] = $lucifer[2]; |
|
684 |
$b['group'] = $lucifer[3]; |
|
685 |
$b['size'] = $lucifer[4]; |
|
686 |
||
18 | 687 |
if ( 8 === $lcount ) { |
16 | 688 |
sscanf( $lucifer[5], '%d-%d-%d', $b['year'], $b['month'], $b['day'] ); |
689 |
sscanf( $lucifer[6], '%d:%d', $b['hour'], $b['minute'] ); |
|
690 |
||
691 |
$b['time'] = mktime( $b['hour'], $b['minute'], 0, $b['month'], $b['day'], $b['year'] ); |
|
692 |
$b['name'] = $lucifer[7]; |
|
693 |
} else { |
|
694 |
$b['month'] = $lucifer[5]; |
|
695 |
$b['day'] = $lucifer[6]; |
|
696 |
||
697 |
if ( preg_match( '/([0-9]{2}):([0-9]{2})/', $lucifer[7], $l2 ) ) { |
|
698 |
$b['year'] = gmdate( 'Y' ); |
|
699 |
$b['hour'] = $l2[1]; |
|
700 |
$b['minute'] = $l2[2]; |
|
701 |
} else { |
|
702 |
$b['year'] = $lucifer[7]; |
|
703 |
$b['hour'] = 0; |
|
704 |
$b['minute'] = 0; |
|
705 |
} |
|
706 |
||
707 |
$b['time'] = strtotime( sprintf( '%d %s %d %02d:%02d', $b['day'], $b['month'], $b['year'], $b['hour'], $b['minute'] ) ); |
|
708 |
$b['name'] = $lucifer[8]; |
|
709 |
} |
|
0 | 710 |
} |
711 |
} |
|
712 |
||
16 | 713 |
// Replace symlinks formatted as "source -> target" with just the source name. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
714 |
if ( isset( $b['islink'] ) && $b['islink'] ) { |
0 | 715 |
$b['name'] = preg_replace( '/(\s*->\s*.*)$/', '', $b['name'] ); |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
716 |
} |
0 | 717 |
|
718 |
return $b; |
|
719 |
} |
|
720 |
||
5 | 721 |
/** |
9 | 722 |
* Gets details for files in a directory or a specific file. |
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
723 |
* |
9 | 724 |
* @since 2.5.0 |
725 |
* |
|
726 |
* @param string $path Path to directory or file. |
|
727 |
* @param bool $include_hidden Optional. Whether to include details of hidden ("." prefixed) files. |
|
728 |
* Default true. |
|
729 |
* @param bool $recursive Optional. Whether to recursively include file details in nested directories. |
|
730 |
* Default false. |
|
731 |
* @return array|false { |
|
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
732 |
* Array of arrays containing file information. False if unable to list directory contents. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
733 |
* |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
734 |
* @type array ...$0 { |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
735 |
* Array of file information. Note that some elements may not be available on all filesystems. |
9 | 736 |
* |
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
737 |
* @type string $name Name of the file or directory. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
738 |
* @type string $perms *nix representation of permissions. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
739 |
* @type string $permsn Octal representation of permissions. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
740 |
* @type int|string|false $number File number. May be a numeric string. False if not available. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
741 |
* @type string|false $owner Owner name or ID, or false if not available. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
742 |
* @type string|false $group File permissions group, or false if not available. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
743 |
* @type int|string|false $size Size of file in bytes. May be a numeric string. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
744 |
* False if not available. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
745 |
* @type int|string|false $lastmodunix Last modified unix timestamp. May be a numeric string. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
746 |
* False if not available. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
747 |
* @type string|false $lastmod Last modified month (3 letters) and day (without leading 0), or |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
748 |
* false if not available. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
749 |
* @type string|false $time Last modified time, or false if not available. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
750 |
* @type string $type Type of resource. 'f' for file, 'd' for directory, 'l' for link. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
751 |
* @type array|false $files If a directory and `$recursive` is true, contains another array of |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
752 |
* files. False if unable to list directory contents. |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
753 |
* } |
9 | 754 |
* } |
5 | 755 |
*/ |
9 | 756 |
public function dirlist( $path = '.', $include_hidden = true, $recursive = false ) { |
757 |
if ( $this->is_file( $path ) ) { |
|
758 |
$limit_file = basename( $path ); |
|
759 |
$path = dirname( $path ) . '/'; |
|
0 | 760 |
} else { |
761 |
$limit_file = false; |
|
762 |
} |
|
763 |
||
16 | 764 |
$pwd = ftp_pwd( $this->link ); |
765 |
||
9 | 766 |
if ( ! @ftp_chdir( $this->link, $path ) ) { // Can't change to folder = folder doesn't exist. |
0 | 767 |
return false; |
9 | 768 |
} |
16 | 769 |
|
770 |
$list = ftp_rawlist( $this->link, '-a', false ); |
|
771 |
||
9 | 772 |
@ftp_chdir( $this->link, $pwd ); |
0 | 773 |
|
9 | 774 |
if ( empty( $list ) ) { // Empty array = non-existent folder (real folder will show . at least). |
0 | 775 |
return false; |
9 | 776 |
} |
0 | 777 |
|
778 |
$dirlist = array(); |
|
16 | 779 |
|
0 | 780 |
foreach ( $list as $k => $v ) { |
9 | 781 |
$entry = $this->parselisting( $v ); |
16 | 782 |
|
9 | 783 |
if ( empty( $entry ) ) { |
0 | 784 |
continue; |
9 | 785 |
} |
0 | 786 |
|
16 | 787 |
if ( '.' === $entry['name'] || '..' === $entry['name'] ) { |
0 | 788 |
continue; |
9 | 789 |
} |
0 | 790 |
|
16 | 791 |
if ( ! $include_hidden && '.' === $entry['name'][0] ) { |
0 | 792 |
continue; |
9 | 793 |
} |
0 | 794 |
|
18 | 795 |
if ( $limit_file && $entry['name'] !== $limit_file ) { |
0 | 796 |
continue; |
9 | 797 |
} |
0 | 798 |
|
799 |
$dirlist[ $entry['name'] ] = $entry; |
|
800 |
} |
|
801 |
||
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
802 |
$path = trailingslashit( $path ); |
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
803 |
$ret = array(); |
16 | 804 |
|
9 | 805 |
foreach ( (array) $dirlist as $struc ) { |
16 | 806 |
if ( 'd' === $struc['type'] ) { |
9 | 807 |
if ( $recursive ) { |
21
48c4eec2b7e6
Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
19
diff
changeset
|
808 |
$struc['files'] = $this->dirlist( $path . $struc['name'], $include_hidden, $recursive ); |
9 | 809 |
} else { |
0 | 810 |
$struc['files'] = array(); |
9 | 811 |
} |
0 | 812 |
} |
813 |
||
814 |
$ret[ $struc['name'] ] = $struc; |
|
815 |
} |
|
16 | 816 |
|
0 | 817 |
return $ret; |
818 |
} |
|
819 |
||
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
820 |
/** |
9 | 821 |
* Destructor. |
822 |
* |
|
823 |
* @since 2.5.0 |
|
7
cf61fcea0001
resynchronize code repo with production
ymh <ymh.work@gmail.com>
parents:
5
diff
changeset
|
824 |
*/ |
5 | 825 |
public function __destruct() { |
9 | 826 |
if ( $this->link ) { |
827 |
ftp_close( $this->link ); |
|
828 |
} |
|
0 | 829 |
} |
830 |
} |