Completed
Branch BUG-9054-ee-config (5f56da)
by
unknown
255:53 queued 241:21
created

EEH_File   D

Complexity

Total Complexity 95

Size/Duplication

Total Lines 602
Duplicated Lines 4.32 %

Coupling/Cohesion

Components 1
Dependencies 2
Metric Value
wmc 95
lcom 1
cbo 2
dl 26
loc 602
rs 4.8639

25 Methods

Rating   Name   Duplication   Size   Complexity  
C _get_wp_filesystem() 0 71 15
A display_request_filesystem_credentials_form() 0 5 2
C verify_filepath_and_permissions() 0 28 7
B _permissions_error_for_unreadable_filepath() 0 22 4
D ensure_folder_exists_and_is_writable() 13 33 9
A verify_is_writable() 0 14 4
C ensure_file_exists_and_is_writable() 13 23 7
A get_parent_folder() 0 7 1
A ensure_folder_exists_recursively() 0 3 1
A get_file_contents() 0 9 2
C write_to_file() 0 25 8
A exists() 0 4 2
A is_readable() 0 8 2
A remove_filename_from_filepath() 0 3 1
A get_filename_from_filepath() 0 3 1
A get_file_extension() 0 3 1
B add_htaccess_deny_from_all() 0 14 5
A get_classname_from_filepath_with_standard_filename() 0 7 1
A standardise_directory_separators() 0 3 1
A end_with_directory_separator() 0 3 1
A standardise_and_end_with_directory_separator() 0 3 1
B get_contents_of_folders() 0 23 6
D copy() 0 38 10
A is_in_uploads_folder() 0 4 2
A convert_local_filepath_to_remote_filepath() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like EEH_File often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EEH_File, and based on these observations, apply Extract Interface, too.

1
<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) exit('No direct script access allowed');
2
/**
3
 *
4
 * Class EEH_File
5
 *
6
 * Description
7
 *
8
 * @package 			Event Espresso
9
 * @subpackage 	core
10
 * @author 				Brent Christensen
11
 * @since 				$VID:$
12
 *
13
 */
