PHP का उपयोग करके एक फ़ाइल परोसने का सबसे तेज़ तरीका


98

मैं एक ऐसा फंक्शन डालने की कोशिश कर रहा हूं, जो एक फ़ाइल पाथ प्राप्त करता है, यह पहचानता है कि यह क्या है, उपयुक्त हेडर सेट करता है, और यह केवल उसी तरह कार्य करता है जैसे कि अन्य राइटर्स करेगा।

मैं ऐसा कर रहा हूं इसका कारण यह है कि मुझे फ़ाइल की सेवा करने से पहले अनुरोध के बारे में कुछ जानकारी संसाधित करने के लिए PHP का उपयोग करने की आवश्यकता है।

गति महत्वपूर्ण है

आभासी () एक विकल्प नहीं है

एक साझा होस्टिंग वातावरण में काम करना चाहिए जहां उपयोगकर्ता का वेब सर्वर (Apache / nginx, आदि) का कोई नियंत्रण नहीं है

यहाँ मैंने अभी तक क्या किया है:

File::output($path);

<?php
class File {
static function output($path) {
    // Check if the file exists
    if(!File::exists($path)) {
        header('HTTP/1.0 404 Not Found');
        exit();
    }

    // Set the content-type header
    header('Content-Type: '.File::mimeType($path));

    // Handle caching
    $fileModificationTime = gmdate('D, d M Y H:i:s', File::modificationTime($path)).' GMT';
    $headers = getallheaders();
    if(isset($headers['If-Modified-Since']) && $headers['If-Modified-Since'] == $fileModificationTime) {
        header('HTTP/1.1 304 Not Modified');
        exit();
    }
    header('Last-Modified: '.$fileModificationTime);

    // Read the file
    readfile($path);

    exit();
}

static function mimeType($path) {
    preg_match("|\.([a-z0-9]{2,4})$|i", $path, $fileSuffix);

    switch(strtolower($fileSuffix[1])) {
        case 'js' :
            return 'application/x-javascript';
        case 'json' :
            return 'application/json';
        case 'jpg' :
        case 'jpeg' :
        case 'jpe' :
            return 'image/jpg';
        case 'png' :
        case 'gif' :
        case 'bmp' :
        case 'tiff' :
            return 'image/'.strtolower($fileSuffix[1]);
        case 'css' :
            return 'text/css';
        case 'xml' :
            return 'application/xml';
        case 'doc' :
        case 'docx' :
            return 'application/msword';
        case 'xls' :
        case 'xlt' :
        case 'xlm' :
        case 'xld' :
        case 'xla' :
        case 'xlc' :
        case 'xlw' :
        case 'xll' :
            return 'application/vnd.ms-excel';
        case 'ppt' :
        case 'pps' :
            return 'application/vnd.ms-powerpoint';
        case 'rtf' :
            return 'application/rtf';
        case 'pdf' :
            return 'application/pdf';
        case 'html' :
        case 'htm' :
        case 'php' :
            return 'text/html';
        case 'txt' :
            return 'text/plain';
        case 'mpeg' :
        case 'mpg' :
        case 'mpe' :
            return 'video/mpeg';
        case 'mp3' :
            return 'audio/mpeg3';
        case 'wav' :
            return 'audio/wav';
        case 'aiff' :
        case 'aif' :
            return 'audio/aiff';
        case 'avi' :
            return 'video/msvideo';
        case 'wmv' :
            return 'video/x-ms-wmv';
        case 'mov' :
            return 'video/quicktime';
        case 'zip' :
            return 'application/zip';
        case 'tar' :
            return 'application/x-tar';
        case 'swf' :
            return 'application/x-shockwave-flash';
        default :
            if(function_exists('mime_content_type')) {
                $fileSuffix = mime_content_type($path);
            }
            return 'unknown/' . trim($fileSuffix[0], '.');
    }
}
}
?>

10
आप अपाचे को ऐसा करने क्यों नहीं दे रहे हैं? यह हमेशा PHP दुभाषिया शुरू करने की तुलना में काफी तेज होने जा रहा है ...
बिली ओपल

