PluginProbe
Import WP – CSV & XML Import Export for WordPress / trunk
Import WP – CSV & XML Import Export for WordPress vtrunk
2.14.24 2.14.23 2.7.0 2.7.1 2.7.10 2.7.11 2.7.12 2.7.13 2.7.14 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.2 2.8.3 2.9.0 2.9.1 trunk 0.1.6 All 142 releases
jc-importer / class / Common / Filesystem / Filesystem.php

Filesystem.php in Import WP – CSV & XML Import Export for WordPress trunk, at class/Common/Filesystem/Filesystem.php

426 lines 13.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace ImportWP\Common\Filesystem;
4
5 use ImportWP\Common\Http\Http;
6 use ImportWP\Common\Util\Logger;
7 use ImportWP\Common\Util\Singleton;
8 use ImportWP\Container;
9 use ImportWP\EventHandler;
10
11 class Filesystem
12 {
13 use Singleton;
14
15 /**
16 * @var ImportWP\Container\Container
17 */
18 private $container;
19
20 /**
21 * @var EventHandler $event_handler
22 */
23 private $event_handler;
24
25 public function __construct(EventHandler $event_handler)
26 {
27 $this->event_handler = $event_handler;
28 $this->container = Container::getInstance();
29 }
30
31 public function copy($source, $destination, $allowed_mimes = null, $filetype = null)
32 {
33
34 if (!file_exists($source)) {
35 Logger::write('File doesn`t exist on local filesystem: ' . $source);
36 return new \WP_Error('IWP_FS_7', __('File doesn`t exist on local filesystem.', 'jc-importer'));
37 }
38
39 if (is_null($filetype)) {
40 $filetype = $this->get_filetype($source);
41 }
42
43 if (!is_null($allowed_mimes)) {
44
45 if (!$filetype) {
46 Logger::write('Unable to determine filetype: ' . $source);
47 return new \WP_Error('IWP_FS_6', __('Unable to determine filetype.', 'jc-importer'));
48 }
49
50 if (!in_array($filetype, $allowed_mimes, true)) {
51 Logger::write('Invalid filetype: ' . $filetype . ', allowed(' . implode(', ', $allowed_mimes) . ')');
52 return new \WP_Error('IWP_FS_4', __('Invalid filetype.', 'jc-importer'));
53 }
54 }
55
56 if (!copy($source, $destination)) {
57 return new \WP_Error('IWP_FS_4', sprintf(__('Unable to copy file: %s.', 'jc-importer'), $source));
58 }
59
60 $type = $this->get_file_mime($source);
61 Logger::write('Copied file: ' . $destination . ' -type=' . $filetype . ' -mime=' . $type);
62 return true;
63 }
64
65 public function upload_file($attachment, $allowed_mimes = null)
66 {
67 // use built in wordpress file upload
68 if (!function_exists('wp_handle_upload')) {
69 require_once ABSPATH . "wp-admin" . '/includes/file.php';
70 }
71
72 $uploaded_file = wp_handle_upload($attachment, ['test_form' => false, 'test_type' => false]);
73
74 if (isset($uploaded_file['error'])) {
75 Logger::write($uploaded_file['error']);
76 return new \WP_Error('IWP_FS_UF', $uploaded_file['error']);
77 }
78
79 $file = $uploaded_file['file'];
80 $type = $uploaded_file['type'];
81
82 $filetype = $this->check_mime_header($uploaded_file['type']);
83
84 // if header doesnt match check for file extension.
85 if (!$filetype) {
86 $filetype = $this->get_filetype_from_ext($attachment['name']);
87 }
88
89 // determine file type from mimetype.
90 if (!is_null($allowed_mimes) && !in_array($filetype, $allowed_mimes, true)) {
91 Logger::write('Invalid filetype: ' . $filetype . ', allowed(' . implode(', ', $allowed_mimes) . ')');
92 return new \WP_Error('IWP_FS_4', __('Invalid filetype.', 'jc-importer'));
93 }
94
95 Logger::write('Uploaded file: ' . $file . ' -type=' . $filetype . ' -mime=' . $type);
96
97 return array(
98 'dest' => $file,
99 'type' => $filetype,
100 'mime' => $type
101 );
102 }
103
104 public function download_file($remote_url, $filetype = null, $allowed_mimes = null, $override_filename = null, $prefix = '')
105 {
106 $remote_url_temp = strtok($remote_url, '?');
107
108 if (!is_null($allowed_mimes)) {
109 if (is_null($filetype)) {
110 $filetype = $this->get_filetype_from_ext($remote_url_temp);
111 }
112 if (!in_array($filetype, $allowed_mimes, true)) {
113 Logger::write('Invalid filetype: ' . $filetype . ', allowed(' . implode(', ', $allowed_mimes) . ')');
114 return new \WP_Error('IWP_FS_4', __('Invalid filetype.', 'jc-importer'));
115 }
116 }
117
118 $wp_upload_dir = wp_upload_dir();
119 $filename = !empty($override_filename) ? $override_filename : $prefix . basename($remote_url_temp);
120
121 // force extension of file if it doesnt match
122 if ($filetype === 'xml') {
123 if (preg_match('/\.(xml|zip|gz)$/', $filename) === 0) {
124 $filename .= '.xml';
125 }
126 } elseif ($filetype === 'csv') {
127 if (preg_match('/\.(csv|zip|gz)$/', $filename) === 0) {
128 $filename .= '.csv';
129 }
130 }
131
132 $dest = wp_unique_filename($wp_upload_dir['path'], $filename);
133 $wp_dest = $wp_upload_dir['path'] . '/' . $dest;
134 touch($wp_dest);
135
136 /**
137 * @var Http $http
138 */
139 $http = Container::getInstance()->get('http');
140
141 $headers = [];
142 if ($filetype === 'xml') {
143 $headers['Content-Type'] = 'text/xml';
144 $headers['Accept'] = 'text/xml';
145 } elseif ($filetype === 'csv') {
146 $headers['Content-Type'] = 'text/csv';
147 $headers['Accept'] = 'text/csv';
148 }
149
150 $result = $http->download_file_stream($remote_url, $wp_dest, $headers);
151 if (is_wp_error($result)) {
152 @unlink($wp_dest);
153 Logger::write($result->get_error_message());
154 return $result;
155 }
156
157 if (is_string($result)) {
158 $filename = !empty($override_filename) ? $override_filename : $prefix . basename($result);
159 $dest = wp_unique_filename($wp_upload_dir['path'], $filename);
160 $wp_tmp_dest = $wp_upload_dir['path'] . '/' . $dest;
161
162 if (copy($wp_dest, $wp_tmp_dest)) {
163 Logger::write('Rename file: ' . $wp_dest . ' -output=' . $wp_tmp_dest);
164 unlink($wp_dest);
165 $wp_dest = $wp_tmp_dest;
166 }
167 }
168
169 $exists = $this->file_exists($wp_dest);
170 if (is_wp_error($exists)) {
171 return $exists;
172 }
173
174 $type = $this->get_file_mime($wp_dest);
175 Logger::write('Downloaded file: ' . $wp_dest . ' -type=' . $filetype . ' -mime=' . $type);
176
177 return array(
178 'dest' => $wp_dest,
179 'type' => $filetype,
180 'mime' => $type
181 );
182 }
183
184 public function file_exists($src)
185 {
186 try {
187 if (!file_exists($src)) {
188 throw new \Exception(sprintf(__("File not found: %s", 'jc-importer'), $src));
189 }
190
191 $size = filesize($src);
192 if ($size == 0) {
193 unlink($src);
194 throw new \Exception(sprintf(__("File not found or empty: %s", 'jc-importer'), $src));
195 }
196 } catch (\Exception $e) {
197 return new \WP_Error('IWP_FS_8', $e->getMessage());
198 }
199
200 return true;
201 }
202
203 public function copy_file($remote_url, $allowed_mimes = null, $override_filename = null, $prefix = '', $filetype = null)
204 {
205 $remote_url = strtok($remote_url, '?');
206
207 $wp_upload_dir = wp_upload_dir();
208
209 $filename = !empty($override_filename) ? $override_filename : $prefix . basename($remote_url);
210 $dest = wp_unique_filename($wp_upload_dir['path'], $filename);
211 $wp_dest = $wp_upload_dir['path'] . '/' . $dest;
212
213 $result = $this->copy($remote_url, $wp_dest, $allowed_mimes, $filetype);
214 if (is_wp_error($result)) {
215 return $result;
216 }
217
218 return array(
219 'dest' => $wp_dest,
220 'type' => is_null($filetype) ? $this->get_filetype($wp_dest) : $filetype,
221 'mime' => $this->get_file_mime($wp_dest)
222 );
223 }
224
225 public function string_to_file($string, $filename)
226 {
227 $wp_upload_dir = wp_upload_dir();
228 $dest = wp_unique_filename($wp_upload_dir['path'], $filename);
229 $wp_dest = $wp_upload_dir['path'] . '/' . $dest;
230
231 if (file_put_contents($wp_dest, $string) === false) {
232 return new \WP_Error('IWP_FS_SF', __("Unable to write string to file", 'jc-importer'));
233 }
234
235 return array(
236 'dest' => $wp_dest,
237 'type' => $this->get_filetype($wp_dest),
238 'mime' => $this->get_file_mime($wp_dest)
239 );
240 }
241
242
243
244 /**
245 * Get and/or create the plugins tmp directory
246 *
247 * @return string
248 */
249
250 public function get_temp_directory($url = false, $folder = 'importwp')
251 {
252 $dir = wp_upload_dir();
253
254 $base = $url ? $dir['baseurl'] : $dir['basedir'];
255 $ds = $url ? '/' : DIRECTORY_SEPARATOR;
256 $path = $base . $ds . $folder;
257
258 // create folders and files if required, force to be dir path instead of url.
259 $dir_path = $dir['basedir'] . DIRECTORY_SEPARATOR . $folder;
260 if (!is_dir($dir_path)) {
261 mkdir($dir_path);
262 }
263
264 if (!file_exists($dir_path . '/.htaccess')) {
265 file_put_contents($dir_path . '/.htaccess', "# Apache 2.4+
266 <IfModule mod_authz_core.c>
267 Require all denied
268 </IfModule>
269
270 # Apache 2.2 and older (or when mod_authz_core isn't available)
271 <IfModule !mod_authz_core.c>
272 Deny from all
273 </IfModule>");
274 }
275
276 if (!file_exists($dir_path . '/index.html')) {
277 touch($dir_path . '/index.html');
278 }
279
280 return $path;
281 }
282
283 /**
284 * Whether a path looks absolute (Unix or Windows).
285 *
286 * @param string $path
287 * @return bool
288 */
289 public static function is_absolute_path($path)
290 {
291 if (!is_string($path) || $path === '') {
292 return false;
293 }
294
295 if ($path[0] === '/' || $path[0] === '\\') {
296 return true;
297 }
298
299 return strlen($path) > 2 && ctype_alpha($path[0]) && $path[1] === ':';
300 }
301
302 /**
303 * Convert an absolute path under the uploads basedir to a relative path.
304 * Paths outside uploads are returned unchanged.
305 *
306 * @param string $path
307 * @return string
308 */
309 public static function to_uploads_relative_path($path)
310 {
311 $path = wp_normalize_path((string) $path);
312 $basedir = wp_normalize_path(untrailingslashit(wp_upload_dir()['basedir']));
313
314 if ($path === $basedir) {
315 return '';
316 }
317
318 if (strpos($path, $basedir . '/') === 0) {
319 return ltrim(substr($path, strlen($basedir)), '/');
320 }
321
322 return $path;
323 }
324
325 /**
326 * Resolve a stored importer file path to an absolute path under the current uploads directory.
327 *
328 * Avoids calling file_exists() on legacy absolute paths that may sit outside open_basedir
329 * after a site move / hosting path change.
330 *
331 * @param string $stored
332 * @return string|false Absolute filesystem path if the file exists, otherwise false.
333 */
334 public static function resolve_importer_file_path($stored)
335 {
336 if (!is_string($stored) || $stored === '') {
337 return false;
338 }
339
340 $stored = wp_normalize_path(trim($stored));
341 $basedir = wp_normalize_path(untrailingslashit(wp_upload_dir()['basedir']));
342 $candidates = [];
343
344 if (self::is_absolute_path($stored)) {
345 if (strpos($stored, $basedir . '/') === 0 || $stored === $basedir) {
346 $candidates[] = $stored;
347 } else {
348 // Remap legacy absolute paths that still contain the importwp suffix.
349 if (preg_match('#/(importwp(?:/[^/]+)*/.+)$#', $stored, $matches)) {
350 $candidates[] = $basedir . '/' . ltrim($matches[1], '/');
351 }
352 $candidates[] = $basedir . '/importwp/uploads/' . basename($stored);
353 }
354 } else {
355 $candidates[] = $basedir . '/' . ltrim($stored, '/');
356 }
357
358 foreach (array_unique($candidates) as $candidate) {
359 $candidate = wp_normalize_path($candidate);
360
361 // Never probe paths outside the current uploads basedir (open_basedir safe).
362 if ($candidate !== $basedir && strpos($candidate, $basedir . '/') !== 0) {
363 continue;
364 }
365
366 if (file_exists($candidate)) {
367 return $candidate;
368 }
369 }
370
371 return false;
372 }
373
374 public function check_mime_header($mime)
375 {
376 switch ($mime) {
377 case 'text/comma-separated-values':
378 case 'text/csv':
379 case 'application/csv':
380 case 'application/excel':
381 case 'application/vnd.ms-excel':
382 case 'application/vnd.msexcel':
383 case 'text/anytext':
384 case 'text/plain':
385 return 'csv';
386 case 'text/xml':
387 case 'application/xml':
388 case 'application/x-xml':
389 return 'xml';
390 }
391
392 return $this->event_handler->run('importer.allowed_mime_types', [false, $mime]);
393 }
394
395 public function get_filetype($file)
396 {
397 $mime_type = $this->get_file_mime($file);
398 if ($mime_type) {
399 return $this->check_mime_header($mime_type);
400 }
401
402 return $this->get_filetype_from_ext($file);
403 }
404
405 public function get_file_mime($file)
406 {
407 $check = wp_check_filetype_and_ext($file, basename($file));
408 return $check['type'];
409 }
410
411 public function get_filetype_from_ext($file)
412 {
413
414 $filetype = null;
415 if (stripos($file, '.csv')) {
416 $filetype = 'csv';
417 } elseif (stripos($file, '.xml')) {
418 $filetype = 'xml';
419 }
420
421 $filetype = apply_filters('iwp/get_filetype_from_ext', $filetype, $file);
422
423 return $filetype;
424 }
425 }
426