URL'den Dosyayı sunucuya indir


341

Bu oldukça basit görünüyor ve öyle. Sunucunuza bir dosya indirmek için tek yapmanız gereken:

file_put_contents("Tmpfile.zip", file_get_contents("http://someurl/file.zip"));

Sadece bir sorun var. Ya 100mb gibi büyük bir dosyanız varsa. Ardından, bellek yetersiz kalır ve dosyayı indiremezsiniz.

İstediğim dosyayı indirirken diske yazmanın bir yolu. Bu şekilde, daha büyük dosyaları hafıza problemlerine girmeden indirebilirim.


4
Bu sunucu yapılandırmanızda ayarlanır, PHP gerçekten bildiğim kadarıyla etrafta dolanamaz (doğrudan bir .ini düzenlemesi hariç)
Ben

Yanıtlar:


494

PHP 5.1.0'dan beri file_put_contents(), $dataparametre olarak bir akış tanıtıcısı geçirerek parça parça yazmayı destekler :

file_put_contents("Tmpfile.zip", fopen("http://someurl/file.zip", 'r'));

Kılavuzdan:

Eğer veriler [ikinci argümanı] bir akım kaynağı, yani akımın geri kalan tampon belirtilen dosyaya kopyalanacaktır. Bu, kullanıma benzer stream_copy_to_stream().

(Teşekkürler Hakre .)


4
Bu benim ilk seçimim olmazdı. Eğer allow_fopen_url Off(güvenlik için iyi bir fikir) php.ini dosyasında açık, senaryonuz dökümü yapılır.
PleaseStand

4
@idealmachine Ben de bu file_get_contents()olsaydı işe yaramayacağını düşünüyorum (bkz OP).
alex

10
@geoff Spesifiktim, istediğiniz fonksiyondan bahsettim. İsteyebileceğiniz şey, kodu sizin için yazacak biriydi - ama eminim bunu kendiniz yapan bir şey öğrendiniz. Ayrıca, birbirimizin SO etkileşimleri hakkında yorum yapacaksak - lütfen biraz daha cevap kabul edin :)
alex

@alex: Lütfen düzenlemeye bakın, dahil etmekten çekinmeyin. o zaman bu yorumu ne zaman kaldırabileceğimi bana bildirin.
hakre

4
'B' bayrağı ayrıca şu durumlarda da kullanılmalıdır fopen; görüntülere ve diğer düz olmayan metin dosyalarına olumsuz etkileri önler.
Wayne Weibel

132
private function downloadFile($url, $path)
{
    $newfname = $path;
    $file = fopen ($url, 'rb');
    if ($file) {
        $newf = fopen ($newfname, 'wb');
        if ($newf) {
            while(!feof($file)) {
                fwrite($newf, fread($file, 1024 * 8), 1024 * 8);
            }
        }
    }
    if ($file) {
        fclose($file);
    }
    if ($newf) {
        fclose($newf);
    }
}

1
snippitiniz için teşekkür ederiz, ancak kodunuzu @xaav açıklayabilir misiniz? Ben php de tam olarak parlak değilim. 1024 * 8 ne içindir? Tekrar teşekkürler.
vvMINOvv

@wMINOw Çizginin uzunluğu.
David Bélanger

2
Özellikle, parametre bayt cinsinden olduğu için bir kerede 8 KB'ye kadar (KB * 8 başına 1024 bayt) okumak anlamına gelir. Satır <= 8KB olduğu sürece, tüm satırı bir kerede okuyacaktır.
Doktor J

1
Bu neden en iyi cevap değil?
GunJack

1
Bu yaklaşımla hataları nasıl ele alırsınız? Bir 404 döndürülürse veya bağlantı kesilirse veya zaman aşımına uğrarsa ne olur?
Adam Swinden

67

CURL kullanmayı deneyin

set_time_limit(0); // unlimited max execution time
$options = array(
  CURLOPT_FILE    => '/path/to/download/the/file/to.zip',
  CURLOPT_TIMEOUT =>  28800, // set this to 8 hours so we dont timeout on big files
  CURLOPT_URL     => 'http://remoteserver.com/path/to/big/file.zip',
);

$ch = curl_init();
curl_setopt_array($ch, $options);
curl_exec($ch);
curl_close($ch);

Emin değilim ama CURLOPT_FILEveri çeker gibi yazar seçeneği ile inanıyorum , yani. arabelleklenmemiş.


2
Normalde, bu iyi olurdu, ama bir web uygulamasında bu kodu var, bu yüzden kullanıcıların cURL yüklü olacak emin olamaz. Ancak buna oy verdim.
xaav

@ Geoff dağıtılmış bir web uygulaması mı? Çünkü barındırma kontrol ederseniz, o zaman kullanıcılarınız için önemli değildir (cURL sunucunuzda bir kütüphanedir).
alex

Hayır. Barındırma işlemini kontrol etmiyorum. Herkesin sahip olabileceği dağıtılmış bir web uygulamasıdır.
xaav

3
Kıvrılma eksik olabilir. Ancak hemen hemen tüm paylaşılan barındırma şirketlerinde varsayılan olarak CURL yüklüdür. Yani, görmeyen birini görmedim.
Mangirdas Skripka