14
class EEH_File extends EEH_Base {
15
16
	/**
17
	 * @var string $_credentials_form
18
	 */
19
	private static $_credentials_form;
20
	
21
	protected static $_wp_filesystem_direct;
22
	
23
	/**
24
	 * @param string|null $filepath the filepath we want to work in. If its in the 
25
	 * wp uploads directory, we'll want to just use the filesystem directly.
26
	 * If not provided, we have to assume its not in the uploads directory
27
	 * @throws EE_Error
28
	 * @return WP_Filesystem_Base
29
	 */
30
	private static function _get_wp_filesystem( $filepath = null) {
31
		if( apply_filters( 
32
				'FHEE__EEH_File___get_wp_filesystem__allow_using_filesystem_direct', 
33
				$filepath && EEH_File::is_in_uploads_folder( $filepath ), 
0 ignored issues
show
Bug Best Practice introduced by
The expression $filepath of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null 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...
34
				$filepath ) ) {
35
			if( ! EEH_File::$_wp_filesystem_direct instanceof WP_Filesystem_Direct ) {
0 ignored issues
show
Bug introduced by
The class WP_Filesystem_Direct does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
36
				require_once(ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php');
37
				$method = 'direct';
38
				$wp_filesystem_direct_file = apply_filters( 'filesystem_method_file', ABSPATH . 'wp-admin/includes/class-wp-filesystem-' . $method . '.php', $method );
39
				//check constants defined, just like in wp-admin/includes/file.php's WP_Filesystem()
40
				if ( ! defined('FS_CHMOD_DIR') ) {
41
					define('FS_CHMOD_DIR', ( fileperms( ABSPATH ) & 0777 | 0755 ) );
42
				}
43
				if ( ! defined('FS_CHMOD_FILE') ) {
44
					define('FS_CHMOD_FILE', ( fileperms( ABSPATH . 'index.php' ) & 0777 | 0644 ) );
45
				}
46
				require_once( $wp_filesystem_direct_file );
47
				EEH_File::$_wp_filesystem_direct = new WP_Filesystem_Direct( array() );
48
			}
49
			return EEH_File::$_wp_filesystem_direct;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return \EEH_File::$_wp_filesystem_direct; (WP_Filesystem_Direct) is incompatible with the return type documented by EEH_File::_get_wp_filesystem of type WP_Filesystem_Base.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
50
		}
51
		global $wp_filesystem;
52
		// no filesystem setup ???
53
		if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) {
0 ignored issues
show
Bug introduced by
The class WP_Filesystem_Base does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
54
			// if some eager beaver's just trying to get in there too early...
55
			// let them do it, because we are one of those eager beavers! :P
56
			/**
57
			 * more explanations are probably merited. http://codex.wordpress.org/Filesystem_API#Initializing_WP_Filesystem_Base
58
			 * says WP_Filesystem should be used after 'wp_loaded', but currently EE's activation process
59
			 * is setup to mostly happen on 'init', and refactoring to have it happen on
60
			 * 'wp_loaded' is too much work on a BETA milestone.
61
			 * So this fix is expected to work if the WP files are owned by the server user,
62
			 * but probably not if the user needs to enter their FTP credentials to modify files
63
			 * and there may be troubles if the WP files are owned by a different user
64
			 * than the server user. But both of these issues should exist in 4.4 and earlier too
65
			 */
66
			if ( FALSE && ! did_action( 'wp_loaded' )) {
67
				$msg = __('An attempt to access and/or write to a file on the server could not be completed due to a lack of sufficient credentials.', 'event_espresso');
68
				if ( WP_DEBUG ) {
69
					$msg .= '<br />' .  __('The WP Filesystem can not be accessed until after the "wp_loaded" hook has run, so it\'s best not to attempt access until the "admin_init" hookpoint.', 'event_espresso');
70
				}
71
				throw new EE_Error( $msg );
72
			} else {
73
				// should be loaded if we are past the wp_loaded hook...
74
				if ( ! function_exists( 'WP_Filesystem' )) {
75
					require_once( ABSPATH . 'wp-admin/includes/file.php' );
76
					require_once( ABSPATH . 'wp-admin/includes/template.php' );
77
				}
78
				// turn on output buffering so that we can capture the credentials form
79
				ob_start();
80
				$credentials = request_filesystem_credentials( '' );
81
				// store credentials form for the time being
82
				EEH_File::$_credentials_form = ob_get_clean();
83
				// basically check for direct or previously configured access
84
				if ( ! WP_Filesystem( $credentials ) ) {
85
					// if credentials do NOT exist
86
					if ( $credentials === FALSE ) {
87
						add_action( 'admin_notices', array( 'EEH_File', 'display_request_filesystem_credentials_form' ), 999 );
88
						throw new EE_Error( __('An attempt to access and/or write to a file on the server could not be completed due to a lack of sufficient credentials.', 'event_espresso'));
89
					} elseif( is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) {						
90
						add_action( 'admin_notices', array( 'EEH_File', 'display_request_filesystem_credentials_form' ), 999 );
91
						throw new EE_Error( 
92
								sprintf( 
93
										__( 'WP Filesystem Error: $1%s', 'event_espresso' ), 
94
										$wp_filesystem->errors->get_error_message() ) );
95
					}
96
				}
97
			}
98
		}
99
		return $wp_filesystem;
100
	}
101
102
	/**
103
	 * display_request_filesystem_credentials_form
104
	 */
105
	public static function display_request_filesystem_credentials_form() {
106
		if ( ! empty( EEH_File::$_credentials_form )) {
107
			echo '<div class="updated espresso-notices-attention"><p>' . EEH_File::$_credentials_form . '</p></div>';
108
		}
109
	}
110
111
112
113
	/**
114
	 *    verify_filepath_and_permissions
115
	 *    checks that a file is readable and has sufficient file permissions set to access
116
	 *
117
	 * @access public
118
	 * @param string $full_file_path - full server path to the folder or file
119
	 * @param string $file_name      - name of file if checking a file
120
	 * @param string $file_ext       - file extension (ie: "php") if checking a file
121
	 * @param string $type_of_file   - general type of file (ie: "module"), this is only used to improve error messages
122
	 * @throws EE_Error
123
	 * @return bool
124
	 */
125
	public static function verify_filepath_and_permissions( $full_file_path = '', $file_name = '', $file_ext = '', $type_of_file = '' ) {
126
		// load WP_Filesystem and set file permissions
127
		$wp_filesystem = EEH_File::_get_wp_filesystem( $full_file_path );
128
		$full_file_path = EEH_File::standardise_directory_separators( $full_file_path );
129
		if ( ! $wp_filesystem->is_readable( EEH_File::convert_local_filepath_to_remote_filepath( $full_file_path ) )) {
130
			$file_name = ! empty( $type_of_file ) ? $file_name . ' ' . $type_of_file : $file_name;
131
			$file_name .= ! empty( $file_ext ) ? ' file' : ' folder';
132
			$msg = sprintf(
133
				__( 'The requested %1$s could not be found or is not readable, possibly due to an incorrect filepath, or incorrect file permissions.%2$s', 'event_espresso' ),
134
				$file_name,
135
				'<br />'
136
			);
137
			if ( EEH_File::exists( $full_file_path )) {
138
				$msg .= EEH_File::_permissions_error_for_unreadable_filepath( $full_file_path, $type_of_file );
139
			} else {
140
				// no file permissions means the file was not found
141
				$msg .= sprintf(
142
					__( 'Please ensure the following path is correct: "%s".', 'event_espresso' ),
143
					$full_file_path
144
				);
145
			}
146
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
147
				throw new EE_Error( $msg . '||' . $msg );
148
			}
149
			return FALSE;
150
		}
151
		return TRUE;
152
	}