4
मुझे फ़ाइल को आउटपुट करने से पहले अनुरोध को संसाधित करने और डेटाबेस में कुछ जानकारी संग्रहीत करने की आवश्यकता है।
किर्क ओईमेट

3
क्या मैं अधिक महंगी नियमित अभिव्यक्तियों के बिना एक्सटेंशन प्राप्त करने का एक तरीका सुझा सकता हूं: $extension = end(explode(".", $pathToFile))या आप इसे रूट और स्ट्रैप के साथ कर सकते हैं $extension = substr($pathToFile, strrpos($pathToFile, '.')):। इसके अलावा, एक mime_content_type()$mimetype = exec("file -bi '$pathToFile'", $output);
वापसी के

आपको सबसे तेज से क्या मतलब है ? सबसे तेज़ डाउनलोड समय?
एलिक्स एक्सल

जवाबों:


140

मेरा पिछला जवाब आंशिक था और अच्छी तरह से प्रलेखित नहीं था, यहां चर्चा में और दूसरों से समाधान के सारांश के साथ एक अद्यतन है।

समाधानों को सबसे अच्छे समाधान से सबसे खराब तक का आदेश दिया जाता है, लेकिन वेब सर्वर पर सबसे अधिक नियंत्रण की आवश्यकता वाले समाधान से भी कम की आवश्यकता होती है। वहाँ एक आसान तरीका है कि एक समाधान है कि दोनों तेजी से और हर जगह काम करने के लिए नहीं लगता है।


X-SendFile हेडर का उपयोग करना

दूसरों द्वारा प्रलेखित के रूप में यह वास्तव में सबसे अच्छा तरीका है। आधार यह है कि आप अपने एक्सेस कंट्रोल को php में करते हैं और फिर फाइल को भेजने के बजाय आप इसे करने के लिए वेब सर्वर को बताते हैं।

मूल php कोड है:

header("X-Sendfile: $file_name");
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . basename($file_name) . '"');

$file_nameफ़ाइल सिस्टम पर पूर्ण पथ कहाँ है।

इस समाधान के साथ मुख्य समस्या यह है कि इसे वेब सर्वर द्वारा अनुमति देने की आवश्यकता है और या तो डिफ़ॉल्ट (अपाचे) द्वारा स्थापित नहीं किया गया है, डिफ़ॉल्ट रूप से सक्रिय नहीं है (लाइटटैप) या एक विशिष्ट कॉन्फ़िगरेशन (nginx) की आवश्यकता है।

अमरीका की एक मूल जनजाति

अपाचे के तहत यदि आप mod_php का उपयोग करते हैं तो आपको mod_xsendfile नामक एक मॉड्यूल को स्थापित करने की आवश्यकता होती है, फिर इसे कॉन्फ़िगर करें (यदि आप अनुमति देते हैं तो Apache config या .htaccess में भी)

XSendFile on
XSendFilePath /home/www/example.com/htdocs/files/

इस मॉड्यूल के साथ फ़ाइल पथ या तो निरपेक्ष हो सकता है या निर्दिष्ट के सापेक्ष हो सकता है XSendFilePath

lighttpd

Mod_fastcgi द्वारा कॉन्फ़िगर किए जाने पर इसका समर्थन करते हैं

"allow-x-send-file" => "enable" 

फीचर के लिए प्रलेखन लाइटटैप विकी पर है, वे X-LIGHTTPD-send-fileहेडर को दस्तावेज करते हैं लेकिन X-Sendfileनाम भी काम करता है

nginx

Nginx पर आप X-Sendfileहेडर का उपयोग नहीं कर सकते हैं आपको अपने स्वयं के हेडर का उपयोग करना चाहिए जिसका नाम है X-Accel-Redirect। यह डिफ़ॉल्ट रूप से सक्षम है और एकमात्र वास्तविक अंतर यह है कि यह तर्क है कि एक यूआरआई होना चाहिए जो फ़ाइल सिस्टम नहीं है। इसका परिणाम यह है कि आपको अपने कॉन्फ़िगरेशन में आंतरिक के रूप में चिह्नित स्थान को परिभाषित करना चाहिए ताकि ग्राहकों को वास्तविक फ़ाइल url खोजने और सीधे उसके पास जाने से बचने के लिए, उनके विकी में इसका एक अच्छा विवरण शामिल हो ।