19
Testlerimden itibaren CURLOPT_FILE dosyasına doğrudan bir dosya yolu atayamazsınız. Bir dosya işleyici olmalı. İlk önce dosyayı ile açın $fh = fopen('/path/to/download/the/file/to.zip', 'w');ve fclose($fh);sonra ile kapatın curl_close($ch);. Ve setCURLOPT_FILE => $fh
Gustavo

22

prodigitalson'un yanıtı benim için işe yaramadı. Daha missing fopen in CURLOPT_FILE fazla ayrıntı var .

Bu, yerel URL'ler dahil olmak üzere benim için çalıştı:

function downloadUrlToFile($url, $outFileName)
{   
    if(is_file($url)) {
        copy($url, $outFileName); 
    } else {
        $options = array(
          CURLOPT_FILE    => fopen($outFileName, 'w'),
          CURLOPT_TIMEOUT =>  28800, // set this to 8 hours so we dont timeout on big files
          CURLOPT_URL     => $url
        );

        $ch = curl_init();
        curl_setopt_array($ch, $options);
        curl_exec($ch);
        curl_close($ch);
    }
}

19
  1. Hedef sunucuda "indirilenler" adlı bir klasör oluşturun
  2. [Bu kodu] .phpdosyaya kaydedin ve hedef sunucuda çalıştırın

İndirici:

<html>
<form method="post">
<input name="url" size="50" />
<input name="submit" type="submit" />
</form>
<?php
    // maximum execution time in seconds
    set_time_limit (24 * 60 * 60);

    if (!isset($_POST['submit'])) die();

    // folder to save downloaded files to. must end with slash
    $destination_folder = 'downloads/';

    $url = $_POST['url'];
    $newfname = $destination_folder . basename($url);

    $file = fopen ($url, "rb");
    if ($file) {
      $newf = fopen ($newfname, "wb");

      if ($newf)
      while(!feof($file)) {
        fwrite($newf, fread($file, 1024 * 8 ), 1024 * 8 );
      }
    }

    if ($file) {
      fclose($file);
    }

    if ($newf) {
      fclose($newf);
    }
?>
</html> 

Bu, kullanıcının mevcut bir PHP uygulaması içinde çalışacak bir çözüm yerine bağımsız bir komut dosyası istediğini varsayar ve ikincisinin OP ve diğerlerinin aradığı şey olduğuna inanıyorum. Bir açıklama, yaklaşımı anlamak isteyen insanlar için de yararlı olacaktır.
Fasulye Sean

1
bunu denediğimde her zaman aktarılan dosya boyutu 50816, ancak dosya boyutum bundan daha büyük .. 120MB .. Herhangi bir fikir neden bu?
Riffaz Starr

set_time_limit (24 * 60 * 60);bir döngü içine konmalıdır. Komut dosyasının başında herhangi bir etkisi yoktur.
Viktor Joras

16
set_time_limit(0); 
$file = file_get_contents('path of your file');
file_put_contents('file.ext', $file);

Cevabınız çok basit ve iyi çalışıyor, cURL'nin dosya alamadığı yerde bana yardımcı oldu, bu işe yaradı. Teşekkürler :)
Tommix

2
Bunun gerçekte ne yaptığını açıklamak isteyebilirsiniz.
alex

6
Bu, OP'nin PHP bellek sınırını aşma sorununu ele almaz.
user9645

Bu oldukça basit ve anlaşılır. Dosyaların küçük olduğu veya ortamın yerel bir gelişme olduğu daha basit durumlar için oldukça yararlıdır.
Valentine Shi

.xlsx dosyaları için herhangi bir fikir? Boş dosyayı 0 bayt bellekle saklıyor.
Dhruv Thakkar

9

3 yol vardır:

  1. file_get_contents ve file_put_contents
  2. CURL
  3. fopen

Burada örnekleri bulabilirsiniz .


8

Php basit bir yöntem kullanın copy()

copy($source_url, $local_path_with_file_name);

Not: hedef dosya zaten varsa, üzerine yazılır

PHP copy () İşlevi

Not: Hedef klasör için 777 iznini ayarlamanız gerekir. Yerel makinenize indirirken bu yöntemi kullanın.

Özel Not: 777, Unix tabanlı sistemde sahip, grup ve herkes için tam okuma / yazma / yürütme izni olan bir izindir. Genel olarak bu izni, bir web sunucusunda kamuoyundan gizlenmesi gerekmeyen varlıklara veririz. Örnek: resim klasörü.


1
Asla 777'yi asla bir web sunucusunda izin olarak ayarlamayacağım ve bunu yapmak için kötü fikri olan herhangi bir web geliştiricisini başlatacağım. Her zaman her yerde. Dikkatli ol ! Bunu yapamazsın ! Güvenliği düşünün. OWASP kurallarına uymak yeterli değildir. Basit şeyler hakkında iyi düşünmek önemlidir.
ThierryB

