This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller { |
||
4 | |||
5 | /** |
||
6 | * Determine the allowed query_vars for a get_items() response and |
||
7 | * prepare for WP_Query. |
||
8 | * |
||
9 | * @param array $prepared_args |
||
10 | * @param WP_REST_Request $request |
||
11 | * @return array $query_args |
||
12 | */ |
||
13 | protected function prepare_items_query( $prepared_args = array(), $request = null ) { |
||
14 | $query_args = parent::prepare_items_query( $prepared_args, $request ); |
||
15 | if ( empty( $query_args['post_status'] ) || ! in_array( $query_args['post_status'], array( 'inherit', 'private', 'trash' ) ) ) { |
||
16 | $query_args['post_status'] = 'inherit'; |
||
17 | } |
||
18 | $media_types = $this->get_media_types(); |
||
19 | if ( ! empty( $request['media_type'] ) && in_array( $request['media_type'], array_keys( $media_types ) ) ) { |
||
20 | $query_args['post_mime_type'] = $media_types[ $request['media_type'] ]; |
||
21 | } |
||
22 | if ( ! empty( $request['mime_type'] ) ) { |
||
23 | $parts = explode( '/', $request['mime_type'] ); |
||
24 | if ( isset( $media_types[ $parts[0] ] ) && in_array( $request['mime_type'], $media_types[ $parts[0] ] ) ) { |
||
25 | $query_args['post_mime_type'] = $request['mime_type']; |
||
26 | } |
||
27 | } |
||
28 | return $query_args; |
||
29 | } |
||
30 | |||
31 | /** |
||
32 | * Check if a given request has access to create an attachment. |
||
33 | * |
||
34 | * @param WP_REST_Request $request Full details about the request. |
||
35 | * @return WP_Error|boolean |
||
36 | */ |
||
37 | public function create_item_permissions_check( $request ) { |
||
38 | $ret = parent::create_item_permissions_check( $request ); |
||
39 | if ( ! $ret || is_wp_error( $ret ) ) { |
||
40 | return $ret; |
||
41 | } |
||
42 | |||
43 | // "upload_files" cap is returned for an attachment by $post_type_obj->cap->create_posts |
||
44 | $post_type_obj = get_post_type_object( $this->post_type ); |
||
45 | if ( ! current_user_can( $post_type_obj->cap->create_posts ) || ! current_user_can( $post_type_obj->cap->edit_posts ) ) { |
||
46 | return new WP_Error( 'rest_cannot_create', __( 'Sorry, you are not allowed to upload media on this site.' ), array( 'status' => 400 ) ); |
||
47 | } |
||
48 | |||
49 | // Attaching media to a post requires ability to edit said post |
||
50 | if ( ! empty( $request['post'] ) ) { |
||
51 | $parent = $this->get_post( (int) $request['post'] ); |
||
52 | $post_parent_type = get_post_type_object( $parent->post_type ); |
||
53 | if ( ! current_user_can( $post_parent_type->cap->edit_post, $request['post'] ) ) { |
||
54 | return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to upload media to this resource.' ), array( 'status' => rest_authorization_required_code() ) ); |
||
55 | } |
||
56 | } |
||
57 | |||
58 | return true; |
||
59 | } |
||
60 | |||
61 | /** |
||
62 | * Create a single attachment |
||
63 | * |
||
64 | * @param WP_REST_Request $request Full details about the request |
||
65 | * @return WP_Error|WP_REST_Response |
||
66 | */ |
||
67 | public function create_item( $request ) { |
||
68 | |||
69 | if ( ! empty( $request['post'] ) && in_array( get_post_type( $request['post'] ), array( 'revision', 'attachment' ) ) ) { |
||
70 | return new WP_Error( 'rest_invalid_param', __( 'Invalid parent type.' ), array( 'status' => 400 ) ); |
||
71 | } |
||
72 | |||
73 | // Get the file via $_FILES or raw data |
||
74 | $files = $request->get_file_params(); |
||
75 | $headers = $request->get_headers(); |
||
76 | if ( ! empty( $files ) ) { |
||
77 | $file = $this->upload_from_file( $files, $headers ); |
||
78 | } else { |
||
79 | $file = $this->upload_from_data( $request->get_body(), $headers ); |
||
80 | } |
||
81 | |||
82 | if ( is_wp_error( $file ) ) { |
||
83 | return $file; |
||
84 | } |
||
85 | |||
86 | $name = basename( $file['file'] ); |
||
87 | $name_parts = pathinfo( $name ); |
||
88 | $name = trim( substr( $name, 0, -(1 + strlen( $name_parts['extension'] ) ) ) ); |
||
89 | |||
90 | $url = $file['url']; |
||
91 | $type = $file['type']; |
||
92 | $file = $file['file']; |
||
93 | |||
94 | // use image exif/iptc data for title and caption defaults if possible |
||
95 | // @codingStandardsIgnoreStart |
||
96 | $image_meta = @wp_read_image_metadata( $file ); |
||
97 | // @codingStandardsIgnoreEnd |
||
98 | if ( ! empty( $image_meta ) ) { |
||
99 | if ( empty( $request['title'] ) && trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) ) { |
||
100 | $request['title'] = $image_meta['title']; |
||
101 | } |
||
102 | |||
103 | if ( empty( $request['caption'] ) && trim( $image_meta['caption'] ) ) { |
||
104 | $request['caption'] = $image_meta['caption']; |
||
105 | } |
||
106 | } |
||
107 | |||
108 | $attachment = $this->prepare_item_for_database( $request ); |
||
109 | $attachment->file = $file; |
||
110 | $attachment->post_mime_type = $type; |
||
111 | $attachment->guid = $url; |
||
112 | |||
113 | if ( empty( $attachment->post_title ) ) { |
||
114 | $attachment->post_title = preg_replace( '/\.[^.]+$/', '', basename( $file ) ); |
||
115 | } |
||
116 | |||
117 | $id = wp_insert_post( $attachment, true ); |
||
118 | View Code Duplication | if ( is_wp_error( $id ) ) { |
|
119 | if ( in_array( $id->get_error_code(), array( 'db_update_error' ) ) ) { |
||
120 | $id->add_data( array( 'status' => 500 ) ); |
||
121 | } else { |
||
122 | $id->add_data( array( 'status' => 400 ) ); |
||
123 | } |
||
124 | return $id; |
||
125 | } |
||
126 | $attachment = $this->get_post( $id ); |
||
127 | |||
128 | /** Include admin functions to get access to wp_generate_attachment_metadata() */ |
||
129 | require_once ABSPATH . 'wp-admin/includes/admin.php'; |
||
130 | |||
131 | wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) ); |
||
132 | |||
133 | if ( isset( $request['alt_text'] ) ) { |
||
134 | update_post_meta( $id, '_wp_attachment_image_alt', sanitize_text_field( $request['alt_text'] ) ); |
||
135 | } |
||
136 | |||
137 | $fields_update = $this->update_additional_fields_for_object( $attachment, $request ); |
||
138 | if ( is_wp_error( $fields_update ) ) { |
||
139 | return $fields_update; |
||
140 | } |
||
141 | |||
142 | $request->set_param( 'context', 'edit' ); |
||
143 | $response = $this->prepare_item_for_response( $attachment, $request ); |
||
0 ignored issues
–
show
|
|||
144 | $response = rest_ensure_response( $response ); |
||
145 | $response->set_status( 201 ); |
||
146 | $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $id ) ) ); |
||
147 | |||
148 | /** |
||
149 | * Fires after a single attachment is created or updated via the REST API. |
||
150 | * |
||
151 | * @param object $attachment Inserted attachment. |
||
152 | * @param WP_REST_Request $request The request sent to the API. |
||
153 | * @param boolean $creating True when creating an attachment, false when updating. |
||
154 | */ |
||
155 | do_action( 'rest_insert_attachment', $attachment, $request, true ); |
||
156 | |||
157 | return $response; |
||
158 | |||
159 | } |
||
160 | |||
161 | /** |
||
162 | * Update a single post |
||
163 | * |
||
164 | * @param WP_REST_Request $request Full details about the request |
||
165 | * @return WP_Error|WP_REST_Response |
||
166 | */ |
||
167 | public function update_item( $request ) { |
||
168 | if ( ! empty( $request['post'] ) && in_array( get_post_type( $request['post'] ), array( 'revision', 'attachment' ) ) ) { |
||
169 | return new WP_Error( 'rest_invalid_param', __( 'Invalid parent type.' ), array( 'status' => 400 ) ); |
||
170 | } |
||
171 | $response = parent::update_item( $request ); |
||
172 | if ( is_wp_error( $response ) ) { |
||
173 | return $response; |
||
174 | } |
||
175 | |||
176 | $response = rest_ensure_response( $response ); |
||
177 | $data = $response->get_data(); |
||
178 | |||
179 | if ( isset( $request['alt_text'] ) ) { |
||
180 | update_post_meta( $data['id'], '_wp_attachment_image_alt', $request['alt_text'] ); |
||
181 | } |
||
182 | |||
183 | $attachment = $this->get_post( $request['id'] ); |
||
184 | |||
185 | $fields_update = $this->update_additional_fields_for_object( $attachment, $request ); |
||
186 | if ( is_wp_error( $fields_update ) ) { |
||
187 | return $fields_update; |
||
188 | } |
||
189 | |||
190 | $request->set_param( 'context', 'edit' ); |
||
191 | $response = $this->prepare_item_for_response( $attachment, $request ); |
||
0 ignored issues
–
show
It seems like
$attachment defined by $this->get_post($request['id']) on line 183 can be null ; however, WP_REST_Attachments_Cont...are_item_for_response() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
Loading history...
|
|||
192 | $response = rest_ensure_response( $response ); |
||
193 | |||
194 | /* This action is documented in lib/endpoints/class-wp-rest-attachments-controller.php */ |
||
195 | do_action( 'rest_insert_attachment', $data, $request, false ); |
||
196 | |||
197 | return $response; |
||
198 | } |
||
199 | |||
200 | /** |
||
201 | * Prepare a single attachment for create or update |
||
202 | * |
||
203 | * @param WP_REST_Request $request Request object |
||
204 | * @return WP_Error|stdClass $prepared_attachment Post object |
||
205 | */ |
||
206 | protected function prepare_item_for_database( $request ) { |
||
207 | $prepared_attachment = parent::prepare_item_for_database( $request ); |
||
208 | |||
209 | if ( isset( $request['caption'] ) ) { |
||
210 | $prepared_attachment->post_excerpt = $request['caption']; |
||
211 | } |
||
212 | |||
213 | if ( isset( $request['description'] ) ) { |
||
214 | $prepared_attachment->post_content = $request['description']; |
||
215 | } |
||
216 | |||
217 | if ( isset( $request['post'] ) ) { |
||
218 | $prepared_attachment->post_parent = (int) $request['post']; |
||
219 | } |
||
220 | |||
221 | return $prepared_attachment; |
||
222 | } |
||
223 | |||
224 | /** |
||
225 | * Prepare a single attachment output for response |
||
226 | * |
||
227 | * @param WP_Post $post Post object |
||
228 | * @param WP_REST_Request $request Request object |
||
229 | * @return WP_REST_Response $response |
||
230 | */ |
||
231 | public function prepare_item_for_response( $post, $request ) { |
||
232 | $response = parent::prepare_item_for_response( $post, $request ); |
||
233 | $data = $response->get_data(); |
||
234 | |||
235 | $data['alt_text'] = get_post_meta( $post->ID, '_wp_attachment_image_alt', true ); |
||
236 | $data['caption'] = $post->post_excerpt; |
||
237 | $data['description'] = $post->post_content; |
||
238 | $data['media_type'] = wp_attachment_is_image( $post->ID ) ? 'image' : 'file'; |
||
239 | $data['mime_type'] = $post->post_mime_type; |
||
240 | $data['media_details'] = wp_get_attachment_metadata( $post->ID ); |
||
241 | $data['post'] = ! empty( $post->post_parent ) ? (int) $post->post_parent : null; |
||
242 | $data['source_url'] = wp_get_attachment_url( $post->ID ); |
||
243 | |||
244 | // Ensure empty details is an empty object |
||
245 | if ( empty( $data['media_details'] ) ) { |
||
246 | $data['media_details'] = new stdClass; |
||
247 | } elseif ( ! empty( $data['media_details']['sizes'] ) ) { |
||
248 | |||
249 | foreach ( $data['media_details']['sizes'] as $size => &$size_data ) { |
||
250 | |||
251 | if ( isset( $size_data['mime-type'] ) ) { |
||
252 | $size_data['mime_type'] = $size_data['mime-type']; |
||
253 | unset( $size_data['mime-type'] ); |
||
254 | } |
||
255 | |||
256 | // Use the same method image_downsize() does |
||
257 | $image_src = wp_get_attachment_image_src( $post->ID, $size ); |
||
258 | if ( ! $image_src ) { |
||
259 | continue; |
||
260 | } |
||
261 | |||
262 | $size_data['source_url'] = $image_src[0]; |
||
263 | } |
||
264 | |||
265 | $full_src = wp_get_attachment_image_src( $post->ID, 'full' ); |
||
266 | if ( ! empty( $full_src ) ) { |
||
267 | $data['media_details']['sizes']['full'] = array( |
||
268 | 'file' => wp_basename( $full_src[0] ), |
||
269 | 'width' => $full_src[1], |
||
270 | 'height' => $full_src[2], |
||
271 | 'mime_type' => $post->post_mime_type, |
||
272 | 'source_url' => $full_src[0], |
||
273 | ); |
||
274 | } |
||
275 | } else { |
||
276 | $data['media_details']['sizes'] = new stdClass; |
||
277 | } |
||
278 | |||
279 | $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; |
||
280 | |||
281 | $data = $this->filter_response_by_context( $data, $context ); |
||
282 | |||
283 | // Wrap the data in a response object |
||
284 | $response = rest_ensure_response( $data ); |
||
285 | |||
286 | $response->add_links( $this->prepare_links( $post ) ); |
||
287 | |||
288 | /** |
||
289 | * Filter an attachment returned from the API. |
||
290 | * |
||
291 | * Allows modification of the attachment right before it is returned. |
||
292 | * |
||
293 | * @param WP_REST_Response $response The response object. |
||
294 | * @param WP_Post $post The original attachment post. |
||
295 | * @param WP_REST_Request $request Request used to generate the response. |
||
296 | */ |
||
297 | return apply_filters( 'rest_prepare_attachment', $response, $post, $request ); |
||
298 | } |
||
299 | |||
300 | /** |
||
301 | * Get the Attachment's schema, conforming to JSON Schema |
||
302 | * |
||
303 | * @return array |
||
304 | */ |
||
305 | public function get_item_schema() { |
||
306 | |||
307 | $schema = parent::get_item_schema(); |
||
308 | |||
309 | $schema['properties']['alt_text'] = array( |
||
310 | 'description' => __( 'Alternative text to display when resource is not displayed.' ), |
||
311 | 'type' => 'string', |
||
312 | 'context' => array( 'view', 'edit', 'embed' ), |
||
313 | 'arg_options' => array( |
||
314 | 'sanitize_callback' => 'sanitize_text_field', |
||
315 | ), |
||
316 | ); |
||
317 | $schema['properties']['caption'] = array( |
||
318 | 'description' => __( 'The caption for the resource.' ), |
||
319 | 'type' => 'string', |
||
320 | 'context' => array( 'view', 'edit' ), |
||
321 | 'arg_options' => array( |
||
322 | 'sanitize_callback' => 'wp_filter_post_kses', |
||
323 | ), |
||
324 | ); |
||
325 | $schema['properties']['description'] = array( |
||
326 | 'description' => __( 'The description for the resource.' ), |
||
327 | 'type' => 'string', |
||
328 | 'context' => array( 'view', 'edit' ), |
||
329 | 'arg_options' => array( |
||
330 | 'sanitize_callback' => 'wp_filter_post_kses', |
||
331 | ), |
||
332 | ); |
||
333 | $schema['properties']['media_type'] = array( |
||
334 | 'description' => __( 'Type of resource.' ), |
||
335 | 'type' => 'string', |
||
336 | 'enum' => array( 'image', 'file' ), |
||
337 | 'context' => array( 'view', 'edit', 'embed' ), |
||
338 | 'readonly' => true, |
||
339 | ); |
||
340 | $schema['properties']['mime_type'] = array( |
||
341 | 'description' => __( 'Mime type of resource.' ), |
||
342 | 'type' => 'string', |
||
343 | 'context' => array( 'view', 'edit', 'embed' ), |
||
344 | 'readonly' => true, |
||
345 | ); |
||
346 | $schema['properties']['media_details'] = array( |
||
347 | 'description' => __( 'Details about the resource file, specific to its type.' ), |
||
348 | 'type' => 'object', |
||
349 | 'context' => array( 'view', 'edit', 'embed' ), |
||
350 | 'readonly' => true, |
||
351 | ); |
||
352 | $schema['properties']['post'] = array( |
||
353 | 'description' => __( 'The id for the associated post of the resource.' ), |
||
354 | 'type' => 'integer', |
||
355 | 'context' => array( 'view', 'edit' ), |
||
356 | ); |
||
357 | $schema['properties']['source_url'] = array( |
||
358 | 'description' => __( 'URL to the original resource file.' ), |
||
359 | 'type' => 'string', |
||
360 | 'format' => 'uri', |
||
361 | 'context' => array( 'view', 'edit', 'embed' ), |
||
362 | 'readonly' => true, |
||
363 | ); |
||
364 | return $schema; |
||
365 | } |
||
366 | |||
367 | /** |
||
368 | * Handle an upload via raw POST data |
||
369 | * |
||
370 | * @param array $data Supplied file data |
||
371 | * @param array $headers HTTP headers from the request |
||
372 | * @return array|WP_Error Data from {@see wp_handle_sideload()} |
||
373 | */ |
||
374 | protected function upload_from_data( $data, $headers ) { |
||
375 | if ( empty( $data ) ) { |
||
376 | return new WP_Error( 'rest_upload_no_data', __( 'No data supplied' ), array( 'status' => 400 ) ); |
||
377 | } |
||
378 | |||
379 | if ( empty( $headers['content_type'] ) ) { |
||
380 | return new WP_Error( 'rest_upload_no_content_type', __( 'No Content-Type supplied' ), array( 'status' => 400 ) ); |
||
381 | } |
||
382 | |||
383 | if ( empty( $headers['content_disposition'] ) ) { |
||
384 | return new WP_Error( 'rest_upload_no_content_disposition', __( 'No Content-Disposition supplied' ), array( 'status' => 400 ) ); |
||
385 | } |
||
386 | |||
387 | $filename = $this->get_filename_from_disposition( $headers['content_disposition'] ); |
||
388 | |||
389 | if ( empty( $filename ) ) { |
||
390 | return new WP_Error( 'rest_upload_invalid_disposition', __( 'Invalid Content-Disposition supplied. Content-Disposition needs to be formatted as `attachment; filename="image.png"` or similar.' ), array( 'status' => 400 ) ); |
||
391 | } |
||
392 | |||
393 | View Code Duplication | if ( ! empty( $headers['content_md5'] ) ) { |
|
394 | $content_md5 = array_shift( $headers['content_md5'] ); |
||
395 | $expected = trim( $content_md5 ); |
||
396 | $actual = md5( $data ); |
||
397 | |||
398 | if ( $expected !== $actual ) { |
||
399 | return new WP_Error( 'rest_upload_hash_mismatch', __( 'Content hash did not match expected' ), array( 'status' => 412 ) ); |
||
400 | } |
||
401 | } |
||
402 | |||
403 | // Get the content-type |
||
404 | $type = array_shift( $headers['content_type'] ); |
||
405 | |||
406 | /** Include admin functions to get access to wp_tempnam() and wp_handle_sideload() */ |
||
407 | require_once ABSPATH . 'wp-admin/includes/admin.php'; |
||
408 | |||
409 | // Save the file |
||
410 | $tmpfname = wp_tempnam( $filename ); |
||
411 | |||
412 | $fp = fopen( $tmpfname, 'w+' ); |
||
413 | |||
414 | if ( ! $fp ) { |
||
415 | return new WP_Error( 'rest_upload_file_error', __( 'Could not open file handle' ), array( 'status' => 500 ) ); |
||
416 | } |
||
417 | |||
418 | fwrite( $fp, $data ); |
||
419 | fclose( $fp ); |
||
420 | |||
421 | // Now, sideload it in |
||
422 | $file_data = array( |
||
423 | 'error' => null, |
||
424 | 'tmp_name' => $tmpfname, |
||
425 | 'name' => $filename, |
||
426 | 'type' => $type, |
||
427 | ); |
||
428 | $overrides = array( |
||
429 | 'test_form' => false, |
||
430 | ); |
||
431 | $sideloaded = wp_handle_sideload( $file_data, $overrides ); |
||
432 | |||
433 | if ( isset( $sideloaded['error'] ) ) { |
||
434 | // @codingStandardsIgnoreStart |
||
435 | @unlink( $tmpfname ); |
||
436 | // @codingStandardsIgnoreEnd |
||
437 | return new WP_Error( 'rest_upload_sideload_error', $sideloaded['error'], array( 'status' => 500 ) ); |
||
438 | } |
||
439 | |||
440 | return $sideloaded; |
||
441 | } |
||
442 | |||
443 | /** |
||
444 | * Parse filename from a Content-Disposition header value. |
||
445 | * |
||
446 | * As per RFC6266: |
||
447 | * |
||
448 | * content-disposition = "Content-Disposition" ":" |
||
449 | * disposition-type *( ";" disposition-parm ) |
||
450 | * |
||
451 | * disposition-type = "inline" | "attachment" | disp-ext-type |
||
452 | * ; case-insensitive |
||
453 | * disp-ext-type = token |
||
454 | * |
||
455 | * disposition-parm = filename-parm | disp-ext-parm |
||
456 | * |
||
457 | * filename-parm = "filename" "=" value |
||
458 | * | "filename*" "=" ext-value |
||
459 | * |
||
460 | * disp-ext-parm = token "=" value |
||
461 | * | ext-token "=" ext-value |
||
462 | * ext-token = <the characters in token, followed by "*"> |
||
463 | * |
||
464 | * @see http://tools.ietf.org/html/rfc2388 |
||
465 | * @see http://tools.ietf.org/html/rfc6266 |
||
466 | * |
||
467 | * @param string[] $disposition_header List of Content-Disposition header values. |
||
468 | * @return string|null Filename if available, or null if not found. |
||
469 | */ |
||
470 | public static function get_filename_from_disposition( $disposition_header ) { |
||
471 | // Get the filename |
||
472 | $filename = null; |
||
473 | |||
474 | foreach ( $disposition_header as $value ) { |
||
475 | $value = trim( $value ); |
||
476 | |||
477 | if ( strpos( $value, ';' ) === false ) { |
||
478 | continue; |
||
479 | } |
||
480 | |||
481 | list( $type, $attr_parts ) = explode( ';', $value, 2 ); |
||
482 | $attr_parts = explode( ';', $attr_parts ); |
||
483 | $attributes = array(); |
||
484 | foreach ( $attr_parts as $part ) { |
||
485 | if ( strpos( $part, '=' ) === false ) { |
||
486 | continue; |
||
487 | } |
||
488 | |||
489 | list( $key, $value ) = explode( '=', $part, 2 ); |
||
490 | $attributes[ trim( $key ) ] = trim( $value ); |
||
491 | } |
||
492 | |||
493 | if ( empty( $attributes['filename'] ) ) { |
||
494 | continue; |
||
495 | } |
||
496 | |||
497 | $filename = trim( $attributes['filename'] ); |
||
498 | |||
499 | // Unquote quoted filename, but after trimming. |
||
500 | if ( substr( $filename, 0, 1 ) === '"' && substr( $filename, -1, 1 ) === '"' ) { |
||
501 | $filename = substr( $filename, 1, -1 ); |
||
502 | } |
||
503 | } |
||
504 | |||
505 | return $filename; |
||
506 | } |
||
507 | |||
508 | /** |
||
509 | * Get the query params for collections of attachments. |
||
510 | * |
||
511 | * @return array |
||
512 | */ |
||
513 | public function get_collection_params() { |
||
514 | $params = parent::get_collection_params(); |
||
515 | $params['status']['default'] = 'inherit'; |
||
516 | $params['status']['enum'] = array( 'inherit', 'private', 'trash' ); |
||
517 | $media_types = $this->get_media_types(); |
||
518 | $params['media_type'] = array( |
||
519 | 'default' => null, |
||
520 | 'description' => __( 'Limit result set to attachments of a particular media type.' ), |
||
521 | 'type' => 'string', |
||
522 | 'enum' => array_keys( $media_types ), |
||
523 | 'validate_callback' => 'rest_validate_request_arg', |
||
524 | ); |
||
525 | $params['mime_type'] = array( |
||
526 | 'default' => null, |
||
527 | 'description' => __( 'Limit result set to attachments of a particular mime type.' ), |
||
528 | 'type' => 'string', |
||
529 | ); |
||
530 | return $params; |
||
531 | } |
||
532 | |||
533 | /** |
||
534 | * Validate whether the user can query private statuses |
||
535 | * |
||
536 | * @param mixed $value |
||
537 | * @param WP_REST_Request $request |
||
538 | * @param string $parameter |
||
539 | * @return WP_Error|boolean |
||
540 | */ |
||
541 | public function validate_user_can_query_private_statuses( $value, $request, $parameter ) { |
||
542 | if ( 'inherit' === $value ) { |
||
543 | return true; |
||
544 | } |
||
545 | return parent::validate_user_can_query_private_statuses( $value, $request, $parameter ); |
||
546 | } |
||
547 | |||
548 | /** |
||
549 | * Handle an upload via multipart/form-data ($_FILES) |
||
550 | * |
||
551 | * @param array $files Data from $_FILES |
||
552 | * @param array $headers HTTP headers from the request |
||
553 | * @return array|WP_Error Data from {@see wp_handle_upload()} |
||
554 | */ |
||
555 | protected function upload_from_file( $files, $headers ) { |
||
556 | if ( empty( $files ) ) { |
||
557 | return new WP_Error( 'rest_upload_no_data', __( 'No data supplied' ), array( 'status' => 400 ) ); |
||
558 | } |
||
559 | |||
560 | // Verify hash, if given |
||
561 | View Code Duplication | if ( ! empty( $headers['content_md5'] ) ) { |
|
562 | $content_md5 = array_shift( $headers['content_md5'] ); |
||
563 | $expected = trim( $content_md5 ); |
||
564 | $actual = md5_file( $files['file']['tmp_name'] ); |
||
565 | if ( $expected !== $actual ) { |
||
566 | return new WP_Error( 'rest_upload_hash_mismatch', __( 'Content hash did not match expected' ), array( 'status' => 412 ) ); |
||
567 | } |
||
568 | } |
||
569 | |||
570 | // Pass off to WP to handle the actual upload |
||
571 | $overrides = array( |
||
572 | 'test_form' => false, |
||
573 | ); |
||
574 | // Bypasses is_uploaded_file() when running unit tests |
||
575 | if ( defined( 'DIR_TESTDATA' ) && DIR_TESTDATA ) { |
||
576 | $overrides['action'] = 'wp_handle_mock_upload'; |
||
577 | } |
||
578 | |||
579 | /** Include admin functions to get access to wp_handle_upload() */ |
||
580 | require_once ABSPATH . 'wp-admin/includes/admin.php'; |
||
581 | $file = wp_handle_upload( $files['file'], $overrides ); |
||
582 | |||
583 | if ( isset( $file['error'] ) ) { |
||
584 | return new WP_Error( 'rest_upload_unknown_error', $file['error'], array( 'status' => 500 ) ); |
||
585 | } |
||
586 | |||
587 | return $file; |
||
588 | } |
||
589 | |||
590 | /** |
||
591 | * Get the supported media types. |
||
592 | * Media types are considered the mime type category |
||
593 | * |
||
594 | * @return array |
||
595 | */ |
||
596 | protected function get_media_types() { |
||
597 | $media_types = array(); |
||
598 | foreach ( get_allowed_mime_types() as $mime_type ) { |
||
599 | $parts = explode( '/', $mime_type ); |
||
600 | if ( ! isset( $media_types[ $parts[0] ] ) ) { |
||
601 | $media_types[ $parts[0] ] = array(); |
||
602 | } |
||
603 | $media_types[ $parts[0] ][] = $mime_type; |
||
604 | } |
||
605 | return $media_types; |
||
606 | } |
||
607 | |||
608 | } |
||
609 |
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: