1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* |
5
|
|
|
* Class EEH_File |
6
|
|
|
* |
7
|
|
|
* Mostly methods are wrappers for WP_Filesystem. Primarily these methods should be used |
8
|
|
|
* when you intend to WRITE to the filesystem. Many of these methods throw an EE_Error |
9
|
|
|
* when the current filesystem user doesn't have permission to read/write the given file. |
10
|
|
|
* Note: that means if FS_METHOD is defined to be ssh or ftp, and the ftp password isn't |
11
|
|
|
* entered into wp-config.php, code like `EEH_File::is_readable()` will THROW AN EXCEPTION |
12
|
|
|
* when trying ot read anything, unless the user has just entered their ftp/ssh credentials |
13
|
|
|
* into the wp filesystem credentials form. See http://ottopress.com/2011/tutorial-using-the-wp_filesystem/ |
14
|
|
|
* If you want to test your usage of EEH_File and WP_Filesystem, you can use our |
15
|
|
|
* filesystem debugger plugin: https://github.com/eventespresso/filesystem-debug-helper, |
16
|
|
|
* which simulates requiring ftp or ssh to access your site (even if your site is |
17
|
|
|
* actually local and you haven't set it up for ftp or ssh access) |
18
|
|
|
* |
19
|
|
|
* @package Event Espresso |
20
|
|
|
* @subpackage core |
21
|
|
|
* @author Brent Christensen |
22
|
|
|
* |
23
|
|
|
* |
24
|
|
|
*/ |
25
|
|
|
class EEH_File extends EEH_Base implements EEHI_File |
26
|
|
|
{ |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* @var string $_credentials_form |
30
|
|
|
*/ |
31
|
|
|
private static $_credentials_form; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* @var WP_Filesystem_Base $_wp_filesystem |
35
|
|
|
*/ |
36
|
|
|
protected static $_wp_filesystem; |
37
|
|
|
|
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @param string $filepath the filepath we want to work in. If its in the |
41
|
|
|
* wp uploads directory, we'll want to just use the filesystem directly. |
42
|
|
|
* If not provided, we have to assume its not in the uploads directory |
43
|
|
|
* @return WP_Filesystem_Base |
44
|
|
|
*/ |
45
|
|
|
private static function _get_wp_filesystem($filepath = ''): WP_Filesystem_Base |
46
|
|
|
{ |
47
|
|
|
if (apply_filters( |
48
|
|
|
'FHEE__EEH_File___get_wp_filesystem__allow_using_filesystem_direct', |
49
|
|
|
$filepath && EEH_File::is_in_uploads_folder($filepath), |
50
|
|
|
$filepath |
51
|
|
|
) |
52
|
|
|
) { |
53
|
|
|
return EEH_File::loadAlternateWpFileSystem(); |
54
|
|
|
} |
55
|
|
|
return EEH_File::loadWpFileSystem(); |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* @return WP_Filesystem_Base |
61
|
|
|
*/ |
62
|
|
|
private static function loadAlternateWpFileSystem(): WP_Filesystem_Base |
63
|
|
|
{ |
64
|
|
|
if (! EEH_File::$_wp_filesystem instanceof WP_Filesystem_Base) { |
65
|
|
|
require_once(ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php'); |
66
|
|
|
$method = 'direct'; |
67
|
|
|
$wp_filesystem_file = |
68
|
|
|
apply_filters( |
69
|
|
|
'filesystem_method_file', |
70
|
|
|
ABSPATH . 'wp-admin/includes/class-wp-filesystem-' . $method . '.php', |
71
|
|
|
$method |
72
|
|
|
); |
73
|
|
|
// added the following validation logic |
74
|
|
|
// because we allow the filesystem filepath to be filtered, |
75
|
|
|
// and are loading whatever file the path pointed to, |
76
|
|
|
// but we were not validating things in any way :scream_emoji: |
77
|
|
|
$valid_wp_filesystem_types = [ |
78
|
|
|
'direct' => 'WP_Filesystem_Direct', |
79
|
|
|
'ftpext' => 'WP_Filesystem_FTPext', |
80
|
|
|
'ftpsockets' => 'WP_Filesystem_ftpsockets', |
81
|
|
|
'ssh2' => 'WP_Filesystem_SSH2', |
82
|
|
|
]; |
83
|
|
|
$valid = false; |
84
|
|
|
$wp_filesystem_class = ''; |
85
|
|
|
foreach ($valid_wp_filesystem_types as $method => $filesystem_class) { |
86
|
|
|
// if file path matches for one of valid types, then toggle $valid to true |
87
|
|
|
if (strpos($wp_filesystem_file, $method) > 0) { |
88
|
|
|
$valid = true; |
89
|
|
|
$wp_filesystem_class = $filesystem_class; |
90
|
|
|
} |
91
|
|
|
} |
92
|
|
View Code Duplication |
if (! $valid || ! file_exists($wp_filesystem_file)) { |
93
|
|
|
EE_Error::add_error( |
94
|
|
|
sprintf( |
95
|
|
|
esc_html__( |
96
|
|
|
'The supplied WP Filesystem filepath "%1$s" is either missing or invalid.', |
97
|
|
|
'event_espresso' |
98
|
|
|
), |
99
|
|
|
$wp_filesystem_file |
100
|
|
|
), |
101
|
|
|
__FILE__, |
102
|
|
|
__FUNCTION__, |
103
|
|
|
__LINE__ |
104
|
|
|
); |
105
|
|
|
} |
106
|
|
|
// check constants defined, just like in the wp-admin/includes/file.php WP_Filesystem() |
107
|
|
|
if (! defined('FS_CHMOD_DIR')) { |
108
|
|
|
define('FS_CHMOD_DIR', (fileperms(ABSPATH) & 0775 | 0755)); |
109
|
|
|
} |
110
|
|
|
if (! defined('FS_CHMOD_FILE')) { |
111
|
|
|
define('FS_CHMOD_FILE', (fileperms(ABSPATH . 'index.php') & 0775 | 0644)); |
112
|
|
|
} |
113
|
|
|
require_once($wp_filesystem_file); |
114
|
|
|
EEH_File::$_wp_filesystem = new $wp_filesystem_class([]); |
115
|
|
|
} |
116
|
|
|
return EEH_File::$_wp_filesystem; |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* @return WP_Filesystem_Base |
122
|
|
|
*/ |
123
|
|
|
private static function loadWpFileSystem(): WP_Filesystem_Base |
124
|
|
|
{ |
125
|
|
|
global $wp_filesystem; |
126
|
|
|
// no filesystem setup ??? |
127
|
|
|
if (! $wp_filesystem instanceof WP_Filesystem_Base) { |
128
|
|
|
// if some eager beaver's just trying to get in there too early... |
129
|
|
|
// let them do it, because we are one of those eager beavers! :P |
130
|
|
|
/** |
131
|
|
|
* more explanations are probably merited. |
132
|
|
|
* http://codex.wordpress.org/Filesystem_API#Initializing_WP_Filesystem_Base |
133
|
|
|
* says WP_Filesystem should be used after 'wp_loaded', but currently EE's activation process |
134
|
|
|
* is setup to mostly happen on 'init', and refactoring to have it happen on |
135
|
|
|
* 'wp_loaded' is too much work on a BETA milestone. |
136
|
|
|
* So this fix is expected to work if the WP files are owned by the server user, |
137
|
|
|
* but probably not if the user needs to enter their FTP credentials to modify files |
138
|
|
|
* and there may be troubles if the WP files are owned by a different user |
139
|
|
|
* than the server user. But both of these issues should exist in 4.4 and earlier too |
140
|
|
|
*/ |
141
|
|
|
// if (false && ! did_action('wp_loaded')) { |
142
|
|
|
// $msg = |
143
|
|
|
// esc_html__( |
144
|
|
|
// 'An attempt to access and/or write to a file on the server could not be completed due to a lack of sufficient credentials.', |
145
|
|
|
// 'event_espresso' |
146
|
|
|
// ); |
147
|
|
|
// if (WP_DEBUG) { |
148
|
|
|
// $msg .= '<br />' . esc_html__( |
149
|
|
|
// '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.', |
150
|
|
|
// 'event_espresso' |
151
|
|
|
// ); |
152
|
|
|
// } |
153
|
|
|
// EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__); |
154
|
|
|
// } |
155
|
|
|
// should be loaded if we are past the wp_loaded hook... |
156
|
|
|
if (! function_exists('WP_Filesystem') || ! function_exists('submit_button')) { |
157
|
|
|
require_once(ABSPATH . 'wp-admin/includes/file.php'); |
158
|
|
|
require_once(ABSPATH . 'wp-admin/includes/template.php'); |
159
|
|
|
} |
160
|
|
|
// turn on output buffering so that we can capture the credentials form |
161
|
|
|
ob_start(); |
162
|
|
|
$credentials = request_filesystem_credentials(false); |
163
|
|
|
// store credentials form for the time being |
164
|
|
|
EEH_File::$_credentials_form = ob_get_clean(); |
165
|
|
|
// if credentials do NOT exist |
166
|
|
|
if ($credentials === false) { |
167
|
|
|
add_action('admin_notices', ['EEH_File', 'display_request_filesystem_credentials_form'], 999); |
168
|
|
|
EE_Error::add_error( |
169
|
|
|
esc_html__( |
170
|
|
|
'An attempt to access and/or write to a file on the server could not be completed due to a lack of sufficient credentials.', |
171
|
|
|
'event_espresso' |
172
|
|
|
), |
173
|
|
|
__FILE__, |
174
|
|
|
__FUNCTION__, |
175
|
|
|
__LINE__ |
176
|
|
|
); |
177
|
|
|
} |
178
|
|
|
// basically check for direct or previously configured access |
179
|
|
|
if (! WP_Filesystem($credentials) |
180
|
|
|
&& is_wp_error($wp_filesystem->errors) |
181
|
|
|
&& $wp_filesystem->errors->get_error_code() |
182
|
|
|
) { |
183
|
|
|
add_action('admin_notices', ['EEH_File', 'display_request_filesystem_credentials_form'], 999); |
184
|
|
|
EE_Error::add_error( |
185
|
|
|
sprintf( |
186
|
|
|
esc_html__('WP Filesystem Error: $1%s', 'event_espresso'), |
187
|
|
|
$wp_filesystem->errors->get_error_message() |
188
|
|
|
), |
189
|
|
|
__FILE__, |
190
|
|
|
__FUNCTION__, |
191
|
|
|
__LINE__ |
192
|
|
|
); |
193
|
|
|
} |
194
|
|
|
} |
195
|
|
|
return $wp_filesystem; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* display_request_filesystem_credentials_form |
201
|
|
|
*/ |
202
|
|
|
public static function display_request_filesystem_credentials_form() |
203
|
|
|
{ |
204
|
|
|
if (! empty(EEH_File::$_credentials_form)) { |
205
|
|
|
echo '<div class="updated espresso-notices-attention"><p>' . EEH_File::$_credentials_form . '</p></div>'; |
206
|
|
|
} |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
|
210
|
|
|
/** |
211
|
|
|
* verify_filepath_and_permissions |
212
|
|
|
* checks that a file is readable and has sufficient file permissions set to access |
213
|
|
|
* |
214
|
|
|
* @access public |
215
|
|
|
* @param string $full_file_path - full server path to the folder or file |
216
|
|
|
* @param string $file_name - name of file if checking a file |
217
|
|
|
* @param string $file_ext - file extension (ie: "php") if checking a file |
218
|
|
|
* @param string $type_of_file - general type of file (ie: "module"), this is only used to improve error messages |
219
|
|
|
* @return bool |
220
|
|
|
*/ |
221
|
|
|
public static function verify_filepath_and_permissions( |
222
|
|
|
string $full_file_path = '', |
223
|
|
|
string $file_name = '', |
224
|
|
|
string $file_ext = '', |
225
|
|
|
string $type_of_file = '' |
226
|
|
|
): bool { |
227
|
|
|
// load WP_Filesystem and set file permissions |
228
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($full_file_path); |
229
|
|
|
$full_file_path = EEH_File::standardise_directory_separators($full_file_path); |
230
|
|
|
if (! $wp_filesystem->is_readable(EEH_File::convert_local_filepath_to_remote_filepath($full_file_path))) { |
231
|
|
|
$file_name = ! empty($type_of_file) ? $file_name . ' ' . $type_of_file : $file_name; |
232
|
|
|
$file_name .= ! empty($file_ext) ? ' file' : ' folder'; |
233
|
|
|
$msg = sprintf( |
234
|
|
|
esc_html__( |
235
|
|
|
'The requested %1$s could not be found or is not readable, possibly due to an incorrect filepath, or incorrect file permissions.%2$s', |
236
|
|
|
'event_espresso' |
237
|
|
|
), |
238
|
|
|
$file_name, |
239
|
|
|
'<br />' |
240
|
|
|
); |
241
|
|
|
if (EEH_File::exists($full_file_path)) { |
242
|
|
|
$msg .= EEH_File::_permissions_error_for_unreadable_filepath($full_file_path, $type_of_file); |
243
|
|
|
} else { |
244
|
|
|
// no file permissions means the file was not found |
245
|
|
|
$msg .= sprintf( |
246
|
|
|
esc_html__('Please ensure the following path is correct: "%s".', 'event_espresso'), |
247
|
|
|
$full_file_path |
248
|
|
|
); |
249
|
|
|
} |
250
|
|
|
if (defined('WP_DEBUG') && WP_DEBUG) { |
251
|
|
|
EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__); |
252
|
|
|
} |
253
|
|
|
return false; |
254
|
|
|
} |
255
|
|
|
return true; |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
|
259
|
|
|
/** |
260
|
|
|
* _permissions_error_for_unreadable_filepath - attempts to determine why permissions are set incorrectly for a |
261
|
|
|
* file or folder |
262
|
|
|
* |
263
|
|
|
* @access private |
264
|
|
|
* @param string $full_file_path - full server path to the folder or file |
265
|
|
|
* @param string $type_of_file - general type of file (ie: "module"), this is only used to improve error messages |
266
|
|
|
* @return string |
267
|
|
|
*/ |
268
|
|
|
private static function _permissions_error_for_unreadable_filepath( |
269
|
|
|
string $full_file_path = '', |
270
|
|
|
string $type_of_file = '' |
271
|
|
|
): string { |
272
|
|
|
// load WP_Filesystem and set file permissions |
273
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($full_file_path); |
274
|
|
|
// check file permissions |
275
|
|
|
$perms = $wp_filesystem->getchmod(EEH_File::convert_local_filepath_to_remote_filepath($full_file_path)); |
276
|
|
|
if ($perms) { |
277
|
|
|
// file permissions exist, but way be set incorrectly |
278
|
|
|
$type_of_file = ! empty($type_of_file) ? $type_of_file . ' ' : ''; |
279
|
|
|
$type_of_file .= ! empty($type_of_file) ? 'file' : 'folder'; |
280
|
|
|
return ' ' . sprintf( |
281
|
|
|
esc_html__( |
282
|
|
|
'File permissions for the requested %1$s are currently set at "%2$s". The recommended permissions are 644 for files and 755 for folders.', |
283
|
|
|
'event_espresso' |
284
|
|
|
), |
285
|
|
|
$type_of_file, |
286
|
|
|
$perms |
287
|
|
|
); |
288
|
|
|
} else { |
289
|
|
|
// file exists but file permissions could not be read ?!?! |
290
|
|
|
return ' ' . sprintf( |
291
|
|
|
esc_html__( |
292
|
|
|
'Please ensure that the server and/or PHP configuration allows the current process to access the following file: "%s".', |
293
|
|
|
'event_espresso' |
294
|
|
|
), |
295
|
|
|
$full_file_path |
296
|
|
|
); |
297
|
|
|
} |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
|
301
|
|
|
/** |
302
|
|
|
* ensure_folder_exists_and_is_writable |
303
|
|
|
* ensures that a folder exists and is writable, will attempt to create folder if it does not exist |
304
|
|
|
* Also ensures all the parent folders exist, and if not tries to create them. |
305
|
|
|
* Also, if this function creates the folder, adds a .htaccess file and index.html file |
306
|
|
|
* |
307
|
|
|
* @param string $folder |
308
|
|
|
* @return bool false if folder isn't writable; true if it exists and is writeable, |
309
|
|
|
*/ |
310
|
|
|
public static function ensure_folder_exists_and_is_writable(string $folder = ''): bool |
311
|
|
|
{ |
312
|
|
|
if (empty($folder)) { |
313
|
|
|
return false; |
314
|
|
|
} |
315
|
|
|
// remove ending / |
316
|
|
|
$folder = EEH_File::standardise_directory_separators(rtrim($folder, '/\\')); |
317
|
|
|
$parent_folder = EEH_File::get_parent_folder($folder); |
318
|
|
|
// add / to folder |
319
|
|
|
$folder = EEH_File::end_with_directory_separator($folder); |
320
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($folder); |
321
|
|
|
$remote_dir = EEH_File::convert_local_filepath_to_remote_filepath($folder); |
322
|
|
|
if (! $wp_filesystem->is_dir($remote_dir)) { |
323
|
|
|
// ok so it doesn't exist. Does its parent? Can we write to it? |
324
|
|
|
if (! EEH_File::ensure_folder_exists_and_is_writable($parent_folder)) { |
325
|
|
|
return false; |
326
|
|
|
} |
327
|
|
|
if (! EEH_File::verify_is_writable($parent_folder)) { |
328
|
|
|
return false; |
329
|
|
|
} |
330
|
|
View Code Duplication |
if (! $wp_filesystem->mkdir(EEH_File::convert_local_filepath_to_remote_filepath($folder))) { |
331
|
|
|
if (defined('WP_DEBUG') && WP_DEBUG) { |
332
|
|
|
$msg = sprintf(__('"%s" could not be created.', 'event_espresso'), $folder); |
333
|
|
|
$msg .= EEH_File::_permissions_error_for_unreadable_filepath($folder); |
334
|
|
|
EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__); |
335
|
|
|
} |
336
|
|
|
return false; |
337
|
|
|
} |
338
|
|
|
EEH_File::add_index_file($folder); |
339
|
|
|
} elseif (! EEH_File::verify_is_writable($folder)) { |
340
|
|
|
return false; |
341
|
|
|
} |
342
|
|
|
return true; |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
|
346
|
|
|
/** |
347
|
|
|
* verify_is_writable - checks if a file or folder is writable |
348
|
|
|
* |
349
|
|
|
* @param string $full_path - full server path to file or folder |
350
|
|
|
* @param string $file_or_folder - whether checking a file or folder |
351
|
|
|
* @return bool |
352
|
|
|
*/ |
353
|
|
|
public static function verify_is_writable(string $full_path = '', string $file_or_folder = 'folder'): bool |
354
|
|
|
{ |
355
|
|
|
// load WP_Filesystem and set file permissions |
356
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($full_path); |
357
|
|
|
$full_path = EEH_File::standardise_directory_separators($full_path); |
358
|
|
|
$remote_path = EEH_File::convert_local_filepath_to_remote_filepath($full_path); |
359
|
|
|
$remote_path = rtrim($remote_path, '/\\'); |
360
|
|
|
if (! $wp_filesystem->is_writable($remote_path)) { |
361
|
|
|
if (defined('WP_DEBUG') && WP_DEBUG) { |
362
|
|
|
$msg = sprintf(__('The "%1$s" %2$s is not writable.', 'event_espresso'), $full_path, $file_or_folder); |
363
|
|
|
$msg .= EEH_File::_permissions_error_for_unreadable_filepath($full_path); |
364
|
|
|
EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__); |
365
|
|
|
} |
366
|
|
|
return false; |
367
|
|
|
} |
368
|
|
|
return true; |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
|
372
|
|
|
/** |
373
|
|
|
* ensure_file_exists_and_is_writable |
374
|
|
|
* ensures that a file exists and is writable, will attempt to create file if it does not exist. |
375
|
|
|
* Also ensures all the parent folders exist, and if not tries to create them. |
376
|
|
|
* |
377
|
|
|
* @param string $full_file_path |
378
|
|
|
* @return bool |
379
|
|
|
*/ |
380
|
|
|
public static function ensure_file_exists_and_is_writable(string $full_file_path = ''): bool |
381
|
|
|
{ |
382
|
|
|
// load WP_Filesystem and set file permissions |
383
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($full_file_path); |
384
|
|
|
$full_file_path = EEH_File::standardise_directory_separators($full_file_path); |
385
|
|
|
$parent_folder = EEH_File::get_parent_folder($full_file_path); |
386
|
|
|
if (! EEH_File::exists($full_file_path)) { |
387
|
|
|
if (! EEH_File::ensure_folder_exists_and_is_writable($parent_folder)) { |
388
|
|
|
return false; |
389
|
|
|
} |
390
|
|
View Code Duplication |
if (! $wp_filesystem->touch(EEH_File::convert_local_filepath_to_remote_filepath($full_file_path))) { |
391
|
|
|
if (defined('WP_DEBUG') && WP_DEBUG) { |
392
|
|
|
$msg = sprintf(__('The "%s" file could not be created.', 'event_espresso'), $full_file_path); |
393
|
|
|
$msg .= EEH_File::_permissions_error_for_unreadable_filepath($full_file_path); |
394
|
|
|
EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__); |
395
|
|
|
} |
396
|
|
|
return false; |
397
|
|
|
} |
398
|
|
|
} |
399
|
|
|
if (! EEH_File::verify_is_writable($full_file_path, 'file')) { |
400
|
|
|
return false; |
401
|
|
|
} |
402
|
|
|
return true; |
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
|
406
|
|
|
/** |
407
|
|
|
* Gets the parent folder. If provided with file, gets the folder that contains it. |
408
|
|
|
* If provided a folder, gets its parent folder. |
409
|
|
|
* |
410
|
|
|
* @param string $file_or_folder_path |
411
|
|
|
* @return string parent folder, ENDING with a directory separator |
412
|
|
|
*/ |
413
|
|
|
public static function get_parent_folder(string $file_or_folder_path): string |
414
|
|
|
{ |
415
|
|
|
// find the last /, ignoring a / on the very end |
416
|
|
|
// eg if given "/var/something/somewhere/", we want to get "somewhere"'s |
417
|
|
|
// parent folder, "/var/something/" |
418
|
|
|
$ds = strlen($file_or_folder_path) > 1 |
419
|
|
|
? strrpos($file_or_folder_path, '/', -2) |
420
|
|
|
: strlen($file_or_folder_path); |
421
|
|
|
return substr($file_or_folder_path, 0, $ds + 1); |
422
|
|
|
} |
423
|
|
|
|
424
|
|
|
|
425
|
|
|
/** |
426
|
|
|
* get_file_contents |
427
|
|
|
* |
428
|
|
|
* @param string $full_file_path |
429
|
|
|
* @return string |
430
|
|
|
*/ |
431
|
|
|
public static function get_file_contents(string $full_file_path = ''): string |
432
|
|
|
{ |
433
|
|
|
$full_file_path = EEH_File::standardise_directory_separators($full_file_path); |
434
|
|
|
if (EEH_File::verify_filepath_and_permissions( |
435
|
|
|
$full_file_path, |
436
|
|
|
EEH_File::get_filename_from_filepath($full_file_path), |
437
|
|
|
EEH_File::get_file_extension($full_file_path) |
438
|
|
|
) |
439
|
|
|
) { |
440
|
|
|
// load WP_Filesystem and set file permissions |
441
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($full_file_path); |
442
|
|
|
return $wp_filesystem->get_contents(EEH_File::convert_local_filepath_to_remote_filepath($full_file_path)); |
443
|
|
|
} |
444
|
|
|
return ''; |
445
|
|
|
} |
446
|
|
|
|
447
|
|
|
|
448
|
|
|
/** |
449
|
|
|
* write_file |
450
|
|
|
* |
451
|
|
|
* @param string $full_file_path |
452
|
|
|
* @param string $file_contents - the content to be written to the file |
453
|
|
|
* @param string $file_type |
454
|
|
|
* @return bool |
455
|
|
|
*/ |
456
|
|
|
public static function write_to_file( |
457
|
|
|
string $full_file_path = '', |
458
|
|
|
string $file_contents = '', |
459
|
|
|
string $file_type = '' |
460
|
|
|
): bool { |
461
|
|
|
$full_file_path = EEH_File::standardise_directory_separators($full_file_path); |
462
|
|
|
$file_type = ! empty($file_type) ? rtrim($file_type, ' ') . ' ' : ''; |
463
|
|
|
$folder = EEH_File::remove_filename_from_filepath($full_file_path); |
464
|
|
View Code Duplication |
if (! EEH_File::verify_is_writable($folder)) { |
465
|
|
|
if (defined('WP_DEBUG') && WP_DEBUG) { |
466
|
|
|
$msg = |
467
|
|
|
sprintf( |
468
|
|
|
esc_html__('The %1$sfile located at "%2$s" is not writable.', 'event_espresso'), |
469
|
|
|
$file_type, |
470
|
|
|
$full_file_path |
471
|
|
|
); |
472
|
|
|
$msg .= EEH_File::_permissions_error_for_unreadable_filepath($full_file_path); |
473
|
|
|
EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__); |
474
|
|
|
} |
475
|
|
|
return false; |
476
|
|
|
} |
477
|
|
|
// load WP_Filesystem and set file permissions |
478
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($full_file_path); |
479
|
|
|
// write the file |
480
|
|
|
if (! $wp_filesystem->put_contents( |
481
|
|
|
EEH_File::convert_local_filepath_to_remote_filepath($full_file_path), |
482
|
|
|
$file_contents |
483
|
|
|
) |
484
|
|
|
) { |
485
|
|
|
if (defined('WP_DEBUG') && WP_DEBUG) { |
486
|
|
|
$msg = |
487
|
|
|
sprintf( |
488
|
|
|
esc_html__('The %1$sfile located at "%2$s" could not be written to.', 'event_espresso'), |
489
|
|
|
$file_type, |
490
|
|
|
$full_file_path |
491
|
|
|
); |
492
|
|
|
$msg .= EEH_File::_permissions_error_for_unreadable_filepath($full_file_path, 'f'); |
493
|
|
|
EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__); |
494
|
|
|
} |
495
|
|
|
return false; |
496
|
|
|
} |
497
|
|
|
return true; |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
|
501
|
|
|
/** |
502
|
|
|
* Wrapper for WP_Filesystem_Base::delete |
503
|
|
|
* |
504
|
|
|
* @param string $filepath |
505
|
|
|
* @param boolean $recursive |
506
|
|
|
* @param boolean|string $type 'd' for directory, 'f' for file |
507
|
|
|
* @return boolean |
508
|
|
|
*/ |
509
|
|
|
public static function delete(string $filepath, bool $recursive = false, $type = false): bool |
510
|
|
|
{ |
511
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem(); |
512
|
|
|
return $wp_filesystem->delete($filepath, $recursive, $type); |
513
|
|
|
} |
514
|
|
|
|
515
|
|
|
|
516
|
|
|
/** |
517
|
|
|
* exists |
518
|
|
|
* checks if a file exists using the WP filesystem |
519
|
|
|
* |
520
|
|
|
* @param string $full_file_path |
521
|
|
|
* @return bool |
522
|
|
|
*/ |
523
|
|
|
public static function exists(string $full_file_path = ''): bool |
524
|
|
|
{ |
525
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($full_file_path); |
526
|
|
|
return $wp_filesystem->exists(EEH_File::convert_local_filepath_to_remote_filepath($full_file_path)); |
527
|
|
|
} |
528
|
|
|
|
529
|
|
|
|
530
|
|
|
/** |
531
|
|
|
* is_readable |
532
|
|
|
* checks if a file is_readable using the WP filesystem |
533
|
|
|
* |
534
|
|
|
* @param string $full_file_path |
535
|
|
|
* @return bool |
536
|
|
|
*/ |
537
|
|
|
public static function is_readable(string $full_file_path = ''): bool |
538
|
|
|
{ |
539
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($full_file_path); |
540
|
|
|
return $wp_filesystem->is_readable(EEH_File::convert_local_filepath_to_remote_filepath($full_file_path)); |
541
|
|
|
} |
542
|
|
|
|
543
|
|
|
|
544
|
|
|
/** |
545
|
|
|
* remove_filename_from_filepath |
546
|
|
|
* given a full path to a file including the filename itself, this removes the filename and returns the path, up |
547
|
|
|
* to, but NOT including the filename OR slash |
548
|
|
|
* |
549
|
|
|
* @param string $full_file_path |
550
|
|
|
* @return string |
551
|
|
|
*/ |
552
|
|
|
public static function remove_filename_from_filepath(string $full_file_path = ''): string |
553
|
|
|
{ |
554
|
|
|
return pathinfo($full_file_path, PATHINFO_DIRNAME); |
555
|
|
|
} |
556
|
|
|
|
557
|
|
|
|
558
|
|
|
/** |
559
|
|
|
* get_filename_from_filepath. Arguably the same as basename() |
560
|
|
|
* |
561
|
|
|
* @param string $full_file_path |
562
|
|
|
* @return string |
563
|
|
|
*/ |
564
|
|
|
public static function get_filename_from_filepath(string $full_file_path = ''): string |
565
|
|
|
{ |
566
|
|
|
return pathinfo($full_file_path, PATHINFO_BASENAME); |
567
|
|
|
} |
568
|
|
|
|
569
|
|
|
|
570
|
|
|
/** |
571
|
|
|
* get_file_extension |
572
|
|
|
* |
573
|
|
|
* @param string $full_file_path |
574
|
|
|
* @return string |
575
|
|
|
*/ |
576
|
|
|
public static function get_file_extension(string $full_file_path = ''): string |
577
|
|
|
{ |
578
|
|
|
return pathinfo($full_file_path, PATHINFO_EXTENSION); |
579
|
|
|
} |
580
|
|
|
|
581
|
|
|
|
582
|
|
|
/** |
583
|
|
|
* add_htaccess_deny_from_all so the web server cannot access this folder |
584
|
|
|
* |
585
|
|
|
* @param string $folder |
586
|
|
|
* @return bool |
587
|
|
|
*/ |
588
|
|
View Code Duplication |
public static function add_htaccess_deny_from_all(string $folder = ''): bool |
589
|
|
|
{ |
590
|
|
|
$folder = EEH_File::standardise_and_end_with_directory_separator($folder); |
591
|
|
|
if (! EEH_File::exists($folder . '.htaccess')) { |
592
|
|
|
if (! EEH_File::write_to_file($folder . '.htaccess', 'deny from all', '.htaccess')) { |
593
|
|
|
return false; |
594
|
|
|
} |
595
|
|
|
} |
596
|
|
|
|
597
|
|
|
return true; |
598
|
|
|
} |
599
|
|
|
|
600
|
|
|
|
601
|
|
|
/** |
602
|
|
|
* Adds an index file to this folder, so folks can't list all the file's contents |
603
|
|
|
* |
604
|
|
|
* @param string $folder |
605
|
|
|
* @return boolean |
606
|
|
|
*/ |
607
|
|
View Code Duplication |
public static function add_index_file(string $folder): bool |
608
|
|
|
{ |
609
|
|
|
$folder = EEH_File::standardise_and_end_with_directory_separator($folder); |
610
|
|
|
if (! EEH_File::exists($folder . 'index.php')) { |
611
|
|
|
if (! EEH_File::write_to_file( |
612
|
|
|
$folder . 'index.php', |
613
|
|
|
'You are not permitted to read from this folder', |
614
|
|
|
'.php' |
615
|
|
|
) |
616
|
|
|
) { |
617
|
|
|
return false; |
618
|
|
|
} |
619
|
|
|
} |
620
|
|
|
return true; |
621
|
|
|
} |
622
|
|
|
|
623
|
|
|
|
624
|
|
|
/** |
625
|
|
|
* Given that the file in $file_path has the normal name, (ie, CLASSNAME.whatever.php), |
626
|
|
|
* extract that classname. |
627
|
|
|
* |
628
|
|
|
* @param string $file_path |
629
|
|
|
* @return string |
630
|
|
|
*/ |
631
|
|
|
public static function get_classname_from_filepath_with_standard_filename(string $file_path): string |
632
|
|
|
{ |
633
|
|
|
// extract file from path |
634
|
|
|
$filename = basename($file_path); |
635
|
|
|
// now remove the first period and everything after |
636
|
|
|
$pos_of_first_period = strpos($filename, '.'); |
637
|
|
|
return substr($filename, 0, $pos_of_first_period); |
638
|
|
|
} |
639
|
|
|
|
640
|
|
|
|
641
|
|
|
/** |
642
|
|
|
* standardise_directory_separators |
643
|
|
|
* convert all directory separators in a file path. |
644
|
|
|
* |
645
|
|
|
* @param string $file_path |
646
|
|
|
* @param bool $rtrim will remove trailing backslash |
647
|
|
|
* @return string |
648
|
|
|
*/ |
649
|
|
|
public static function standardise_directory_separators(string $file_path, bool $rtrim = false): string |
650
|
|
|
{ |
651
|
|
|
$file_path = $rtrim ? rtrim($file_path, '/\\') : $file_path; |
652
|
|
|
return str_replace(['\\', '/'], '/', $file_path); |
653
|
|
|
} |
654
|
|
|
|
655
|
|
|
|
656
|
|
|
/** |
657
|
|
|
* end_with_directory_separator |
658
|
|
|
* ensures that file path ends with '/' |
659
|
|
|
* |
660
|
|
|
* @param string $file_path |
661
|
|
|
* @return string |
662
|
|
|
*/ |
663
|
|
|
public static function end_with_directory_separator(string $file_path): string |
664
|
|
|
{ |
665
|
|
|
return rtrim($file_path, '/\\') . '/'; |
666
|
|
|
} |
667
|
|
|
|
668
|
|
|
|
669
|
|
|
/** |
670
|
|
|
* shorthand for both EEH_FIle::end_with_directory_separator AND EEH_File::standardise_directory_separators |
671
|
|
|
* |
672
|
|
|
* @param string $file_path |
673
|
|
|
* @return string |
674
|
|
|
*/ |
675
|
|
|
public static function standardise_and_end_with_directory_separator(string $file_path): string |
676
|
|
|
{ |
677
|
|
|
return self::end_with_directory_separator(self::standardise_directory_separators($file_path)); |
678
|
|
|
} |
679
|
|
|
|
680
|
|
|
|
681
|
|
|
/** |
682
|
|
|
* takes the folder name (with or without trailing slash) and finds the files it in, |
683
|
|
|
* and what the class's name inside of each should be. |
684
|
|
|
* |
685
|
|
|
* @param array $folder_paths |
686
|
|
|
* @param boolean $index_numerically if TRUE, the returned array will be indexed numerically; |
687
|
|
|
* if FALSE (Default), returned array will be indexed by the filenames minus |
688
|
|
|
* extensions. Set it TRUE if you know there are files in the directory with the |
689
|
|
|
* same name but different extensions |
690
|
|
|
* @return array if $index_numerically == TRUE keys are numeric , |
691
|
|
|
* if $index_numerically == FALSE (Default) keys are what the class names SHOULD |
692
|
|
|
* be; and values are their file paths |
693
|
|
|
*/ |
694
|
|
|
public static function get_contents_of_folders(array $folder_paths = [], bool $index_numerically = false): array |
695
|
|
|
{ |
696
|
|
|
$class_to_folder_path = []; |
697
|
|
|
foreach ($folder_paths as $folder_path) { |
698
|
|
|
$folder_path = self::standardise_and_end_with_directory_separator($folder_path); |
699
|
|
|
// load WP_Filesystem and set file permissions |
700
|
|
|
$files_in_folder = glob($folder_path . '*.php'); |
701
|
|
|
$class_to_folder_path = []; |
702
|
|
|
if ($files_in_folder) { |
|
|
|
|
703
|
|
|
foreach ($files_in_folder as $file_path) { |
704
|
|
|
// only add files, not folders |
705
|
|
|
if (! is_dir($file_path)) { |
706
|
|
|
if ($index_numerically) { |
707
|
|
|
$class_to_folder_path[] = $file_path; |
708
|
|
|
} else { |
709
|
|
|
$classname = |
710
|
|
|
self::get_classname_from_filepath_with_standard_filename($file_path); |
711
|
|
|
$class_to_folder_path[ $classname ] = $file_path; |
712
|
|
|
} |
713
|
|
|
} |
714
|
|
|
} |
715
|
|
|
} |
716
|
|
|
} |
717
|
|
|
return $class_to_folder_path; |
718
|
|
|
} |
719
|
|
|
|
720
|
|
|
|
721
|
|
|
/** |
722
|
|
|
* Copies a file. Mostly a wrapper of WP_Filesystem::copy |
723
|
|
|
* |
724
|
|
|
* @param string $source_file |
725
|
|
|
* @param string $destination_file |
726
|
|
|
* @param boolean $overwrite |
727
|
|
|
* @return boolean success |
728
|
|
|
*/ |
729
|
|
|
public static function copy(string $source_file, string $destination_file, bool $overwrite = false): bool |
730
|
|
|
{ |
731
|
|
|
$source_file = EEH_File::validateFileForCopyOrMove($source_file); |
732
|
|
|
$destination_file = EEH_File::validateFolderForCopyOrMove($destination_file); |
733
|
|
|
if (! $source_file || ! $destination_file) { |
734
|
|
|
return false; |
735
|
|
|
} |
736
|
|
|
// load WP_Filesystem and set file permissions |
737
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($destination_file); |
738
|
|
|
// write the file |
739
|
|
|
$copied = $wp_filesystem->copy( |
740
|
|
|
EEH_File::convert_local_filepath_to_remote_filepath($source_file), |
741
|
|
|
EEH_File::convert_local_filepath_to_remote_filepath($destination_file), |
742
|
|
|
$overwrite |
743
|
|
|
); |
744
|
|
View Code Duplication |
if (! $copied) { |
745
|
|
|
if (defined('WP_DEBUG') && WP_DEBUG) { |
746
|
|
|
$msg = sprintf( |
747
|
|
|
esc_html__( |
748
|
|
|
'Attempted writing to file %1$s, but could not, probably because of permissions issues', |
749
|
|
|
'event_espresso' |
750
|
|
|
), |
751
|
|
|
$source_file |
752
|
|
|
); |
753
|
|
|
$msg .= EEH_File::_permissions_error_for_unreadable_filepath($source_file, 'f'); |
754
|
|
|
EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__); |
755
|
|
|
} |
756
|
|
|
return false; |
757
|
|
|
} |
758
|
|
|
return true; |
759
|
|
|
} |
760
|
|
|
|
761
|
|
|
|
762
|
|
|
/** |
763
|
|
|
* Reports whether or not the filepath is in the EE uploads folder or not |
764
|
|
|
* |
765
|
|
|
* @param string $filepath |
766
|
|
|
* @return boolean |
767
|
|
|
*/ |
768
|
|
|
public static function is_in_uploads_folder(string $filepath): bool |
769
|
|
|
{ |
770
|
|
|
$uploads = wp_upload_dir(); |
771
|
|
|
return strpos($filepath, $uploads['basedir']) === 0; |
772
|
|
|
} |
773
|
|
|
|
774
|
|
|
|
775
|
|
|
/** |
776
|
|
|
* Given a "local" filepath (what you probably thought was the only filepath), |
777
|
|
|
* converts it into a "remote" filepath (the filepath the currently-in-use |
778
|
|
|
* $wp_filesystem needs to use access the folder or file). |
779
|
|
|
* See http://wordpress.stackexchange.com/questions/124900/using-wp-filesystem-in-plugins |
780
|
|
|
* |
781
|
|
|
* @param string $local_filepath the filepath to the folder/file locally |
782
|
|
|
* @return string the remote filepath (eg the filepath the filesystem method, eg |
783
|
|
|
* ftp or ssh, will use to access the folder |
784
|
|
|
*/ |
785
|
|
|
public static function convert_local_filepath_to_remote_filepath(string $local_filepath): string |
786
|
|
|
{ |
787
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($local_filepath); |
788
|
|
|
return str_replace(WP_CONTENT_DIR . '/', $wp_filesystem->wp_content_dir(), $local_filepath); |
789
|
|
|
} |
790
|
|
|
|
791
|
|
|
|
792
|
|
|
/** |
793
|
|
|
* wrapper for WP_Filesystem::chmod() |
794
|
|
|
* |
795
|
|
|
* @param string $file Path to the file. |
796
|
|
|
* @param int|false $mode Optional. The permissions as octal number, usually 0644 for files, |
797
|
|
|
* 0755 for directories. Default false. |
798
|
|
|
* @param bool $recursive Optional. If set to true, changes file permissions recursively. |
799
|
|
|
* Default false. |
800
|
|
|
* @return bool True on success, false on failure. |
801
|
|
|
*/ |
802
|
|
|
public static function chmod(string $file, $mode = false, bool $recursive = false): bool |
803
|
|
|
{ |
804
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($file); |
805
|
|
|
return $wp_filesystem->chmod($file, $mode, $recursive); |
806
|
|
|
} |
807
|
|
|
|
808
|
|
|
|
809
|
|
|
/** |
810
|
|
|
* wrapper for WP_Filesystem::getchmod() |
811
|
|
|
* |
812
|
|
|
* @param string $file Path to the file. |
813
|
|
|
* @return string Mode of the file (the last 3 digits). |
814
|
|
|
*/ |
815
|
|
|
public static function permissions(string $file): string |
816
|
|
|
{ |
817
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($file); |
818
|
|
|
return $wp_filesystem->getchmod($file); |
819
|
|
|
} |
820
|
|
|
|
821
|
|
|
|
822
|
|
|
/** |
823
|
|
|
* wrapper for WP_Filesystem::owner() |
824
|
|
|
* |
825
|
|
|
* @param string $file Path to the file. |
826
|
|
|
* @return string|false Username of the owner on success, false on failure. |
827
|
|
|
*/ |
828
|
|
|
public static function owner(string $file) |
829
|
|
|
{ |
830
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($file); |
831
|
|
|
return $wp_filesystem->owner($file); |
832
|
|
|
} |
833
|
|
|
|
834
|
|
|
|
835
|
|
|
/** |
836
|
|
|
* wrapper for WP_Filesystem::group() |
837
|
|
|
* |
838
|
|
|
* @param string $file Path to the file. |
839
|
|
|
* @return string|false The group on success, false on failure. |
840
|
|
|
*/ |
841
|
|
|
public static function group(string $file) |
842
|
|
|
{ |
843
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($file); |
844
|
|
|
return $wp_filesystem->group($file); |
845
|
|
|
} |
846
|
|
|
|
847
|
|
|
|
848
|
|
|
/** |
849
|
|
|
* wrapper for WP_Filesystem::move() |
850
|
|
|
* |
851
|
|
|
* @param string $source Path to the source file. |
852
|
|
|
* @param string $destination Path to the destination file. |
853
|
|
|
* @param bool $overwrite Optional. Whether to overwrite the destination file if it exists. |
854
|
|
|
* Default false. |
855
|
|
|
* @return bool True on success, false on failure. |
856
|
|
|
*/ |
857
|
|
|
public static function move(string $source, string $destination, bool $overwrite = false): bool |
858
|
|
|
{ |
859
|
|
|
// throw new RuntimeException("source: {$source} && destination: {$destination}"); |
860
|
|
|
$source = EEH_File::validateFileForCopyOrMove($source); |
861
|
|
|
$destination = EEH_File::validateFolderForCopyOrMove($destination); |
862
|
|
|
if (! $source || ! $destination) { |
863
|
|
|
return false; |
864
|
|
|
} |
865
|
|
|
$wp_filesystem = EEH_File::_get_wp_filesystem($source); |
866
|
|
|
if ($wp_filesystem->move($source, $destination, $overwrite)) { |
867
|
|
|
return true; |
868
|
|
|
} |
869
|
|
|
if (defined('WP_DEBUG') && WP_DEBUG) { |
870
|
|
|
$file = EEH_File::convert_local_filepath_to_remote_filepath($source); |
871
|
|
|
$owner = EEH_File::owner($file); |
872
|
|
|
$group = EEH_File::group($file); |
873
|
|
|
$permissions = EEH_File::permissions($file); |
874
|
|
|
EE_Error::add_error( |
875
|
|
|
sprintf( |
876
|
|
|
esc_html__( |
877
|
|
|
'Unable to move the file "%1$s" to new location (possible permissions errors). The existing "owner:group permissions" for the file are: "%2$s"', |
878
|
|
|
'event_espresso' |
879
|
|
|
), |
880
|
|
|
$destination, |
881
|
|
|
"{$owner}:{$group} $permissions" |
882
|
|
|
), |
883
|
|
|
__FILE__, |
884
|
|
|
__FUNCTION__, |
885
|
|
|
__LINE__ |
886
|
|
|
); |
887
|
|
|
} |
888
|
|
|
return false; |
889
|
|
|
} |
890
|
|
|
|
891
|
|
|
|
892
|
|
|
/** |
893
|
|
|
* @param string $source_file |
894
|
|
|
* @return string |
895
|
|
|
*/ |
896
|
|
|
private static function validateFileForCopyOrMove(string $source_file): string |
897
|
|
|
{ |
898
|
|
|
$full_source_path = EEH_File::standardise_directory_separators($source_file); |
899
|
|
View Code Duplication |
if (! EEH_File::exists($full_source_path)) { |
900
|
|
|
if (defined('WP_DEBUG') && WP_DEBUG) { |
901
|
|
|
$msg = |
902
|
|
|
sprintf( |
903
|
|
|
esc_html__('The file located at "%2$s" is not readable or doesn\'t exist.', 'event_espresso'), |
904
|
|
|
'', |
905
|
|
|
$full_source_path |
906
|
|
|
); |
907
|
|
|
$msg .= EEH_File::_permissions_error_for_unreadable_filepath($full_source_path); |
908
|
|
|
EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__); |
909
|
|
|
} |
910
|
|
|
return ''; |
911
|
|
|
} |
912
|
|
|
return $full_source_path; |
913
|
|
|
} |
914
|
|
|
|
915
|
|
|
|
916
|
|
|
/** |
917
|
|
|
* @param string $destination_file |
918
|
|
|
* @return string |
919
|
|
|
*/ |
920
|
|
|
private static function validateFolderForCopyOrMove(string $destination_file): string |
921
|
|
|
{ |
922
|
|
|
$full_dest_path = EEH_File::standardise_directory_separators($destination_file); |
923
|
|
|
$folder = EEH_File::remove_filename_from_filepath($full_dest_path); |
924
|
|
|
EEH_File::ensure_folder_exists_and_is_writable($folder); |
925
|
|
View Code Duplication |
if (! EEH_File::verify_is_writable($folder)) { |
926
|
|
|
if (defined('WP_DEBUG') && WP_DEBUG) { |
927
|
|
|
$msg = sprintf( |
928
|
|
|
esc_html__('The file located at "%2$s" is not writable.', 'event_espresso'), |
929
|
|
|
'', |
930
|
|
|
$full_dest_path |
931
|
|
|
); |
932
|
|
|
$msg .= EEH_File::_permissions_error_for_unreadable_filepath($full_dest_path); |
933
|
|
|
EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__); |
934
|
|
|
} |
935
|
|
|
return ''; |
936
|
|
|
} |
937
|
|
|
return $full_dest_path; |
938
|
|
|
} |
939
|
|
|
} |
940
|
|
|
|
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.