Як зробити файл PDF завантажуваним у HTML посилання?


124

Я посилаю посилання на PDF-файл на свою веб-сторінку для завантаження, як нижче

<a href="myfile.pdf">Download Brochure</a>

Проблема полягає в тому, що тоді користувач натискає на це посилання

  • Якщо користувач встановив Adobe Acrobat, він відкриває файл у тому ж вікні браузера в Adobe Reader.
  • Якщо Adobe Acrobat не встановлений, він з’являється користувачеві для завантаження файлу.

Але я хочу, щоб він завжди спливав перед користувачем для завантаження, незалежно від того, "Adobe acrobat" встановлений чи ні.

Скажіть, будь ласка, як я можу це зробити?

Відповіді:


116

Замість того, щоб посилатися на файл .PDF, замість цього зробіть щось на кшталт

<a href="pdf_server.php?file=pdffilename">Download my eBook</a>

який видає користувацький заголовок, відкриває PDF (двійковий сейф) і друкує дані у браузері користувача, тоді вони можуть вибрати збереження PDF, незважаючи на налаштування свого браузера. Pdf_server.php повинен виглядати так:

header("Content-Type: application/octet-stream");

$file = $_GET["file"] .".pdf";
header("Content-Disposition: attachment; filename=" . urlencode($file));   
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Description: File Transfer");            
header("Content-Length: " . filesize($file));
flush(); // this doesn't really matter.
$fp = fopen($file, "r");
while (!feof($fp))
{
    echo fread($fp, 65536);
    flush(); // this is essential for large downloads
} 
fclose($fp); 

PS: і, очевидно, виконайте певні перевірки правильності змінної "file", щоб люди не крали ваші файли, такі як не приймають розширення файлів, заперечують косої риси, додають .pdf до значення


2
У мене виникає ще одна проблема в цьому, що мій файл знаходиться за адресою /products/brochure/myfile.pdf Я даю $ file змінну як $ file_path = $ _SERVER ['DOCUMENT_ROOT']. '/ Products / brochure /'. $ файл; але завантаження файлу як "% 2Fvar% 2Fwww% 2Fweb15% 2Fweb% 2Fproducts% 2Fbrochure% 2myfile.pdf"
Prashant

3
@TravisO "Content-type: application/force-download"тут ніде не вказано: iana.org/assignments/media-types/application Це абсолютно хибний заголовок. Будь ласка, не складайте заголовків і не надсилайте їх. Чи можете ви оновити свою відповідь. Дякую.
Ніколас Вілсон

4
Будьте обережні, використовуючи цей код дослівно. Це вводить серйозну вразливість LFI, оскільки ви передаєте GET-змінні безпосередньо в fopen.
Joost

4
Цей код, ймовірно, небезпечний іншим способом. Якщо ви передаєте HTTP-посилання на fopen, я думаю, що це піде для отримання файлу з іншого сервера. Може бути використаний зловмисником для спроби сканувати вашу внутрішню мережу на предмет відкритих PDF-файлів.
Rory McCune

2
Не кажучи вже про те, як легко було б обійти будь-які «перевірки правильності», на вашу думку, ви будете робити параметр «файл». Атаки проходження ін'єкційного шляху / каталогів вкрай вірогідні.
AviD

209

Це поширена проблема, але мало хто знає, що існує просте рішення HTML 5:

<a href="./directory/yourfile.pdf" download="newfilename">Download the pdf</a>

Де newfilenameзапропоноване ім’я файлу для користувача, щоб зберегти файл. Або за замовчуванням ім'я файлу на стороні сервера, якщо ви залишите його порожнім, наприклад:

<a href="./directory/yourfile.pdf" download>Download the pdf</a>

Сумісність: я тестував це на Firefox 21 та Iron, обидва працювали чудово. Можливо, він не працює в браузерах, несумісних із HTML5 або застарілими. Єдиний я перевірений браузер, який не змусив завантажувати це IE ...

Перевірте сумісність тут: http://caniuse.com/#feat=download


9
Це просте рішення, але, на жаль, не дуже широко підтримується, особливо. немає підтримки І.Є. caniuse.com/#feat=download
benebun

2
Так, я знаю правильно. Ось чому у мене є побічна примітка щодо сумісності. І за словами вашого джерела, і IE і Safari не підтримують такий підхід, або, принаймні, ще ніколи :) Так чи інакше, якщо ви хочете, щоб усі браузери змусили завантажувати, я пропоную замість цього перевірити деякі інші відповіді ...
T_D

3
працює як шарм із хромованою версією 39.0.2171.65 (64-розрядна)!
еделани

