Wordpress 3.7
[autoinstalls/wordpress.git] / wp-admin / includes / class-wp-filesystem-base.php
1 <?php
2 /**
3  * Base WordPress Filesystem
4  *
5  * @package WordPress
6  * @subpackage Filesystem
7  */
8
9 /**
10  * Base WordPress Filesystem class for which Filesystem implementations extend
11  *
12  * @since 2.5.0
13  */
14 class WP_Filesystem_Base {
15         /**
16          * Whether to display debug data for the connection.
17          *
18          * @access public
19          * @since 2.5.0
20          * @var bool
21          */
22         var $verbose = false;
23
24         /**
25          * Cached list of local filepaths to mapped remote filepaths.
26          *
27          * @access private
28          * @since 2.7.0
29          * @var array
30          */
31         var $cache = array();
32
33         /**
34          * The Access method of the current connection, Set automatically.
35          *
36          * @access public
37          * @since 2.5.0
38          * @var string
39          */
40         var $method = '';
41
42         /**
43          * Constructor (empty).
44          */
45         function __construct() {}
46
47         /**
48          * Return the path on the remote filesystem of ABSPATH.
49          *
50          * @access public
51          * @since 2.7.0
52          *
53          * @return string The location of the remote path.
54          */
55         function abspath() {
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') )
59                         $folder = '/';
60                 return $folder;
61         }
62
63         /**
64          * Return the path on the remote filesystem of WP_CONTENT_DIR.
65          *
66          * @access public
67          * @since 2.7.0
68          *
69          * @return string The location of the remote path.
70          */
71         function wp_content_dir() {
72                 return $this->find_folder(WP_CONTENT_DIR);
73         }
74
75         /**
76          * Return the path on the remote filesystem of WP_PLUGIN_DIR.
77          *
78          * @access public
79          * @since 2.7.0
80          *
81          * @return string The location of the remote path.
82          */
83         function wp_plugins_dir() {
84                 return $this->find_folder(WP_PLUGIN_DIR);
85         }
86
87         /**
88          * Return the path on the remote filesystem of the Themes Directory.
89          *
90          * @access public
91          * @since 2.7.0
92          *
93          * @param string $theme The Theme stylesheet or template for the directory.
94          * @return string The location of the remote path.
95          */
96         function wp_themes_dir( $theme = false ) {
97                 $theme_root = get_theme_root( $theme );
98
99                 // Account for relative theme roots
100                 if ( '/themes' == $theme_root || ! is_dir( $theme_root ) )
101                         $theme_root = WP_CONTENT_DIR . $theme_root;
102
103                 return $this->find_folder( $theme_root );
104         }
105
106         /**
107          * Return the path on the remote filesystem of WP_LANG_DIR.
108          *
109          * @access public
110          * @since 3.2.0
111          *
112          * @return string The location of the remote path.
113          */
114         function wp_lang_dir() {
115                 return $this->find_folder(WP_LANG_DIR);
116         }
117
118         /**
119          * Locate a folder on the remote filesystem.
120          *
121          * @access public
122          * @since 2.5.0
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()
129          *
130          * @param string $base The folder to start searching from.
131          * @param bool   $echo True to display debug information.
132          *                     Default false.
133          * @return string The location of the remote path.
134          */
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();
139         }
140
141         /**
142          * Locate a folder on the remote filesystem.
143          *
144          * @access public
145          * @since 2.5.0
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()
152          *
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.
156          */
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();
161         }
162
163         /**
164          * Locate a folder on the remote filesystem.
165          *
166          * Assumes that on Windows systems, Stripping off the Drive
167          * letter is OK Sanitizes \\ to / in windows filepaths.
168          *
169          * @access public
170          * @since 2.7.0
171          *
172          * @param string $folder the folder to locate.
173          * @return string The location of the remote path.
174          */
175         function find_folder( $folder ) {
176
177                 if ( isset( $this->cache[ $folder ] ) )
178                         return $this->cache[ $folder ];
179
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
186                         );
187
188                         // Direct matches ( folder = CONSTANT/ )
189                         foreach ( $constant_overrides as $constant => $dir ) {
190                                 if ( ! defined( $constant ) )
191                                         continue;
192                                 if ( $folder === $dir )
193                                         return trailingslashit( constant( $constant ) );
194                         }
195
196                         // Prefix Matches ( folder = CONSTANT/subdir )
197                         foreach ( $constant_overrides as $constant => $dir ) {
198                                 if ( ! defined( $constant ) )
199                                         continue;
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 );
203
204                                         if ( $this->is_dir( $potential_folder ) ) {
205                                                 $this->cache[ $folder ] = $potential_folder;
206                                                 return $potential_folder;
207                                         }
208                                 }
209                         }
210                 } elseif ( 'direct' == $this->method ) {
211                         $folder = str_replace('\\', '/', $folder); // Windows path sanitisation
212                         return trailingslashit($folder);
213                 }
214
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
217
218                 if ( isset($this->cache[ $folder ] ) )
219                         return $this->cache[ $folder ];
220
221                 if ( $this->exists($folder) ) { // Folder exists at that absolute path.
222                         $folder = trailingslashit($folder);
223                         $this->cache[ $folder ] = $folder;
224                         return $folder;
225                 }
226                 if ( $return = $this->search_for_folder($folder) )
227                         $this->cache[ $folder ] = $return;
228                 return $return;
229         }
230
231         /**
232          * Locate a folder on the remote filesystem.
233          *
234          * Expects Windows sanitized path.
235          *
236          * @access private
237          * @since 2.7.0
238          *
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.
243          */
244         function search_for_folder( $folder, $base = '.', $loop = false ) {
245                 if ( empty( $base ) || '.' == $base )
246                         $base = trailingslashit($this->cwd());
247
248                 $folder = untrailingslashit($folder);
249
250                 if ( $this->verbose )
251                         printf( "\n" . __('Looking for %1$s in %2$s') . "<br/>\n", $folder, $base );
252
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 ];
257
258                 $files = $this->dirlist( $base );
259
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.
263
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) )
276                                         return $ret;
277                         }
278                 }
279
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);
285                 }
286
287                 // Prevent this function from looping again.
288                 // No need to proceed if we've just searched in /
289                 if ( $loop || '/' == $base )
290                         return false;
291
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 );
295
296         }
297
298         /**
299          * Return the *nix-style file permissions for a file.
300          *
301          * From the PHP documentation page for fileperms().
302          *
303          * @link http://docs.php.net/fileperms
304          *
305          * @access public
306          * @since 2.5.0
307          *
308          * @param string $file String filename.
309          * @return string The *nix-style representation of permissions.
310          */
311         function gethchmod( $file ){
312                 $perms = $this->getchmod($file);
313                 if (($perms & 0xC000) == 0xC000) // Socket
314                         $info = 's';
315                 elseif (($perms & 0xA000) == 0xA000) // Symbolic Link
316                         $info = 'l';
317                 elseif (($perms & 0x8000) == 0x8000) // Regular
318                         $info = '-';
319                 elseif (($perms & 0x6000) == 0x6000) // Block special
320                         $info = 'b';
321                 elseif (($perms & 0x4000) == 0x4000) // Directory
322                         $info = 'd';
323                 elseif (($perms & 0x2000) == 0x2000) // Character special
324                         $info = 'c';
325                 elseif (($perms & 0x1000) == 0x1000) // FIFO pipe
326                         $info = 'p';
327                 else // Unknown
328                         $info = 'u';
329
330                 // Owner
331                 $info .= (($perms & 0x0100) ? 'r' : '-');
332                 $info .= (($perms & 0x0080) ? 'w' : '-');
333                 $info .= (($perms & 0x0040) ?
334                                         (($perms & 0x0800) ? 's' : 'x' ) :
335                                         (($perms & 0x0800) ? 'S' : '-'));
336
337                 // Group
338                 $info .= (($perms & 0x0020) ? 'r' : '-');
339                 $info .= (($perms & 0x0010) ? 'w' : '-');
340                 $info .= (($perms & 0x0008) ?
341                                         (($perms & 0x0400) ? 's' : 'x' ) :
342                                         (($perms & 0x0400) ? 'S' : '-'));
343
344                 // World
345                 $info .= (($perms & 0x0004) ? 'r' : '-');
346                 $info .= (($perms & 0x0002) ? 'w' : '-');
347                 $info .= (($perms & 0x0001) ?
348                                         (($perms & 0x0200) ? 't' : 'x' ) :
349                                         (($perms & 0x0200) ? 'T' : '-'));
350                 return $info;
351         }
352
353         /**
354          * Convert *nix-style file permissions to a octal number.
355          *
356          * Converts '-rw-r--r--' to 0644
357          * From "info at rvgate dot nl"'s comment on the PHP documentation for chmod()
358          *
359          * @link http://docs.php.net/manual/en/function.chmod.php#49614
360          *
361          * @access public
362          * @since 2.5.0
363          *
364          * @param string $mode string The *nix-style file permission.
365          * @return int octal representation
366          */
367         function getnumchmodfromh( $mode ) {
368                 $realmode = '';
369                 $legal =  array('', 'w', 'r', 'x', '-');
370                 $attarray = preg_split('//', $mode);
371
372                 for ($i=0; $i < count($attarray); $i++)
373                    if ($key = array_search($attarray[$i], $legal))
374                            $realmode .= $legal[$key];
375
376                 $mode = str_pad($realmode, 10, '-', STR_PAD_LEFT);
377                 $trans = array('-'=>'0', 'r'=>'4', 'w'=>'2', 'x'=>'1');
378                 $mode = strtr($mode,$trans);
379
380                 $newmode = $mode[0];
381                 $newmode .= $mode[1] + $mode[2] + $mode[3];
382                 $newmode .= $mode[4] + $mode[5] + $mode[6];
383                 $newmode .= $mode[7] + $mode[8] + $mode[9];
384                 return $newmode;
385         }
386
387         /**
388          * Determine if the string provided contains binary characters.
389          *
390          * @access private
391          * @since 2.7.0
392          *
393          * @param string $text String to test against.
394          * @return bool true if string is binary, false otherwise.
395          */
396         function is_binary( $text ) {
397                 return (bool) preg_match( '|[^\x20-\x7E]|', $text ); // chr(32)..chr(127)
398         }
399
400         /**
401          * Change the ownership of a file / folder.
402          *
403          * Default behavior is to do nothing, override this in your subclass, if desired.
404          *
405          * @since 2.5.0
406          *
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.
411          */
412         function chown( $file, $owner, $recursive = false ) {
413                 return false;
414         }
415
416         /**
417          * Connect filesystem.
418          *
419          * @since 2.5.0
420          *
421          * @return bool True on success or false on failure (always true for WP_Filesystem_Direct).
422          */
423         function connect() {
424                 return true;
425         }
426
427         /**
428          * Read entire file into a string.
429          *
430          * @since 2.5.0
431          *
432          * @param string $file Name of the file to read.
433          * @return string|bool Returns the read data or false on failure.
434          */
435         function get_contents( $file ) {
436                 return false;
437         }
438
439         /**
440          * Read entire file into an array.
441          *
442          * @since 2.5.0
443          *
444          * @param string $file Path to the file.
445          * @return array|bool the file contents in an array or false on failure.
446          */
447         function get_contents_array( $file ) {
448                 return false;
449         }
450
451         /**
452          * Write a string to a file.
453          *
454          * @since 2.5.0
455          *
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.
460          */
461         function put_contents( $file, $contents, $mode = false ) {
462                 return false;
463         }
464
465         /**
466          * Get the current working directory.
467          *
468          * @since 2.5.0
469          *
470          * @return string|bool The current working directory on success, or false on failure.
471          */
472         function cwd() {
473                 return false;
474         }
475
476         /**
477          * Change current directory.
478          *
479          * @since 2.5.0
480          *
481          * @param string $dir The new current directory.
482          * @return bool Returns true on success or false on failure.
483          */
484         function chdir( $dir ) {
485                 return false;
486         }
487
488         /**
489          * Change the file group.
490          *
491          * @since 2.5.0
492          *
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.
497          */
498         function chgrp( $file, $group, $recursive = false ) {
499                 return false;
500         }
501
502         /**
503          * Change filesystem permissions.
504          *
505          * @since 2.5.0
506          *
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.
511          */
512         function chmod( $file, $mode = false, $recursive = false ) {
513                 return false;
514         }
515
516         /**
517          * Get the file owner.
518          *
519          * @since 2.5.0
520          *
521          * @param string $file Path to the file.
522          * @return string|bool Username of the user or false on error.
523          */
524         function owner( $file ) {
525                 return false;
526         }
527
528         /**
529          * Get the file's group.
530          *
531          * @since 2.5.0
532          *
533          * @param string $file Path to the file.
534          * @return string|bool The group or false on error.
535          */
536         function group( $file ) {
537                 return false;
538         }
539
540         /**
541          * Copy a file.
542          *
543          * @since 2.5.0
544          *
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.
548          *                            Default false.
549          * @param int    $mode        Optional. The permissions as octal number, usually 0644 for files, 0755 for dirs.
550          *                            Default false.
551          * @return bool True if file copied successfully, False otherwise.
552          */
553         function copy( $source, $destination, $overwrite = false, $mode = false ) {
554                 return false;
555         }
556
557         /**
558          * Move a file.
559          *
560          * @since 2.5.0
561          *
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.
565          *                            Default false.
566          * @return bool True if file copied successfully, False otherwise.
567          */
568         function move( $source, $destination, $overwrite = false ) {
569                 return false;
570         }
571
572         /**
573          * Delete a file or directory.
574          *
575          * @since 2.5.0
576          *
577          * @param string $file      Path to the file.
578          * @param bool   $recursive Optional. If set True changes file group recursively. Defaults to False.
579          *                          Default false.
580          * @param bool   $type      Type of resource. 'f' for file, 'd' for directory.
581          *                          Default false.
582          * @return bool True if the file or directory was deleted, false on failure.
583          */
584         function delete( $file, $recursive = false, $type = false ) {
585                 return false;
586         }
587
588         /**
589          * Check if a file or directory exists.
590          *
591          * @since 2.5.0
592          *
593          * @param string $file Path to file/directory.
594          * @return bool Whether $file exists or not.
595          */
596         function exists( $file ) {
597                 return false;
598         }
599
600         /**
601          * Check if resource is a file.
602          *
603          * @since 2.5.0
604          *
605          * @param string $file File path.
606          * @return bool Whether $file is a file.
607          */
608         function is_file( $file ) {
609                 return false;
610         }
611
612         /**
613          * Check if resource is a directory.
614          *
615          * @since 2.5.0
616          *
617          * @param string $path Directory path.
618          * @return bool Whether $path is a directory.
619          */
620         function is_dir( $path ) {
621                 return false;
622         }
623
624         /**
625          * Check if a file is readable.
626          *
627          * @since 2.5.0
628          *
629          * @param string $file Path to file.
630          * @return bool Whether $file is readable.
631          */
632         function is_readable( $file ) {
633                 return false;
634         }
635
636         /**
637          * Check if a file or directory is writable.
638          *
639          * @since 2.5.0
640          *
641          * @param string $path Path to file/directory.
642          * @return bool Whether $file is writable.
643          */
644         function is_writable( $file ) {
645                 return false;
646         }
647
648         /**
649          * Gets the file's last access time.
650          *
651          * @since 2.5.0
652          *
653          * @param string $file Path to file.
654          * @return int Unix timestamp representing last access time.
655          */
656         function atime( $file ) {
657                 return false;
658         }
659
660         /**
661          * Gets the file modification time.
662          *
663          * @since 2.5.0
664          *
665          * @param string $file Path to file.
666          * @return int Unix timestamp representing modification time.
667          */
668         function mtime( $file ) {
669                 return false;
670         }
671
672         /**
673          * Gets the file size (in bytes).
674          *
675          * @since 2.5.0
676          *
677          * @param string $file Path to file.
678          * @return int Size of the file in bytes.
679          */
680         function size( $file ) {
681                 return false;
682         }
683
684         /**
685          * Set the access and modification times of a file.
686          *
687          * Note: If $file doesn't exist, it will be created.
688          *
689          * @since 2.5.0
690          *
691          * @param string $file  Path to file.
692          * @param int    $time  Optional. Modified time to set for file.
693          *                      Default 0.
694          * @param int    $atime Optional. Access time to set for file.
695          *                      Default 0.
696          * @return bool Whether operation was successful or not.
697          */
698         function touch( $file, $time = 0, $atime = 0 ) {
699                 return false;
700         }
701
702         /**
703          * Create a directory.
704          *
705          * @since 2.5.0
706          *
707          * @param string $path  Path for new directory.
708          * @param mixed  $chmod Optional. The permissions as octal number, (or False to skip chmod)
709          *                      Default false.
710          * @param mixed  $chown Optional. A user name or number (or False to skip chown)
711          *                      Default false.
712          * @param mixed  $chgrp Optional. A group name or number (or False to skip chgrp).
713          *                      Default false.
714          * @return bool False if directory cannot be created, true otherwise.
715          */
716         function mkdir( $path, $chmod = false, $chown = false, $chgrp = false ) {
717                 return false;
718         }
719
720         /**
721          * Delete a directory.
722          *
723          * @since 2.5.0
724          *
725          * @param string $path      Path to directory.
726          * @param bool   $recursive Optional. Whether to recursively remove files/directories.
727          *                          Default false.
728          * @return bool Whether directory is deleted successfully or not.
729          */
730         function rmdir( $path, $recursive = false ) {
731                 return false;
732         }
733
734         /**
735          * Get details for files in a directory or a specific file.
736          *
737          * @since 2.5.0
738          *
739          * @param string $path           Path to directory or file.
740          * @param bool   $include_hidden Optional. Whether to include details of hidden ("." prefixed) files.
741          *                               Default true.
742          * @param bool   $recursive      Optional. Whether to recursively include file details in nested directories.
743          *                               Default false.
744          * @return array|bool {
745          *     Array of files. False if unable to list directory contents.
746          *
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.
757          * }
758          */
759         function dirlist( $path, $include_hidden = true, $recursive = false ) {
760                 return false;
761         }
762
763 } // WP_Filesystem_Base