Skip to content

Commit b4f0fc9

Browse files
committed
Media: Allow uploading images from URLs without extensions.
Enable `download_url()` to fetch and verify file types if the URL does not contain a file extension. This allows URL downloads to handle media endpoints like istockphoto.com that use file IDs and formatting arguments to deliver images. Props masteradhoc, mitogh, joedolson, hellofromTonya, antpb, audrasjb, navi161, dmsnell. Fixes #54738. git-svn-id: https://develop.svn.wordpress.org/trunk@59902 602fd350-edb4-49c9-b593-d223f7449a82
1 parent cad2f8c commit b4f0fc9

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

src/wp-admin/includes/file.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,24 @@ function download_url( $url, $timeout = 300, $signature_verification = false ) {
12411241
}
12421242
}
12431243

1244+
$mime_type = wp_remote_retrieve_header( $response, 'content-type' );
1245+
if ( $mime_type && 'tmp' === pathinfo( $tmpfname, PATHINFO_EXTENSION ) ) {
1246+
$valid_mime_types = array_flip( get_allowed_mime_types() );
1247+
if ( ! empty( $valid_mime_types[ $mime_type ] ) ) {
1248+
$extensions = explode( '|', $valid_mime_types[ $mime_type ] );
1249+
$new_image_name = substr( $tmpfname, 0, -4 ) . ".{$extensions[0]}";
1250+
if ( 0 === validate_file( $new_image_name ) ) {
1251+
if ( rename( $tmpfname, $new_image_name ) ) {
1252+
$tmpfname = $new_image_name;
1253+
}
1254+
1255+
if ( ( $tmpfname !== $new_image_name ) && file_exists( $new_image_name ) ) {
1256+
unlink( $new_image_name );
1257+
}
1258+
}
1259+
}
1260+
}
1261+
12441262
$content_md5 = wp_remote_retrieve_header( $response, 'Content-MD5' );
12451263

12461264
if ( $content_md5 ) {

tests/phpunit/tests/admin/includesFile.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,4 +389,78 @@ public function mock_http_request( $response, $parsed_args, $url ) {
389389

390390
return $response;
391391
}
392+
393+
/**
394+
* Test that `download_url()` properly handles setting the file name when set using
395+
* the content type header on URLs with no file extension.
396+
*
397+
* @dataProvider data_download_url_should_use_the_content_type_header_to_set_extension_of_a_file_if_extension_was_not_determined
398+
*
399+
* @covers ::download_url
400+
* @ticket 54738
401+
*
402+
* @param string $filter A callback containing a fake Content-Type header.
403+
* @param string $ext The expected file extension to match.
404+
*/
405+
public function test_download_url_should_use_the_content_type_header_to_set_extension_of_a_file_if_extension_was_not_determined( $filter, $extension ) {
406+
add_filter( 'pre_http_request', $filter );
407+
408+
$filename = download_url( 'url_with_content_type_header' );
409+
$this->assertStringEndsWith( $extension, $filename );
410+
$this->assertFileExists( $filename );
411+
$this->unlink( $filename );
412+
}
413+
414+
/**
415+
* Data provider for test_download_url_should_use_the_content_type_header_to_set_extension_of_a_file_if_extension_was_not_determined
416+
*
417+
* @see test_download_url_should_use_the_content_type_header_to_set_extension_of_a_file_if_extension_was_not_determined()
418+
* @test
419+
* @ticket 54738
420+
*
421+
* @return Generator
422+
*/
423+
public function data_download_url_should_use_the_content_type_header_to_set_extension_of_a_file_if_extension_was_not_determined() {
424+
yield 'Content-Type header in the response' => array(
425+
function () {
426+
return array(
427+
'response' => array(
428+
'code' => 200,
429+
),
430+
'headers' => array(
431+
'content-type' => 'image/jpeg',
432+
),
433+
);
434+
},
435+
'.jpg',
436+
);
437+
438+
yield 'Invalid Content-Type header' => array(
439+
function () {
440+
return array(
441+
'response' => array(
442+
'code' => 200,
443+
),
444+
'headers' => array(
445+
'content-type' => '../../filename-from-content-disposition-header.txt',
446+
),
447+
);
448+
},
449+
'.tmp',
450+
);
451+
452+
yield 'Valid content type but not supported mime type' => array(
453+
function () {
454+
return array(
455+
'response' => array(
456+
'code' => 200,
457+
),
458+
'headers' => array(
459+
'content-type' => 'image/x-xbm',
460+
),
461+
);
462+
},
463+
'.tmp',
464+
);
465+
}
392466
}

0 commit comments

Comments
 (0)