साइमलिंक और लोकेशन हेडर

जब आप किसी उपयोगकर्ता को किसी फ़ाइल तक पहुँचने के लिए अधिकृत करते हैं और उसका उपयोग करके उपयोगकर्ता को पुनर्निर्देशित करते हैं, तो आप उनके साथ सहानुभूति और रीडायरेक्ट का उपयोग कर सकते हैं , यादृच्छिक नामों के साथ अपनी फ़ाइल के लिए सिम्लिंक बनाएँ।

header("Location: " . $url_of_symlink);

जाहिर है आपको उन्हें या तो प्रून करने का एक तरीका चाहिए होगा जब स्क्रिप्ट बनाने के लिए उन्हें बुलाया जाएगा या क्रोन के माध्यम से (मशीन पर यदि आपके पास एक्सेस है या किसी वेबक्रॉन सेवा के माध्यम से अन्यथा)

अपाचे के तहत आप सक्षम करने के लिए सक्षम होना चाहिए FollowSymLinksएक में .htaccessया अपाचे config में।

आईपी ​​और स्थान हेडर द्वारा अभिगम नियंत्रण

एक अन्य हैक स्पष्ट उपयोगकर्ता आईपी की अनुमति देकर php से अपाचे एक्सेस फ़ाइलों को उत्पन्न करना है। अपाचे के तहत इसका मतलब है mod_authz_host( mod_access) Allow fromकमांड का उपयोग करना ।

समस्या यह है कि फ़ाइल तक लॉक करना (जैसा कि कई उपयोगकर्ता एक ही समय में ऐसा करना चाह सकते हैं) गैर तुच्छ है और कुछ उपयोगकर्ताओं को लंबे समय तक इंतजार कर सकता है। और आपको अभी भी वैसे भी फ़ाइल को prune करने की आवश्यकता है।

जाहिर है एक और समस्या यह होगी कि एक ही आईपी के पीछे कई लोग संभावित रूप से फाइल तक पहुंच सकते हैं।

जब बाकी सब फेल हो जाए

क्या तुम सच में मदद करने के लिए अपने वेब सर्वर पाने के लिए किसी भी तरह से नहीं है, तो, एकमात्र समाधान शेष है readfile यह बहुत अच्छी तरह से वर्तमान में उपयोग और काम में सभी php संस्करणों में उपलब्ध है (लेकिन वास्तव में कुशल नहीं है)।


संयुक्त समाधान

यदि आप अपने php कोड को हर जगह उपयोग करने योग्य बनाना चाहते हैं, तो वास्तव में तेजी से फाइल भेजने का सबसे अच्छा तरीका है, कहीं न कहीं एक विन्यास योग्य विकल्प होना, यह निर्देश देने के साथ कि वेब सर्वर पर निर्भर करता है कि कैसे सक्रिय किया जाए और हो सकता है कि आपके इंस्टा में एक ऑटो डिटेक्शन हो। स्क्रिप्ट।

यह बहुत कुछ के लिए सॉफ्टवेयर में किया जाता है के समान है

  • स्वच्छ urls ( mod_rewriteअपाचे पर)
  • क्रिप्टो कार्य ( mcryptphp मॉड्यूल)
  • मल्टीबीट स्ट्रिंग सपोर्ट ( mbstringphp मॉड्यूल)

क्या कुछ PHP काम करने से पहले कोई समस्या है (करने से पहले कुकी / अन्य GET / POST params डेटाबेस के खिलाफ जांच करें) header("Location: " . $path);?
अफरीज़ा एन। दुःख सिपाही १10'१०

