PluginProbe
JetFormBuilder — Dynamic Blocks Form Builder / 3.6.6
JetFormBuilder — Dynamic Blocks Form Builder v3.6.6
3.6.6.1 3.6.6 3.6.5.4 3.6.5.3 3.6.5.2 3.6.5.1 3.6.5 3.6.4.2 3.6.4.1 3.6.4 3.6.3.1 3.6.3 3.6.2.2 3.6.2.1 3.6.2 3.6.1.1 3.6.1 3.6.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 All 134 releases
jetformbuilder / modules / block-parsers / fields / media-field-parser.php

media-field-parser.php in JetFormBuilder — Dynamic Blocks Form Builder 3.6.6, at modules/block-parsers/fields/media-field-parser.php

178 lines 5.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3
4 namespace JFB_Modules\Block_Parsers\Fields;
5
6 use Jet_Form_Builder\Classes\Resources\Has_Error_File;
7 use Jet_Form_Builder\Classes\Resources\Media_Block_Value;
8 use Jet_Form_Builder\Exceptions\Request_Exception;
9 use Jet_Form_Builder\Request\Exceptions\Sanitize_Value_Exception;
10 use Jet_Form_Builder\Classes\Resources\Upload_Exception;
11 use JFB_Modules\Block_Parsers\Field_Data_Parser;
12 use JFB_Modules\Block_Parsers\File_Uploader;
13
14 // If this file is called directly, abort.
15 if ( ! defined( 'WPINC' ) ) {
16 die;
17 }
18
19 class Media_Field_Parser extends Field_Data_Parser {
20
21 public function type() {
22 return 'media-field';
23 }
24
25 protected function allows_array_value(): bool {
26 return true;
27 }
28
29 /**
30 * @since 3.0.4 Added `jet-form-builder/media-field/before-upload` hook
31 *
32 * @return array|false|int|string|null
33 * @throws Sanitize_Value_Exception
34 */
35 public function get_response() {
36 if (
37 empty( $this->get_file() ) ||
38 (
39 is_object( $this->get_file() ) &&
40 is_a( $this->get_file(), Has_Error_File::class ) &&
41 $this->get_file()->has_error()
42 )
43 ) {
44 /**
45 * We should leave here $this->value for case, while this field exporting
46 * with values from Form Record
47 *
48 * @see https://github.com/Crocoblock/issues-tracker/issues/4422
49 */
50 return $this->sanitize_submitted_attachment_ids( $this->value );
51 }
52 do_action( 'jet-form-builder/media-field/before-upload', $this );
53
54 $uploader = ( new File_Uploader() )->set_context( $this );
55
56 try {
57 /** @var Media_Block_Value $uploads */
58 $uploads = $uploader->upload();
59 } catch ( Upload_Exception $exception ) {
60 $this->collect_error( $exception->getMessage() );
61 return false;
62 }
63
64 $this->set_file( $uploads );
65
66 switch ( $this->get_value_format() ) {
67 case 'id':
68 return $uploads->get_attachment_id();
69 case 'both':
70 return $uploads->get_attachment_both();
71 case 'ids':
72 return $uploads->get_attachment_ids();
73 default:
74 return $uploads->get_attachment_url();
75 }
76 }
77
78 protected function get_value_format(): string {
79 return empty( $this->settings['insert_attachment'] )
80 ? 'url'
81 : ( $this->settings['value_format'] ?? 'url' );
82 }
83
84 /**
85 * When no file is uploaded with this submission, `$this->value` is whatever
86 * the request supplied verbatim. If this field is configured to store
87 * attachment IDs, only accept IDs of attachments the plugin itself created
88 * via a form upload (marked in Uploaded_File::add_attachment()); anything
89 * else is dropped as if it was never submitted, since it may reference an
90 * attachment unrelated to this submitter.
91 *
92 * This has to preserve the exact value shapes the upload path itself
93 * produces for each `value_format`, otherwise re-submitting an unchanged
94 * field (no new file) would corrupt or empty it:
95 * - `both`, single file: associative `array( 'id' => .., 'url' => .. )`
96 * (@see Uploaded_File::get_attachment_both()).
97 * - `both`, multiple files: list of the associative shape above
98 * (@see Uploaded_Collection::get_attachment_both()).
99 * - `id`/`ids`, single file: a scalar numeric-string ID.
100 * - `ids`, multiple files: a plain list of numeric-string IDs
101 * (@see Uploaded_Collection::get_attachment_ids()).
102 * - `id`, multiple files: a comma-joined string of IDs, e.g. `"5,8"`
103 * (@see Uploaded_Collection::get_attachment_id()).
104 *
105 * @param array|string|int|null $value
106 *
107 * @return array|string|int|null
108 */
109 protected function sanitize_submitted_attachment_ids( $value ) {
110 if ( ! in_array( $this->get_value_format(), array( 'id', 'ids', 'both' ), true ) ) {
111 return $value;
112 }
113
114 // Single-item `both` shape: associative array( 'id' => .., 'url' => .. ).
115 // Must not be run through array_filter()/array_values(), which would
116 // reindex it into a plain list and discard the 'id'/'url' keys.
117 if ( is_array( $value ) && array_key_exists( 'id', $value ) && ! is_array( $value['id'] ?? null ) ) {
118 return $this->is_allowed_submitted_attachment( $value ) ? $value : array();
119 }
120
121 if ( is_array( $value ) ) {
122 $filtered = array_values(
123 array_filter(
124 $value,
125 array( $this, 'is_allowed_submitted_attachment' )
126 )
127 );
128
129 return $filtered;
130 }
131
132 // Multi-file `id` format round-trips as a comma-joined string (e.g. "5,8").
133 // is_numeric() on the whole string is false, so it must be split first.
134 if ( is_string( $value ) && false !== strpos( $value, ',' ) ) {
135 $allowed = array_filter(
136 array_map( 'trim', explode( ',', $value ) ),
137 array( $this, 'is_allowed_submitted_attachment' )
138 );
139
140 return implode( ',', $allowed );
141 }
142
143 return $this->is_allowed_submitted_attachment( $value ) ? $value : '';
144 }
145
146 /**
147 * Requires both the form marker AND (when recorded) a matching uploader before an
148 * attachment ID submitted without a file is accepted into the post meta. Checking only
149 * `_jfb_uploaded_by_form` (as an earlier revision of this method did) would let any
150 * user attach another user's plugin-uploaded file to their own post just by knowing its
151 * ID - the marker alone says "some form uploaded this", not "you uploaded this". The
152 * per-uploader check itself is `Media_Cleanup::is_owned_by_current_actor()` - shared
153 * with `delete_attachments()`'s own ownership check - so acceptance and deletion always
154 * apply the exact same trust model to the same marker, rather than two independently
155 * maintained copies that could silently drift apart.
156 *
157 * @param mixed $item
158 *
159 * @return bool
160 */
161 private function is_allowed_submitted_attachment( $item ): bool {
162 $attachment_id = is_array( $item ) ? ( $item['id'] ?? null ) : $item;
163
164 if ( empty( $attachment_id ) || ! is_numeric( $attachment_id ) ) {
165 return false;
166 }
167
168 $attachment_id = absint( $attachment_id );
169
170 if ( ! get_post_meta( $attachment_id, '_jfb_uploaded_by_form', true ) ) {
171 return false;
172 }
173
174 return \JFB_Modules\Media_Cleanup\Module::is_owned_by_current_actor( $attachment_id );
175 }
176
177 }
178