2009-09-08 5 views
13

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

चूंकि फ़ाइलें बहुत बड़ी होंगी, इसलिए इसे फिर से लागू करने के लिए अच्छा होना चाहिए। मैंने the standard पढ़ा है, लेकिन यह काफी लंबा है और कुछ लचीलापन की अनुमति देता है। चूंकि मुझे इसे जल्दी से करने की आवश्यकता है, इसलिए मैं इस सुविधा के एक स्थिर, परीक्षण कार्यान्वयन को प्राथमिकता दूंगा।

क्या कोई मुझे ऐसी स्क्रिप्ट पर इंगित कर सकता है?

उत्तर

8

ऐसा लगता है कि मुझे वह मिला जो मुझे चाहिए था। http://www.coneural.org/florian/papers/04_byteserving.php

और बस मामले में मूल पेज काम करने के लिए बंद हो जाता है (स्क्रिप्ट पहले से ही बहुत पुरानी है) यहाँ, इसकी एक प्रति है:: ताकि अन्य इस से लाभ हो सकता है, यहाँ लिंक है

<?php 
/* 

The following byte serving code is (C) 2004 Razvan Florian. You may find the latest version at 
http://www.coneural.org/florian/papers/04_byteserving.php 

*/ 
function set_range($range, $filesize, &$first, &$last){ 
    /* 
    Sets the first and last bytes of a range, given a range expressed as a string 
    and the size of the file. 

    If the end of the range is not specified, or the end of the range is greater 
    than the length of the file, $last is set as the end of the file. 

    If the begining of the range is not specified, the meaning of the value after 
    the dash is "get the last n bytes of the file". 

    If $first is greater than $last, the range is not satisfiable, and we should 
    return a response with a status of 416 (Requested range not satisfiable). 

    Examples: 
    $range='0-499', $filesize=1000 => $first=0, $last=499 . 
    $range='500-', $filesize=1000 => $first=500, $last=999 . 
    $range='500-1200', $filesize=1000 => $first=500, $last=999 . 
    $range='-200', $filesize=1000 => $first=800, $last=999 . 

    */ 
    $dash=strpos($range,'-'); 
    $first=trim(substr($range,0,$dash)); 
    $last=trim(substr($range,$dash+1)); 
    if ($first=='') { 
    //suffix byte range: gets last n bytes 
    $suffix=$last; 
    $last=$filesize-1; 
    $first=$filesize-$suffix; 
    if($first<0) $first=0; 
    } else { 
    if ($last=='' || $last>$filesize-1) $last=$filesize-1; 
    } 
    if($first>$last){ 
    //unsatisfiable range 
    header("Status: 416 Requested range not satisfiable"); 
    header("Content-Range: */$filesize"); 
    exit; 
    } 
} 

function buffered_read($file, $bytes, $buffer_size=1024){ 
    /* 
    Outputs up to $bytes from the file $file to standard output, $buffer_size bytes at a time. 
    */ 
    $bytes_left=$bytes; 
    while($bytes_left>0 && !feof($file)){ 
    if($bytes_left>$buffer_size) 
     $bytes_to_read=$buffer_size; 
    else 
     $bytes_to_read=$bytes_left; 
    $bytes_left-=$bytes_to_read; 
    $contents=fread($file, $bytes_to_read); 
    echo $contents; 
    flush(); 
    } 
} 

function byteserve($filename){ 
    /* 
    Byteserves the file $filename. 

    When there is a request for a single range, the content is transmitted 
    with a Content-Range header, and a Content-Length header showing the number 
    of bytes actually transferred. 

    When there is a request for multiple ranges, these are transmitted as a 
    multipart message. The multipart media type used for this purpose is 
    "multipart/byteranges". 
    */ 

    $filesize=filesize($filename); 
    $file=fopen($filename,"rb"); 

    $ranges=NULL; 
    if ($_SERVER['REQUEST_METHOD']=='GET' && isset($_SERVER['HTTP_RANGE']) && $range=stristr(trim($_SERVER['HTTP_RANGE']),'bytes=')){ 
    $range=substr($range,6); 
    $boundary='g45d64df96bmdf4sdgh45hf5';//set a random boundary 
    $ranges=explode(',',$range); 
    } 

    if($ranges && count($ranges)){ 
    header("HTTP/1.1 206 Partial content"); 
    header("Accept-Ranges: bytes"); 
    if(count($ranges)>1){ 
     /* 
     More than one range is requested. 
     */ 

     //compute content length 
     $content_length=0; 
     foreach ($ranges as $range){ 
     set_range($range, $filesize, $first, $last); 
     $content_length+=strlen("\r\n--$boundary\r\n"); 
     $content_length+=strlen("Content-type: application/pdf\r\n"); 
     $content_length+=strlen("Content-range: bytes $first-$last/$filesize\r\n\r\n"); 
     $content_length+=$last-$first+1;   
     } 
     $content_length+=strlen("\r\n--$boundary--\r\n"); 

     //output headers 
     header("Content-Length: $content_length"); 
     //see http://httpd.apache.org/docs/misc/known_client_problems.html for an discussion of x-byteranges vs. byteranges 
     header("Content-Type: multipart/x-byteranges; boundary=$boundary"); 

     //output the content 
     foreach ($ranges as $range){ 
     set_range($range, $filesize, $first, $last); 
     echo "\r\n--$boundary\r\n"; 
     echo "Content-type: application/pdf\r\n"; 
     echo "Content-range: bytes $first-$last/$filesize\r\n\r\n"; 
     fseek($file,$first); 
     buffered_read ($file, $last-$first+1);   
     } 
     echo "\r\n--$boundary--\r\n"; 
    } else { 
     /* 
     A single range is requested. 
     */ 
     $range=$ranges[0]; 
     set_range($range, $filesize, $first, $last); 
     header("Content-Length: ".($last-$first+1)); 
     header("Content-Range: bytes $first-$last/$filesize"); 
     header("Content-Type: application/pdf"); 
     fseek($file,$first); 
     buffered_read($file, $last-$first+1); 
    } 
    } else{ 
    //no byteserving 
    header("Accept-Ranges: bytes"); 
    header("Content-Length: $filesize"); 
    header("Content-Type: application/pdf"); 
    readfile($filename); 
    } 
    fclose($file); 
} 