2
इस तरह की कार्रवाई के लिए कोई समस्या नहीं है, जिस चीज से आपको सावधान रहने की जरूरत है वह सामग्री (प्रिंट, गूंज) भेज रही है क्योंकि हेडर को किसी भी सामग्री से पहले आना चाहिए और इस हेडर को भेजने के बाद चीजें करना चाहिए, यह एक तत्काल पुनर्निर्देशन और कोड नहीं है क्योंकि यह होगा ज्यादातर समय निष्पादित किया जाता है, लेकिन आपके पास कोई गारंटी नहीं है कि ब्राउज़र कनेक्शन काट नहीं करेगा।
जुलिएन रोनाग्लिया

जोर्ड्स: मुझे नहीं पता था कि अपाचे ने भी इसका समर्थन किया है, मैं इसे अपने जवाब में जोड़ूंगा जब मेरे पास समय होगा। इसके साथ एकमात्र समस्या यह है कि मैं एकीकृत नहीं है (उदाहरण के लिए एक्स-एक्सेल-रीडायरेक्ट नेग्नेक्स) इसलिए एक दूसरा समाधान की आवश्यकता है यदि सर्वर या तो इसका समर्थन नहीं करता है। लेकिन मुझे इसे अपने जवाब में जोड़ना चाहिए।
बजे जूलियन रोनाग्लिया

जहाँ मैं .htaccess को xsendFilePath को नियंत्रित करने की अनुमति दे सकता हूँ?
कीने वियाना

1
@Keyne मुझे नहीं लगता कि आप कर सकते हैं। tn123.org/mod_xsendfile करता XSendFilePath विकल्प के लिए संदर्भ में सूची .htaccess नहीं
cheshirekow

33

सबसे तेज़ तरीका: नहीं। Nginx के लिए x-sendfile हेडर में देखें , अन्य वेब सर्वरों के लिए भी ऐसी ही चीजें हैं। इसका मतलब यह है कि आप अभी भी php में एक्सेस कंट्रोल आदि कर सकते हैं, लेकिन उसके लिए डिज़ाइन किए गए वेब सर्वर पर फाइल भेजने की वास्तविक जानकारी सौंपते हैं।

पुनश्च: मुझे लगता है कि php में फ़ाइल को पढ़ने और भेजने की तुलना में nginx के साथ इसका उपयोग करने में कितना अधिक कुशल है, इस बारे में मुझे ठंड लग रही है। जरा सोचें कि क्या 100 लोग किसी फाइल को डाउनलोड कर रहे हैं: php + अपाचे के साथ, उदार होने के नाते, Thats शायद 100 * 15mb = 1.5GB (लगभग, मुझे गोली मार), राम के वहीं। Nginx सिर्फ फ़ाइल को कर्नेल में भेजने से रोक देगा, और फिर इसे डिस्क से सीधे नेटवर्क बफ़र में लोड किया जाता है। शीघ्र!

PPS: और, इस विधि से आप अभी भी सभी एक्सेस कंट्रोल, डेटाबेस सामान जो आप चाहते हैं, कर सकते हैं।


4
मुझे सिर्फ इतना कहना है कि यह अपाचे के लिए भी मौजूद है: jasny.net/articles/how-i-php-x-sendfile । आप स्क्रिप्ट को सर्वर से सूँघ सकते हैं और उपयुक्त हेडर भेज सकते हैं। यदि कोई मौजूद नहीं है (और उपयोगकर्ता के पास सवाल के अनुसार सर्वर पर कोई नियंत्रण नहीं है), एक सामान्य पर वापस आ जाओreadfile()
फैनीज़ हत्जिदकिस

अब यह सिर्फ भयानक है - मैं हमेशा अपने वर्चुअल मेजबानों में मेमोरी सीमा से टकराते हुए नफरत करता था ताकि PHP एक फ़ाइल की सेवा कर सके, और इसके साथ मुझे नहीं होना चाहिए। मैं इसे बहुत जल्द आज़माऊंगा।
ग्रेग डब्ल्यू

