Title: download_url
Published: April 25, 2014
Last modified: May 20, 2026

---

# download_url( string $url, int $timeout = 300, bool $signature_verification = false ): string|󠀁[WP_Error](https://developer.wordpress.org/reference/classes/wp_error/)󠁿

## In this article

 * [Description](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#description)
 * [Parameters](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#parameters)
 * [Return](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#return)
 * [Source](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#source)
 * [Hooks](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#hooks)
 * [Related](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#related)
 * [Changelog](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#changelog)
 * [User Contributed Notes](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#user-contributed-notes)

[ Back to top](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#wp--skip-link--target)

Downloads a URL to a local temporary file using the WordPress HTTP API.

## 󠀁[Description](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#description)󠁿

Please note that the calling function must delete or move the file.

## 󠀁[Parameters](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#parameters)󠁿

 `$url`stringrequired

The URL of the file to download.

`$timeout`intoptional

The timeout for the request to download the file.
 Default 300 seconds.

Default:`300`

`$signature_verification`booloptional

Whether to perform Signature Verification.

Default:`false`

## 󠀁[Return](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#return)󠁿

 string|[WP_Error](https://developer.wordpress.org/reference/classes/wp_error/) 
Filename on success, [WP_Error](https://developer.wordpress.org/reference/classes/wp_error/)
on failure.

## 󠀁[Source](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#source)󠁿

    ```php
    function download_url( $url, $timeout = 300, $signature_verification = false ) {
    	// WARNING: The file is not automatically deleted, the script must delete or move the file.
    	if ( ! $url ) {
    		return new WP_Error( 'http_no_url', __( 'No URL Provided.' ) );
    	}

    	$url_path     = parse_url( $url, PHP_URL_PATH );
    	$url_filename = '';
    	if ( is_string( $url_path ) && '' !== $url_path ) {
    		$url_filename = basename( $url_path );
    	}

    	$tmpfname = wp_tempnam( $url_filename );
    	if ( ! $tmpfname ) {
    		return new WP_Error( 'http_no_file', __( 'Could not create temporary file.' ) );
    	}

    	$response = wp_safe_remote_get(
    		$url,
    		array(
    			'timeout'  => $timeout,
    			'stream'   => true,
    			'filename' => $tmpfname,
    		)
    	);

    	if ( is_wp_error( $response ) ) {
    		unlink( $tmpfname );
    		return $response;
    	}

    	$response_code = wp_remote_retrieve_response_code( $response );

    	if ( 200 !== $response_code ) {
    		$data = array(
    			'code' => $response_code,
    		);

    		// Retrieve a sample of the response body for debugging purposes.
    		$tmpf = fopen( $tmpfname, 'rb' );

    		if ( $tmpf ) {
    			/**
    			 * Filters the maximum error response body size in `download_url()`.
    			 *
    			 * @since 5.1.0
    			 *
    			 * @see download_url()
    			 *
    			 * @param int $size The maximum error response body size. Default 1 KB.
    			 */
    			$response_size = apply_filters( 'download_url_error_max_body_size', KB_IN_BYTES );

    			$data['body'] = fread( $tmpf, $response_size );
    			fclose( $tmpf );
    		}

    		unlink( $tmpfname );

    		return new WP_Error( 'http_404', trim( wp_remote_retrieve_response_message( $response ) ), $data );
    	}

    	$content_disposition = wp_remote_retrieve_header( $response, 'Content-Disposition' );

    	if ( $content_disposition ) {
    		$content_disposition = strtolower( $content_disposition );

    		if ( str_starts_with( $content_disposition, 'attachment; filename=' ) ) {
    			$tmpfname_disposition = sanitize_file_name( substr( $content_disposition, 21 ) );
    		} else {
    			$tmpfname_disposition = '';
    		}

    		// Potential file name must be valid string.
    		if ( $tmpfname_disposition && is_string( $tmpfname_disposition )
    			&& ( 0 === validate_file( $tmpfname_disposition ) )
    		) {
    			$tmpfname_disposition = dirname( $tmpfname ) . '/' . $tmpfname_disposition;

    			if ( rename( $tmpfname, $tmpfname_disposition ) ) {
    				$tmpfname = $tmpfname_disposition;
    			}

    			if ( ( $tmpfname !== $tmpfname_disposition ) && file_exists( $tmpfname_disposition ) ) {
    				unlink( $tmpfname_disposition );
    			}
    		}
    	}

    	$mime_type = wp_remote_retrieve_header( $response, 'content-type' );
    	if ( $mime_type && 'tmp' === pathinfo( $tmpfname, PATHINFO_EXTENSION ) ) {
    		$valid_mime_types = array_flip( get_allowed_mime_types() );
    		if ( ! empty( $valid_mime_types[ $mime_type ] ) ) {
    			$extensions     = explode( '|', $valid_mime_types[ $mime_type ] );
    			$new_image_name = substr( $tmpfname, 0, -4 ) . ".{$extensions[0]}";
    			if ( 0 === validate_file( $new_image_name ) ) {
    				if ( rename( $tmpfname, $new_image_name ) ) {
    					$tmpfname = $new_image_name;
    				}

    				if ( ( $tmpfname !== $new_image_name ) && file_exists( $new_image_name ) ) {
    					unlink( $new_image_name );
    				}
    			}
    		}
    	}

    	$content_md5 = wp_remote_retrieve_header( $response, 'Content-MD5' );

    	if ( $content_md5 ) {
    		$md5_check = verify_file_md5( $tmpfname, $content_md5 );

    		if ( is_wp_error( $md5_check ) ) {
    			unlink( $tmpfname );
    			return $md5_check;
    		}
    	}

    	// If the caller expects signature verification to occur, check to see if this URL supports it.
    	if ( $signature_verification ) {
    		/**
    		 * Filters the list of hosts which should have Signature Verification attempted on.
    		 *
    		 * @since 5.2.0
    		 *
    		 * @param string[] $hostnames List of hostnames.
    		 */
    		$signed_hostnames = apply_filters( 'wp_signature_hosts', array( 'wordpress.org', 'downloads.wordpress.org', 's.w.org' ) );

    		$signature_verification = in_array( parse_url( $url, PHP_URL_HOST ), $signed_hostnames, true );
    	}

    	// Perform signature validation if supported.
    	if ( $signature_verification ) {
    		$signature = wp_remote_retrieve_header( $response, 'X-Content-Signature' );

    		if ( ! $signature ) {
    			/*
    			 * Retrieve signatures from a file if the header wasn't included.
    			 * WordPress.org stores signatures at $package_url.sig.
    			 */

    			$signature_url = false;

    			if ( is_string( $url_path ) && ( str_ends_with( $url_path, '.zip' ) || str_ends_with( $url_path, '.tar.gz' ) ) ) {
    				$signature_url = str_replace( $url_path, $url_path . '.sig', $url );
    			}

    			/**
    			 * Filters the URL where the signature for a file is located.
    			 *
    			 * @since 5.2.0
    			 *
    			 * @param false|string $signature_url The URL where signatures can be found for a file, or false if none are known.
    			 * @param string $url                 The URL being verified.
    			 */
    			$signature_url = apply_filters( 'wp_signature_url', $signature_url, $url );

    			if ( $signature_url ) {
    				$signature_request = wp_safe_remote_get(
    					$signature_url,
    					array(
    						'limit_response_size' => 10 * KB_IN_BYTES, // 10KB should be large enough for quite a few signatures.
    					)
    				);

    				if ( ! is_wp_error( $signature_request ) && 200 === wp_remote_retrieve_response_code( $signature_request ) ) {
    					$signature = explode( "\n", wp_remote_retrieve_body( $signature_request ) );
    				}
    			}
    		}

    		// Perform the checks.
    		$signature_verification = verify_file_signature( $tmpfname, $signature, $url_filename );
    	}

    	if ( is_wp_error( $signature_verification ) ) {
    		if (
    			/**
    			 * Filters whether Signature Verification failures should be allowed to soft fail.
    			 *
    			 * WARNING: This may be removed from a future release.
    			 *
    			 * @since 5.2.0
    			 *
    			 * @param bool   $signature_softfail If a softfail is allowed.
    			 * @param string $url                The url being accessed.
    			 */
    			apply_filters( 'wp_signature_softfail', true, $url )
    		) {
    			$signature_verification->add_data( $tmpfname, 'softfail-filename' );
    		} else {
    			// Hard-fail.
    			unlink( $tmpfname );
    		}

    		return $signature_verification;
    	}

    	return $tmpfname;
    }
    ```

[View all references](https://developer.wordpress.org/reference/files/wp-admin/includes/file.php/)
[View on Trac](https://core.trac.wordpress.org/browser/tags/7.0/src/wp-admin/includes/file.php#L1149)
[View on GitHub](https://github.com/WordPress/wordpress-develop/blob/7.0/src/wp-admin/includes/file.php#L1149-L1349)

## 󠀁[Hooks](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#hooks)󠁿

 [apply_filters( ‘download_url_error_max_body_size’, int $size )](https://developer.wordpress.org/reference/hooks/download_url_error_max_body_size/)

Filters the maximum error response body size in `download_url()`.

 [apply_filters( ‘wp_signature_hosts’, string[] $hostnames )](https://developer.wordpress.org/reference/hooks/wp_signature_hosts/)

Filters the list of hosts which should have Signature Verification attempted on.

 [apply_filters( ‘wp_signature_softfail’, bool $signature_softfail, string $url )](https://developer.wordpress.org/reference/hooks/wp_signature_softfail/)

Filters whether Signature Verification failures should be allowed to soft fail.

 [apply_filters( ‘wp_signature_url’, false|string $signature_url, string $url )](https://developer.wordpress.org/reference/hooks/wp_signature_url/)

Filters the URL where the signature for a file is located.

## 󠀁[Related](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#related)󠁿

| Uses | Description | 
| [verify_file_signature()](https://developer.wordpress.org/reference/functions/verify_file_signature/)`wp-admin/includes/file.php` |

Verifies the contents of a file against its ED25519 signature.

  | 
| [wp_tempnam()](https://developer.wordpress.org/reference/functions/wp_tempnam/)`wp-admin/includes/file.php` |

Returns a filename of a temporary unique file.

  | 
| [verify_file_md5()](https://developer.wordpress.org/reference/functions/verify_file_md5/)`wp-admin/includes/file.php` |

Calculates and compares the MD5 of a file to its expected value.

  | 
| [sanitize_file_name()](https://developer.wordpress.org/reference/functions/sanitize_file_name/)`wp-includes/formatting.php` |

Sanitizes a filename, replacing whitespace with dashes.

  | 
| [validate_file()](https://developer.wordpress.org/reference/functions/validate_file/)`wp-includes/functions.php` |

Validates a file name and path against an allowed set of rules.

  | 
| [get_allowed_mime_types()](https://developer.wordpress.org/reference/functions/get_allowed_mime_types/)`wp-includes/functions.php` |

Retrieves the list of allowed mime types and file extensions.

  | 
| [wp_safe_remote_get()](https://developer.wordpress.org/reference/functions/wp_safe_remote_get/)`wp-includes/http.php` |

Retrieves the raw response from a safe HTTP request using the GET method.

  | 
| [wp_remote_retrieve_response_code()](https://developer.wordpress.org/reference/functions/wp_remote_retrieve_response_code/)`wp-includes/http.php` |

Retrieves only the response code from the raw response.

  | 
| [wp_remote_retrieve_response_message()](https://developer.wordpress.org/reference/functions/wp_remote_retrieve_response_message/)`wp-includes/http.php` |

Retrieves only the response message from the raw response.

  | 
| [wp_remote_retrieve_header()](https://developer.wordpress.org/reference/functions/wp_remote_retrieve_header/)`wp-includes/http.php` |

Retrieves a single header by name from the raw response.

  | 
| [wp_remote_retrieve_body()](https://developer.wordpress.org/reference/functions/wp_remote_retrieve_body/)`wp-includes/http.php` |

Retrieves only the body from the raw response.

  | 
| [__()](https://developer.wordpress.org/reference/functions/__/)`wp-includes/l10n.php` |

Retrieves the translation of $text.

  | 
| [apply_filters()](https://developer.wordpress.org/reference/functions/apply_filters/)`wp-includes/plugin.php` |

Calls the callback functions that have been added to a filter hook.

  | 
| [is_wp_error()](https://developer.wordpress.org/reference/functions/is_wp_error/)`wp-includes/load.php` |

Checks whether the given variable is a WordPress Error.

  | 
| [WP_Error::__construct()](https://developer.wordpress.org/reference/classes/wp_error/__construct/)`wp-includes/class-wp-error.php` |

Initializes the error.

  |

[Show 10 more](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#)
[Show less](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#)

| Used by | Description | 
| [WP_Upgrader::download_package()](https://developer.wordpress.org/reference/classes/wp_upgrader/download_package/)`wp-admin/includes/class-wp-upgrader.php` |

Downloads a package for a WordPress core, plugin, theme, or translation upgrade.

  | 
| [media_sideload_image()](https://developer.wordpress.org/reference/functions/media_sideload_image/)`wp-admin/includes/media.php` |

Downloads an image from the specified URL, saves it as an attachment, and optionally attaches it to a post.

  |

## 󠀁[Changelog](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#changelog)󠁿

| Version | Description | 
| [5.9.0](https://developer.wordpress.org/reference/since/5.9.0/) | Support for Content-Disposition filename was added. | 
| [5.2.0](https://developer.wordpress.org/reference/since/5.2.0/) | Signature Verification with SoftFail was added. | 
| [2.5.0](https://developer.wordpress.org/reference/since/2.5.0/) | Introduced. |

## 󠀁[User Contributed Notes](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#user-contributed-notes)󠁿

 1.   [Skip to note 5 content](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#comment-content-3048)
 2.    [Breno Alves](https://profiles.wordpress.org/breno-alves/)  [  7 years ago  ](https://developer.wordpress.org/reference/functions/download_url/#comment-3048)
 3.  [You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fdownload_url%2F%23comment-3048)
     Vote results for this note: 9[You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fdownload_url%2F%23comment-3048)
 4.  To be able to use this function in the front-end nor cron you must include `wp-
     admin/includes/file.php` file.
 5.      ```php
         <?php
     
         // If the function it's not available, require it.
         if ( ! function_exists( 'download_url' ) ) {
         	require_once ABSPATH . 'wp-admin/includes/file.php';
         }
     
         // Now you can use it!
         $file_url = 'https://example.com/myfile.ext';
         $tmp_file = download_url( $file_url );
     
         // Sets file final destination.
         $filepath = ABSPATH . 'wp-content/uploads/myfile.ext';
     
         // Copies the file to the final destination and deletes temporary file.
         copy( $tmp_file, $filepath );
         @unlink( $tmp_file );
         ```
     
 6.   [Log in to add feedback](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fdownload_url%2F%3Freplytocom%3D3048%23feedback-editor-3048)
 7.   [Skip to note 6 content](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#comment-content-6738)
 8.    Anonymous User  [  3 years ago  ](https://developer.wordpress.org/reference/functions/download_url/#comment-6738)
 9.  [You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fdownload_url%2F%23comment-6738)
     Vote results for this note: 0[You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fdownload_url%2F%23comment-6738)
 10. `unlink()` (and worse, its `@` silenced version) is discouraged in WPCS.
      Use 
     [`wp_delete_file()`](https://developer.wordpress.org/reference/functions/wp_delete_file/)
     instead.
 11.  [Log in to add feedback](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fdownload_url%2F%3Freplytocom%3D6738%23feedback-editor-6738)
 12.  [Skip to note 7 content](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#comment-content-7235)
 13.   [Sabuj Kundu](https://profiles.wordpress.org/manchumahara/)  [  2 years ago  ](https://developer.wordpress.org/reference/functions/download_url/#comment-7235)
 14. [You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fdownload_url%2F%23comment-7235)
     Vote results for this note: 0[You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fdownload_url%2F%23comment-7235)
 15. **Please note that: This function doesn’t work for local domain url to download.
     Don’t waste time like me. Explanation below: **
 16. I was testing `download_url()` function in local development to download a file
     from one site to another in local server and always found error “A valid URL was
     not provided”. What I found after debug and checking the source code function `
     download_url()` calls another function `wp_safe_remote_get()` which is like below
 17.     ```php
         function wp_safe_remote_get( $url, $args = array() ) {
         	$args['reject_unsafe_urls'] = true;
         	$http                       = _wp_http_get_object();
         	return $http->get( $url, $args );
         }
         ```
     
 18. `$args['reject_unsafe_urls'] = true;` param actually rejects local domain.
 19.  [Log in to add feedback](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fdownload_url%2F%3Freplytocom%3D7235%23feedback-editor-7235)
 20.  [Skip to note 8 content](https://developer.wordpress.org/reference/functions/download_url/?output_format=md#comment-content-3422)
 21.   [Marcio Zebedeu](https://profiles.wordpress.org/marcio-zebedeu/)  [  7 years ago  ](https://developer.wordpress.org/reference/functions/download_url/#comment-3422)
 22. [You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fdownload_url%2F%23comment-3422)
     Vote results for this note: -6[You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fdownload_url%2F%23comment-3422)
 23. WordPress files can be called easily by accessing the wp-load file.php which is
     located at the root of wordpress installation.
 24.     ```php
             require_once(BASE_PATH . 'wp-load.php');
         ```
     
 25.     ```php
             /*
                 link to file to be downloaded
             */
         	    public function download( $url = "http://www.example.com/example/downloads/information/php.pdf&quot;){
                 download_url( $url );
         }
         ```
     
 26.  * Calling wp-load.php is a bad practice and shoud be discouraged. Use wp redirects
        and htaccess redirects to make virtual pages instead.
      * [JCV](https://profiles.wordpress.org/psykonevro/) [5 years ago](https://developer.wordpress.org/reference/functions/download_url/#comment-5054)
 27.  [Log in to add feedback](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fdownload_url%2F%3Freplytocom%3D3422%23feedback-editor-3422)

You must [log in](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fdownload_url%2F)
before being able to contribute a note or feedback.