@ThierryB. Not: Yerel yol verdim. & bu dahili uygulamalarda kullanılabilir. Soru-cevap konularını iyi okuma ve anlama. Farklı senaryolar düşünün. Ve bu kabul edilmedi / en iyi cevap. Her sorunun içinde artıları ve eksileri ile farklı cevaplar var .. Anlamanız için örnek: Fibonacci bile sadece bir tanesinin en iyi olacağı birden fazla benzersiz çözüme sahiptir. Diğerleri farklı senaryolarda kullanılacaktır.
Pradeep Kumar Prabaharan

Tamam, ancak en iyi uygulamaları düşünmek ve bunları güvenli yerlerde uygulamak için zaman ayırmanız, uygulamanız gereken kavramları daha iyi anlamanıza yardımcı olur. Bir davetsiz misafir ($) evinizin içindeyse, bazı tuzaklar yapıyor veya en iyi şekilde bir şeyler inşa ediyorsanız, ona baş ağrısı verebilirsiniz;)
ThierryB

5

Bunu dosya indirmek için kullanıyorum

function cURLcheckBasicFunctions()
{
  if( !function_exists("curl_init") &&
      !function_exists("curl_setopt") &&
      !function_exists("curl_exec") &&
      !function_exists("curl_close") ) return false;
  else return true;
}

/*
 * Returns string status information.
 * Can be changed to int or bool return types.
 */
function cURLdownload($url, $file)
{
  if( !cURLcheckBasicFunctions() ) return "UNAVAILABLE: cURL Basic Functions";
  $ch = curl_init();
  if($ch)
  {

    $fp = fopen($file, "w");
    if($fp)
    {
      if( !curl_setopt($ch, CURLOPT_URL, $url) )
      {
        fclose($fp); // to match fopen()
        curl_close($ch); // to match curl_init()
        return "FAIL: curl_setopt(CURLOPT_URL)";
      }
      if ((!ini_get('open_basedir') && !ini_get('safe_mode')) || $redirects < 1) {
        curl_setopt($ch, CURLOPT_USERAGENT, '"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.11) Gecko/20071204 Ubuntu/7.10 (gutsy) Firefox/2.0.0.11');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        //curl_setopt($ch, CURLOPT_REFERER, 'http://domain.com/');
        if( !curl_setopt($ch, CURLOPT_HEADER, $curlopt_header)) return "FAIL: curl_setopt(CURLOPT_HEADER)";
        if( !curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $redirects > 0)) return "FAIL: curl_setopt(CURLOPT_FOLLOWLOCATION)";
        if( !curl_setopt($ch, CURLOPT_FILE, $fp) ) return "FAIL: curl_setopt(CURLOPT_FILE)";
        if( !curl_setopt($ch, CURLOPT_MAXREDIRS, $redirects) ) return "FAIL: curl_setopt(CURLOPT_MAXREDIRS)";

        return curl_exec($ch);
    } else {
        curl_setopt($ch, CURLOPT_USERAGENT, '"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.11) Gecko/20071204 Ubuntu/7.10 (gutsy) Firefox/2.0.0.11');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        //curl_setopt($ch, CURLOPT_REFERER, 'http://domain.com/');
        if( !curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false)) return "FAIL: curl_setopt(CURLOPT_FOLLOWLOCATION)";
        if( !curl_setopt($ch, CURLOPT_FILE, $fp) ) return "FAIL: curl_setopt(CURLOPT_FILE)";
        if( !curl_setopt($ch, CURLOPT_HEADER, true)) return "FAIL: curl_setopt(CURLOPT_HEADER)";
        if( !curl_setopt($ch, CURLOPT_RETURNTRANSFER, true)) return "FAIL: curl_setopt(CURLOPT_RETURNTRANSFER)";
        if( !curl_setopt($ch, CURLOPT_FORBID_REUSE, false)) return "FAIL: curl_setopt(CURLOPT_FORBID_REUSE)";
        curl_setopt($ch, CURLOPT_USERAGENT, '"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.11) Gecko/20071204 Ubuntu/7.10 (gutsy) Firefox/2.0.0.11');
    }
      // if( !curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true) ) return "FAIL: curl_setopt(CURLOPT_FOLLOWLOCATION)";
      // if( !curl_setopt($ch, CURLOPT_FILE, $fp) ) return "FAIL: curl_setopt(CURLOPT_FILE)";
      // if( !curl_setopt($ch, CURLOPT_HEADER, 0) ) return "FAIL: curl_setopt(CURLOPT_HEADER)";
      if( !curl_exec($ch) ) return "FAIL: curl_exec()";
      curl_close($ch);
      fclose($fp);
      return "SUCCESS: $file [$url]";
    }
    else return "FAIL: fopen()";
  }
  else return "FAIL: curl_init()";
}

4

Bir PHP 4 ve 5 Çözümü:

readfile () , kendi başına büyük dosyalar gönderirken bile bellek sorunları göstermez. Fopen sarmalayıcıları etkinleştirildiyse, URL bu işlevle dosya adı olarak kullanılabilir.

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


1
Bu soruya cevap vermez, çünkü soru çıktı tamponuna değil disk üzerine yazmakla ilgilidir.
Lorenz Meyer
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.