سؤال

أنا أستخدم تنزيل القسري لتحميل في معظمه من الكود البريدية وملفات MP3 في الموقعhttp://pr1pad.kissyour.net.) - لتتبع التنزيلات في Google Analytics، في قاعدة البيانات وإخفاء مسار التنزيل الحقيقي:

إنه هذا:

extending CI model

... - bunch of code

function _fullread ($sd, $len) {
 $ret = '';
 $read = 0;
 while ($read < $len && ($buf = fread($sd, $len - $read))) {
  $read += strlen($buf);
  $ret .= $buf;
 }
 return $ret;
}

function download(){    
    /* DOWNLOAD ITSELF */

    ini_set('memory_limit', '160M');
    apache_setenv('no-gzip', '1');
    ob_end_flush();

    header("Pragma: public");
    header("Expires: 0");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header("Cache-Control: public",FALSE);
    header("Content-Description: File Transfer");
    header("Content-type: application/octet-stream");
     if (isset($_SERVER['HTTP_USER_AGENT']) && 
      (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false))
      header('Content-Type: application/force-download'); //IE HEADER
    header("Accept-Ranges: bytes");
    header("Content-Disposition: attachment; filename=\"" . basename("dir-with-    files/".$filename) . "\";");
    header("Content-Transfer-Encoding: binary");
    header("Content-Length: " . filesize("dir-with-files/".$filename));

    // Send file for download
    if ($stream = fopen("dir-with-files/$filename", 'rb')){
     while(!feof($stream) && connection_status() == 0){
      //reset time limit for big files
      set_time_limit(0);
      print($this->_fullread($stream,1024*16));
      flush();
     }
     fclose($stream);
    }
}

انها على مصباح مع CI 1.7.2 - إنها طريقة خاصة بي تفضل من العديد من المجموعات في جميع أنحاء الإنترنت، لأنه أثناء التطوير، جاءت هذه المشكلات: - الحد من الخادم. ini_set لم تساعد، لذلك اعتدت مؤقتا _fullread بدلا من ذلك طبيعي fread, ، الذي تم استخدامه في دست @readonly- ob_end_flush ()، لأن الموقع قد تم في CI1.7.2 وكنت بحاجة لتنظيف المخزن المؤقت

الآن ... لا يعمل. فعلت ذلك، ثم توقف عن إظهار الوقت المتوقع / وقت التنزيل - حاولت تنظيفه وأثناء تنظيف الكود، حدث شيء ما، لا أعرف ماذا وفي أي الإصدار السابق - لم تنجح (بدون تغيير في الإعدادات WhatsoEver) - تعديل: لا تعمل = إخراج كل شيء في نافذة المتصفح.

لذلك قلت، برغي، سوف أنظر هنا.