153
154
155
156
	/**
157
	 * _permissions_error_for_unreadable_filepath - attempts to determine why permissions are set incorrectly for a file or folder
158
	 *
159
	 * @access private
160
	 * @param string $full_file_path - full server path to the folder or file
161
	 * @param string $type_of_file - general type of file (ie: "module"), this is only used to improve error messages
162
	 * @return string
163
	 */
164
	private static function _permissions_error_for_unreadable_filepath( $full_file_path = '', $type_of_file = '' ){
165
		// load WP_Filesystem and set file permissions
166
		$wp_filesystem = EEH_File::_get_wp_filesystem( $full_file_path );
167
		// check file permissions
168
		$perms = $wp_filesystem->getchmod( EEH_File::convert_local_filepath_to_remote_filepath( $full_file_path ) );
169
		if ( $perms ) {
170
			// file permissions exist, but way be set incorrectly
171
			$type_of_file = ! empty( $type_of_file ) ? $type_of_file . ' ' : '';
172
			$type_of_file .= ! empty( $type_of_file ) ? 'file' : 'folder';
173
			return sprintf(
174
				__( 'File permissions for the requested %1$s are currently set at "%2$s". The recommended permissions are 644 for files and 755 for folders.', 'event_espresso' ),
175
				$type_of_file,
176
				$perms
177
			);
178
		} else {
179
			// file exists but file permissions could not be read ?!?!
180
			return sprintf(
181
				__( 'Please ensure that the server and/or PHP configuration allows the current process to access the following file: "%s".', 'event_espresso' ),
182
				$full_file_path
183
			);
184
		}
185
	}
186
187
188
189
	/**
190
	 * ensure_folder_exists_and_is_writable
191
	 * ensures that a folder exists and is writable, will attempt to create folder if it does not exist
192
	 * Also ensures all the parent folders exist, and if not tries to create them.
193
	 * Also, if this function creates the folder, adds a .htaccess file and index.html file
194
	 * @param string $folder
195
	 * @throws EE_Error if the folder exists and is writeable, but for some reason we 
196
	 * can't write to it
197
	 * @return bool false if folder isn't writable; true if it exists and is writeable,
198
	 */
199
	public static function ensure_folder_exists_and_is_writable( $folder = '' ){
200
		if ( empty( $folder )) {
201
			return false;
202
		}
203
		// remove ending DS
204
		$folder = EEH_File::standardise_directory_separators( rtrim( $folder, '/\\' ));
205
		$parent_folder = EEH_File::get_parent_folder( $folder );
206
		// add DS to folder
207
		$folder = EEH_File::end_with_directory_separator( $folder );
208
		$wp_filesystem = EEH_File::_get_wp_filesystem( $folder );
209
		if ( ! $wp_filesystem->is_dir( EEH_File::convert_local_filepath_to_remote_filepath( $folder ) ) ) {
210
			//ok so it doesn't exist. Does its parent? Can we write to it?
211
			if(	! EEH_File::ensure_folder_exists_and_is_writable( $parent_folder ) ) {
212
				return false;
213
			}
214 View Code Duplication
			if ( ! EEH_File::verify_is_writable( $parent_folder, 'folder' )) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
215
				return false;
216
			} else {
217
				if ( ! $wp_filesystem->mkdir( EEH_File::convert_local_filepath_to_remote_filepath(  $folder ) ) ) {
218
					if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
219
						$msg = sprintf( __( '"%s" could not be created.', 'event_espresso' ), $folder );
220
						$msg .= EEH_File::_permissions_error_for_unreadable_filepath( $folder );
221
						throw new EE_Error( $msg );
222
					}
223
					return false;
224
				}
225
				EEH_File::add_htaccess_deny_from_all( $folder );
226
			}