Рішення просте, але, на жаль, не підтримується в IE та Safari.
валькірілов

каже, що не має дозволу на доступ
Hackbal Teamz

50

Не переглядайте кожен рядок файлів. Використовуйте натомість readfile , його швидше. Це не з веб-сайту: http://php.net/manual/en/function.readfile.php

$file = $_GET["file"];
if (file_exists($file)) {
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header("Content-Type: application/force-download");
    header('Content-Disposition: attachment; filename=' . urlencode(basename($file)));
    // header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    ob_clean();
    flush();
    readfile($file);
    exit;
}

Переконайтеся, що саніфікуйте змінну get, оскільки хтось може завантажити деякі файли php ...


4
Функція читання файлів дійсно швидша. Я особисто рекомендую використовувати цю відповідь замість прийнятої
Хосе Гаррідо

24

Замість того, щоб використовувати сценарій PHP, для читання та флеш-файлу більш акуратно переписувати заголовок, використовуючи .htaccess. Це збереже "приємну" URL-адресу ( myfile.pdfзамість download.php?myfile).

<FilesMatch "\.pdf$">
ForceType applicaton/octet-stream
Header set Content-Disposition attachment
</FilesMatch>

Чи не змусить це ВСЕ ваші файли PDF завантажувати?
TecBrat

1
@TecBrat Так, але це запитувало ОП. Якщо ви хочете обмежитися лише кількома файлами PDF, відредагуйте ^\.pdf$регулярний вираз.
Роб Ш

1
@TecBrat або поміщайте .htaccess файл лише у підпапку, де це потрібно.
хабакук

14

Я знайшов спосіб зробити це за допомогою старого простого HTML та JavaScript / jQuery, що витончено погіршує. Тестовано в IE7-10, Safari, Chrome та FF:

HTML для посилання для завантаження:

<p>Thanks for downloading! If your download doesn't start shortly, 
<a id="downloadLink" href="...yourpdf.pdf" target="_blank" 
type="application/octet-stream" download="yourpdf.pdf">click here</a>.</p>

jQuery (чистий код JavaScript був би більш дослідним), який імітує натискання на посилання після невеликої затримки:

var delay = 3000;
window.setTimeout(function(){$('#downloadLink')[0].click();},delay);

Щоб зробити це більш надійним, ви можете додати функцію виявлення функцій HTML5, а якщо її немає, тоді використовуйте window.open()для відкриття нового вікна з файлом.


5

Це ключ:

header("Content-Type: application/octet-stream");

Додаток типу вмісту / x-pdf-документ або додаток / pdf надсилається під час надсилання PDF-файлу. Adobe Reader зазвичай встановлює обробник для цього типу MIME, щоб браузер передав документ Adobe Reader, коли отримано будь-який з типів PDF MIME.


3

Я знаю, що я дуже пізно відповів на це, але я знайшов хак для цього в JavaScript.

function downloadFile(src){
    var link=document.createElement('a');
    document.body.appendChild(link);
    link.href= src;
    link.download = '';
    link.click();
}

0

Спробуйте це:

<a href="pdf_server_with_path.php?file=pdffilename&path=http://myurl.com/mypath/">Download my eBook</a>

Код pdf_server_with_path.php:

header("Content-Type: application/octet-stream");

$file = $_GET["file"] .".pdf";
$path = $_GET["path"];
$fullfile = $path.$file;

header("Content-Disposition: attachment; filename=" . Urlencode($file));   
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Description: File Transfer");            
header("Content-Length: " . Filesize($fullfile));
flush(); // this doesn't really matter.
$fp = fopen($fullfile, "r");
while (!feof($fp))
{
    echo fread($fp, 65536);
    flush(); // this is essential for large downloads
} 
fclose($fp);

0

Ось інший підхід. Я вважаю за краще скоріше покладатися на підтримку браузера або адресувати це на рівні програми, щоб використовувати логіку веб-сервера.

Якщо ви використовуєте Apache і можете помістити файл .htaccess у відповідний каталог, ви можете використовувати код нижче. Звичайно, ви можете також помістити це в httpd.conf, якщо у вас є доступ до цього.

<FilesMatch "\.(?i:pdf)$">
  Header set Content-Disposition attachment
</FilesMatch>

Директива FilesMatch - це лише регулярний вираз, тому його можна встановити так детально, як вам потрібно, або ви можете додати в інші розширення.

Рядок заголовка робить те саме, що і перший рядок у скриптах PHP, наведених вище. Якщо вам також потрібно встановити рядки типу вмісту, ви можете це зробити так само, але я не вважав це необхідним.