لذلك، أنا أبحث أساسا عن البرنامج النصي أو وظيفة، والتي يمكنني وضعها على نموذج الإخراج وسوف تفعل:

  • Call Force-Download (في Chrome Start Download، في IE، FF، Safari افتح مشروط فتح / حفظ / إلغاء)
  • إظهار حجم الملف ووقت DL المقدر (الأمر الذي يصل إلى المتصفح، وأنا أعلم، ولكن أولا، يجب أن يعرف المتصفح الملفات
  • العمل (تم اختباره وأكدت!) في IE6،7،8، FF3، Opera، Chrome & Safari على جهاز الكمبيوتر + ماك (Linux ... أنا لا أهتم حقا) - هذا هو الجزء الرئيسي
  • على الخادم، لدي أيضا شيء مثل حد ذاكرة 56 ميجابايت، والذي لا يمكنني إضافته إليه، لذلك هذا مهم أيضا

شكرا لكم مقدما.

تعديل: الآن أشعر أكثر ثمل ثم من أي وقت مضى / من قبل، منذ أن حاولت إجبار التنزيل مع .htaccess - أثناء عمله، كان لديه عدد قليل من مشاكل القاصر / الرئيسية (اختيار لك)

  • وأظهرت المسار الكامل (القاصر بالنسبة لي)
  • ينتظر حتى يتم الانتهاء من التنزيل بأكمله (عرض ك "الاتصال") ثم أظهر فقط تنزيله - والتنزيلات في ثانية واحدة (مخصص لي)

الآن، على الرغم من أنني حذفت. HTACCESS، فلا يزال ينتظر حتى اكتمال التنزيل (تماما كما لو كان قيد التنزيل إلى ذاكرة التخزين المؤقت أولا) ويحصل فقط connected وإظهار فتح / حفظ مربع الحوار.

هل كانت مفيدة؟

المحلول

لذلك، استخدمت هذا الرمز (يتم تعديله من النسخة المعدلة من تنزيل HTTP المستأنف على الإنترنت)

function _output_file($file, $path)
{
    $size = filesize($path.$file);

    @ob_end_clean(); //turn off output buffering to decrease cpu usage

    // required for IE, otherwise Content-Disposition may be ignored
    if(ini_get('zlib.output_compression'))
    ini_set('zlib.output_compression', 'Off');

    header('Content-Type: application/force-download');
    header('Content-Disposition: attachment; filename="'.basename($file).'"');
    header("Content-Transfer-Encoding: binary");
    header('Accept-Ranges: bytes');

    /* The three lines below basically make the 
    download non-cacheable */
    header("Cache-control: no-cache, pre-check=0, post-check=0");
    header("Cache-control: private");
    header('Pragma: private');
    header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");

    // multipart-download and download resuming support
    if(isset($_SERVER['HTTP_RANGE']))
    {
        list($a, $range) = explode("=",$_SERVER['HTTP_RANGE'],2);
        list($range) = explode(",",$range,2);
        list($range, $range_end) = explode("-", $range);
        $range=intval($range);
        if(!$range_end) {
            $range_end=$size-1;
        } else {
            $range_end=intval($range_end);
        }

        $new_length = $range_end-$range+1;
        header("HTTP/1.1 206 Partial Content");
        header("Content-Length: $new_length");
        header("Content-Range: bytes $range-$range_end/$size");
    } else {
        $new_length=$size;
        header("Content-Length: ".$size);
    }

    /* output the file itself */
    $chunksize = 1*(1024*1024); //you may want to change this
    $bytes_send = 0;
    if ($file = fopen($path.$file, 'rb'))
    {
        if(isset($_SERVER['HTTP_RANGE']))
        fseek($file, $range);

        while
            (!feof($file) && 
             (!connection_aborted()) && 
             ($bytes_send<$new_length) )
        {
            $buffer = fread($file, $chunksize);
            print($buffer); //echo($buffer); // is also possible
            flush();
            $bytes_send += strlen($buffer);
        }
    fclose($file);
    } else die('Error - can not open file.');

die();
}

ثم في النموذج:

function download_file($filename){
    /*
        DOWNLOAD
    */
    $path = "datadirwithmyfiles/"; //directory

    //track analytics

    include('includes/Galvanize.php'); //great plugin
    $GA = new Galvanize('UA-XXXXXXX-7');
    $GA->trackPageView();

    $this->_output_file($filename, $path);

}

إنه يعمل كما هو متوقع في جميع متصفح الإشارة على الفوز / ماك - حتى الآن، لا توجد مشاكل معها.

نصائح أخرى

حسنا، هذا سؤال قديم وقبل آدم بالفعل إجابته الخاصة، لذلك من المفترض أنه حصل على هذا العمل لنفسه، لكنه لم يشرح سبب عمله. شيء واحد لاحظته هو في السؤال الذي استخدم رؤوسه:

header("Pragma: public");
header("Cache-Control: public",FALSE);

في حين في الحل الذي استخدمه:

header("Cache-control: private");
header('Pragma: private');

لم يشرح السبب في أنه غير هؤلاء ولكنني أظن أنه يتعلق باستخدام SSL. لقد حلت مؤخرا مشكلة مماثلة في البرامج التي تحتاج إلى تمكين التنزيل عبر كل من HTTP و HTTPS، باستخدام ما يلي لإضافة الرأس الصحيح:

if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) {
    header("Cache-control: private");
    header('Pragma: private');
} else {
    header('Pragma: public');
}

نأمل أن يجد شخص ما المعلومات في هذه الإجابة إضافة مفيدة إلى ما سبق.

