Как скачать существующий файл на PHP - PullRequest
4 голосов
/ 26 августа 2010

У меня есть pdf файл на моем сервере. Я хочу создать такую ​​ссылку, чтобы пользователь мог щелкнуть по ней и скачать этот файл PDF. Я использую Zend Frame работы с Php.

Ответы [ 6 ]

4 голосов
/ 27 августа 2010

Я предполагаю, что есть причина, по которой вы не можете просто ссылаться на pdf напрямую, например, необходимость аутентификации пользователя.В этом случае вам нужно будет установить правильные заголовки, и, как другие заметили, вы можете использовать get_file_contents для обслуживания PDF.Однако использование get_file_contents требует, чтобы вы прочитали файл в память перед отправкой ответа.Если файл большой или вы получаете много запросов одновременно, вы можете легко исчерпать память.Отличным решением, если вы используете Apache или Lighttpd, является использование XSendFile.С XSendFile вы устанавливаете заголовок ответа X-Sendfile на путь к файлу, и ваш веб-сервер обслуживает файл напрямую с диска - без указания местоположения файла на диске.

Проблема с этим решением заключается в том, что модульбыть установлен на Apache, и он должен быть настроен для работы с Lighttpd.

После установки XSendFile ваш код действия Zend Framework будет выглядеть примерно так:

// user auth or other code here -- there has to be a reason you're not
// just pointing to the pdf file directly

$this->_helper->layout->disableLayout();
$this->_helper->viewRenderer->setNoRender();

$this->getResponse()->setHeader('Content-type', 'application/pdf')
                    ->setHeader('X-Sendfile', 'path-to-file')
                    ->sendResponse();
4 голосов
/ 26 августа 2010

поместите этот код в php-файл и назовите его f.e. "Download.php":

<?php

$fullPath = "path/to/your/file.ext";

if ($fd = fopen ($fullPath, "r")) {

    $fsize = filesize($fullPath);
    $path_parts = pathinfo($fullPath);
    $ext = strtolower($path_parts["extension"]);

    header("Content-type: application/pdf");
    header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");            
    header("Content-length: $fsize");
    header("Cache-control: private");

    while(!feof($fd)) {
        $buffer = fread($fd, 2048);
        echo $buffer;
    }
}

fclose ($fd);
exit;

?>

Пример: поместите ссылку такого типа в документ, где предлагается загрузка файла:

<a href="download.php?download_file=some_file.pdf">Download here</a>

Подробнее:

http://www.finalwebsites.com/forums/topic/php-file-download

2 голосов
/ 26 августа 2010

Я использовал этот многоразовый помощник для отправки файлов пользователям. Это работает хорошо и лучше, чем возиться с заголовками самостоятельно.

2 голосов
/ 26 августа 2010
        header("Content-type: application/pdf");
        header("Content-Disposition: attachment; filename=filename.pdf"); 
        $pdfiledata = file_get_contents($filename);
        echo $pdfiledata;
1 голос
/ 27 августа 2010

Я всегда использовал функцию становиться_файлом из библиотеки с открытым исходным кодом BalPHP , которую вы можете сразу подключить и воспроизвести (вставить) в свой проект. Это позволяет:

  • Мгновенная загрузка файла
  • Простое указание таких параметров, как тип контента, срок службы кэша, размер буфера.
  • Поддерживает многоэтапные транзакции, что позволяет быстрее загружать файлы, которые не убивают ваш сервер при передаче больших файлов.
  • Поддерживает функции паузы / возобновления.
  • И etags для кеширования:

Вы можете найти последнюю версию здесь: http://github.com/balupton/balphp/blob/master/trunk/lib/core/functions/_files.funcs.php#L75

А здесь он скопирован и вставлен по состоянию на 27 августа 2010 года:

/**
 * Become a file download, should be the last script that runs in your program
 *
 * http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt
 *
 * @version 3, July 18, 2009 (Added suport for data)
 * @since 2, August 11, 2007
 *
 * @author Benjamin "balupton" Lupton <contact@balupton.com> - {@link http://www.balupton.com/}
 *
 * @param string    $file_path
 * @param string    $content_type
 * @param int       $buffer_size
 * @param string    $file_name
 * @param timestamp $file_time
 *
 * @return boolean  true on success, false on error
 */