1
और क्रेडिट के लिए जहां क्रेडिट की वजह से है, लाइटट्पड इसे लागू करने वाला पहला वेब सर्वर था (और बाकी ने इसे कॉपी किया, जो ठीक है क्योंकि यह एक महान विचार है। लेकिन क्रेडिट जहां क्रेडिट देय है) ...
ircmaxell

1
यह उत्तर आगे बढ़ता रहता है, लेकिन यह ऐसे वातावरण में काम नहीं करेगा जहाँ वेब सर्वर और इसकी सेटिंग्स उपयोगकर्ता के नियंत्रण से बाहर हैं।
कर्क ऊटीमेट

आपने वास्तव में मुझे यह उत्तर पोस्ट करने के बाद अपने प्रश्न में जोड़ा है। और अगर प्रदर्शन एक मुद्दा है, तो वेब सर्वर को आपके नियंत्रण में होना चाहिए।
जोर्ड्स

23

यहाँ एक शुद्ध PHP समाधान जाता है। मैंने अपने व्यक्तिगत ढांचे से निम्नलिखित कार्य को अनुकूलित किया है :

function Download($path, $speed = null, $multipart = true)
{
    while (ob_get_level() > 0)
    {
        ob_end_clean();
    }

    if (is_file($path = realpath($path)) === true)
    {
        $file = @fopen($path, 'rb');
        $size = sprintf('%u', filesize($path));
        $speed = (empty($speed) === true) ? 1024 : floatval($speed);

        if (is_resource($file) === true)
        {
            set_time_limit(0);

            if (strlen(session_id()) > 0)
            {
                session_write_close();
            }

            if ($multipart === true)
            {
                $range = array(0, $size - 1);

                if (array_key_exists('HTTP_RANGE', $_SERVER) === true)
                {
                    $range = array_map('intval', explode('-', preg_replace('~.*=([^,]*).*~', '$1', $_SERVER['HTTP_RANGE'])));

                    if (empty($range[1]) === true)
                    {
                        $range[1] = $size - 1;
                    }

                    foreach ($range as $key => $value)
                    {
                        $range[$key] = max(0, min($value, $size - 1));
                    }

                    if (($range[0] > 0) || ($range[1] < ($size - 1)))
                    {
                        header(sprintf('%s %03u %s', 'HTTP/1.1', 206, 'Partial Content'), true, 206);
                    }
                }

                header('Accept-Ranges: bytes');
                header('Content-Range: bytes ' . sprintf('%u-%u/%u', $range[0], $range[1], $size));
            }

            else
            {
                $range = array(0, $size - 1);
            }

            header('Pragma: public');
            header('Cache-Control: public, no-cache');
            header('Content-Type: application/octet-stream');
            header('Content-Length: ' . sprintf('%u', $range[1] - $range[0] + 1));
            header('Content-Disposition: attachment; filename="' . basename($path) . '"');
            header('Content-Transfer-Encoding: binary');

            if ($range[0] > 0)
            {
                fseek($file, $range[0]);
            }

            while ((feof($file) !== true) && (connection_status() === CONNECTION_NORMAL))
            {
                echo fread($file, round($speed * 1024)); flush(); sleep(1);
            }

            fclose($file);
        }

        exit();
    }

    else
    {
        header(sprintf('%s %03u %s', 'HTTP/1.1', 404, 'Not Found'), true, 404);
    }

    return false;
}

यह कोड जितना कुशल हो सकता है, यह सत्र हैंडलर को बंद कर देता है ताकि अन्य PHP स्क्रिप्ट समान उपयोगकर्ता / सत्र के लिए समवर्ती रूप से चल सकें। यह श्रेणियों में डाउनलोड करने का समर्थन भी करता है (जो कि अपाचे डिफ़ॉल्ट रूप से मुझे संदेह है) भी करता है, ताकि लोग डाउनलोड को रोक / फिर से शुरू कर सकें और डाउनलोड त्वरक के साथ उच्च डाउनलोड गति से भी लाभ उठा सकें। यह आपको अधिकतम गति (Kbps में) निर्दिष्ट करने की अनुमति देता है जिस पर डाउनलोड (भाग) को $speedतर्क के माध्यम से परोसा जाना चाहिए ।