227
		} elseif ( ! EEH_File::verify_is_writable( $folder, 'folder' )) {
228
			return false;
229
		}
230
		return true;
231
	}
232
233
234
235
	/**
236
	 * verify_is_writable - checks if a file or folder is writable
237
	 * @param string $full_path      - full server path to file or folder
238
	 * @param string $file_or_folder - whether checking a file or folder
239
	 * @throws EE_Error
240
	 * @return bool
241
	 */
242
	public static function verify_is_writable( $full_path = '', $file_or_folder = 'folder' ){
243
		// load WP_Filesystem and set file permissions
244
		$wp_filesystem = EEH_File::_get_wp_filesystem( $full_path );
245
		$full_path = EEH_File::standardise_directory_separators( $full_path );
246
		if ( ! $wp_filesystem->is_writable( EEH_File::convert_local_filepath_to_remote_filepath( $full_path ) ) ) {
247
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
248
				$msg = sprintf( __( 'The "%1$s" %2$s is not writable.', 'event_espresso' ), $full_path, $file_or_folder );
249
				$msg .= EEH_File::_permissions_error_for_unreadable_filepath( $full_path );
250
				throw new EE_Error( $msg );
251
			}
252
			return FALSE;
253
		}
254
		return TRUE;
255
	}
256
257
258
259
	/**
260
	 * ensure_file_exists_and_is_writable
261
	 * ensures that a file exists and is writable, will attempt to create file if it does not exist.
262
	 * Also ensures all the parent folders exist, and if not tries to create them.
263
	 * @param string $full_file_path
264
	 * @throws EE_Error
265
	 * @return bool
266
	 */
267
	public static function ensure_file_exists_and_is_writable( $full_file_path = '' ) {
268
		// load WP_Filesystem and set file permissions
269
		$wp_filesystem = EEH_File::_get_wp_filesystem( $full_file_path );
270
		$full_file_path = EEH_File::standardise_directory_separators( $full_file_path );
271
		$parent_folder = EEH_File::get_parent_folder( $full_file_path );
272 View Code Duplication
		if ( ! EEH_File::exists( $full_file_path )) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
273
			if( ! EEH_File::ensure_folder_exists_and_is_writable( $parent_folder ) ) {
274
				return false;
275
			}
276
			if ( ! $wp_filesystem->touch( EEH_File::convert_local_filepath_to_remote_filepath( $full_file_path ) ) ) {
277
				if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
278
					$msg = sprintf( __( 'The "%s" file could not be created.', 'event_espresso' ), $full_file_path );
279
					$msg .= EEH_File::_permissions_error_for_unreadable_filepath( $full_file_path );
280
					throw new EE_Error( $msg );
281
				}
282
				return false;
283
			}
284
		}
285
		if ( ! EEH_File::verify_is_writable( $full_file_path, 'file' )) {
286
			return false;
287
		}
288
		return true;
289
	}
290
	
291
	/**
292
	 * Gets the parent folder. If provided with file, gets the folder that contains it.
293
	 * If provided a folder, gets its parent folder.
294
	 * @param string $file_or_folder_path
295
	 * @return string parent folder, ENDING with a directory separator
296
	 */
297
	public static function get_parent_folder( $file_or_folder_path ) {
298
		//find the last DS, ignoring a DS on the very end
299
		//eg if given "/var/something/somewhere/", we want to get "somewhere"'s
300
		//parent folder, "/var/something/"
301
		$ds = strrpos( $file_or_folder_path, DS, -2 );
302
		return substr( $file_or_folder_path, 0, $ds + 1 );
303
	}
304
	
305
	public static function ensure_folder_exists_recursively( $folder ) {
0 ignored issues
show
Unused Code introduced by
The parameter $folder is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
306
		
307
	}
