FileSystemController.php
11.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
<?php
namespace EnableMediaReplace\FileSystem\Controller;
use EnableMediaReplace\ShortpixelLogger\ShortPixelLogger as Log;
use EnableMediaReplace\FileSystem\Model\File\DirectoryModel as DirectoryModel;
use EnableMediaReplace\FileSystem\Model\File\FileModel as FileModel;
/** Controller for FileSystem operations
*
* This controller is used for -compound- ( complex ) FS operations, using the provided models File en Directory.
* USE via \wpSPIO()->filesystem();
*/
Class FileSystemController
{
public function __construct()
{
}
/** Get FileModel for a certain path. This can exist or not
*
* @param String Path Full Path to the file
* @return FileModel FileModel Object. If file does not exist, not all values are set.
*/
public function getFile($path)
{
return new FileModel($path);
}
/** Get DirectoryModel for a certain path. This can exist or not
*
* @param String $path Full Path to the Directory.
* @return DirectoryModel Object with status set on current directory.
*/
public function getDirectory($path)
{
return new DirectoryModel($path);
}
/** This function returns the WordPress Basedir for uploads ( without date and such )
* Normally this would point to /wp-content/uploads.
* @returns DirectoryModel
*/
public function getWPUploadBase()
{
$upload_dir = wp_upload_dir(null, false);
return $this->getDirectory($upload_dir['basedir']);
}
/** This function returns the Absolute Path of the WordPress installation where the **CONTENT** directory is located.
* Normally this would be the same as ABSPATH, but there are installations out there with -cough- alternative approaches
* @returns DirectoryModel Either the ABSPATH or where the WP_CONTENT_DIR is located
*/
public function getWPAbsPath()
{
$wpContentAbs = str_replace( 'wp-content', '', WP_CONTENT_DIR);
if (ABSPATH == $wpContentAbs)
$abspath = ABSPATH;
else
$abspath = $wpContentAbs;
if (defined('UPLOADS')) // if this is set, lead.
$abspath = trailingslashit(ABSPATH) . UPLOADS;
$abspath = apply_filters('shortpixel/filesystem/abspath', $abspath );
return $this->getDirectory($abspath);
}
public function getFullPathForWP(FileModel $file)
{
$fullpath = $file->getFullPath();
$abspath = $this->getWPAbsPath();
if (! strpos($abspath, $fullpath))
{
}
}
/** Utility function that tries to convert a file-path to a webURL.
*
* If possible, rely on other better methods to find URL ( e.g. via WP functions ).
*/
public function pathToUrl(FileModel $file)
{
$filepath = $file->getFullPath();
$directory = $file->getFileDir();
$is_multi_site = (function_exists("is_multisite") && is_multisite()) ? true : false;
$is_main_site = is_main_site();
//$is_multi_site = $this->env->is_multisite;
//$is_main_site = $this->env->is_mainsite;
// stolen from wp_get_attachment_url
if ( ( $uploads = wp_get_upload_dir() ) && (false === $uploads['error'] || strlen(trim($uploads['error'])) == 0 ) ) {
// Check that the upload base exists in the file location.
if ( 0 === strpos( $filepath, $uploads['basedir'] ) ) { // Simple as it should, filepath and basedir share.
// Replace file location with url location.
$url = str_replace( $uploads['basedir'], $uploads['baseurl'], $filepath );
}
// Multisite backups are stored under uploads/ShortpixelBackups/etc , but basedir would include uploads/sites/2 etc, not matching above
// If this is case, test if removing the last two directories will result in a 'clean' uploads reference.
// This is used by getting preview path ( backup pathToUrl) in bulk and for comparer..
elseif ($is_multi_site && ! $is_main_site && 0 === strpos($filepath, dirname(dirname($uploads['basedir']))) )
{
$url = str_replace( dirname(dirname($uploads['basedir'])), dirname(dirname($uploads['baseurl'])), $filepath );
$homeUrl = home_url();
// The result didn't end in a full URL because URL might have less subdirs ( dirname dirname) .
// This happens when site has blogs.dir (sigh) on a subdomain . Try to substitue the ABSPATH root with the home_url
if (strpos($url, $homeUrl) === false)
{
$url = str_replace( trailingslashit(ABSPATH), trailingslashit($homeUrl), $filepath);
}
} elseif ( false !== strpos( $filepath, 'wp-content/uploads' ) ) {
// Get the directory name relative to the basedir (back compat for pre-2.7 uploads)
//$relativePath = $this->getFile(_wp_get_attachment_relative_path( $filepath ) );
//$basename = wp_basename($relativePath->getFullPath());
$url = trailingslashit( $uploads['baseurl'] . '/' . _wp_get_attachment_relative_path( $filepath ) ) . wp_basename( $filepath );
} else {
// It's a newly-uploaded file, therefore $file is relative to the basedir.
$url = $uploads['baseurl'] . "/$filepath";
}
}
$wp_home_path = (string) $this->getWPAbsPath();
// If the whole WP homepath is still in URL, assume the replace when wrong ( not replaced w/ URL)
// This happens when file is outside of wp_uploads_dir
if (strpos($url, $wp_home_path) !== false)
{
// This is SITE URL, for the same reason it should be home_url in FILEMODEL. The difference is when the site is running on a subdirectory
// (1) ** This is a fix for a real-life issue, do not change if this causes issues, another fix is needed then.
// (2) ** Also a real life fix when a path is /wwwroot/assets/sites/2/ etc, in get site url, the home URL is the site URL, without appending the sites stuff. Fails on original image.
if ($is_multi_site && ! $is_main_site)
{
$wp_home_path = trailingslashit($uploads['basedir']);
$home_url = trailingslashit($uploads['baseurl']);
}
else
$home_url = trailingslashit(get_site_url()); // (1)
$url = str_replace($wp_home_path, $home_url, $filepath);
}
// can happen if there are WP path errors.
if (is_null($url))
return false;
$parsed = parse_url($url); // returns array, null, or false.
// Some hosts set the content dir to a relative path instead of a full URL. Api can't handle that, so add domain and such if this is the case.
if ( !isset($parsed['scheme']) ) {//no absolute URLs used -> we implement a hack
if (isset($parsed['host'])) // This is for URL's for // without http or https. hackhack.
{
$scheme = is_ssl() ? 'https:' : 'http:';
return $scheme. $url;
}
else
{
// From Metafacade. Multiple solutions /hacks.
$home_url = trailingslashit((function_exists("is_multisite") && is_multisite()) ? trim(network_site_url("/")) : trim(home_url()));
return $home_url . ltrim($url,'/');//get the file URL
}
}
if (! is_null($parsed) && $parsed !== false)
return $url;
return false;
}
/** Utility function to check if a path is an URL
* Checks if this path looks like an URL.
* @param $path String Path to check
* @return Boolean If path seems domain.
*/
public function pathIsUrl($path)
{
$is_http = (substr($path, 0, 4) == 'http') ? true : false;
$is_https = (substr($path, 0, 5) == 'https') ? true : false;
$is_neutralscheme = (substr($path, 0, 2) == '//') ? true : false; // when URL is relative like //wp-content/etc
$has_urldots = (strpos($path, '://') !== false) ? true : false; // Like S3 offloads
if ($is_http || $is_https || $is_neutralscheme || $has_urldots)
return true;
else
return false;
}
/** Sort files / directories in a certain way.
* Future dev to include options via arg.
*/
public function sortFiles($array, $args = array() )
{
if (count($array) == 0)
return $array;
// what are we sorting.
$class = get_class($array[0]);
$is_files = ($class == 'EnableMediaReplace\FileModel') ? true : false; // if not files, then dirs.
usort($array, function ($a, $b) use ($is_files)
{
if ($is_files)
return strcmp($a->getFileName(), $b->getFileName());
else {
return strcmp($a->getName(), $b->getName());
}
}
);
return $array;
}
public function downloadFile($url, $destinationPath)
{
//$downloadTimeout = defined(SHORTPIXEL_MAX_EXECUTION_TIME) ? max(SHORTPIXEL_MAX_EXECUTION_TIME - 10, 15) :;
$max_exec = intval(ini_get('max_execution_time'));
if ($max_exec === 0) // max execution time of zero means infinite. Quantify.
$max_exec = 60;
elseif($max_exec < 0) // some hosts like to set negative figures on this. Ignore that.
$max_exec = 30;
$downloadTimeout = $max_exec;
$destinationFile = $this->getFile($destinationPath);
$args_for_get = array(
'stream' => true,
'filename' => $destinationPath,
);
$response = wp_remote_get( $url, $args_for_get );
if(is_wp_error( $response )) {
Log::addError('Download file failed', array($url, $response->get_error_messages(), $response->get_error_codes() ));
// Try to get it then via this way.
$response = download_url($url, $downloadTimeout);
if (!is_wp_error($response)) // response when alright is a tmp filepath. But given path can't be trusted since that can be reason for fail.
{
$tmpFile = $this->getFile($response);
$result = $tmpFile->move($destinationFile);
} // download_url ..
else {
Log::addError('Secondary download failed', array($url, $response->get_error_messages(), $response->get_error_codes() ));
}
}
else { // success, at least the download.
$destinationFile = $this->getFile($response['filename']);
}
Log::addDebug('Remote Download attempt result', array($url, $destinationPath));
if ($destinationFile->exists())
return true;
else
return false;
}
/** Get all files from a directory tree, starting at given dir.
* @param DirectoryModel $dir to recursive into
* @param Array $filters Collection of optional filters as accepted by FileFilter in directoryModel
* @return Array Array of FileModel Objects
**/
public function getFilesRecursive(DirectoryModel $dir, $filters = array() )
{
$fileArray = array();
if (! $dir->exists())
return $fileArray;
$files = $dir->getFiles($filters);
$fileArray = array_merge($fileArray, $files);
$subdirs = $dir->getSubDirectories();
foreach($subdirs as $subdir)
{
$fileArray = array_merge($fileArray, $this->getFilesRecursive($subdir, $filters));
}
return $fileArray;
}
// Url very sparingly.
public function url_exists($url)
{
if (! function_exists('curl_init'))
{
return null;
}
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($responseCode == 200)
{
return true;
}
else {
return false;
}
}
}