2
जाहिर है कि यह केवल एक अच्छा विचार है यदि आप एक्स-सेंडफाइल का उपयोग नहीं कर सकते हैं या कर्नेल फ़ाइल को भेजने के लिए इसका कोई एक प्रकार है। आपको ऊपर दिए गए feof () / fread () लूप को [ php.net/manual/en/function.eio-sendfile.phponders(PHP के eio_sendfile ()) कॉल से बदलने में सक्षम होना चाहिए , जो PHP में समान कार्य को पूरा करता है। यह सीधे कर्नेल में करने के रूप में तेज़ नहीं है, क्योंकि PHP में उत्पन्न किसी भी आउटपुट को अभी भी वेबसर्वर प्रक्रिया के माध्यम से बाहर जाना पड़ता है, लेकिन यह PHP कोड में इसे करने की तुलना में बहुत तेजी से नरकुवा होने जा रहा है।
ब्रायन सी

@BrianC: ज़रूर, लेकिन आप X-Sendfile (जो उपलब्ध नहीं हो सकता है) के साथ गति या मल्टीपार्ट की क्षमता को सीमित नहीं कर सकते हैं और eioहमेशा उपलब्ध भी नहीं हैं। फिर भी, +1, उस pecl एक्सटेंशन के बारे में नहीं जानता था। =)
एलिक्स एक्सल

क्या यह स्थानांतरण-एन्कोडिंग का समर्थन करने के लिए उपयोगी होगा: chunked और सामग्री-एन्कोडिंग: gzip?
skibulk

क्यों $size = sprintf('%u', filesize($path))?
शविश

14
header('Location: ' . $path);
exit(0);

अपाचे को आपके लिए काम करने दें।


12
यह x-sendfile विधि की तुलना में सरल है, लेकिन केवल लोगों में लॉग इन करने के लिए, किसी फ़ाइल तक पहुंच को प्रतिबंधित करने के लिए काम नहीं करेगा। यदि आपको ऐसा करने की आवश्यकता नहीं है, तो यह बहुत अच्छा है!
जॉर्ड्स सेप

Mod_rewrite के साथ एक रेफ़रर चेक भी जोड़ें।
sanmai

1
हेडर को पास करने से पहले आप अनुमान लगा सकते हैं। इस तरह आप भी PHP की मेमोरी के माध्यम से कई टन सामान नहीं भर रहे हैं।
ब्रेंट

7
@UltimateBrent स्थान अभी भी सभी के लिए सुलभ होना चाहिए .. और एक संदर्भ जाँच ग्राहक से आता है, पर कोई सुरक्षा नहीं है
clientyvind Skaar

@ जिम्बो एक उपयोगकर्ता टोकन जिसे आप चेक करने जा रहे हैं कि कैसे? PHP के साथ? अचानक आपके समाधान में कमी आ रही है।
मार्क अमेरी

1

कैश सपोर्ट के साथ एक बेहतर कार्यान्वयन, अनुकूलित हेडर।

serveStaticFile($fn, array(
        'headers'=>array(
            'Content-Type' => 'image/x-icon',
            'Cache-Control' =>  'public, max-age=604800',
            'Expires' => gmdate("D, d M Y H:i:s", time() + 30 * 86400) . " GMT",
        )
    ));

