| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * WordPress Direct Filesystem. 4 * 5 * @package WordPress 6 * @subpackage Filesystem 7 */ 8 9 /** 10 * WordPress Filesystem Class for direct PHP file and folder manipulation. 11 * 12 * @since 2.5.0 13 * 14 * @see WP_Filesystem_Base 15 * @phpstan-import-type FileListing from WP_Filesystem_Base 16 */ 17 class WP_Filesystem_Direct extends WP_Filesystem_Base { 18 19 /** 20 * Constructor. 21 * 22 * @since 2.5.0 23 * 24 * @param mixed $arg Not used. 25 */ 26 public function __construct( $arg ) { 27 // The $arg parameter is required for signature parity with the other transports, but is unused here. 28 unset( $arg ); 29 $this->method = 'direct'; 30 $this->errors = new WP_Error(); 31 } 32 33 /** 34 * Reads entire file into a string. 35 * 36 * @since 2.5.0 37 * 38 * @param string $file Name of the file to read. 39 * @return string|false Read data on success, false on failure. 40 */ 41 public function get_contents( $file ) { 42 return @file_get_contents( $file ); 43 } 44 45 /** 46 * Reads entire file into an array. 47 * 48 * @since 2.5.0 49 * 50 * @param string $file Path to the file. 51 * @return string[]|false File contents in an array on success, false on failure. 52 */ 53 public function get_contents_array( $file ) { 54 return @file( $file ); 55 } 56 57 /** 58 * Writes a string to a file. 59 * 60 * @since 2.5.0 61 * 62 * @param string $file Remote path to the file where to write the data. 63 * @param string $contents The data to write. 64 * @param int|false $mode Optional. The file permissions as octal number, usually 0644. 65 * Default false. 66 * @return bool True on success, false on failure. 67 */ 68 public function put_contents( $file, $contents, $mode = false ) { 69 $fp = @fopen( $file, 'wb' ); 70 71 if ( ! $fp ) { 72 return false; 73 } 74 75 mbstring_binary_safe_encoding(); 76 77 $data_length = strlen( $contents ); 78 79 $bytes_written = fwrite( $fp, $contents ); 80 81 reset_mbstring_encoding(); 82 83 fclose( $fp ); 84 85 if ( $data_length !== $bytes_written ) { 86 return false; 87 } 88 89 $this->chmod( $file, $mode ); 90 91 return true; 92 } 93 94 /** 95 * Gets the current working directory. 96 * 97 * @since 2.5.0 98 * 99 * @return string|false The current working directory on success, false on failure. 100 */ 101 public function cwd() { 102 return getcwd(); 103 } 104 105 /** 106 * Changes current directory. 107 * 108 * @since 2.5.0 109 * 110 * @param string $dir The new current directory. 111 * @return bool True on success, false on failure. 112 */ 113 public function chdir( $dir ) { 114 return @chdir( $dir ); 115 } 116 117 /** 118 * Changes the file group. 119 * 120 * @since 2.5.0 121 * 122 * @param string $file Path to the file. 123 * @param string|int $group A group name or number. 124 * @param bool $recursive Optional. If set to true, changes file group recursively. 125 * Default false. 126 * @return bool True on success, false on failure. 127 */ 128 public function chgrp( $file, $group, $recursive = false ) { 129 if ( ! $this->exists( $file ) ) { 130 return false; 131 } 132 133 if ( ! $recursive ) { 134 return chgrp( $file, $group ); 135 } 136 137 if ( ! $this->is_dir( $file ) ) { 138 return chgrp( $file, $group ); 139 } 140 141 // Is a directory, and we want recursive. 142 $file = trailingslashit( $file ); 143 $filelist = $this->dirlist( $file ); 144 if ( false === $filelist ) { 145 return false; 146 } 147 148 foreach ( $filelist as $file_listing ) { 149 $this->chgrp( $file . $file_listing['name'], $group, $recursive ); 150 } 151 152 return true; 153 } 154 155 /** 156 * Changes filesystem permissions. 157 * 158 * @since 2.5.0 159 * 160 * @param string $file Path to the file. 161 * @param int|false $mode Optional. The permissions as octal number, usually 0644 for files, 162 * 0755 for directories. Default false. 163 * @param bool $recursive Optional. If set to true, changes file permissions recursively. 164 * Default false. 165 * @return bool True on success, false on failure. 166 */ 167 public function chmod( $file, $mode = false, $recursive = false ) { 168 if ( ! $mode ) { 169 if ( $this->is_file( $file ) ) { 170 $mode = FS_CHMOD_FILE; 171 } elseif ( $this->is_dir( $file ) ) { 172 $mode = FS_CHMOD_DIR; 173 } else { 174 return false; 175 } 176 } 177 178 if ( ! $recursive || ! $this->is_dir( $file ) ) { 179 $current_mode = fileperms( $file ) & 0777 | 0644; 180 181 /* 182 * fileperms() populates the stat cache, so have to clear it 183 * to maintain parity with the previous behavior. 184 */ 185 clearstatcache( true, $file ); 186 187 /* 188 * Avoid calling chmod() if the requested mode is already set, 189 * to prevent throwing a warning when we aren't the owner. 190 */ 191 if ( $current_mode === $mode ) { 192 return true; 193 } 194 195 return chmod( $file, $mode ); 196 } 197 198 // Is a directory, and we want recursive. 199 $file = trailingslashit( $file ); 200 $filelist = $this->dirlist( $file ); 201 202 foreach ( (array) $filelist as $filename => $filemeta ) { 203 $this->chmod( $file . $filename, $mode, $recursive ); 204 } 205 206 return true; 207 } 208 209 /** 210 * Changes the owner of a file or directory. 211 * 212 * @since 2.5.0 213 * 214 * @param string $file Path to the file or directory. 215 * @param string|int $owner A user name or number. 216 * @param bool $recursive Optional. If set to true, changes file owner recursively. 217 * Default false. 218 * @return bool True on success, false on failure. 219 */ 220 public function chown( $file, $owner, $recursive = false ) { 221 if ( ! $this->exists( $file ) ) { 222 return false; 223 } 224 225 if ( ! $recursive ) { 226 return chown( $file, $owner ); 227 } 228 229 if ( ! $this->is_dir( $file ) ) { 230 return chown( $file, $owner ); 231 } 232 233 // Is a directory, and we want recursive. 234 $filelist = $this->dirlist( $file ); 235 if ( false === $filelist ) { 236 return false; 237 } 238 239 foreach ( $filelist as $file_listing ) { 240 $this->chown( $file . '/' . $file_listing['name'], $owner, $recursive ); 241 } 242 243 return true; 244 } 245 246 /** 247 * Gets the file owner. 248 * 249 * @since 2.5.0 250 * 251 * @param string $file Path to the file. 252 * @return string|int<1, max>|false Username of the owner on success, or UID of file owner if not available; false on failure. 253 */ 254 public function owner( $file ) { 255 $owneruid = @fileowner( $file ); 256 257 if ( ! $owneruid ) { 258 return false; 259 } 260 261 if ( ! function_exists( 'posix_getpwuid' ) ) { 262 return $owneruid; 263 } 264 265 $ownerarray = posix_getpwuid( $owneruid ); 266 267 if ( ! $ownerarray ) { 268 return false; 269 } 270 271 return $ownerarray['name']; 272 } 273 274 /** 275 * Gets the permissions of the specified file or filepath in their octal format. 276 * 277 * @since 2.5.0 278 * 279 * @param string $file Path to the file. 280 * @return string Mode of the file (the last 3 digits), or the string "0" on failure. 281 */ 282 public function getchmod( $file ) { 283 $perms = @fileperms( $file ); 284 if ( false === $perms ) { 285 return '0'; 286 } 287 288 return substr( decoct( $perms ), -3 ); 289 } 290 291 /** 292 * Gets the file's group. 293 * 294 * @since 2.5.0 295 * 296 * @param string $file Path to the file. 297 * @return string|int<1, max>|false Group name on success, or GID of the file's group if not available; false on failure. 298 */ 299 public function group( $file ) { 300 $gid = @filegroup( $file ); 301 302 if ( ! $gid ) { 303 return false; 304 } 305 306 if ( ! function_exists( 'posix_getgrgid' ) ) { 307 return $gid; 308 } 309 310 $grouparray = posix_getgrgid( $gid ); 311 312 if ( ! $grouparray ) { 313 return false; 314 } 315 316 return $grouparray['name']; 317 } 318 319 /** 320 * Copies a file. 321 * 322 * @since 2.5.0 323 * 324 * @param string $source Path to the source file. 325 * @param string $destination Path to the destination file. 326 * @param bool $overwrite Optional. Whether to overwrite the destination file if it exists. 327 * Default false. 328 * @param int|false $mode Optional. The permissions as octal number, usually 0644 for files, 329 * 0755 for dirs. Default false. 330 * @return bool True on success, false on failure. 331 */ 332 public function copy( $source, $destination, $overwrite = false, $mode = false ) { 333 if ( ! $overwrite && $this->exists( $destination ) ) { 334 return false; 335 } 336 337 $rtval = copy( $source, $destination ); 338 339 if ( $mode ) { 340 $this->chmod( $destination, $mode ); 341 } 342 343 return $rtval; 344 } 345 346 /** 347 * Moves a file or directory. 348 * 349 * After moving files or directories, OPcache will need to be invalidated. 350 * 351 * If moving a directory fails, `copy_dir()` can be used for a recursive copy. 352 * 353 * Use `move_dir()` for moving directories with OPcache invalidation and a 354 * fallback to `copy_dir()`. 355 * 356 * @since 2.5.0 357 * 358 * @param string $source Path to the source file. 359 * @param string $destination Path to the destination file. 360 * @param bool $overwrite Optional. Whether to overwrite the destination file if it exists. 361 * Default false. 362 * @return bool True on success, false on failure. 363 */ 364 public function move( $source, $destination, $overwrite = false ) { 365 if ( ! $overwrite && $this->exists( $destination ) ) { 366 return false; 367 } 368 369 if ( $overwrite && $this->exists( $destination ) && ! $this->delete( $destination, true ) ) { 370 // Can't overwrite if the destination couldn't be deleted. 371 return false; 372 } 373 374 // Try using rename first. if that fails (for example, source is read only) try copy. 375 if ( @rename( $source, $destination ) ) { 376 return true; 377 } 378 379 // Backward compatibility: Only fall back to `::copy()` for single files. 380 if ( $this->is_file( $source ) && $this->copy( $source, $destination, $overwrite ) && $this->exists( $destination ) ) { 381 $this->delete( $source ); 382 383 return true; 384 } else { 385 return false; 386 } 387 } 388 389 /** 390 * Deletes a file or directory. 391 * 392 * @since 2.5.0 393 * 394 * @param string $file Path to the file or directory. 395 * @param bool $recursive Optional. If set to true, deletes files and folders recursively. 396 * Default false. 397 * @param string|false $type Type of resource. 'f' for file, 'd' for directory. 398 * Default false. 399 * @return bool True on success, false on failure. 400 */ 401 public function delete( $file, $recursive = false, $type = false ) { 402 if ( empty( $file ) ) { 403 // Some filesystems report this as /, which can cause non-expected recursive deletion of all files in the filesystem. 404 return false; 405 } 406 407 $file = str_replace( '\\', '/', $file ); // For Win32, occasional problems deleting files otherwise. 408 409 if ( 'f' === $type || $this->is_file( $file ) ) { 410 return @unlink( $file ); 411 } 412 413 if ( ! $recursive && $this->is_dir( $file ) ) { 414 return @rmdir( $file ); 415 } 416 417 // At this point it's a folder, and we're in recursive mode. 418 $file = trailingslashit( $file ); 419 $filelist = $this->dirlist( $file, true ); 420 421 $retval = true; 422 423 if ( is_array( $filelist ) ) { 424 foreach ( $filelist as $filename => $fileinfo ) { 425 if ( ! $this->delete( $file . $filename, $recursive, $fileinfo['type'] ) ) { 426 $retval = false; 427 } 428 } 429 } 430 431 if ( file_exists( $file ) && ! @rmdir( $file ) ) { 432 $retval = false; 433 } 434 435 return $retval; 436 } 437 438 /** 439 * Checks if a file or directory exists. 440 * 441 * @since 2.5.0 442 * 443 * @param string $path Path to file or directory. 444 * @return bool Whether $path exists or not. 445 */ 446 public function exists( $path ) { 447 return @file_exists( $path ); 448 } 449 450 /** 451 * Checks if resource is a file. 452 * 453 * @since 2.5.0 454 * 455 * @param string $file File path. 456 * @return bool Whether $file is a file. 457 */ 458 public function is_file( $file ) { 459 return @is_file( $file ); 460 } 461 462 /** 463 * Checks if resource is a directory. 464 * 465 * @since 2.5.0 466 * 467 * @param string $path Directory path. 468 * @return bool Whether $path is a directory. 469 */ 470 public function is_dir( $path ) { 471 return @is_dir( $path ); 472 } 473 474 /** 475 * Checks if a file is readable. 476 * 477 * @since 2.5.0 478 * 479 * @param string $file Path to file. 480 * @return bool Whether $file is readable. 481 */ 482 public function is_readable( $file ) { 483 return @is_readable( $file ); 484 } 485 486 /** 487 * Checks if a file or directory is writable. 488 * 489 * @since 2.5.0 490 * 491 * @param string $path Path to file or directory. 492 * @return bool Whether $path is writable. 493 */ 494 public function is_writable( $path ) { 495 return @is_writable( $path ); 496 } 497 498 /** 499 * Gets the file's last access time. 500 * 501 * @since 2.5.0 502 * 503 * @param string $file Path to file. 504 * @return int|false Unix timestamp representing last access time, false on failure. 505 */ 506 public function atime( $file ) { 507 return @fileatime( $file ); 508 } 509 510 /** 511 * Gets the file modification time. 512 * 513 * @since 2.5.0 514 * 515 * @param string $file Path to file. 516 * @return int|false Unix timestamp representing modification time, false on failure. 517 */ 518 public function mtime( $file ) { 519 return @filemtime( $file ); 520 } 521 522 /** 523 * Gets the file size (in bytes). 524 * 525 * @since 2.5.0 526 * 527 * @param string $file Path to file. 528 * @return int|false Size of the file in bytes on success, false on failure. 529 */ 530 public function size( $file ) { 531 return @filesize( $file ); 532 } 533 534 /** 535 * Sets the access and modification times of a file. 536 * 537 * Note: If $file doesn't exist, it will be created. 538 * 539 * @since 2.5.0 540 * 541 * @param string $file Path to file. 542 * @param int $time Optional. Modified time to set for file. 543 * Default 0. 544 * @param int $atime Optional. Access time to set for file. 545 * Default 0. 546 * @return bool True on success, false on failure. 547 */ 548 public function touch( $file, $time = 0, $atime = 0 ) { 549 if ( 0 === $time ) { 550 $time = time(); 551 } 552 553 if ( 0 === $atime ) { 554 $atime = time(); 555 } 556 557 return touch( $file, $time, $atime ); 558 } 559 560 /** 561 * Creates a directory. 562 * 563 * @since 2.5.0 564 * 565 * @param string $path Path for new directory. 566 * @param int|false $chmod Optional. The permissions as octal number (or false to skip chmod). 567 * Default false. 568 * @param string|int|false $chown Optional. A user name or number (or false to skip chown). 569 * Default false. 570 * @param string|int|false $chgrp Optional. A group name or number (or false to skip chgrp). 571 * Default false. 572 * @return bool True on success, false on failure. 573 */ 574 public function mkdir( $path, $chmod = false, $chown = false, $chgrp = false ) { 575 // Safe mode fails with a trailing slash under certain PHP versions. 576 $path = untrailingslashit( $path ); 577 578 if ( empty( $path ) ) { 579 return false; 580 } 581 582 if ( ! $chmod ) { 583 $chmod = FS_CHMOD_DIR; 584 } 585 586 if ( ! @mkdir( $path ) ) { 587 return false; 588 } 589 590 $this->chmod( $path, $chmod ); 591 592 if ( $chown ) { 593 $this->chown( $path, $chown ); 594 } 595 596 if ( $chgrp ) { 597 $this->chgrp( $path, $chgrp ); 598 } 599 600 return true; 601 } 602 603 /** 604 * Deletes a directory. 605 * 606 * @since 2.5.0 607 * 608 * @param string $path Path to directory. 609 * @param bool $recursive Optional. Whether to recursively remove files/directories. 610 * Default false. 611 * @return bool True on success, false on failure. 612 */ 613 public function rmdir( $path, $recursive = false ) { 614 return $this->delete( $path, $recursive ); 615 } 616 617 /** 618 * Gets details for files in a directory or a specific file. 619 * 620 * @since 2.5.0 621 * 622 * @param string $path Path to directory or file. 623 * @param bool $include_hidden Optional. Whether to include details of hidden ("." prefixed) files. 624 * Default true. 625 * @param bool $recursive Optional. Whether to recursively include file details in nested directories. 626 * Default false. 627 * @return array|false { 628 * Array of arrays containing file information. False if unable to list directory contents. 629 * 630 * @type array ...$0 { 631 * Array of file information. Note that some elements may not be available on all filesystems. 632 * 633 * @type string $name Name of the file or directory. 634 * @type string $perms *nix representation of permissions. 635 * @type string $permsn Octal representation of permissions. 636 * @type false $number File number. Always false in this context. 637 * @type string|false $owner Owner name or ID, or false if not available. 638 * @type string|false $group File permissions group, or false if not available. 639 * @type int|string|false $size Size of file in bytes. May be a numeric string. 640 * False if not available. 641 * @type int|string|false $lastmodunix Last modified unix timestamp. May be a numeric string. 642 * False if not available. 643 * @type string|false $lastmod Last modified month (3 letters) and day (without leading 0), or 644 * false if not available. 645 * @type string|false $time Last modified time, or false if not available. 646 * @type string $type Type of resource. 'f' for file, 'd' for directory, 'l' for link. 647 * @type array|false $files If a directory and `$recursive` is true, contains another array of 648 * files. False if unable to list directory contents. 649 * } 650 * } 651 * @phpstan-return array<string, FileListing>|false 652 */ 653 public function dirlist( $path, $include_hidden = true, $recursive = false ) { 654 if ( $this->is_file( $path ) ) { 655 $limit_file = basename( $path ); 656 $path = dirname( $path ); 657 } else { 658 $limit_file = false; 659 } 660 661 if ( ! $this->is_dir( $path ) || ! $this->is_readable( $path ) ) { 662 return false; 663 } 664 665 $dir = dir( $path ); 666 667 if ( ! $dir ) { 668 return false; 669 } 670 671 $path = trailingslashit( $path ); 672 $ret = array(); 673 674 while ( false !== ( $entry = $dir->read() ) ) { 675 $struc = array(); 676 $struc['name'] = $entry; 677 678 if ( '.' === $struc['name'] || '..' === $struc['name'] ) { 679 continue; 680 } 681 682 if ( ! $include_hidden && '.' === $struc['name'][0] ) { 683 continue; 684 } 685 686 if ( $limit_file && $struc['name'] !== $limit_file ) { 687 continue; 688 } 689 690 $struc['perms'] = $this->gethchmod( $path . $entry ); 691 $struc['permsn'] = $this->getnumchmodfromh( $struc['perms'] ); 692 $struc['number'] = false; 693 $struc['owner'] = $this->owner( $path . $entry ); 694 $struc['group'] = $this->group( $path . $entry ); 695 $struc['size'] = $this->size( $path . $entry ); 696 $struc['lastmodunix'] = $this->mtime( $path . $entry ); 697 $struc['lastmod'] = is_int( $struc['lastmodunix'] ) ? gmdate( 'M j', $struc['lastmodunix'] ) : false; 698 $struc['time'] = is_int( $struc['lastmodunix'] ) ? gmdate( 'h:i:s', $struc['lastmodunix'] ) : false; 699 $struc['type'] = $this->is_dir( $path . $entry ) ? 'd' : 'f'; 700 701 if ( 'd' === $struc['type'] ) { 702 if ( $recursive ) { 703 $struc['files'] = $this->dirlist( $path . $struc['name'], $include_hidden, $recursive ); 704 } else { 705 $struc['files'] = array(); 706 } 707 } 708 709 $ret[ $struc['name'] ] = $struc; 710 } 711 712 $dir->close(); 713 unset( $dir ); 714 715 return $ret; 716 } 717 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sat Jul 25 08:20:20 2026 | Cross-referenced by PHPXref |