Completed
Pull Request — master (#2)
by Stephen
13:19
created

WP_Filesystem_MockFS::put_contents()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 3
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
1
<?php
2
class WP_Filesystem_MockFS extends WP_Filesystem_Base {
3
	private $cwd;
4
5
	// Holds a array of objects which contain an array of objects, etc.
6
	private $fs = null;
7
8
	// Holds a array of /path/to/file.php and /path/to/dir/ map to an object in $fs above
9
	// a fast more efficient way of determining if a path exists, and access to that node
10
	private $fs_map = array();
11
12
	public $verbose = false; // Enable to debug WP_Filesystem_Base::find_folder() / etc.
13
	public $errors = array();
14
	public $method = 'MockFS';
15
16
	function __construct() {}
17
18
	function connect() {
19
		return true;
20
	}
21
22
	// Copy of core's function, but accepts a path.
23
	function abspath( $path = false ) {
24
		if ( ! $path )
25
			$path = ABSPATH;
26
		$folder = $this->find_folder( $path );
0 ignored issues
show
Bug introduced by
It seems like $path defined by parameter $path on line 23 can also be of type boolean; however, WP_Filesystem_Base::find_folder() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
27
28
		// Perhaps the FTP folder is rooted at the WordPress install, Check for wp-includes folder in root, Could have some false positives, but rare.
29
		if ( ! $folder && $this->is_dir('/wp-includes') )
0 ignored issues
show
Bug Best Practice introduced by
The expression $folder of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
30
			$folder = '/';
31
		return $folder;
32
	}
33
34
	// Mock FS specific functions:
35
36
	/**
37
	 * Sets initial filesystem environment and/or clears the current environment.
38
	 * Can also be passed the initial filesystem to be setup which is passed to self::setfs()
39
	 */
40
	function init( $paths = '', $home_dir = '/' ) {
41
		$this->fs = new MockFS_Directory_Node( '/' );
42
		$this->fs_map = array(
43
			'/' => $this->fs,
44
		);
45
		$this->cache = array(); // Used by find_folder() and friends
46
		$this->cwd = isset( $this->fs_map[ $home_dir ] ) ? $this->fs_map[ $home_dir ] : '/';
47
		$this->setfs( $paths );
48
	}
49
50
	/**
51
	 * "Bulk Loads" a filesystem into the internal virtual filesystem
52
	 */
53
	function setfs( $paths ) {
54
		if ( ! is_array($paths) )
55
			$paths = explode( "\n", $paths );
56
57
		$paths = array_filter( array_map( 'trim', $paths ) );
58
59
		foreach ( $paths as $path ) {
60
			// Allow for comments
61
			if ( '#' == $path[0] )
62
				continue;
63
64
			// Directories
65
			if ( '/' == $path[ strlen($path) -1 ] )
66
				$this->mkdir( $path );
67
			else // Files (with dummy content for now)
68
				$this->put_contents( $path, 'This is a test file' );
69
		}
70
71
	}
72
73
	/**
74
	 * Locates a filesystem "node"
75
	 */
76
	private function locate_node( $path ) {
77
		return isset( $this->fs_map[ $path ] ) ? $this->fs_map[ $path ] : false;
78
	}
79
80
	/**
81
	 * Locates a filesystem node for the parent of the given item
82
	 */
83
	private function locate_parent_node( $path ) {
84
		$dirname = str_replace( '\\', '/', dirname( $path ) );
85
		return $this->locate_node( trailingslashit( $dirname ) );
86
	}
87
88
	// Here starteth the WP_Filesystem functions.
89
90
	function mkdir( $path, /* Optional args are ignored */ $chmod = false, $chown = false, $chgrp = false ) {
91
		$path = trailingslashit( $path );
92
93
		$parent_node = $this->locate_parent_node( $path );
94
		if ( ! $parent_node ) {
95
			$dirname = str_replace( '\\', '/', dirname( $path ) );
96
			$this->mkdir( $dirname );
97
			$parent_node = $this->locate_parent_node( $path );
98
			if ( ! $parent_node )
99
				return false;
100
		}
101
102
		$node = new MockFS_Directory_Node( $path );
103
104
		$parent_node->children[ $node->name ] = $node;
105
		$this->fs_map[ $path ] = $node;
106
107
		return true;
108
	}
109
110
	function put_contents( $path, $contents = '', $mode = null ) {
111
		if ( ! $this->is_dir( dirname( $path ) ) )
112
			$this->mkdir( dirname( $path ) );
113
114
		$parent = $this->locate_parent_node( $path );
115
		$new_file = new MockFS_File_Node( $path, $contents );
116
117
		$parent->children[ $new_file->name ] = $new_file;
118
		$this->fs_map[ $path ] = $new_file;
119
	}
120
121
	function get_contents( $file ) {
122
		if ( ! $this->is_file( $file ) )
123
			return false;
124
		return $this->fs_map[ $file ]->contents;
125
	}
126
127
	function cwd() {
128
		return $this->cwd->path;
129
	}
130
131
	function chdir( $path ) {
132
		if ( ! isset( $this->fs_map[ $path ] ) )
133
			return false;
134
135
		$this->cwd = $this->fs_map[ $path ];
136
		return true;
137
	}
138
139
	function exists( $path ) {
140
		return isset( $this->fs_map[ $path ] ) || isset( $this->fs_map[ trailingslashit( $path ) ] );
141
	}
142
143
	function is_file( $file ) {
144
		return isset( $this->fs_map[ $file ] ) && $this->fs_map[ $file ]->is_file();
145
	}
146
147
	function is_dir( $path ) {
148
		$path = trailingslashit( $path );
149
150
		return isset( $this->fs_map[ $path ] ) && $this->fs_map[ $path ]->is_dir();
151
	}
152
153
	function dirlist( $path = '.', $include_hidden = true, $recursive = false ) {
154
155
		if ( empty( $path ) || '.' == $path )
156
			$path = $this->cwd();
157
158
		if ( ! $this->exists( $path ) )
159
			return false;
160
161
		$limit_file = false;
162
		if ( $this->is_file( $path ) ) {
163
			$limit_file = $this->locate_node( $path )->name;
164
			$path = dirname( $path ) . '/';
165
		}
166
167
		$ret = array();
168
		foreach ( $this->fs_map[ $path ]->children as $entry ) {
169
			if ( '.' == $entry->name || '..' == $entry->name )
170
				continue;
171
172
			if ( ! $include_hidden && '.' == $entry->name )
173
				continue;
174
175
			if ( $limit_file && $entry->name != $limit_file )
176
				continue;
177
178
			$struc = array();
179
			$struc['name'] = $entry->name;
180
			$struc['type'] = $entry->type;
181
182
			if ( 'd' == $struc['type'] ) {
183
				if ( $recursive )
184
					$struc['files'] = $this->dirlist( trailingslashit( $path ) . trailingslashit( $struc['name'] ), $include_hidden, $recursive );
185
				else
186
					$struc['files'] = array();
187
			}
188
189
			$ret[ $entry->name ] = $struc;
190
		}
191
		return $ret;
192
	}
193
194
}
195
196
class MockFS_Node {
197
	public $name; // The "name" of the entry, does not include a slash (exception, root)
198
	public $type; // The type of the entry 'f' for file, 'd' for Directory
199
	public $path; // The full path to the entry.
200
201
	function __construct( $path ) {
202
		$this->path = $path;
203
		$this->name = basename( $path );
204
	}
205
206
	function is_file() {
207
		return $this->type == 'f';
208
	}
209
210
	function is_dir() {
211
		return $this->type == 'd';
212
	}
213
}
214
215
class MockFS_Directory_Node extends MockFS_Node {
216
	public $type = 'd';
217
	public $children = array(); // The child nodes of this directory
218
}
219
220
class MockFS_File_Node extends MockFS_Node {
221
	public $type = 'f';
222
	public $contents = ''; // The contents of the file
223
224
	function __construct( $path, $contents = '' ) {
225
		parent::__construct( $path );
226
		$this->contents = $contents;
227
	}
228
}