function serveStaticFile($path, $options = array()) {
    $path = realpath($path);
    if (is_file($path)) {
        if(session_id())
            session_write_close();

        header_remove();
        set_time_limit(0);
        $size = filesize($path);
        $lastModifiedTime = filemtime($path);
        $fp = @fopen($path, 'rb');
        $range = array(0, $size - 1);

        header('Last-Modified: ' . gmdate("D, d M Y H:i:s", $lastModifiedTime)." GMT");
        if (( ! empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModifiedTime ) ) {
            header("HTTP/1.1 304 Not Modified", true, 304);
            return true;
        }

        if (isset($_SERVER['HTTP_RANGE'])) {
            //$valid = preg_match('^bytes=\d*-\d*(,\d*-\d*)*$', $_SERVER['HTTP_RANGE']);
            if(substr($_SERVER['HTTP_RANGE'], 0, 6) != 'bytes=') {
                header('HTTP/1.1 416 Requested Range Not Satisfiable', true, 416);
                header('Content-Range: bytes */' . $size); // Required in 416.
                return false;
            }

            $ranges = explode(',', substr($_SERVER['HTTP_RANGE'], 6));
            $range = explode('-', $ranges[0]); // to do: only support the first range now.

            if ($range[0] === '') $range[0] = 0;
            if ($range[1] === '') $range[1] = $size - 1;

            if (($range[0] >= 0) && ($range[1] <= $size - 1) && ($range[0] <= $range[1])) {
                header('HTTP/1.1 206 Partial Content', true, 206);
                header('Content-Range: bytes ' . sprintf('%u-%u/%u', $range[0], $range[1], $size));
            }
            else {
                header('HTTP/1.1 416 Requested Range Not Satisfiable', true, 416);
                header('Content-Range: bytes */' . $size);
                return false;
            }
        }

        $contentLength = $range[1] - $range[0] + 1;

        //header('Content-Disposition: attachment; filename="xxxxx"');
        $headers = array(
            'Accept-Ranges' => 'bytes',
            'Content-Length' => $contentLength,
            'Content-Type' => 'application/octet-stream',
        );

        if(!empty($options['headers'])) {
            $headers = array_merge($headers, $options['headers']);
        }
        foreach($headers as $k=>$v) {
            header("$k: $v", true);
        }

        if ($range[0] > 0) {
            fseek($fp, $range[0]);
        }
        $sentSize = 0;
        while (!feof($fp) && (connection_status() === CONNECTION_NORMAL)) {
            $readingSize = $contentLength - $sentSize;
            $readingSize = min($readingSize, 512 * 1024);
            if($readingSize <= 0) break;

            $data = fread($fp, $readingSize);
            if(!$data) break;
            $sentSize += strlen($data);
            echo $data;
            flush();
        }

        fclose($fp);
        return true;
    }
    else {
        header('HTTP/1.1 404 Not Found', true, 404);
        return false;
    }
}

0

यदि आपके पास अपने php में PECL एक्सटेंशन जोड़ने की संभावना है, तो आप सामग्री-प्रकार निर्धारित करने के लिए Fileinfo पैकेज से कार्यों का उपयोग कर सकते हैं और फिर उचित हेडर भेज सकते हैं ...


/ टक्कर, क्या आपने इस संभावना का उल्लेख किया है? :)
एंड्रियास लिंडेन

0

Downloadयहां बताई गई PHP फंक्शन वास्तव में डाउनलोड होने के लिए फाइल शुरू होने से पहले कुछ देरी कर रहा था। मुझे नहीं पता कि यह वार्निश कैश या क्या का उपयोग करने के कारण हुआ था, लेकिन मेरे लिए इसने sleep(1);पूरी तरह से हटाने और सेट $speedकरने में मदद की 1024। अब यह बिना किसी समस्या के काम करता है जो नरक के रूप में तेज है। हो सकता है कि आप उस फ़ंक्शन को भी संशोधित कर सकें, क्योंकि मैंने देखा कि यह पूरे इंटरनेट पर उपयोग किया जाता है।


0

मैंने PHP और स्वचालित MIME प्रकार का पता लगाने के साथ फ़ाइलों की सेवा करने के लिए एक बहुत ही सरल फ़ंक्शन को कोडित किया:

function serve_file($filepath, $new_filename=null) {
    $filename = basename($filepath);
    if (!$new_filename) {
        $new_filename = $filename;
    }
    $mime_type = mime_content_type($filepath);
    header('Content-type: '.$mime_type);
    header('Content-Disposition: attachment; filename="downloaded.pdf"');
    readfile($filepath);
}

प्रयोग

serve_file("/no_apache/invoice243.pdf");
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.