PluginProbe
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor / 4.0.1
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor v4.0.1
4.0.3 4.0.2 4.0.1 4.0.0 3.16.6 3.16.5 3.16.4 3.16.3 3.16.2 3.16.1 3.16.0 3.15.9 3.9.9 3.9.5 3.9.6 3.9.7 3.9.8 1.1.7 1.1.8 1.1.9 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 341 releases
profile-builder / front-end / default-fields / upload / upload_helper_functions.php

upload_helper_functions.php in User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor 4.0.1, at front-end/default-fields/upload/upload_helper_functions.php

614 lines 30.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // Exit if accessed directly
3 if ( ! defined( 'ABSPATH' ) ) exit;
4
5 /** Simple file input when the field is set to it, or the user cannot upload_files. */
6 function wppb_use_simple_upload_field( $field ) {
7 if ( ! empty( $field['simple-upload'] ) && $field['simple-upload'] === 'yes' ) {
8 return true;
9 }
10
11 return ! current_user_can( 'upload_files' );
12 }
13
14 /**
15 * Whether this request includes a simple-upload for the field.
16 * Checkout and some payment forms post the hidden attachment ID without $_FILES.
17 */
18 function wppb_simple_upload_was_submitted( $field, $request_data ) {
19 $meta = wppb_handle_meta_name( $field['meta-name'] );
20 $file_key = 'simple_upload_' . $meta;
21
22 if ( isset( $_FILES[ $file_key ] ) ) {
23 return true;
24 }
25
26 if ( isset( $request_data['pay_gate'] ) && in_array( $request_data['pay_gate'], array( 'stripe_connect', 'paypal_connect' ), true ) ) {
27 return true;
28 }
29
30 return array_key_exists( $meta, $request_data );
31 }
32
33 /* for a request of a upload from the frontend and no user is logged in don't query for attachments */
34 add_action( 'after_setup_theme', 'wppb_modify_query_attachements_when_not_logged_in' );
35 if( !function_exists( 'wppb_modify_query_attachements_when_not_logged_in' ) ) {
36 function wppb_modify_query_attachements_when_not_logged_in()
37 {
38 if ( strpos(wp_get_referer(), 'wp-admin') === false && !is_user_logged_in() ) {
39 add_action('wp_ajax_query-attachments', 'wppb_wp_ajax_not_loggedin_query_attachments', 0);
40 add_action('wp_ajax_nopriv_query-attachments', 'wppb_wp_ajax_not_loggedin_query_attachments', 0);
41 function wppb_wp_ajax_not_loggedin_query_attachments()
42 {
43 wp_send_json_success();
44 }
45 }
46 }
47 }
48
49 /* restrict file types of the upload field functionality */
50 add_filter('wp_handle_upload_prefilter', 'wppb_upload_file_type');
51 if( !function_exists( 'wppb_upload_file_type' ) ) {
52 function wppb_upload_file_type($file)
53 {
54 if( isset( $_POST['wppb_upload'] ) && $_POST['wppb_upload'] == 'true' && isset( $_POST['_wpnonce'] ) && wp_verify_nonce( sanitize_text_field( $_POST['_wpnonce'] ), 'media-form' ) ) {
55
56 // file size limits.
57 $size = $file['size'];
58 $limit = apply_filters('wppb_server_max_upload_size_byte_constant', wppb_return_bytes(ini_get('upload_max_filesize')));
59 if ( $size > $limit ) {
60 $limit = $limit / ( 1024 * 1024 ) ;
61 $file['error'] = __("Files must be smaller than ", "profile-builder") . $limit . 'MB';
62 }
63
64 if (isset($_POST['meta_name']) && !empty($_POST['meta_name'])) {
65 $meta_name = sanitize_text_field( $_POST['meta_name'] );
66 /*let's get the field details so we can see if we have any file restrictions */
67 $all_fields = apply_filters( 'wppb_form_fields', get_option('wppb_manage_fields'), array( 'context' => 'upload_helper', 'upload_meta_name' => $meta_name ) );
68 if (!empty($all_fields)) {
69 foreach ($all_fields as $field) {
70 if ($field['meta-name'] == $meta_name) {
71
72 // per-field file size limit
73 if ( !empty( $field['max-file-size'] ) && is_numeric( $field['max-file-size'] ) && floatval( $field['max-file-size'] ) > 0 ) {
74 $field_limit = floatval( $field['max-file-size'] ) * 1024 * 1024;
75 $effective_limit = min( $field_limit, $limit );
76 if ( $size > $effective_limit ) {
77 $file['error'] = __( "Files must be smaller than ", "profile-builder" ) . floatval( $field['max-file-size'] ) . 'MB';
78 return $file;
79 }
80 }
81
82 $allowed_upload_extensions = '';
83
84 if ($field['field'] == 'Upload' && !empty($field['allowed-upload-extensions']))
85 $allowed_upload_extensions = $field['allowed-upload-extensions'];
86 if ($field['field'] == 'Avatar' && !empty($field['allowed-image-extensions'])) {
87 if (trim($field['allowed-image-extensions']) == '.*')
88 $allowed_upload_extensions = '.jpg,.jpeg,.gif,.png,.ico';
89 else
90 $allowed_upload_extensions = $field['allowed-image-extensions'];
91 }
92
93 $ext = strtolower( substr(strrchr($file['name'], '.'), 1) );
94
95 if (!empty($allowed_upload_extensions) && $allowed_upload_extensions != '.*') {
96 $allowed = str_replace('.', '', array_map('trim', explode(",", strtolower( $allowed_upload_extensions))));
97 //first check if the user uploaded the right type
98 if (!in_array($ext, (array)$allowed)) {
99 $file['error'] = __("Sorry, you cannot upload this file type for this field.", 'profile-builder');
100 return $file;
101 }
102 }
103
104 //check if the type is allowed at all by WordPress
105 foreach (get_allowed_mime_types() as $key => $value) {
106 if (strpos($key, $ext) !== false || $key == $ext)
107 return $file;
108 }
109
110 $file['error'] = __("Sorry, you cannot upload this file type for this field.", 'profile-builder');
111
112 break;
113 }
114 }
115 }
116 }
117
118 if (empty($_POST['meta_name']))
119 $file['error'] = __("An error occurred, please try again later.", 'profile-builder');
120 }
121
122 return $file;
123 }
124 }
125
126 /**
127 * Function that performs validation for the simple upload field
128 *
129 * @param $field - simple upload field
130 * @param $upload - data to be uploaded
131 *
132 * @return bool
133 */
134 function wppb_valid_simple_upload( $field, $upload ){
135 $limit = apply_filters( 'wppb_server_max_upload_size_byte_constant', wppb_return_bytes( ini_get( 'upload_max_filesize' ) ) );
136 $allowed_mime_types = get_allowed_mime_types();
137 $all_fields = apply_filters( 'wppb_form_fields', get_option( 'wppb_manage_fields' ), array( 'context' => 'upload_helper', 'upload_meta_name' => $field[ 'meta-name' ] ) );
138 if ( !empty( $all_fields ) ) {
139 foreach ( $all_fields as $form_field ) {
140 if ($form_field[ 'meta-name' ] == $field[ 'meta-name' ] ) {
141 // apply per-field size limit if set
142 if ( !empty( $form_field['max-file-size'] ) && is_numeric( $form_field['max-file-size'] ) && floatval( $form_field['max-file-size'] ) > 0 ) {
143 $field_limit = floatval( $form_field['max-file-size'] ) * 1024 * 1024;
144 $limit = min( $field_limit, $limit );
145 }
146 $allowed_upload_extensions = '';
147 if ( $form_field[ 'field' ] == 'Upload' && !empty( $form_field[ 'allowed-upload-extensions' ] ) ) {
148 $allowed_upload_extensions = $form_field[ 'allowed-upload-extensions' ];
149 }
150 if ( $form_field[ 'field' ] == 'Avatar' ) {
151 if ( trim( $field[ 'allowed-image-extensions' ] ) == '.*' || trim( $field[ 'allowed-image-extensions' ] ) == '' ) {
152 $allowed_upload_extensions = '.jpg,.jpeg,.gif,.png';
153 }
154 else {
155 $allowed_upload_extensions = $form_field[ 'allowed-image-extensions' ];
156 }
157 }
158 if ( !empty( $allowed_upload_extensions ) && $allowed_upload_extensions != '.*' ) {
159 $allowed_upload_extensions = str_replace( '.', '', array_map( 'trim', explode( ",", strtolower( $allowed_upload_extensions ) ) ) );
160 } else {
161 $allowed = true;
162 }
163 if ( empty( $upload['tmp_name'] ) || empty( $upload['name'] ) ) {
164 return false;
165 }
166
167 $checked = wp_check_filetype_and_ext( $upload['tmp_name'], $upload['name'] );
168 $detected_type = ! empty( $checked['type'] ) ? $checked['type'] : '';
169 $detected_ext = ! empty( $checked['ext'] ) ? strtolower( $checked['ext'] ) : '';
170 $allowed_by_wordpress = ( $detected_type !== '' && in_array( $detected_type, $allowed_mime_types, true ) );
171
172 if ( $allowed_by_wordpress && $detected_ext !== '' ) {
173 if ( !isset( $allowed ) ){
174 $allowed = in_array( $detected_ext, $allowed_upload_extensions, true );
175 }
176 if ( $upload[ 'size' ] > $limit ){
177 $allowed = false;
178 }
179 return $allowed;
180 }
181 else{
182 return false;
183 }
184 }
185 }
186 }
187 }
188
189 /**
190 * Function that registers intermediate avatar sizes
191 *
192 * @param $field - avatar field
193 *
194 */
195 function wppb_add_avatar_sizes( $field ){
196 if( !empty( $field['avatar-size'] ) )
197 add_image_size( 'wppb-avatar-size-'.$field['avatar-size'], $field['avatar-size'], $field['avatar-size'], true );
198 else
199 add_image_size( 'wppb-avatar-size-100', 100, 100, true );
200
201 add_image_size( 'wppb-avatar-size-64', 64, 64, true );
202 add_image_size( 'wppb-avatar-size-26', 26, 26, true );
203 }
204
205 //Function that registers avatar sizes for userlisting
206 function wppb_userlisting_avatar(){
207 $userlisting_posts = get_posts( array( 'posts_per_page' => -1, 'post_status' =>'publish', 'post_type' => 'wppb-ul-cpt', 'orderby' => 'post_date', 'order' => 'ASC' ) );
208 if( !empty( $userlisting_posts ) ){
209 foreach ( $userlisting_posts as $post ){
210 $this_form_settings = get_post_meta( $post->ID, 'wppb_ul_page_settings', true );
211 $all_userlisting_avatar_size = apply_filters( 'all_userlisting_avatar_size', ( isset( $this_form_settings[0]['avatar-size-all-userlisting'] ) ? (int)$this_form_settings[0]['avatar-size-all-userlisting'] : 100 ) );
212 $single_userlisting_avatar_size = apply_filters( 'single_userlisting_avatar_size', ( isset( $this_form_settings[0]['avatar-size-single-userlisting'] ) ? (int)$this_form_settings[0]['avatar-size-single-userlisting'] : 100 ) );
213
214 add_image_size( 'wppb-avatar-size-'.$all_userlisting_avatar_size, $all_userlisting_avatar_size, $all_userlisting_avatar_size, true );
215 add_image_size( 'wppb-avatar-size-'.$single_userlisting_avatar_size, $single_userlisting_avatar_size, $single_userlisting_avatar_size, true );
216 }
217 }
218 }
219
220 /**
221 * Function that checks if the simple upload field belongs to a repeater field with conditional logic enabled
222 *
223 * @param $field - simple upload field
224 *
225 * @return bool
226 */
227 function wppb_belongs_to_repeater_with_conditional_logic( $field ){
228 $all_fields = apply_filters( 'wppb_form_fields', get_option( 'wppb_manage_fields' ), array( 'context' => 'upload_helper', 'upload_meta_name' => $field[ 'meta-name' ] ) );
229 if ( !empty( $all_fields ) ) {
230 foreach ( $all_fields as $form_field ) {
231 if ( $form_field[ 'field' ] == 'Repeater' && isset( $form_field[ 'conditional-logic-enabled' ] ) && $form_field[ 'conditional-logic-enabled' ] == 'yes' ) {
232 $repeater_group = get_option( $form_field[ 'meta-name' ], 'not_set' );
233 if ( $repeater_group == 'not_set' ) {
234 continue;
235 }
236 else{
237 $repeater_count = count( $repeater_group );
238 for ( $i = 0; $i < $repeater_count; $i++ ){
239 if ( $repeater_group[ $i ][ 'field' ] == 'Upload' && wppb_use_simple_upload_field( $repeater_group[ $i ] ) && isset( $_REQUEST[ $form_field[ 'meta-name' ] . '_extra_groups_count' ] ) ){
240 $groups = absint( $_REQUEST[ $form_field[ 'meta-name' ] . '_extra_groups_count' ] );
241 for ( $j = 0; $j <= $groups; $j++ ){
242 $name = $repeater_group[ $i ][ 'meta-name' ];
243 if ( $j != 0 ){
244 $name .= '_' . $j;
245 }
246 if ( $field[ 'meta-name' ] == $name ){
247 return true;
248 }
249 }
250 }
251 }
252 }
253 }
254 }
255 }
256 return false;
257 }
258
259 function wppb_default_fields_make_upload_button( $field, $input_value, $extra_attr = '' ){
260 // change the upload limit displayed in the upload window (per-field aware)
261 $per_field_max = $field;
262 add_filter('upload_size_limit', function($wp_limit) use ($per_field_max) {
263 $server_limit = apply_filters('wppb_server_max_upload_size_byte_constant', wppb_return_bytes(ini_get('upload_max_filesize')));
264 if ( !empty( $per_field_max['max-file-size'] ) && is_numeric( $per_field_max['max-file-size'] ) && floatval( $per_field_max['max-file-size'] ) > 0 ) {
265 $field_limit = floatval( $per_field_max['max-file-size'] ) * 1024 * 1024;
266 return min( $field_limit, $server_limit );
267 }
268 return $server_limit;
269 }, 10, 1);
270
271 $upload_button = '';
272 $upload_input_id = str_replace( '-', '_', Wordpress_Creation_Kit_PB::wck_generate_slug( $field['meta-name'] ) );
273
274 /* container for the image preview (or file ico) and name and file type */
275 if( !empty( $input_value ) ){
276 /* it can hold multiple attachments separated by comma */
277 $values = explode( ',', $input_value );
278 foreach( $values as $value ) {
279 if( !empty( $value ) && is_numeric( $value ) ){
280 $thumbnail = wp_get_attachment_image($value, array(80, 80), true);
281 $file_name = get_the_title($value);
282 $file_type = get_post_mime_type($value);
283 $attachment_url = wp_get_attachment_url($value);
284 $upload_button .= '<div id="' . esc_attr($upload_input_id) . '_info_container" class="upload-field-details" data-attachment_id="' . $value . '">';
285 $upload_button .= '<div class="file-thumb">';
286 $upload_button .= "<a href='{$attachment_url}' target='_blank' class='wppb-attachment-link'>" . $thumbnail . "</a>";
287 $upload_button .= '</div>';
288 $upload_button .= '<p><span class="file-name">';
289 $upload_button .= $file_name;
290 $upload_button .= '</span><span class="file-type">';
291 $upload_button .= $file_type;
292 $upload_button .= '</span>';
293 $upload_button .= '<span class="wppb-remove-upload" tabindex="0">' . apply_filters( 'wppb_upload_button_remove_label', __( 'Remove', 'profile-builder' ) ) . '</span>';
294 $upload_button .= '</p></div>';
295 }
296 }
297 $hide_upload_button = ' style="display:none;"';
298 }
299 else{
300 $hide_upload_button = '';
301 }
302
303 if ( wppb_use_simple_upload_field( $field ) ){
304 //If selected accordingly in form fields, generate a simple upload button
305 $upload_button .= '<input type="file" id="upload_' . esc_attr(Wordpress_Creation_Kit_PB::wck_generate_slug($field['meta-name'], $field)) . '_button" class="wppb_simple_upload" data-field_type="'. esc_attr( $field['field'] ) .'" name="simple_upload_'. esc_attr( Wordpress_Creation_Kit_PB::wck_generate_slug( $field['meta-name'], $field ) ) .'"';
306 $upload_button .= $hide_upload_button . '>';
307 $upload_button .= '<p id="p_simple_upload_'. esc_attr(Wordpress_Creation_Kit_PB::wck_generate_slug($field['meta-name'], $field)) .'"></p>';
308 $limit = apply_filters( 'wppb_server_max_upload_size_byte_constant', wppb_return_bytes( ini_get( 'upload_max_filesize' ) ) );
309 $all_fields = apply_filters( 'wppb_form_fields', get_option( 'wppb_manage_fields' ), array( 'context' => 'upload_helper', 'upload_meta_name' => $field[ 'meta-name' ] ) );
310 if ( !empty( $all_fields ) ) {
311 foreach ( $all_fields as $form_field ) {
312 if ($form_field[ 'meta-name' ] == $field[ 'meta-name' ] ) {
313 // apply per-field size limit if set
314 if ( !empty( $form_field['max-file-size'] ) && is_numeric( $form_field['max-file-size'] ) && floatval( $form_field['max-file-size'] ) > 0 ) {
315 $field_limit = floatval( $form_field['max-file-size'] ) * 1024 * 1024;
316 $limit = min( $field_limit, $limit );
317 }
318 $allowed_upload_extensions = '';
319 if ( $form_field[ 'field' ] == 'Upload' && !empty( $form_field[ 'allowed-upload-extensions' ] ) ) {
320 $allowed_upload_extensions = $form_field[ 'allowed-upload-extensions' ];
321 }
322 if ( $form_field[ 'field' ] == 'Avatar' ) {
323 if ( trim( $field[ 'allowed-image-extensions' ] ) == '.*' || trim( $field[ 'allowed-image-extensions' ] ) == '' ) {
324 $allowed_upload_extensions = '.jpg,.jpeg,.gif,.png';
325 }
326 else {
327 $allowed_upload_extensions = $form_field[ 'allowed-image-extensions' ];
328 }
329 }
330 }
331 if ( !empty( $allowed_upload_extensions ) && $allowed_upload_extensions != '.*' ) {
332 $allowed_extensions = str_replace( '.', '', array_map( 'trim', explode( ",", strtolower( $allowed_upload_extensions ) ) ) );
333 $allowed_extensions = implode( ',', $allowed_extensions );
334 } else {
335 $allowed_extensions = '';
336 }
337 }
338 }
339 $upload_button .= '<input id="allowed_extensions_simple_upload_'. esc_attr( $upload_input_id ) .'" type="hidden" size="36" name="allowed_extensions_simple_upload_'. esc_attr( Wordpress_Creation_Kit_PB::wck_generate_slug( $field['meta-name'], $field ) ) .'" value="'. esc_attr( $allowed_extensions ) .'"/>';
340 $upload_button .= '<input id="size_limit_simple_upload_'. esc_attr( $upload_input_id ) .'" type="hidden" name="size_limit_simple_upload_'. esc_attr( Wordpress_Creation_Kit_PB::wck_generate_slug( $field['meta-name'], $field ) ) .'" value="'. esc_attr( $limit ) .'"/>';
341 $allowed_mime_types = get_allowed_mime_types();
342 $allowed_types = '';
343 if ( !empty( $allowed_mime_types ) ) {
344 foreach ($allowed_mime_types as $key => $val){
345 $allowed_types .= $key . '=>' . $val . ',';
346 }
347 }
348 $error_messages = array(
349 'limit_error_message' => __( 'Files must be smaller than ', 'profile-builder' ),
350 'upload_type_error_message' => __( 'Sorry, you cannot upload this file type for this field.', 'profile-builder' ),
351 );
352 $size_limit = array(
353 'size_limit' => $limit
354 );
355 $allowed_wordpress_formats = array(
356 'allowed_wordpress_formats' => $allowed_mime_types
357 );
358 wp_localize_script( 'wppb-upload-script', 'wppb_error_messages', $error_messages );
359 wp_localize_script( 'wppb-upload-script', 'wppb_limit', $size_limit );
360 wp_localize_script( 'wppb-upload-script', 'wppb_allowed_wordpress_formats', $allowed_wordpress_formats );
361 }
362 else{
363 //Otherwise, generate the WordPress upload button
364 $upload_button .= '<a href="#" class="button wppb_upload_button" id="upload_' . esc_attr(Wordpress_Creation_Kit_PB::wck_generate_slug($field['meta-name'], $field)) . '_button" '.$hide_upload_button.' data-uploader_title="' . $field["field-title"] . '" data-uploader_button_text="'. __( 'Select File', 'profile-builder' ) .'" data-upload_mn="'. $field['meta-name'] .'" data-upload_input="' . esc_attr($upload_input_id) . '"';
365
366 if (is_user_logged_in())
367 $upload_button .= ' data-uploader_logged_in="true"';
368 $upload_button .= ' data-multiple_upload="false"';
369
370 $upload_button .= '>' . apply_filters( 'wppb_upload_button_select_label', __( 'Upload ', 'profile-builder' ) ) . '</a>';
371 }
372
373 $upload_button .= '<input id="'. esc_attr( $upload_input_id ) .'" type="hidden" size="36" name="'. esc_attr( Wordpress_Creation_Kit_PB::wck_generate_slug( $field['meta-name'], $field ) ) .'" value="'. esc_attr( wp_unslash( $input_value ) ) .'"/>';
374 return $upload_button;
375 }
376
377 /**
378 * Function to save an attachment from the simple upload field
379 * @param $field_name
380 * @return string|WP_Error
381 */
382 function wppb_default_fields_save_simple_upload_file( $field_name ) {
383 require_once(ABSPATH . 'wp-admin/includes/file.php');
384 $upload_overrides = array('test_form' => false);
385
386 if( isset( $_FILES[$field_name] ) )
387 $file = wp_handle_upload($_FILES[$field_name], $upload_overrides);
388
389 if (isset($file['error'])) {
390 return new WP_Error('upload_error', $file['error']);
391 }
392 $filename = isset( $_FILES[$field_name]['name'] ) ? sanitize_text_field( $_FILES[$field_name]['name'] ) : '';
393 $wp_filetype = wp_check_filetype($filename, null);
394 $attachment = array(
395 'post_mime_type' => $wp_filetype['type'],
396 'post_title' => $filename,
397 'post_content' => '',
398 'post_status' => 'inherit'
399 );
400 $attachment_id = wp_insert_attachment($attachment, $file['file']);
401 if (!is_wp_error($attachment_id) && is_numeric($attachment_id)) {
402 require_once(ABSPATH . 'wp-admin/includes/image.php');
403 $attachment_data = wp_generate_attachment_metadata($attachment_id, $file['file']);
404 wp_update_attachment_metadata($attachment_id, $attachment_data);
405 return trim($attachment_id);
406 } else {
407 return '';
408 }
409 }
410
411 // Deferred to plugins_loaded so older Profile Builder Pro versions (which declare
412 // wppb_verify_attachment_id unconditionally during their own file load) win the
413 // declaration race and our function_exists guard then skips — avoiding a fatal.
414 add_action( 'plugins_loaded', 'wppb_register_attachment_ownership_helpers', 20 );
415 function wppb_register_attachment_ownership_helpers() {
416
417 /**
418 * Verifies if an attachment either doesn't exist or already belongs to the user.
419 * Used for IDOR protection on both Upload and Avatar fields.
420 *
421 * @param string|int $attachment_id The attachment post ID to verify.
422 * @param int|null $user_id The user ID to check ownership against.
423 *
424 * @return bool True if the attachment is valid for this user, false otherwise.
425 */
426 if ( !function_exists( 'wppb_verify_attachment_id' ) ) {
427 function wppb_verify_attachment_id( $attachment_id, $user_id = null ) {
428 if ( $attachment_id !== '' && is_numeric( $attachment_id ) ) {
429 $attachment = get_post( absint( trim( $attachment_id ) ) );
430 if ( $attachment && $attachment->post_type === 'attachment' ) {
431
432 // Get current user info for admin bypass checks
433 $current_user_id = get_current_user_id();
434 $current_user = $current_user_id ? get_userdata( $current_user_id ) : null;
435 $is_admin = $current_user && current_user_can( 'manage_options' );
436
437 if ( $user_id ) {
438 // Allow admins to upload files for users
439 if ( $is_admin ) {
440 return true;
441 }
442 // The attachment is claimable when it already belongs to the target
443 // user, or to the user performing the request. An author-less
444 // attachment (post_author == 0) is only claimable by an
445 // unauthenticated request (e.g. a visitor registering, whose upload
446 // has no author yet). This prevents an authenticated user from
447 // claiming (IDOR) an author-0 attachment created by someone else's
448 // anonymous/nopriv upload.
449 if ( $attachment->post_author == $user_id
450 || ( $current_user_id && $attachment->post_author == $current_user_id )
451 || ( 0 === (int) $current_user_id && 0 === (int) $attachment->post_author ) ) {
452 return true;
453 }
454 } else {
455 // If no user ID is provided, check if current user is admin
456 if ( $is_admin ) {
457 return true;
458 }
459 // Without an explicit target user, an authenticated user may only
460 // reference an attachment they already own; an author-less
461 // attachment is only claimable by an unauthenticated request.
462 if ( ( $current_user_id && $attachment->post_author == $current_user_id )
463 || ( 0 === (int) $current_user_id && 0 === (int) $attachment->post_author ) ) {
464 return true;
465 }
466 }
467 }
468 }
469 return false;
470 }
471 }
472
473 /**
474 * Validates attachment ownership and updates the user meta and post author.
475 * Used for IDOR-safe saving on both Upload and Avatar fields.
476 *
477 * @param string|int $attachment_id The attachment post ID.
478 * @param array $field The field definition array (must contain 'meta-name').
479 * @param int $user_id The user ID to save for.
480 */
481 if ( !function_exists( 'wppb_save_attachment_id' ) ) {
482 function wppb_save_attachment_id( $attachment_id, $field, $user_id ) {
483 // Verify that the attachment either doesn't exist or already belongs to the user
484 if ( wppb_verify_attachment_id( $attachment_id, $user_id ) ) {
485 update_user_meta( $user_id, $field['meta-name'], absint( $attachment_id ) );
486 wp_update_post( array(
487 'ID' => absint( trim( $attachment_id ) ),
488 'post_author' => $user_id
489 ) );
490 } else {
491 update_user_meta( $user_id, $field['meta-name'], '' );
492 }
493 }
494 }
495 }
496
497 /**
498 * Resolves a simple-upload AJAX `name` parameter to a configured form field.
499 *
500 * @param string $post_name Sanitized value of $_POST['name'] from the AJAX request.
501 * @param string|array $field_type Expected field type(s), e.g. 'Avatar' or 'Upload'.
502 *
503 * @return array|false Field definition array, or false when not found or not simple-upload.
504 */
505 function wppb_resolve_simple_upload_ajax_field( $post_name, $field_type ) {
506 if ( empty( $post_name ) ) {
507 return false;
508 }
509
510 $field_types = is_array( $field_type ) ? $field_type : array( $field_type );
511 $all_fields = apply_filters( 'wppb_form_fields', get_option( 'wppb_manage_fields' ), array( 'context' => 'simple_upload_ajax', 'upload_post_name' => $post_name ) );
512
513 if ( empty( $all_fields ) ) {
514 return false;
515 }
516
517 foreach ( $all_fields as $field ) {
518 if ( ! in_array( $field['field'], $field_types, true ) ) {
519 continue;
520 }
521 if ( ! wppb_use_simple_upload_field( $field ) ) {
522 continue;
523 }
524
525 $field_slug = str_replace( '-', '_', Wordpress_Creation_Kit_PB::wck_generate_slug( $field['meta-name'], $field ) );
526 if ( $field_slug === $post_name ) {
527 return $field;
528 }
529 }
530
531 // The field was not found among the top-level form fields. Repeater fields store
532 // their inner Upload fields in a separate option keyed by the repeater's
533 // meta-name, so those fields are never part of the wppb_manage_fields list scanned
534 // above. Scan the repeater groups as well, otherwise Simple Upload inside a
535 // Repeater field is silently rejected (the lookup fails and the file input clears).
536 return wppb_resolve_simple_upload_ajax_field_in_repeater( $post_name, $field_types, $all_fields );
537 }
538
539 /**
540 * Resolves a simple-upload AJAX `name` parameter to an Upload field nested inside a
541 * Repeater field.
542 *
543 * Repeater sub-fields are stored unindexed in an option keyed by the repeater's
544 * meta-name. On the front-end each group posts either "<slug>" (the first group) or
545 * "<slug>_N" (the Nth extra group), where <slug> is the dash-normalized wck slug of
546 * the inner field's meta-name.
547 *
548 * @param string $post_name Sanitized value of $_POST['name'] from the AJAX request.
549 * @param array $field_types Expected field type(s), e.g. array( 'Upload' ).
550 * @param array $all_fields The already-resolved top-level form fields.
551 *
552 * @return array|false Inner field definition array, or false when not found.
553 */
554 function wppb_resolve_simple_upload_ajax_field_in_repeater( $post_name, $field_types, $all_fields ) {
555 foreach ( $all_fields as $form_field ) {
556 if ( empty( $form_field['field'] ) || $form_field['field'] !== 'Repeater' ) {
557 continue;
558 }
559
560 $repeater_group = get_option( $form_field['meta-name'], 'not_set' );
561 if ( $repeater_group === 'not_set' || ! is_array( $repeater_group ) ) {
562 continue;
563 }
564
565 foreach ( $repeater_group as $inner_field ) {
566 if ( empty( $inner_field['field'] ) || ! in_array( $inner_field['field'], $field_types, true ) ) {
567 continue;
568 }
569 if ( ! wppb_use_simple_upload_field( $inner_field ) ) {
570 continue;
571 }
572
573 $base_slug = str_replace( '-', '_', Wordpress_Creation_Kit_PB::wck_generate_slug( $inner_field['meta-name'], $inner_field ) );
574 if ( $base_slug === $post_name || preg_match( '/^' . preg_quote( $base_slug, '/' ) . '_[0-9]+$/', $post_name ) ) {
575 return $inner_field;
576 }
577 }
578 }
579
580 return false;
581 }
582
583 function wppb_check_that_field_is_defined( $meta_name, $field_types = array() ){
584
585 if( empty( $meta_name ) )
586 return false;
587
588 $defined_fields = apply_filters( 'wppb_form_fields', get_option( 'wppb_manage_fields' ), array( 'context' => 'upload_helper', 'upload_meta_name' => $meta_name ) );
589
590 if( empty( $defined_fields ) )
591 return false;
592 else {
593
594 if( empty( $field_types ) ){
595 foreach( $defined_fields as $field ){
596
597 if( $field['meta-name'] == $meta_name )
598 return true;
599
600 }
601 } else {
602 foreach( $defined_fields as $field ){
603
604 if( in_array( $field['field'], $field_types ) && $field['meta-name'] == $meta_name )
605 return true;
606
607 }
608 }
609
610 }
611
612 return false;
613
614 }