0

Я вирішив шахту, використовуючи всю URL-адресу файлу PDF (Замість того, щоб просто вводити ім'я файлу чи місцезнаходження в href): a href = "domain. Com / pdf / filename.pdf"


0

якщо вам потрібно обмежити швидкість завантаження, використовуйте цей код !!

<?php
$local_file = 'file.zip';
$download_file = 'name.zip';

// set the download rate limit (=> 20,5 kb/s)
$download_rate = 20.5;
if(file_exists($local_file) && is_file($local_file))
{
header('Cache-control: private');
header('Content-Type: application/octet-stream');
header('Content-Length: '.filesize($local_file));
header('Content-Disposition: filename='.$download_file);

flush();
$file = fopen($local_file, "r");
while(!feof($file))
{
    // send the current file part to the browser
    print fread($file, round($download_rate * 1024));
    // flush the content to the browser
    flush();
    // sleep one second
    sleep(1);
}
fclose($file);}
else {
die('Error: The file '.$local_file.' does not exist!');
}

?>

Для отримання додаткової інформації натисніть тут


0
<!DOCTYPE html>  
<html xmlns="http://www.w3.org/1999/xhtml">  
<head>  
    <title>File Uploader</title>  
    <script src="../Script/angular1.3.8.js"></script>  
    <script src="../Script/angular-route.js"></script>  
    <script src="../UserScript/MyApp.js"></script>  
    <script src="../UserScript/FileUploder.js"></script>  
    <>  
        .percent {  
            position: absolute;  
            width: 300px;  
            height: 14px;  
            z-index: 1;  
            text-align: center;  
            font-size: 0.8em;  
            color: white;  
        }  

        .progress-bar {  
            width: 300px;  
            height: 14px;  
            border-radius: 10px;  
            border: 1px solid #CCC;  
            background-image: -webkit-gradient(linear, left top, left bottom, from(#6666cc), to(#4b4b95));  
            border-image: initial;  
        }  

        .uploaded {  
            padding: 0;  
            height: 14px;  
            border-radius: 10px;  
            background-image: -webkit-gradient(linear, left top, left bottom, from(#66cc00), to(#4b9500));  
            border-image: initial;  
        }  
    </>  
</head>  
<body ng-app="MyApp" ng-controller="FileUploder">  
    <div>  
        <table ="width:100%;border:solid;">  
            <tr>  
                <td>Select File</td>  
                <td>  
                    <input type="file" ng-model-instant id="fileToUpload" onchange="angular.element(this).scope().setFiles(this)" />  
                </td>  
            </tr>  
            <tr>  
                <td>File Size</td>  
                <td>  
                    <div ng-repeat="file in files.slice(0)">  
                        <span ng-switch="file.size > 1024*1024">  
                            <span ng-switch-when="true">{{file.size / 1024 / 1024 | number:2}} MB</span>  
                            <span ng-switch-default>{{file.size / 1024 | number:2}} kB</span>  
                        </span>  
                    </div>  
                </td>  
            </tr>             
            <tr>  
                <td>  
                    File Attach Status  
                </td>  
                <td>{{AttachStatus}}</td>  
            </tr>  
            <tr>  
                <td>  
                    <input type="button" value="Upload" ng-click="fnUpload();" />  
                </td>  
                <td>  
                    <input type="button" value="DownLoad" ng-click="fnDownLoad();" />  
                </td>  
            </tr>  
        </table>  
    </div>  
</body>  
</html>   

1
Ви повинні пояснити, що ви вказали у своєму коді. Навіть у короткій формі, якщо це неможливо детально або не потрібно в деталях.
Сурай Кумар

-1

У додатку Ruby on Rails (особливо, на зразок дорогоцінного каміння Prawn та плагіна Prawnto Rails) ви можете це зробити трохи простіше, ніж повний сценарій (як попередній приклад PHP).

У вашому контролері:

def index

 respond_to do |format|
   format.html # Your HTML view
   format.pdf { render :layout => false }
 end
end

Візуалізація: layout => false false повідомляє браузеру відкрити "Ви хочете завантажити цей файл?" підказка замість спроби надати PDF-файл. Тоді ви зможете нормально зв’язатися з файлом: http://mysite.com/myawesomepdf.pdf


Де написати цей код? який контролер, я новачок у PHP, будь ласка, поясніть.
Прашант

@Prashant Це не PHP, це Ruby on Rails.
eloyesp

@Prashant: Якщо вам потрібен приклад PHP, подивіться їх на те, що йде далі, але прочитайте коментарі про те, як вони можуть бути небезпечними.
Еван Донован
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.