function serve($filename, $download=0){ 
    //Just serves the file without byteserving 
    //if $download=true, then the save file dialog appears 
    $filesize=filesize($filename); 
    header("Content-Length: $filesize"); 
    header("Content-Type: application/pdf"); 
    $filename_parts=pathinfo($filename); 
    if($download) header('Content-disposition: attachment; filename='.$filename_parts['basename']); 
    readfile($filename); 
} 

//unset magic quotes; otherwise, file contents will be modified 
set_magic_quotes_runtime(0); 

//do not send cache limiter header 
ini_set('session.cache_limiter','none'); 


$filename='myfile.pdf'; //this is the PDF file that will be byteserved 
byteserve($filename); //byteserve it! 
?> 
+0

विल्क्स उत्तर कोड मेरे लिए बहुत अच्छा काम करता है। मुझे ब्राउज़र विंडो में पीडीएफ के उद्घाटन के लिए इसकी ज़रूरत है। और अब यह काम करता है। –

+0

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

+0

@ सियामकशपसंद - आपका क्या मतलब है - "दूरस्थ फाइल डाउनलोड करें"? अगर फ़ाइल को डाउनलोड करने की आवश्यकता है तो आपके सर्वर पर नहीं है, तो आप डाउनलोड नहीं कर रहे हैं - आप रीडायरेक्ट कर रहे हैं। –

0

देखें http://us3.php.net/manual/en/function.fread.php

एक विकल्प यह है कि वेब सर्वर प्रश्न में फ़ाइल पर रीडायरेक्ट करके http को संभाल सकता है।

एक PHP स्क्रिप्ट हेडर ("स्थान $ urltofile") कॉल करने से पहले और किसी भी अन्य कार्यों (डाउनलोड गिनती बढ़ाने, सुरक्षा, प्रमाणीकरण, फ़ाइल सत्यापित) किसी भी चेक की जरूरत कर सकते हैं;

मैंने अपाचे के साथ इसका परीक्षण किया। डाउनलोड कार्यों को बाधित/फिर से शुरू करें। सर्वर का माइम प्रकार कॉन्फ़िगरेशन क्लाइंट व्यवहार निर्धारित करेगा। Apache के लिए, यदि mime.types में डिफ़ॉल्ट उपयुक्त नहीं हैं, तो mod_mime के लिए कॉन्फ़िगरेशन निर्देश फ़ाइल डाउनलोड करने के लिए फ़ाइल की निर्देशिका में .htaccess फ़ाइल में जा सकते हैं। यदि वास्तव में आवश्यक है, तो यह रीडायरेक्ट होने से पहले PHP स्क्रिप्ट द्वारा लिखे गए भी हो सकता है।

+1

हेडर ('स्थान:') विचार खराब है, क्योंकि सत्यापन बाईपास करने के लिए छोटा है। आपका लिंक भी टूटा हुआ है, लेकिन मैंने साइट पर आपके द्वारा उल्लिखित कोड ढूंढने में कामयाब रहा। बहुत बुरा यह दांतों के लिए कॉपीराइट किया गया है और मुझे इसका उपयोग करने की अनुमति देने के लिए वेबसाइट से संपर्क करना होगा। लेकिन यह अभी भी मान्य लगता है। –

0

शायद वेब सर्वर में वेब सर्वर को लागू करने के बजाय (यो डॉग!) आप lighttpd या mod X-Sendfile दोनों में lighttpd और Apache2 दोनों के लिए mod trigger before download का उपयोग कर सकते हैं?

0

आपको पीईआर HTTP_Download का उपयोग करना चाहिए। यह उपयोग करने के लिए बहुत आसान है और यह फिर से शुरू करने की अनुमति देता है डाउनलोड सिर्फ फ़ाइल:

http://pear.php.net/manual/en/package.http.http-download.intro.php

1

इस के आधार पर:

http://w-shadow.com/blog/2007/08/12/how-to-force-file-download-with-php/

(जो आप भी इस्तेमाल कर सकते हैं)

मैंने एक छोटा सा lib बनाया जो PECL http_send_file एक्सटेंशन करता है:

http://php.net/manual/en/function.http-send-file.php

(जो आप भी इस्तेमाल कर सकते हैं)

lib http_send_file जैसा दिखता है, लेकिन अगर आप PECL lib स्थापित करने का विकल्प नहीं है, तो आप http: भेजें फ़ाइल lib इस्तेमाल कर सकते हैं:

https://github.com/diversen/http-send-file

संबंधित मुद्दे