308
309
310
311
	/**
312
	 * get_file_contents
313
	 * @param string $full_file_path
314
	 * @return string
315
	 */
316
	public static function get_file_contents( $full_file_path = '' ){
317
		$full_file_path = EEH_File::standardise_directory_separators( $full_file_path );
318
		if ( EEH_File::verify_filepath_and_permissions( $full_file_path, EEH_File::get_filename_from_filepath( $full_file_path ) , EEH_File::get_file_extension( $full_file_path ))) {
319
			// load WP_Filesystem and set file permissions
320
			$wp_filesystem = EEH_File::_get_wp_filesystem( $full_file_path );
321
			return $wp_filesystem->get_contents(EEH_File::convert_local_filepath_to_remote_filepath( $full_file_path ) );
322
		}
323
		return '';
324
	}
325
326
327
328
	/**
329
	 * write_file
330
	 * @param string $full_file_path
331
	 * @param string $file_contents - the content to be written to the file
332
	 * @param string $file_type
333
	 * @throws EE_Error
334
	 * @return bool
335
	 */
336
	public static function write_to_file( $full_file_path = '', $file_contents = '', $file_type = '' ){
337
		$full_file_path = EEH_File::standardise_directory_separators( $full_file_path );
338
		$file_type = ! empty( $file_type ) ? rtrim( $file_type, ' ' ) . ' ' : '';
339
		$folder = EEH_File::remove_filename_from_filepath( $full_file_path );
340
		if ( ! EEH_File::verify_is_writable( $folder, 'folder' )) {
341
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
342
				$msg = sprintf( __( 'The %1$sfile located at "%2$s" is not writable.', 'event_espresso' ), $file_type, $full_file_path );
343
				$msg .= EEH_File::_permissions_error_for_unreadable_filepath( $full_file_path );
344
				throw new EE_Error( $msg );
345
			}
346
			return FALSE;
347
		}
348
		// load WP_Filesystem and set file permissions
349
		$wp_filesystem = EEH_File::_get_wp_filesystem( $full_file_path );
350
		// write the file
351
		if ( ! $wp_filesystem->put_contents(EEH_File::convert_local_filepath_to_remote_filepath( $full_file_path ), $file_contents )) {
352
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
353
				$msg = sprintf( __( 'The %1$sfile located at "%2$s" could not be written to.', 'event_espresso' ), $file_type, $full_file_path );
354
				$msg .= EEH_File::_permissions_error_for_unreadable_filepath( $full_file_path, 'f' );
355
				throw new EE_Error( $msg );
356
			}
357
			return FALSE;
358
		}
359
		return TRUE;
360
	}
361
362
363
364
	/**
365
	 * exists
366
	 * checks if a file exists using the WP filesystem
367
	 *
368
	 * @param string $full_file_path
369
	 * @return bool
370
	 */
371
	public static function exists( $full_file_path = '' ) {
372
		$wp_filesystem = EEH_File::_get_wp_filesystem( $full_file_path );
373
		return $wp_filesystem->exists( EEH_File::convert_local_filepath_to_remote_filepath( $full_file_path ) ) ? TRUE : FALSE;
374
	}
375
376
377
378
	/**
379
	 * is_readable
380
	 * checks if a file is_readable using the WP filesystem
381
	 *
382
	 * @param string $full_file_path
383
	 * @return bool
384
	 */
385
	public static function is_readable( $full_file_path = '' ) {
386
		$wp_filesystem = EEH_File::_get_wp_filesystem( $full_file_path );
387
		if( $wp_filesystem->is_readable( EEH_File::convert_local_filepath_to_remote_filepath(  $full_file_path ) ) ) {
388
			return true;
389
		} else {
390
			return false;
391
		}
392
	}
393
394
395
396
	/**
397
	 * remove_filename_from_filepath
398
	 * given a full path to a file including the filename itself, this removes  the filename and returns the path, up to, but NOT including the filename OR slash
399
	 *
400
	 * @param string $full_file_path
401
	 * @return string
402
	 */
403
	public static function remove_filename_from_filepath( $full_file_path = '' ) {
404
		return pathinfo( $full_file_path, PATHINFO_DIRNAME );
405
	}
406
407
408
	/**
409
	 * get_filename_from_filepath. Arguably the same as basename()
410
	 *
411
	 * @param string $full_file_path
412
	 * @return string
413
	 */
