3 * Base WordPress Filesystem
6 * @subpackage Filesystem
10 * Base WordPress Filesystem class for which Filesystem implementations extend
14 class WP_Filesystem_Base {
16 * Whether to display debug data for the connection.
25 * Cached list of local filepaths to mapped remote filepaths.
34 * The Access method of the current connection, Set automatically.
43 * Constructor (empty).
45 function __construct() {}
48 * Return the path on the remote filesystem of ABSPATH.
53 * @return string The location of the remote path.
56 $folder = $this->find_folder(ABSPATH);
57 // Perhaps the FTP folder is rooted at the WordPress install, Check for wp-includes folder in root, Could have some false positives, but rare.
58 if ( ! $folder && $this->is_dir('/wp-includes') )
64 * Return the path on the remote filesystem of WP_CONTENT_DIR.
69 * @return string The location of the remote path.
71 function wp_content_dir() {
72 return $this->find_folder(WP_CONTENT_DIR);
76 * Return the path on the remote filesystem of WP_PLUGIN_DIR.
81 * @return string The location of the remote path.
83 function wp_plugins_dir() {
84 return $this->find_folder(WP_PLUGIN_DIR);
88 * Return the path on the remote filesystem of the Themes Directory.
93 * @param string $theme The Theme stylesheet or template for the directory.
94 * @return string The location of the remote path.
96 function wp_themes_dir( $theme = false ) {
97 $theme_root = get_theme_root( $theme );
99 // Account for relative theme roots
100 if ( '/themes' == $theme_root || ! is_dir( $theme_root ) )
101 $theme_root = WP_CONTENT_DIR . $theme_root;
103 return $this->find_folder( $theme_root );
107 * Return the path on the remote filesystem of WP_LANG_DIR.
112 * @return string The location of the remote path.
114 function wp_lang_dir() {
115 return $this->find_folder(WP_LANG_DIR);
119 * Locate a folder on the remote filesystem.
123 * @deprecated 2.7.0 use WP_Filesystem::abspath() or WP_Filesystem::wp_*_dir() instead.
124 * @see WP_Filesystem::abspath()
125 * @see WP_Filesystem::wp_content_dir()
126 * @see WP_Filesystem::wp_plugins_dir()
127 * @see WP_Filesystem::wp_themes_dir()
128 * @see WP_Filesystem::wp_lang_dir()
130 * @param string $base The folder to start searching from.
131 * @param bool $echo True to display debug information.
133 * @return string The location of the remote path.
135 function find_base_dir( $base = '.', $echo = false ) {
136 _deprecated_function(__FUNCTION__, '2.7', 'WP_Filesystem::abspath() or WP_Filesystem::wp_*_dir()' );
137 $this->verbose = $echo;
138 return $this->abspath();
142 * Locate a folder on the remote filesystem.
146 * @deprecated 2.7.0 use WP_Filesystem::abspath() or WP_Filesystem::wp_*_dir() methods instead.
147 * @see WP_Filesystem::abspath()
148 * @see WP_Filesystem::wp_content_dir()
149 * @see WP_Filesystem::wp_plugins_dir()
150 * @see WP_Filesystem::wp_themes_dir()
151 * @see WP_Filesystem::wp_lang_dir()
153 * @param string $base The folder to start searching from.
154 * @param bool $echo True to display debug information.
155 * @return string The location of the remote path.
157 function get_base_dir( $base = '.', $echo = false ) {
158 _deprecated_function(__FUNCTION__, '2.7', 'WP_Filesystem::abspath() or WP_Filesystem::wp_*_dir()' );
159 $this->verbose = $echo;
160 return $this->abspath();
164 * Locate a folder on the remote filesystem.
166 * Assumes that on Windows systems, Stripping off the Drive
167 * letter is OK Sanitizes \\ to / in windows filepaths.
172 * @param string $folder the folder to locate.
173 * @return string The location of the remote path.
175 function find_folder( $folder ) {
177 if ( isset( $this->cache[ $folder ] ) )
178 return $this->cache[ $folder ];
180 if ( stripos($this->method, 'ftp') !== false ) {
181 $constant_overrides = array(
182 'FTP_BASE' => ABSPATH,
183 'FTP_CONTENT_DIR' => WP_CONTENT_DIR,
184 'FTP_PLUGIN_DIR' => WP_PLUGIN_DIR,
185 'FTP_LANG_DIR' => WP_LANG_DIR
188 // Direct matches ( folder = CONSTANT/ )
189 foreach ( $constant_overrides as $constant => $dir ) {
190 if ( ! defined( $constant ) )
192 if ( $folder === $dir )
193 return trailingslashit( constant( $constant ) );
196 // Prefix Matches ( folder = CONSTANT/subdir )
197 foreach ( $constant_overrides as $constant => $dir ) {
198 if ( ! defined( $constant ) )
200 if ( 0 === stripos( $folder, $dir ) ) { // $folder starts with $dir
201 $potential_folder = preg_replace( '#^' . preg_quote( $dir, '#' ) . '/#i', trailingslashit( constant( $constant ) ), $folder );
202 $potential_folder = trailingslashit( $potential_folder );
204 if ( $this->is_dir( $potential_folder ) ) {
205 $this->cache[ $folder ] = $potential_folder;
206 return $potential_folder;
210 } elseif ( 'direct' == $this->method ) {
211 $folder = str_replace('\\', '/', $folder); // Windows path sanitisation
212 return trailingslashit($folder);
215 $folder = preg_replace('|^([a-z]{1}):|i', '', $folder); // Strip out windows drive letter if it's there.
216 $folder = str_replace('\\', '/', $folder); // Windows path sanitisation
218 if ( isset($this->cache[ $folder ] ) )
219 return $this->cache[ $folder ];
221 if ( $this->exists($folder) ) { // Folder exists at that absolute path.
222 $folder = trailingslashit($folder);
223 $this->cache[ $folder ] = $folder;
226 if ( $return = $this->search_for_folder($folder) )
227 $this->cache[ $folder ] = $return;
232 * Locate a folder on the remote filesystem.
234 * Expects Windows sanitized path.
239 * @param string $folder The folder to locate.
240 * @param string $base The folder to start searching from.
241 * @param bool $loop If the function has recursed, Internal use only.
242 * @return string The location of the remote path.
244 function search_for_folder( $folder, $base = '.', $loop = false ) {
245 if ( empty( $base ) || '.' == $base )
246 $base = trailingslashit($this->cwd());
248 $folder = untrailingslashit($folder);
250 if ( $this->verbose )
251 printf( "\n" . __('Looking for %1$s in %2$s') . "<br/>\n", $folder, $base );
253 $folder_parts = explode('/', $folder);
254 $folder_part_keys = array_keys( $folder_parts );
255 $last_index = array_pop( $folder_part_keys );
256 $last_path = $folder_parts[ $last_index ];
258 $files = $this->dirlist( $base );
260 foreach ( $folder_parts as $index => $key ) {
261 if ( $index == $last_index )
262 continue; // We want this to be caught by the next code block.
264 // Working from /home/ to /user/ to /wordpress/ see if that file exists within the current folder,
265 // If it's found, change into it and follow through looking for it.
266 // If it cant find WordPress down that route, it'll continue onto the next folder level, and see if that matches, and so on.
267 // If it reaches the end, and still cant find it, it'll return false for the entire function.
268 if ( isset($files[ $key ]) ){
269 // Lets try that folder:
270 $newdir = trailingslashit(path_join($base, $key));
271 if ( $this->verbose )
272 printf( "\n" . __('Changing to %s') . "<br/>\n", $newdir );
273 // only search for the remaining path tokens in the directory, not the full path again
274 $newfolder = implode( '/', array_slice( $folder_parts, $index + 1 ) );
275 if ( $ret = $this->search_for_folder( $newfolder, $newdir, $loop) )
280 // Only check this as a last resort, to prevent locating the incorrect install. All above procedures will fail quickly if this is the right branch to take.
281 if (isset( $files[ $last_path ] ) ) {
282 if ( $this->verbose )
283 printf( "\n" . __('Found %s') . "<br/>\n", $base . $last_path );
284 return trailingslashit($base . $last_path);
287 // Prevent this function from looping again.
288 // No need to proceed if we've just searched in /
289 if ( $loop || '/' == $base )
292 // As an extra last resort, Change back to / if the folder wasn't found.
293 // This comes into effect when the CWD is /home/user/ but WP is at /var/www/....
294 return $this->search_for_folder( $folder, '/', true );
299 * Return the *nix-style file permissions for a file.
301 * From the PHP documentation page for fileperms().
303 * @link http://docs.php.net/fileperms
308 * @param string $file String filename.
309 * @return string The *nix-style representation of permissions.
311 function gethchmod( $file ){
312 $perms = $this->getchmod($file);
313 if (($perms & 0xC000) == 0xC000) // Socket
315 elseif (($perms & 0xA000) == 0xA000) // Symbolic Link
317 elseif (($perms & 0x8000) == 0x8000) // Regular
319 elseif (($perms & 0x6000) == 0x6000) // Block special
321 elseif (($perms & 0x4000) == 0x4000) // Directory
323 elseif (($perms & 0x2000) == 0x2000) // Character special
325 elseif (($perms & 0x1000) == 0x1000) // FIFO pipe
331 $info .= (($perms & 0x0100) ? 'r' : '-');
332 $info .= (($perms & 0x0080) ? 'w' : '-');
333 $info .= (($perms & 0x0040) ?
334 (($perms & 0x0800) ? 's' : 'x' ) :
335 (($perms & 0x0800) ? 'S' : '-'));
338 $info .= (($perms & 0x0020) ? 'r' : '-');
339 $info .= (($perms & 0x0010) ? 'w' : '-');
340 $info .= (($perms & 0x0008) ?
341 (($perms & 0x0400) ? 's' : 'x' ) :
342 (($perms & 0x0400) ? 'S' : '-'));
345 $info .= (($perms & 0x0004) ? 'r' : '-');
346 $info .= (($perms & 0x0002) ? 'w' : '-');
347 $info .= (($perms & 0x0001) ?
348 (($perms & 0x0200) ? 't' : 'x' ) :
349 (($perms & 0x0200) ? 'T' : '-'));
354 * Convert *nix-style file permissions to a octal number.
356 * Converts '-rw-r--r--' to 0644
357 * From "info at rvgate dot nl"'s comment on the PHP documentation for chmod()
359 * @link http://docs.php.net/manual/en/function.chmod.php#49614
364 * @param string $mode string The *nix-style file permission.
365 * @return int octal representation
367 function getnumchmodfromh( $mode ) {
369 $legal = array('', 'w', 'r', 'x', '-');
370 $attarray = preg_split('//', $mode);
372 for ($i=0; $i < count($attarray); $i++)
373 if ($key = array_search($attarray[$i], $legal))
374 $realmode .= $legal[$key];
376 $mode = str_pad($realmode, 10, '-', STR_PAD_LEFT);
377 $trans = array('-'=>'0', 'r'=>'4', 'w'=>'2', 'x'=>'1');
378 $mode = strtr($mode,$trans);
381 $newmode .= $mode[1] + $mode[2] + $mode[3];
382 $newmode .= $mode[4] + $mode[5] + $mode[6];
383 $newmode .= $mode[7] + $mode[8] + $mode[9];
388 * Determine if the string provided contains binary characters.
393 * @param string $text String to test against.
394 * @return bool true if string is binary, false otherwise.
396 function is_binary( $text ) {
397 return (bool) preg_match( '|[^\x20-\x7E]|', $text ); // chr(32)..chr(127)
401 * Change the ownership of a file / folder.
403 * Default behavior is to do nothing, override this in your subclass, if desired.
407 * @param string $file Path to the file.
408 * @param mixed $owner A user name or number.
409 * @param bool $recursive Optional. If set True changes file owner recursivly. Defaults to False.
410 * @return bool Returns true on success or false on failure.
412 function chown( $file, $owner, $recursive = false ) {
417 * Connect filesystem.
421 * @return bool True on success or false on failure (always true for WP_Filesystem_Direct).
428 * Read entire file into a string.
432 * @param string $file Name of the file to read.
433 * @return string|bool Returns the read data or false on failure.
435 function get_contents( $file ) {
440 * Read entire file into an array.
444 * @param string $file Path to the file.
445 * @return array|bool the file contents in an array or false on failure.
447 function get_contents_array( $file ) {
452 * Write a string to a file.
456 * @param string $file Remote path to the file where to write the data.
457 * @param string $contents The data to write.
458 * @param int $mode Optional. The file permissions as octal number, usually 0644.
459 * @return bool False on failure.
461 function put_contents( $file, $contents, $mode = false ) {
466 * Get the current working directory.
470 * @return string|bool The current working directory on success, or false on failure.
477 * Change current directory.
481 * @param string $dir The new current directory.
482 * @return bool Returns true on success or false on failure.
484 function chdir( $dir ) {
489 * Change the file group.
493 * @param string $file Path to the file.
494 * @param mixed $group A group name or number.
495 * @param bool $recursive Optional. If set True changes file group recursively. Defaults to False.
496 * @return bool Returns true on success or false on failure.
498 function chgrp( $file, $group, $recursive = false ) {
503 * Change filesystem permissions.
507 * @param string $file Path to the file.
508 * @param int $mode Optional. The permissions as octal number, usually 0644 for files, 0755 for dirs.
509 * @param bool $recursive Optional. If set True changes file group recursively. Defaults to False.
510 * @return bool Returns true on success or false on failure.
512 function chmod( $file, $mode = false, $recursive = false ) {
517 * Get the file owner.
521 * @param string $file Path to the file.
522 * @return string|bool Username of the user or false on error.
524 function owner( $file ) {
529 * Get the file's group.
533 * @param string $file Path to the file.
534 * @return string|bool The group or false on error.
536 function group( $file ) {
545 * @param string $source Path to the source file.
546 * @param string $destination Path to the destination file.
547 * @param bool $overwrite Optional. Whether to overwrite the destination file if it exists.
549 * @param int $mode Optional. The permissions as octal number, usually 0644 for files, 0755 for dirs.
551 * @return bool True if file copied successfully, False otherwise.
553 function copy( $source, $destination, $overwrite = false, $mode = false ) {
562 * @param string $source Path to the source file.
563 * @param string $destination Path to the destination file.
564 * @param bool $overwrite Optional. Whether to overwrite the destination file if it exists.
566 * @return bool True if file copied successfully, False otherwise.
568 function move( $source, $destination, $overwrite = false ) {
573 * Delete a file or directory.
577 * @param string $file Path to the file.
578 * @param bool $recursive Optional. If set True changes file group recursively. Defaults to False.
580 * @param bool $type Type of resource. 'f' for file, 'd' for directory.
582 * @return bool True if the file or directory was deleted, false on failure.
584 function delete( $file, $recursive = false, $type = false ) {
589 * Check if a file or directory exists.
593 * @param string $file Path to file/directory.
594 * @return bool Whether $file exists or not.
596 function exists( $file ) {
601 * Check if resource is a file.
605 * @param string $file File path.
606 * @return bool Whether $file is a file.
608 function is_file( $file ) {
613 * Check if resource is a directory.
617 * @param string $path Directory path.
618 * @return bool Whether $path is a directory.
620 function is_dir( $path ) {
625 * Check if a file is readable.
629 * @param string $file Path to file.
630 * @return bool Whether $file is readable.
632 function is_readable( $file ) {
637 * Check if a file or directory is writable.
641 * @param string $path Path to file/directory.
642 * @return bool Whether $file is writable.
644 function is_writable( $file ) {
649 * Gets the file's last access time.
653 * @param string $file Path to file.
654 * @return int Unix timestamp representing last access time.
656 function atime( $file ) {
661 * Gets the file modification time.
665 * @param string $file Path to file.
666 * @return int Unix timestamp representing modification time.
668 function mtime( $file ) {
673 * Gets the file size (in bytes).
677 * @param string $file Path to file.
678 * @return int Size of the file in bytes.
680 function size( $file ) {
685 * Set the access and modification times of a file.
687 * Note: If $file doesn't exist, it will be created.
691 * @param string $file Path to file.
692 * @param int $time Optional. Modified time to set for file.
694 * @param int $atime Optional. Access time to set for file.
696 * @return bool Whether operation was successful or not.
698 function touch( $file, $time = 0, $atime = 0 ) {
703 * Create a directory.
707 * @param string $path Path for new directory.
708 * @param mixed $chmod Optional. The permissions as octal number, (or False to skip chmod)
710 * @param mixed $chown Optional. A user name or number (or False to skip chown)
712 * @param mixed $chgrp Optional. A group name or number (or False to skip chgrp).
714 * @return bool False if directory cannot be created, true otherwise.
716 function mkdir( $path, $chmod = false, $chown = false, $chgrp = false ) {
721 * Delete a directory.
725 * @param string $path Path to directory.
726 * @param bool $recursive Optional. Whether to recursively remove files/directories.
728 * @return bool Whether directory is deleted successfully or not.
730 function rmdir( $path, $recursive = false ) {
735 * Get details for files in a directory or a specific file.
739 * @param string $path Path to directory or file.
740 * @param bool $include_hidden Optional. Whether to include details of hidden ("." prefixed) files.
742 * @param bool $recursive Optional. Whether to recursively include file details in nested directories.
744 * @return array|bool {
745 * Array of files. False if unable to list directory contents.
747 * @type string 'name' Name of the file/directory.
748 * @type string 'perms' *nix representation of permissions.
749 * @type int 'permsn' Octal representation of permissions.
750 * @type string 'owner' Owner name or ID.
751 * @type int 'size' Size of file in bytes.
752 * @type int 'lastmodunix' Last modified unix timestamp.
753 * @type mixed 'lastmod' Last modified month (3 letter) and day (without leading 0).
754 * @type int 'time' Last modified time.
755 * @type string 'type' Type of resource. 'f' for file, 'd' for directory.
756 * @type mixed 'files' If a directory and $recursive is true, contains another array of files.
759 function dirlist( $path, $include_hidden = true, $recursive = false ) {
763 } // WP_Filesystem_Base