function become_file_download ( $file_path_or_data, $content_type = NULL, $buffer_size = null, $file_name = null, $file_time = null, $expires = null ) {

    // Prepare
    if ( empty($buffer_size) )
        $buffer_size = 4096;
    if ( empty($content_type) )
        $content_type = 'application/force-download';

    // Check if we are data
    $file_descriptor = null;
    if ( file_exists($file_path_or_data) && $file_descriptor = fopen($file_path_or_data, 'rb') ) {
        // We could be a file
        // Set some variables
        $file_data = null;
        $file_path = $file_path_or_data;
        $file_name = $file_name ? $file_name : basename($file_path);
        $file_size = filesize($file_path);
        $file_time = filemtime($file_path);
        $etag = md5($file_time . $file_name);
    } elseif ( $file_name !== null ) {
        // We are just data
        $file_data = $file_path_or_data;
        $file_path = null;
        $file_size = strlen($file_data);
        $etag = md5($file_data);
        if ( $file_time === null )
            $file_time = time();
        else
            $file_time = ensure_timestamp($file_time);
    } else {
        // We couldn't find the file
        header('HTTP/1.1 404 Not Found');
        return false;
    }

    // Prepare timestamps
    $expires = ensure_timestamp($expires);

    // Set some variables
    $date = gmdate('D, d M Y H:i:s') . ' GMT';
    $expires = gmdate('D, d M Y H:i:s', $expires) . ' GMT';
    $last_modified = gmdate('D, d M Y H:i:s', $file_time) . ' GMT';

    // Say we can go on forever
    set_time_limit(0);

    // Check relevance
    $etag_relevant = !empty($_SERVER['HTTP_IF_NONE_MATCH']) && trim(stripslashes($_SERVER['HTTP_IF_NONE_MATCH']), '\'"') === $etag;
    $date_relevant = !empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $file_time;

    // Handle download
    if ( $etag_relevant || $date_relevant ) {
        // Not modified
        header('HTTP/1.0 304 Not Modified');
        header('Status: 304 Not Modified');

        header('Pragma: public');
        header('Cache-Control: private');

        header('ETag: "' . $etag . '"');
        header('Date: ' . $date);
        header('Expires: ' . $expires);
        header('Last-modified: ' . $last_modified);
        return true;
    } elseif ( !empty($_SERVER['HTTP_RANGE']) ) {
        // Partial download


        /*
         * bytes=0-99,500-1499,4000-
         */

        // Explode RANGE
        list($size_unit,$ranges) = explode($_SERVER['HTTP_RANGE'], '=', 2);

        // Explode RANGES
        $ranges = explode(',', $ranges);

        // Cycle through ranges
        foreach ( $ranges as $range ) {
            // We have a range


            /*
             * All bytes until the end of document, except for the first 500 bytes:
             * Content-Range: bytes 500-1233/1234
             */

            // Set range start
            $range_start = null;
            if ( !empty($range[0]) && is_numeric($range[0]) ) {
                // The range has a start
                $range_start = intval($range[0]);
            } else {
                $range_start = 0;
            }

            // Set range end
            if ( !empty($range[1]) && is_numeric($range[1]) ) {
                // The range has an end
                $range_end = intval($range[1]);
            } else {
                $range_end = $file_size - 1;
            }

            // Set the range size
            $range_size = $range_end - $range_start + 1;

            // Set the headers
            header('HTTP/1.1 206 Partial Content');

            header('Pragma: public');
            header('Cache-Control: private');

            header('ETag: "' . $etag . '"');
            header('Date: ' . $date);
            header('Expires: ' . $expires);
            header('Last-modified: ' . $last_modified);

            header('Content-Transfer-Encoding: binary');
            header('Accept-Ranges: bytes');

            header('Content-Range: bytes ' . $range_start . '-' . $range_end . '/' . $file_size);
            header('Content-Length: ' . $range_size);

            header('Content-Type: ' . $content_type);
            if ( $content_type === 'application/force-download' )
                header('Content-Disposition: attachment; filename=' . urlencode($file_name));

            // Handle our data transfer
            if ( !$file_path ) {
                // We are using file_data
                echo substr($file_data, $range_start, $range_end - $range_start);
            } else {
                // Seek to our location
                fseek($file_descriptor, $range_start);

                // Read the file
                $remaining = $range_size;
                while ( $remaining > 0 ) {
                    // 0-6   | buffer = 3 | remaining = 7
                    // 0,1,2 | buffer = 3 | remaining = 4
                    // 3,4,5 | buffer = 3 | remaining = 1
                    // 6     | buffer = 1 | remaining = 0


                    // Set buffer size
                    $buffer_size = min($buffer_size, $remaining);

                    // Output file contents
                    echo fread($file_descriptor, $buffer_size);
                    flush();
                    ob_flush();

                    // Update remaining
                    $remaining -= $buffer_size;
                }
            }
        }
    } else {
        // Usual download


        // header('Pragma: public');
        // header('Cache-control: must-revalidate, post-check=0, pre-check=0');
        // header('Expires: '.      gmdate('D, d M Y H:i:s').' GMT');


        // Set headers
        header('HTTP/1.1 200 OK');

        header('Pragma: public');
        header('Cache-Control: private');

        header('ETag: "' . $etag . '"');
        header('Date: ' . $date);
        header('Expires: ' . $expires);
        header('Last-modified: ' . $last_modified);

        header('Content-Transfer-Encoding: binary');
        header('Accept-Ranges: bytes');

        header('Content-Length: ' . $file_size);

        header('Content-Type: ' . $content_type);
        if ( $content_type === 'application/force-download' )
            header('Content-Disposition: attachment; filename=' . urlencode($file_name));

        // Handle our data transfer
        if ( !$file_path ) {
            // We are using file_data
            echo $file_data;
        } else {
            // Seek to our location
            // Read the file
            $file_descriptor = fopen($file_path, 'r');
            while ( !feof($file_descriptor) ) {
                // Output file contents
                echo fread($file_descriptor, $buffer_size);
                flush();
                ob_flush();
            }
        }
    }

    // Close the file
    if ( $file_descriptor )
        fclose($file_descriptor);

    // Done
    return true;
}

Это также зависит от другой функции plug and play, которая называется sure_timestamp , которую вы можете найти здесь: http://github.com/balupton/balphp/blob/master/trunk/lib/core/functions/_datetime.funcs.php#L31

/**
 * Gets the days between two timestamps
 * @version 1, January 28, 2010
 * @param mixed $value
 * @return timestamp
 */
function ensure_timestamp ( $value = null ) {
    $result = null;

    if ( $value === null ) $result = time();
    elseif ( is_numeric($value) ) $result = $value;
    elseif ( is_string($value) ) $result = strtotime($value);
    else throw new Exception('Unknown timestamp type.');

    return $result;
}
1 голос
/ 26 августа 2010

Я не знаю, предоставляет ли Zend класс для этого. В целом это достигается с помощью функции заголовка. взгляните на сайт PHP:

http://php.net/manual/en/function.header.php

Есть несколько примеров загрузки файлов.

Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...