414
	public static function get_filename_from_filepath( $full_file_path = '' ) {
415
		return pathinfo( $full_file_path, PATHINFO_BASENAME );
416
	}
417
418
419
	/**
420
	 * get_file_extension
421
	 *
422
	 * @param string $full_file_path
423
	 * @return string
424
	 */
425
	public static function get_file_extension( $full_file_path = '' ) {
426
		return pathinfo( $full_file_path, PATHINFO_EXTENSION );
427
	}
428
429
430
431
	/**
432
	 * add_htaccess_deny_from_all and an index.html file
433
	 * in order to prevent folks from exploring filesystem at their leisure
434
	 * @param string $folder
435
	 * @return bool
436
	 */
437
	public static function add_htaccess_deny_from_all( $folder = '' ) {
438
		$folder = EEH_File::standardise_and_end_with_directory_separator( $folder );
439
		if ( ! EEH_File::exists( $folder . '.htaccess' ) ) {
440
			if ( ! EEH_File::write_to_file( $folder . '.htaccess', 'deny from all', '.htaccess' )) {
441
				return FALSE;
442
			}
443
		}
444
		if ( ! EEH_File::exists( $folder . 'index.html' ) ) {
445
			if ( ! EEH_File::write_to_file( $folder . 'index.html', 'cheating huh?', '.html' )) {
446
				return FALSE;
447
			}
448
		}
449
		return TRUE;
450
	}
451
452
453
454
	/**
455
	 * Given that the file in $file_path has the normal name, (ie, CLASSNAME.whatever.php),
456
	 * extract that classname.
457
	 * @param string $file_path
458
	 * @return string
459
	 */
460
	public static function get_classname_from_filepath_with_standard_filename( $file_path ){
461
		//extract file from path
462
		$filename = basename( $file_path );
463
		//now remove the first period and everything after
464
		$pos_of_first_period = strpos( $filename,'.' );
465
		return substr($filename, 0, $pos_of_first_period);
466
	}
467
468
469
470
	/**
471
	 * standardise_directory_separators
472
	 *  convert all directory separators in a file path to whatever is set for DS
473
	 * @param string $file_path
474
	 * @return string
475
	 */
476
	public static function standardise_directory_separators( $file_path ){
477
		return str_replace( array( '\\', '/' ), DS, $file_path );
478
	}
479
480
481
482
	/**
483
	 * end_with_directory_separator
484
	 *  ensures that file path ends with DS
485
	 * @param string $file_path
486
	 * @return string
487
	 */
488
	public static function end_with_directory_separator( $file_path ){
489
		return rtrim( $file_path, '/\\' ) . DS;
490
	}
491
492
493
494
	/**
495
	 * shorthand for both EEH_FIle::end_with_directory_separator AND EEH_File::standardise_directory_separators
496
	 * @param $file_path
497
	 * @return string
498
	 */
499
	public static function standardise_and_end_with_directory_separator( $file_path ){
500
		return self::end_with_directory_separator( self::standardise_directory_separators( $file_path ));
501
	}
502
503
504
505
	/**
506
	 * takes the folder name (with or without trailing slash) and finds the files it in,
507
	 * and what the class's name inside of each should be.
508
	 * @param array $folder_paths
509
	 * @param boolean $index_numerically if TRUE, the returned array will be indexed numerically;
510
	 *		if FALSE (Default), returned array will be indexed by the filenames minus extensions.
511
	 *		Set it TRUE if you know there are files in the directory with the same name but different extensions
512
	 * @throws \EE_Error
513
	 * @return array if $index_numerically == TRUE keys are numeric ,
514
	 *		if $index_numerically == FALSE (Default) keys are what the class names SHOULD be;
515
	 *		 and values are their filepaths
516
	 */
517
	public static function get_contents_of_folders( $folder_paths = array(), $index_numerically = FALSE ){
518
		$class_to_folder_path = array();
519
		foreach( $folder_paths as $folder_path ){
520
			$folder_path = self::standardise_and_end_with_directory_separator( $folder_path );
521
			// load WP_Filesystem and set file permissions
522
			$files_in_folder = glob( $folder_path . '*' );
523
			$class_to_folder_path = array();
524
			if ( $files_in_folder ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $files_in_folder of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
525
				foreach( $files_in_folder as $file_path ){
526
					//only add files, not folders
527
					if ( ! is_dir( $file_path )) {
528
						if ( $index_numerically ) {
529
							$class_to_folder_path[] = $file_path;
530
						} else {
531
							$classname = self::get_classname_from_filepath_with_standard_filename( $file_path );
532
							$class_to_folder_path[$classname] = $file_path;
533
						}
534
					}
535
				}
536
			}
537
		}
538
		return $class_to_folder_path;
539
	}
