Diff: STRATO-apps/wordpress_03/app/wp-content/plugins/fluentformpro/src/Uploader.php

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
1 + <?php
2 +
3 + namespace FluentFormPro;
4 +
5 + use FluentForm\App\Modules\Form\FormHandler;
6 + use FluentForm\App\Modules\Form\FormFieldsParser;
7 + use FluentForm\Framework\Helpers\ArrayHelper;
8 +
9 + class Uploader extends FormHandler
10 + {
11 + /**
12 + * Uploads files to the server.
13 + */
14 + public function upload()
15 + {
16 + $formId = intval($this->request->get('formId'));
17 +
18 + $attributes = $this->request->all();
19 +
20 + $sanitizeMap = [
21 + 'formId' => 'intval',
22 + ];
23 + $attributes = fluentform_backend_sanitizer($attributes, $sanitizeMap);
24 +
25 + $this->formData = $attributes;
26 +
27 + if ($formId) {
28 + $this->setForm($formId);
29 +
30 + $this->validateNonce();
31 +
32 + if ($this->form) {
33 + // Get the HTTP files. It'll be an array with always one item.
34 + $files = $this->request->files();
35 +
36 + do_action_deprecated(
37 + 'fluentform_starting_file_upload',
38 + [
39 + $files,
40 + $this->form
41 + ],
42 + FLUENTFORM_FRAMEWORK_UPGRADE,
43 + 'fluentform/starting_file_upload',
44 + 'Use fluentform/starting_file_upload instead of fluentform_starting_file_upload.'
45 + );
46 +
47 + do_action('fluentform/starting_file_upload', $files, $this->form);
48 +
49 + // Get the form attribute name then.
50 + $arrayKeys = array_keys($files);
51 + $attribute = array_pop($arrayKeys);
52 +
53 + // Get the specific form field by using the element type and it's attribute name.
54 + $field = FormFieldsParser::getField(
55 + $this->form,
56 + ['input_file', 'input_image', 'featured_image'],
57 + $attribute,
58 + ['rules', 'settings']
59 + );
60 +
61 + if ($field) {
62 + // Extract the validation rules & messages for file upload element.
63 + list($rules, $messages) = FormFieldsParser::getValidations(
64 + $this->form,
65 + $files,
66 + $field
67 + );
68 + /**
69 + * Delegate 'max_file_size', 'allowed_file_types' rules & messages to
70 + * 'max', 'mimes' since the validation library doesn't recognise those
71 + */
72 + list($rules, $messages) = $this->delegateValidations($rules, $messages);
73 + $delegateValidations = apply_filters_deprecated(
74 + 'fluentform_file_upload_validations',
75 + [
76 + [$rules, $messages],
77 + $this->form
78 + ],
79 + FLUENTFORM_FRAMEWORK_UPGRADE,
80 + 'fluentform/file_upload_validations',
81 + 'Use fluentform/file_upload_validations instead of fluentform_file_upload_validations.'
82 + );
83 +
84 + // Fire an event so that one can hook into it to work with the rules & messages.
85 + $validations = $this->app->applyFilters(
86 + 'fluentform/file_upload_validations',
87 + $delegateValidations,
88 + $this->form
89 + );
90 +
91 + $validator = fluentValidator(
92 + $files,
93 + $validations[0],
94 + $validations[1]
95 + );
96 +
97 + if ($validator->validate()->fails()) {
98 + $errors = $validator->errors();
99 + $errors = apply_filters_deprecated(
100 + 'fluentform_file_upload_validation_error',
101 + [
102 + $errors,
103 + $this->form
104 + ],
105 + FLUENTFORM_FRAMEWORK_UPGRADE,
106 + 'fluentform/file_upload_validation_error',
107 + 'Use fluentform/file_upload_validation_error instead of fluentform_file_upload_validation_error.'
108 + );
109 + // Fire an event so that one can hook into it to work with the errors.
110 + $errors = $this->app->applyFilters(
111 + 'fluentform/file_upload_validation_error',
112 + $errors,
113 + $this->form
114 + );
115 +
116 + wp_send_json([
117 + 'errors' => $errors
118 + ], 422);
119 + }
120 +
121 + // let's upload to a temp location
122 + $field = current($field);
123 +
124 + //add default upload location for old inputs
125 + if (!$uploadLocation = ArrayHelper::get($field, 'settings.upload_file_location')) {
126 + $uploadLocation = 'default';
127 + }
128 +
129 + $uploadedFiles = [];
130 + if (!empty($uploadLocation)) {
131 + $this->overrideUploadDir();
132 + $uploadedFiles = $this->uploadToTemp($files, $field);
133 + }
134 +
135 + wp_send_json_success([
136 + 'files' => $uploadedFiles
137 + ], 200);
138 + }
139 + }
140 + }
141 + }
142 +
143 + /**
144 + * Uploads files to its target locations
145 + * @return void
146 + */
147 + public function processFiles()
148 + {
149 + $fileTypes = ['input_file', 'input_image', 'featured_image'];
150 +
151 + foreach ($fileTypes as $fileType) {
152 + add_filter('fluentform/input_data_' . $fileType, function ($files, $field, $formData, $form) {
153 + if (!$this->form) {
154 + $this->setForm($form->id);
155 + }
156 + $uploadLocation = $this->getUploadLocation($field);
157 + $files = is_array($files) ? $files : [$files];
158 +
159 + $isSkip = apply_filters('fluentform/skip_cloud_file_decryption', false);
160 +
161 + if (!$isSkip) {
162 + $files = $this->maybeDecrypt($files);
163 + }
164 +
165 + do_action_deprecated(
166 + 'fluentform_starting_file_processing',
167 + [
168 + $files,
169 + $uploadLocation,
170 + $formData,
171 + $form
172 + ],
173 + FLUENTFORM_FRAMEWORK_UPGRADE,
174 + 'fluentform/starting_file_processing',
175 + 'Use fluentform/starting_file_processing instead of fluentform_starting_file_processing.'
176 + );
177 + do_action('fluentform/starting_file_processing', $files, $uploadLocation, $formData, $form);
178 + $this->initUploads($files, $uploadLocation, $formData);
179 + $formattedFiles = [];
180 + foreach ($files as $file) {
181 + $formattedFiles[] = $this->getProcessedUrl($file, $uploadLocation);
182 + }
183 + return $formattedFiles;
184 + }, 10, 4);
185 + }
186 + }
187 +
188 + /**
189 + * Register filters for custom upload dir
190 + */
191 + public function overrideUploadDir()
192 + {
193 + add_filter('wp_handle_upload_prefilter', function ($file) {
194 + add_filter('upload_dir', [$this, 'setCustomUploadDir']);
195 +
196 + add_filter('wp_handle_upload', function ($fileinfo) {
197 + remove_filter('upload_dir', [$this, 'setCustomUploadDir']);
198 + $fileinfo['file'] = basename($fileinfo['file']);
199 + return $fileinfo;
200 + });
201 +
202 + return $this->renameFileName($file);
203 + });
204 + }
205 +
206 + /**
207 + * Set plugin's custom upload dir
208 + * @param array $param
209 + * @return array $param
210 + */
211 + public function setCustomUploadDir($param)
212 + {
213 + $param['url'] = $param['baseurl'] . FLUENTFORM_UPLOAD_DIR . '/temp';
214 + $param['path'] = $param['basedir'] . FLUENTFORM_UPLOAD_DIR . '/temp';
215 +
216 + $param = apply_filters_deprecated(
217 + 'fluentform_file_upload_params',
218 + [
219 + $param,
220 + $this->formData,
221 + $this->form
222 + ],
223 + FLUENTFORM_FRAMEWORK_UPGRADE,
224 + 'fluentform/file_upload_params',
225 + 'Use fluentform/file_upload_params instead of fluentform_file_upload_params.'
226 + );
227 +
228 + $param = apply_filters('fluentform/file_upload_params', $param, $this->formData, $this->form);
229 +
230 + $this->secureDirectory($param['path']);
231 +
232 + return $param;
233 + }
234 +
235 + /**
236 + * Rename the uploaded file name before saving
237 + * @param array $file
238 + * @return array $file
239 + */
240 + public function renameFileName($file)
241 + {
242 + $originalFileArray = $file;
243 + $prefix = 'ff-' . md5(uniqid(rand())) . '-ff-';
244 +
245 + $file['name'] = $prefix . $file['name'];
246 +
247 + $file = apply_filters_deprecated(
248 + 'fluentform_uploaded_file_name',
249 + [
250 + $file,
251 + $originalFileArray,
252 + $this->formData,
253 + $this->form
254 + ],
255 + FLUENTFORM_FRAMEWORK_UPGRADE,
256 + 'fluentform/uploaded_file_name',
257 + 'Use fluentform/uploaded_file_name instead of fluentform_uploaded_file_name.'
258 + );
259 +
260 + return apply_filters('fluentform/uploaded_file_name', $file, $originalFileArray, $this->formData, $this->form);
261 + }
262 +
263 + /**
264 + * Prepare the validation rules & messages specific to
265 + * file type inputs when actual form is submitted.
266 + *
267 + * @param $validations
268 + * @param $form \stdClass
269 + * @return array
270 + */
271 + public function prepareValidations($validations, $form)
272 + {
273 + $element = FormFieldsParser::getElement($form, ['input_file', 'input_image']);
274 +
275 + if (count($element)) {
276 + // Delegate the `max_file_count` validation to `max`
277 + $validations = $this->delegateValidations(
278 + $validations[0],
279 + $validations[1],
280 + ['max_file_count'],
281 + ['max']
282 + );
283 + }
284 +
285 + return $validations;
286 + }
287 +
288 + /**
289 + * Process uploads from temp directory location to its final location
290 + *
291 + * @param $formData
292 + * @param $form
293 + * @return void
294 + */
295 + public function initUploads($files, $uploadLocation, $formData)
296 + {
297 + if (empty($files)) {
298 + return;
299 + }
300 + if ($uploadLocation == 'wp_media') {
301 + $this->copyToWpMedia($files);
302 + } elseif ($uploadLocation == 'default') {
303 + $this->copyToDefault($files);
304 + } elseif ($uploadLocation == 'cloud_storage') {
305 + //for file upload addons
306 + do_action('fluentform/upload_to_cloud', $files, $uploadLocation, $formData, $this->form);
307 + }
308 + }
309 +
310 + /**
311 + * Copy files to default location
312 + *
313 + * @param array $files
314 + */
315 + protected function copyToDefault($files)
316 + {
317 + $uploadedFiles = [];
318 + $wpUploadDir = wp_upload_dir();
319 +
320 + foreach ($files as $file) {
321 + $fileInfo = pathinfo($file);
322 + $filename = $fileInfo['basename'];
323 +
324 + $filePath = $wpUploadDir['basedir'] . FLUENTFORM_UPLOAD_DIR;
325 + $tempFilePath = $filePath . '/temp/' . $filename;
326 + $filePath = apply_filters_deprecated(
327 + 'fluentform_default_upload_path',
328 + [
329 + $filePath,
330 + $this->form
331 + ],
332 + FLUENTFORM_FRAMEWORK_UPGRADE,
333 + 'fluentform/default_upload_path',
334 + 'Use fluentform/default_upload_path instead of fluentform_default_upload_path.'
335 + );
336 + $destinationFilePath = apply_filters('fluentform/default_upload_path', $filePath, $this->form);
337 + $this->secureDirectory($filePath);
338 +
339 + $destinationFilePath = trailingslashit($destinationFilePath) . $filename;
340 +
341 + self::copyFile($tempFilePath, $destinationFilePath);
342 + }
343 + return $uploadedFiles;
344 + }
345 +
346 +
347 + /**
348 + * Copy files to WordPress Media
349 + *
350 + * @param $files
351 + * @return void
352 + */
353 + public function copyToWpMedia($files)
354 + {
355 + $uploadedFiles = [];
356 + $wpUploadDir = wp_upload_dir();
357 +
358 + foreach ($files as $file) {
359 + $fileInfo = pathinfo($file);
360 + $filename = $fileInfo['basename'];
361 + $tempFilePath = $wpUploadDir['basedir'] . FLUENTFORM_UPLOAD_DIR . '/temp/' . $filename;
362 + $destinationFilePath = $wpUploadDir['path'] . '/' . $filename;
363 +
364 + $mimeType = wp_check_filetype($tempFilePath);
365 + //Copy this file into the wp uploads dir
366 + $move = self::copyFile($tempFilePath, $destinationFilePath);
367 + if (!$move) {
368 + continue;
369 + }
370 + $destinationFileFileUrl = $wpUploadDir['url'] . '/' . $filename;
371 + $uploadId = wp_insert_attachment(
372 + [
373 + 'guid' => $destinationFileFileUrl,
374 + 'post_mime_type' => $mimeType['type'],
375 + 'post_title' => preg_replace('/\.[^.]+$/', '', $filename),
376 + 'post_content' => '',
377 + 'post_status' => 'inherit',
378 + ],
379 + $destinationFilePath
380 + );
381 +
382 + // wp_generate_attachment_metadata() needs this file.
383 + require_once ABSPATH . 'wp-admin/includes/image.php';
384 + if (!is_wp_error($uploadId)) {
385 + wp_update_attachment_metadata(
386 + $uploadId,
387 + wp_generate_attachment_metadata($uploadId, $destinationFilePath)
388 + );
389 + }
390 + }
391 + }
392 +
393 + /**
394 + * Upload files to temp directory
395 + *
396 + * @param array $files
397 + * @param array $field
398 + * @return array
399 + */
400 + private function uploadToTemp($files, $field)
401 + {
402 + $uploadedFiles = [];
403 + foreach ($files as $file) {
404 + /**
405 + * @var $file \FluentForm\Framework\Request\File
406 + */
407 + $filesArray = $file->toArray();
408 +
409 + $args = [
410 + 'test_form' => false
411 + ];
412 + $args = apply_filters_deprecated(
413 + 'fluentform_uploader_args',
414 + [
415 + $args,
416 + $filesArray,
417 + $this->form
418 + ],
419 + FLUENTFORM_FRAMEWORK_UPGRADE,
420 + 'fluentform/uploader_args',
421 + 'Use fluentform/uploader_args instead of fluentform_uploader_args.'
422 + );
423 +
424 + $uploaderArgs = apply_filters('fluentform/uploader_args', $args, $filesArray, $this->form);
425 +
426 + $uploadFile = wp_handle_upload(
427 + $filesArray,
428 + $uploaderArgs
429 + );
430 +
431 + if ($error = ArrayHelper::get($uploadFile, 'error')) {
432 + wp_send_json([
433 + 'errors' => [
434 + 'error' => $error
435 + ]
436 + ], 422);
437 + }
438 +
439 + $file = ArrayHelper::get($uploadFile, 'file');
440 +
441 + if ($file) {
442 + $uploadFile['file'] = \FluentForm\App\Helpers\Protector::encrypt($file);
443 + $uploadFile['url'] = str_replace($file, $uploadFile['file'], $uploadFile['url']);
444 +
445 + $uploadFile = apply_filters_deprecated(
446 + 'fluent_file_uploaded',
447 + [
448 + $uploadFile,
449 + $this->formData,
450 + $this->form
451 + ],
452 + FLUENTFORM_FRAMEWORK_UPGRADE,
453 + 'fluentform/file_uploaded',
454 + 'Use fluentform/file_uploaded instead of fluent_file_uploaded.'
455 + );
456 +
457 + $uploadedFiles[] = apply_filters('fluentform/file_uploaded', $uploadFile, $this->formData, $this->form);
458 + }
459 + }
460 + return $uploadedFiles;
461 + }
462 +
463 + private static function copyFile($fromPath = null, $toPath = null)
464 + {
465 + $status = false;
466 +
467 + if (!empty($fromPath) && is_file($fromPath)) {
468 + //if destination dir exists if not make it
469 + if (!file_exists(dirname($toPath))) {
470 + mkdir(dirname($toPath));
471 + }
472 + if (file_exists(dirname($toPath))) {
473 + //Move file into dir
474 + if (copy($fromPath, $toPath)) {
475 + if (file_exists($toPath)) {
476 + $status = true;
477 + }
478 + }
479 + }
480 + }
481 +
482 + return $status;
483 + }
484 +
485 +
486 + /**
487 + * Get File url after processing uploads
488 + *
489 + * @param $file
490 + * @param $uploadLocations
491 + * @return string|void
492 + */
493 + public function getProcessedUrl($file, $location)
494 + {
495 + $wpUploadDir = wp_upload_dir();
496 + $fileInfo = pathinfo($file);
497 + $filename = $fileInfo['basename'];
498 + $filePath = $wpUploadDir['baseurl'] . FLUENTFORM_UPLOAD_DIR;
499 + if ($location == 'wp_media') {
500 + $fileUrl = $wpUploadDir['url'] . '/' . $filename;
501 + } elseif ($location == 'default') {
502 + $filePath = apply_filters_deprecated(
503 + 'fluentform_default_file_upload_url',
504 + [
505 + $filePath,
506 + $this->form
507 + ],
508 + FLUENTFORM_FRAMEWORK_UPGRADE,
509 + 'fluentform/default_file_upload_url',
510 + 'Use fluentform/default_file_upload_url instead of fluentform_default_file_upload_url.'
511 + );
512 + $fileUrl = apply_filters('fluentform/default_file_upload_url', $filePath, $this->form);
513 + $fileUrl = trailingslashit($fileUrl) .$filename;
514 + } else if ($location == 'cloud_storage') {
515 + return $file;
516 + } else {
517 + //if not location found store temp file url for other file uploader
518 + $fileUrl = $filePath . '/temp/' . $filename;
519 + }
520 + return $fileUrl;
521 + }
522 +
523 + /**
524 + * Cleanup temp Directory
525 + *
526 + * @return void
527 + */
528 + public static function removeOldTempFiles()
529 + {
530 + $maxFileAge = apply_filters('fluentform/temp_file_delete_time', 2 * 3600);
531 + $wpUploadDir = wp_upload_dir();
532 + $tempDir = $wpUploadDir['basedir'] . FLUENTFORM_UPLOAD_DIR . '/temp/';
533 +
534 + // Remove old temp files
535 + if (is_dir($tempDir) && ($dir = opendir($tempDir))) {
536 + $deletedCount = 0;
537 + $maxDeletions = apply_filters('fluentform/temp_file_cleanup_batch_size', 50);
538 +
539 + while (($file = readdir($dir)) !== false) {
540 + if ($file === '.' || $file === '..') {
541 + continue;
542 + }
543 +
544 + $tempFilePath = $tempDir . $file;
545 + if (is_file($tempFilePath) && (filemtime($tempFilePath) < time() - $maxFileAge)) {
546 + if (@unlink($tempFilePath)) {
547 + $deletedCount++;
548 + }
549 +
550 + // Limit batch size to prevent timeouts
551 + if ($deletedCount >= $maxDeletions) {
552 + break;
553 + }
554 + }
555 + }
556 + closedir($dir);
557 +
558 + do_action('fluentform/temp_files_cleaned', $tempDir, $deletedCount, $maxFileAge, $maxDeletions);
559 + }
560 + }
561 +
562 + /**
563 + * Adds htaccess file to directory
564 + * @param $path
565 + * @return void
566 + */
567 + private function secureDirectory($path)
568 + {
569 + if (!is_dir($path)) {
570 + mkdir($path, 0755);
571 + file_put_contents(
572 + $path . '/.htaccess',
573 + file_get_contents(__DIR__ . '/Stubs/htaccess.stub')
574 + );
575 +
576 + file_put_contents(
577 + $path . '/index.php',
578 + file_get_contents(__DIR__ . '/Stubs/index.stub')
579 + );
580 + }
581 +
582 + /*
583 + * @todo: Rempve this block after November 2023
584 + */
585 +
586 + if(!file_exists($path . '/index.php')) {
587 + file_put_contents(
588 + $path . '/index.php',
589 + file_get_contents(__DIR__ . '/Stubs/index.stub')
590 + );
591 + }
592 + }
593 +
594 +
595 + /**
596 + * Maybe Decrypt file names
597 + *
598 + * @param $files
599 + * @return array
600 + */
601 + private function maybeDecrypt($files)
602 + {
603 + $decrypted = [];
604 + foreach ($files as $file) {
605 + $decrypted[] = \FluentForm\App\Helpers\Helper::maybeDecryptUrl($file);
606 + }
607 + return $decrypted;
608 + }
609 +
610 + public function deleteFile()
611 + {
612 + if (!empty($file_name = $this->request->get('path'))) {
613 + if (!empty($this->request->get('attachment_id')) && wp_delete_attachment(
614 + $this->request->get('attachment_id')
615 + )) {
616 + wp_die();
617 + } else {
618 + $file_name = \FluentForm\App\Helpers\Protector::decrypt($file_name);
619 + wp_die(@unlink(wp_upload_dir()['basedir'] . FLUENTFORM_UPLOAD_DIR . '/temp/' . $file_name));
620 + }
621 + }
622 + }
623 +
624 + /**
625 + * @param $upload_file_location
626 + * @return mixed
627 + */
628 + public function getUploadLocation($field)
629 + {
630 + if (!$locationType = ArrayHelper::get($field, 'raw.settings.file_location_type')) {
631 + $locationType = 'follow_global_settings';
632 + }
633 + if ($locationType == 'follow_global_settings') {
634 + $settings = get_option('_fluentform_global_form_settings', false);
635 + $location = ArrayHelper::get($settings, 'misc.file_upload_locations');
636 + } else {
637 + $location = ArrayHelper::get($field, 'raw.settings.upload_file_location');
638 + }
639 +
640 + if (empty($location)) {
641 + $location = 'default';
642 + }
643 +
644 + $location = apply_filters('fluentform/change_file_upload_location', $location);
645 + return $location;
646 + }
647 + }
648 +