PluginProbe
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent / 3.5.4
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent v3.5.4
3.5.4 3.5.3 3.5.2 3.5.1 3.4.9 3.5.0 3.4.8 3.4.7 trunk 2.3.1 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6
← All changes | includes/rest-api/class-wpsc-rest-attachment.php +97 -29 3.4.8 → 3.5.4 View file →
@@ -65,68 +65,136 @@
65 65 if ( ! isset( $file_parameters['file'] ) ) {
66 66 return new WP_Error( 'rest_missing_callback_param', 'Missing parameter(s): file', array( 'status' => 400 ) );
67 67 }
68 68
69 - $file = $file_parameters['file'];
69 + $file = $file_parameters['file'];
70 70 $file_settings = get_option( 'wpsc-gs-file-attachments' );
71 - $filename = time() . '_' . sanitize_file_name( $file['name'] );
71 +
72 + $original_name = sanitize_file_name( $file['name'] );
73 + $filename = time() . '_' . $original_name;
72 74 $extension = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
73 75 $today = new DateTime();
74 - $upload_dir = wp_upload_dir();
75 76
76 - // Allowed file extension.
77 + // Allowed extensions.
77 78 $allowed_file_extensions = explode( ',', $file_settings['allowed-file-extensions'] );
78 79 $allowed_file_extensions = array_map( 'trim', $allowed_file_extensions );
79 80 $allowed_file_extensions = array_map( 'strtolower', $allowed_file_extensions );
80 - if ( ! ( in_array( $extension, $allowed_file_extensions ) ) ) {
81 +
82 + if ( ! in_array( $extension, $allowed_file_extensions, true ) ) {
81 83 wp_send_json_error( 'File extension not allowed!', 400 );
82 84 }
83 85
84 86 // Allowed file size.
85 87 $allowed_file_size = intval( $file_settings['attachments-max-filesize'] ) * 1000000;
86 - if ( ! ( isset( $file['size'] ) && $file['size'] <= $allowed_file_size ) ) {
88 + if ( ! isset( $file['size'] ) || $file['size'] > $allowed_file_size ) {
87 89 wp_send_json_error( 'File size exceeds allowed limit!', 400 );
88 90 }
89 91
90 - // Init attachment data.
92 + // Ensure wp_handle_upload is available.
93 + if ( ! function_exists( 'wp_handle_upload' ) ) {
94 + require_once ABSPATH . 'wp-admin/includes/file.php';
95 + }
96 +
97 + // Validate MIME using SAME custom mime rules.
98 + add_filter( 'upload_mimes', array( 'WPSC_Attachment', 'wpsc_custom_upload_mimes' ) );
99 + $wp_filetype = wp_check_filetype_and_ext( $file['tmp_name'], $file['name'] );
100 + remove_filter( 'upload_mimes', array( 'WPSC_Attachment', 'wpsc_custom_upload_mimes' ) );
101 +
102 + if ( empty( $wp_filetype['ext'] ) || empty( $wp_filetype['type'] ) ) {
103 + wp_send_json_error( 'Invalid file type!', 400 );
104 + }
105 +
106 + // Strict extension match check.
107 + if ( strtolower( $wp_filetype['ext'] ) !== $extension ) {
108 + wp_send_json_error( 'File extension mismatch detected!', 400 );
109 + }
110 +
111 + if ( ! in_array( strtolower( $wp_filetype['ext'] ), $allowed_file_extensions, true ) ) {
112 + wp_send_json_error( 'File type does not match allowed extension!', 400 );
113 + }
114 +
91 115 $data = array(
92 - 'name' => sanitize_file_name( $file['name'] ),
116 + 'name' => $original_name,
93 117 'date_created' => $today->format( 'Y-m-d H:i:s' ),
94 118 );
95 119
96 - // Check for image type. Add a ".txt" extension to non-image file to prevent executing uploaded files on server.
97 - $img_extensions = array( 'png', 'jpeg', 'jpg', 'bmp', 'pdf', 'gif' );
98 - if ( ! in_array( $extension, $img_extensions ) ) {
120 + // List of safe image extensions.
121 + $safe_images = array( 'png', 'jpeg', 'jpg', 'bmp', 'gif', 'webp' );
122 +
123 + if ( in_array( $extension, $safe_images, true ) && ! wp_get_image_mime( $file['tmp_name'] ) ) {
124 + wp_send_json_error( 'Invalid image file!', 400 );
125 + }
126 +
127 + // PDF validation.
128 + if ( 'pdf' === $extension && 'application/pdf' !== $wp_filetype['type'] ) {
129 + wp_send_json_error( 'Invalid PDF file!', 400 );
130 + }
131 +
132 + if ( in_array( $extension, $safe_images, true ) || 'pdf' === $extension ) {
133 + $data['is_image'] = 1;
134 + } else {
99 135 $data['is_image'] = 0;
100 - } else {
101 - $data['is_image'] = 1;
102 136 }
103 137
104 - // File path.
105 - $file_path = $upload_dir['basedir'] . '/wpsc/' . $today->format( 'Y' ) . '/' . $today->format( 'm' );
106 - if ( ! file_exists( $file_path ) ) {
107 - mkdir( $file_path, 0755, true );
108 - }
109 - $file_path .= '/' . $filename;
138 + $ext = pathinfo( $filename, PATHINFO_EXTENSION );
139 + $file_name = substr( $filename, 0, -( strlen( $ext ) + 1 ) );
140 + $filename = $file_name . '.' . strtolower( $ext );
110 141
111 - $filepath_short = '/wpsc/' . $today->format( 'Y' ) . '/' . $today->format( 'm' ) . '/' . $filename;
112 - $data['file_path'] = $filepath_short;
142 + $filepath_short = '/wpsc/' . $today->format( 'Y' ) . '/' . $today->format( 'm' ) . '/' . $filename;
143 + $data['file_path'] = $filepath_short;
113 144
114 - // Insert record in database.
115 - if ( move_uploaded_file( $file['tmp_name'], $file_path ) ) {
145 + $upload_overrides = array(
146 + 'test_form' => false,
147 + );
116 148
149 + $file['name'] = $filename;
150 +
151 + add_filter( 'upload_dir', array( 'WPSC_Attachment', 'wpsc_upload_dir' ) );
152 + add_filter( 'upload_mimes', array( 'WPSC_Attachment', 'wpsc_custom_upload_mimes' ) );
153 +
154 + $uploaded_file = wp_handle_upload( $file, $upload_overrides );
155 +
156 + remove_filter( 'upload_dir', array( 'WPSC_Attachment', 'wpsc_upload_dir' ) );
157 + remove_filter( 'upload_mimes', array( 'WPSC_Attachment', 'wpsc_custom_upload_mimes' ) );
158 +
159 + if ( $uploaded_file && empty( $uploaded_file['error'] ) ) {
160 +
161 + // Normalize path for cross-platform compatibility.
162 + $normalized_path = wp_normalize_path( $uploaded_file['file'] );
163 +
164 + $pos = strpos( $normalized_path, '/wpsc/' );
165 + if ( $pos === false ) {
166 + wp_send_json_error( 'Something went wrong!', 500 );
167 + }
168 +
169 + $new_path = substr( $normalized_path, $pos );
170 +
171 + if ( $new_path[0] !== '/' ) {
172 + $new_path = '/' . $new_path;
173 + }
174 +
175 + $data['file_path'] = $new_path;
176 +
117 177 $attachment = WPSC_Attachment::insert( $data );
118 178 if ( ! $attachment->id ) {
119 - wp_send_json_error( 'Something went wrong, attachment record not created!', 500 );
179 + wp_send_json_error( 'Something went wrong!', 500 );
120 180 }
121 - $data = array(
122 - 'id' => intval( $attachment->id ),
123 - 'name' => $attachment->name,
181 +
182 + // Record who uploaded it so that only they can later bind it
183 + // to a ticket.
184 + WPSC_Attachment::set_uploader( $attachment );
185 +
186 + return new WP_REST_Response(
187 + array(
188 + 'id' => intval( $attachment->id ),
189 + 'name' => $attachment->name,
190 + ),
191 + 200
124 192 );
125 - return new WP_REST_Response( $data, 200 );
126 193 }
127 194
128 - wp_send_json_error( 'Something went wrong, file not saved!', 500 );
195 + $error_message = isset( $uploaded_file['error'] ) ? $uploaded_file['error'] : 'Something went wrong!';
196 + wp_send_json_error( $error_message, 500 );
129 197 }
130 198
131 199 /**
132 200 * Single attachment