540
541
542
543
	/**
544
	 * Copies a file. Mostly a wrapper of WP_Filesystem::copy
545
	 * @param string $source_file
546
	 * @param string $destination_file
547
	 * @param boolean $overwrite
548
	 * @return boolean success
549
	 * @throws EE_Error
550
	 */
551
	public static function copy( $source_file, $destination_file, $overwrite = FALSE ){
552
		$full_source_path = EEH_File::standardise_directory_separators( $source_file );
553
		if( ! EEH_File::exists( $full_source_path ) ){
554
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
555
				$msg = sprintf( __( 'The file located at "%2$s" is not readable or doesn\'t exist.', 'event_espresso' ), $full_source_path );
556
				$msg .= EEH_File::_permissions_error_for_unreadable_filepath( $full_source_path );
557
				throw new EE_Error( $msg );
558
			}
559
			return FALSE;
560
		}
561
562
		$full_dest_path = EEH_File::standardise_directory_separators( $destination_file );
563
		$folder = EEH_File::remove_filename_from_filepath( $full_dest_path );
564
		if ( ! EEH_File::verify_is_writable( $folder, 'folder' )) {
565
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
566
				$msg = sprintf( __( 'The file located at "%2$s" is not writable.', 'event_espresso' ), $full_dest_path );
567
				$msg .= EEH_File::_permissions_error_for_unreadable_filepath( $full_dest_path );
568
				throw new EE_Error( $msg );
569
			}
570
			return FALSE;
571
		}
572
573
		// load WP_Filesystem and set file permissions
574
		$wp_filesystem = EEH_File::_get_wp_filesystem( $destination_file );
575
		// write the file
576
		if ( ! $wp_filesystem->copy( 
577
						EEH_File::convert_local_filepath_to_remote_filepath( $full_source_path ), 
578
						EEH_File::convert_local_filepath_to_remote_filepath( $full_dest_path ), 
579
						$overwrite )) {
580
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
581
				$msg = sprintf( __( 'Attempted writing to file %1$s, but could not, probably because of permissions issues', 'event_espresso' ), $full_source_path );
582
				$msg .= EEH_File::_permissions_error_for_unreadable_filepath( $full_source_path, 'f' );
583
				throw new EE_Error( $msg );
584
			}
585
			return FALSE;
586
		}
587
		return TRUE;
588
	}
589
	
590
	/**
591
	 * Reports whether or not the filepath is in the EE uploads folder or not
592
	 * @param string $filepath
593
	 * @return boolean
594
	 */
595
	public static function is_in_uploads_folder( $filepath ) {
596
		$uploads = wp_upload_dir();
597
		return strpos( $filepath, $uploads[ 'basedir' ] ) === 0 ? true : false;
598
	}
599
	
600
	/**
601
	 * Given a "local" filepath (what you probably thought was the only filepath),
602
	 * converts it into a "remote" filepath (the filepath the currently-in-use 
603
	 * $wp_filesystem needs to use access the folder or file).
604
	 * See http://wordpress.stackexchange.com/questions/124900/using-wp-filesystem-in-plugins
605
	 * @param WP_Filesystem_Base $wp_filesystem we aren't initially sure which one
0 ignored issues
show
Bug introduced by
There is no parameter named $wp_filesystem. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
606
	 * is in use, so you need to provide it
607
	 * @param string $local_filepath the filepath to the folder/file locally
608
	 * @return string the remote filepath (eg the filepath the filesystem method, eg 
609
	 * ftp or ssh, will use to access the folder
610
	 */
611
	public static function convert_local_filepath_to_remote_filepath( $local_filepath ) {
612
		$wp_filesystem = EEH_File::_get_wp_filesystem( $local_filepath );
613
		return str_replace( WP_CONTENT_DIR . DS, $wp_filesystem->wp_content_dir(), $local_filepath );
614
	}
615
}
616
// End of file EEH_File.helper.php
617
// Location: /helpers/EEH_File.helper.php