هناك شيء واحد أجده غريبا: أنت تتصل ob_end_flush() في بداية الوظيفة. ينظف هذا في الواقع المخزن المؤقت الإخراج، ولكنه يخرج أيضا كل شيء إلى العميل أولا (أفترض بما في ذلك، بما في ذلك رؤوس المحتوى المحددة بواسطة Codeigniter). تغيير المكالمة إلى ob_end_clean(), إنه يمسح المخزن المؤقت ويتجاهله. هذا سوف يعطيك بداية نظيفة لتوليد رؤوسك الخاصة.

نصيحة أخرى:

بدلا من قراءة الملف كدفق ويمره على Block-Wise، يمكنك إعطاء هذه الوظيفة جرب:

// ...
if (file_exists("dir-with-files/$filename")) {
   readfile($file);
}

هذا يعتني كل شيء تقريبا.

print($this->_fullread($stream,1024*16));

أفترض _fullread هو ضمن الفصل؟ إذا كان الرمز يبدو وكأنه ما ورد أعلاه $this-> لن تعمل.

هل يخرج محتويات الملف إلى الشاشة إذا علقت على جميع الأشياء الرأسية؟

مجرد تسديدة في الظلام ... كل رأس أرسله في رمز "أقسيم التنزيل" (الذي لا يتم اختباره كما هو الحال بالنسبة لك) هو نفسه لك، إلا أنني استدعاء: رأس ("التحكم في التخزين المؤقت: خاص" ،خاطئة)؛

بدلا من: رأس ("Cache-Control-Control: Public"، خطأ)؛

لا أعرف ما إذا كان ذلك سيساعد أم لا.

إذا كنت ستعمل هذا النوع من "صدى عليه باستخدام طريقة PHP"، فلن تكون قادرا على إظهار وقت متبقي أو حجم متوقع للمستخدمين. لماذا ا؟ لأنه إذا حاول المتصفح استئناف التنزيل الخاص بك في الوسط، فلن يكون لديك طريقة للتعامل مع هذه الحالة في PHP.

إذا كان لديك تنزيل ملف عادي، فإن Apache قادر على دعم التنزيل المستأنف عبر HTTP، ولكن في الحالة يتم إيقاف التنزيل مؤقتا، لا يحتوي Apache على طريقة لمعرفة المكان الذي تم تنفيذ فيه في أمورك النصية عندما يسأل العميل عن الجزء التالي.

في الأساس، عندما يتوقف المستعرض على التنزيل، سينهي الاتصال إلى WebServer بالكامل. عند استئناف التنزيل، يتم إعادة فتح الاتصال، والطلب يحتوي على علامة يقول "ابدأ من البايت رقم X". ولكن إلى WebServer النظر في PHP الخاص بك أعلاه، من أين تأتي البايت س؟

أثناء النظر في النظرية، قد يكون من الممكن أن يحدد الخادم مكان استئناف البرنامج النصي الخاص بك في حالة عدم توقف التنزيل، ولا يحاول Apache معرفة مكان استئنافه. نتيجة لذلك، ينص الرأس المرسل إلى المتصفح على أن الخادم لا يدعم السيرة الذاتية، مما يؤدي إلى إيقاف تشغيل العناصر المتوقعة والحد من الفتحات الزمنية في معظم المتصفحات الرئيسية.

تحرير: يبدو أنك قد تكون قادرا على التعامل مع هذه الحالة، لكنها ستستغرق الكثير من التعليمات البرمجية من جانبك. يرى http://www.php.net/manual/en/function.fread.php#84115. .

بدلا من محاولة إخفاء Download Your On من العالم، اجعل الأمر يتعذر الوصول إليه من الخارج والوصول إلى الملفات فقط باستخدام البرنامج النصي أعلاه. للقيام بذلك، تضع ملف HTACCESS (TextFile اسمه ".htaccess" لا تنسى النقطة الرائدة) في الدليل. محتويات HTACCESS سيكون هذا:

order deny,allow
deny from all
allow from localhost

الآن محاولة الوصول إلى المسار من * World سيجعل WebServer إنشاء 401 ممنوع.

الأمن من خلال الغموض ليس ما تريد.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top