How to create 'save as' url?
Categories:
Creating a 'Save As' URL for Direct File Downloads

Learn how to construct URLs that prompt browsers to download a file directly, rather than displaying it inline. This guide covers various methods for achieving 'Save As' functionality.
When serving files from a web server, the default browser behavior for certain file types (like images, PDFs, or plain text) is often to display them directly within the browser window. However, there are many scenarios where you want to force a download, presenting the user with a 'Save As' dialog. This article explores different techniques to achieve this, focusing on server-side headers and client-side approaches.
The 'Content-Disposition' Header
The most robust and widely supported method for triggering a 'Save As' dialog is by setting the Content-Disposition
HTTP header on the server response. This header tells the browser how to handle the file. When set to attachment
, the browser will typically prompt the user to save the file, regardless of its MIME type.
<?php
$file = 'path/to/your/file.pdf';
$filename = basename($file);
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
?>
PHP example for forcing a file download using Content-Disposition
.
from flask import Flask, send_file
app = Flask(__name__)
@app.route('/download/<filename>')
def download_file(filename):
path_to_file = f'./files/{filename}' # Assuming files are in a 'files' directory
return send_file(path_to_file, as_attachment=True)
if __name__ == '__main__':
app.run(debug=True)
Python Flask example for serving a file as an attachment.
Content-Type
header to application/octet-stream
for generic binary data, or the correct MIME type if known, alongside Content-Disposition: attachment
. This helps ensure consistent behavior across browsers.Client-Side Approaches with HTML5 'download' Attribute
For simple cases, HTML5 introduced the download
attribute for the <a>
tag. This attribute suggests a filename for the downloaded file and, crucially, hints to the browser that the linked resource should be downloaded rather than navigated to. This method is purely client-side and doesn't require server-side header manipulation.
<a href="/files/document.pdf" download="MyReport.pdf">Download My Report</a>
<a href="/images/photo.jpg" download>Download Photo</a>
Using the HTML5 download
attribute for direct downloads.
download
attribute only works for same-origin URLs. If the href
points to a different domain, the attribute will be ignored, and the browser will follow its default behavior (usually navigating to the URL). For cross-origin downloads, server-side Content-Disposition
is essential.flowchart TD A[User Clicks Link] --> B{Is 'download' attribute present?} B -->|Yes| C{Is URL same-origin?} C -->|Yes| D[Browser prompts 'Save As' with suggested filename] C -->|No| E[Browser navigates to URL or displays inline] B -->|No| F{Server responds with 'Content-Disposition: attachment'?} F -->|Yes| D F -->|No| E
Decision flow for browser download behavior.
Considerations for Dynamic Content and Security
When generating download URLs for dynamic content or user-uploaded files, ensure proper validation and sanitization. Malicious users could try to inject harmful content or path traversal characters into filenames. Always sanitize filenames and ensure the server-side script only serves files from expected directories.
function sanitizeFilename(filename) {
// Remove any directory traversal attempts and invalid characters
return filename.replace(/\.\.\//g, '').replace(/[^a-zA-Z0-9\-_.]/g, '');
}
// Example usage (client-side, for suggested filename)
const originalFilename = "../../evil/script.js";
const safeFilename = sanitizeFilename(originalFilename);
console.log(safeFilename); // "evilscript.js"
// For server-side, always use a robust library or framework function
// to handle file paths and serving securely.
Basic client-side filename sanitization example.
Range
header) to allow for resumable downloads. This enhances user experience, especially on unstable networks.