PHP ile büyük dosyaları hizmet

8 Cevap php

Yani bir PHP komut dosyası yoluyla büyük dosyalar hizmet etmeye çalışıyorum, onlar bir web erişilebilir dizinde değil, bu yüzden bu onlara erişim sağlamak için anlamaya en iyi yoludur.

Ben bu dosyayı hizmet yarasa kapalı düşünebildiğim tek yolu, bellek (fopen, fread, vb.) Yüklenerek uygun MIME türüne başlık ayar verilerini, ve sonra sadece dosyanın tüm içeriğini yankılanan gereğidir.

Bu sorun ben tek seferde belleğe bu ~ 700MB dosyaları yüklemek ve indirmek tamamlandığında kadar orada tüm şey tutmak zorunda olduğunu. Ben indirdikleri gibi ihtiyacım bölgelerinde akışı eğer güzel olurdu.

Herhangi bir fikir?

8 Cevap

Sen her şeyi okumak gerekmez - sadece bir döngü, diyelim ki, onu okuma 32Kb topakları ve çıkış olarak göndererek girin. Daha da iyisi, sizin için çok daha aynı şeyi yapar fpassthru hangi kullanmak ....

$name = 'mybigfile.zip';
$fp = fopen($name, 'rb');

// send the right headers
header("Content-Type: application/zip");
header("Content-Length: " . filesize($name));

// dump the file and stop the script
fpassthru($fp);
exit;

even less lines Eğer readfile kullanırsanız, fopen çağrıyı hangi gerekmez ...

$name = 'mybigfile.zip';

// send the right headers
header("Content-Type: application/zip");
header("Content-Length: " . filesize($name));

// dump the file and stop the script
readfile($name);
exit;

Hatta şirin almak istiyorsanız, istemcilerin dosyanın belirli bir bayt aralığı talep sağlayan Content-Range başlığını destekleyebilir. Bu sadece mevcut sayfayı oluşturmak için gereken dosyanın parçalarını istekleri Adobe Acrobat, PDF dosyaları hizmet için özellikle yararlıdır. Bu biraz ilgili, ama see this for an example.

Php ile büyük dosya göndermek için en iyi yolu, X-Sendfile başlığıdır. Bu web sunucusu sendfile(2) gibi sıfır-kopya mekanizmalar yoluyla çok daha hızlı dosya hizmet veriyor. Bir plugin ile lighttpd ve apache tarafından desteklenmektedir.

Örnek:

$file = "/absolute/path/to/file"; // can be protected by .htaccess
header('X-Sendfile: '.$file);
header('Content-type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
// other headers ...
exit;

Sunucu X-Sendfile başlığını okur ve dosyayı gönderir.

Yol daha sonra tüm trafik yalak php geçen önlemek için web hizmet dizininde bu klasöre bir sembolik bağlantı (sembolik) yapabilirsiniz web sunumu dizininde (htdocs) değil çünkü dosyaları web sunucusu tarafından erişilebilir değilse.

Böyle bir şey yapabilirsiniz

ln -s /home/files/big_files_folder /home/www/htdocs

Statik dosyaları hizmet için php kullanarak, çok daha yavaştır yüksek trafik varsa, bellek tüketimi çok büyük olacak ve istekleri büyük bir sayı ele olmayabilir.

fpassthru() bakabilirsiniz. PHP daha yeni sürümlerinde bu this comment devletler gibi, bunları bellekte tutmak olmadan dosyaları hizmet etmelidir.

Strange, neither fpassthru() nor readfile() did it for me, always had a memory error. I resorted to use passthru() without the 'f':

$name = 'mybigfile.zip';
// send the right headers
header("Content-Type: application/zip");
header("Content-Length: " . filesize($name));
// dump the file and stop the script
passthru('/bin/cat '.$filename);
exit;

Bu Execs 'cat' Unix komut ve tarayıcıya çıktısı gönderebilirsiniz.

ince için yorumum: Eğer sadece bir yerde bir sembolik bağ koymayın sebebi site alanı GÜVENLİK olduğunu.

Fpassthru () yararlarından biri, bu işlevi dosyaları ancak herhangi bir geçerli kolu ile değil sadece çalışmak olabilir. Örneğin soket.

Ve readfile () () (as file_get_contents gibi gibi) mümkünse, OS önbelleğe alma mekanizması kullanılarak nedeni biraz daha hızlı olmalı.

Bir ipucu daha. fpassthru () istemci içerik (yavaş bağlantı oldukça uzun bir süre gerektirebilir) alıncaya kadar, açık kolu tutun ve böylece bazı kilit mekanizmasını kullanmanız gerekir bu dosyaya paralel yazıyor mümkünse.

Python cevapları tüm iyi. Ama asıl dosyalara sembolik bağlantılar içeren bir web erişilebilir dizin yapmak değil herhangi bir sebep var mı? Bazı ekstra sunucu yapılandırma sürebilir, ama çalışmak gerektiğini.