Beispiel dafür, wie PHP Curl verwendet, um eine Datei einer bestimmten Größe herunterzuladen

黄舟
Freigeben: 2023-03-16 16:40:01
Original
2070 Leute haben es durchsucht

Mit der auf libcurl in PHP basierenden Curl-Funktion können Sie eine HTTP-Anfrage an die Ziel-URL initiieren und den zurückgegebenen Antwortinhalt erhalten. Die übliche Anforderungsmethode ähnelt dem folgenden Code:


public function callFunction($url, $postData, $method, header='')
{    
$maxRetryTimes = 3;    
$curl = curl_init();    
/******初始化请求参数start******/
    if(strtoupper($method) !== 'GET' && $postData){
        curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($postData));
    }elseif (strtoupper($method) === 'GET' && $postData){        
    $url .= '?'. http_build_query($postData);
    }    /******初始化请求参数end******/
    curl_setopt_array($curl, array(
        CURLOPT_URL => $url,
        CURLOPT_TIMEOUT => 10,
        CURLOPT_NOBODY => 0,
        CURLOPT_RETURNTRANSFER => 1
    ));    if(method == 'POST'){
        curl_setopt($curl, CURLOPT_POST, true);
    }    if(false == empty()){
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    }    $response = false;    while(($response === false) && (--$maxRetryTimes > 0)){        
    $response = trim(curl_exec($curl));
    }    return $response;
}
Nach dem Login kopieren

Die $response im obigen Code ist die von curl from initiierte http-Anfrage $ Wenn die von der URL erhaltenen Daten nicht die Größe angeben, die über den Bereich im $-Header heruntergeladen werden soll, muss unabhängig von der Größe der Ressource der vollständige Inhalt der URI angefordert und zurückgegeben werden. Normalerweise wird Curl nur zum Anfordern einiger Schnittstellen oder zum Remoteaufruf einer Funktion zum Abrufen von Daten verwendet. Daher ist der Parameter CURLOPT_TIMEOUT in diesem Szenario sehr wichtig.

Das Verwendungsszenario von Curl besteht nicht nur darin, auf die Datenschnittstelle zuzugreifen, sondern auch zu erkennen, ob eine URL-Ressource den richtigen http-Dienst bereitstellen kann. Wenn es sich bei der vom Benutzer eingegebenen URL um eine Ressourcendatei wie eine PDF- oder PPT-Datei handelt und die Netzwerkbedingungen schlecht sind und Curl zum Anfordern einer größeren Ressource verwendet wird, kommt es zwangsläufig zu einer Zeitüberschreitung oder es werden mehr Internetressourcen verbraucht . Die vorherige Strategie bestand darin, den Inhalt vollständig herunterzuladen (Curl lädt ihn herunter und speichert ihn im Speicher). Wenn der Zielwert überschritten wird, wird die Überwachungsaufgabe angehalten. Diese Einschränkung nach dem Vorfall behebt tatsächlich die Symptome und nicht die Grundursache. Schließlich stellte der Kunde neue Anforderungen. Die Aufgabe konnte nicht gestoppt werden und es wurde nur die Datei der angegebenen Größe heruntergeladen und der MD5-Wert an den Kunden zurückgegeben Überprüfen Sie die Richtigkeit.

Nach einigen Versuchen wurde dieses Problem gelöst. Der Aufnahmevorgang ist wie folgt.

1. Versuchen Sie, CURLOPT_MAXFILESIZE zu verwenden.

Es gibt Versionsanforderungen für PHP- und libcurl-Versionen, die vollständig vorverarbeitet werden. Wenn festgestellt wird, dass das Ziel größer als die Einstellung ist, wird direkt ein Fehler zurückgegeben, der die Größenbeschränkung überschreitet, ohne dass das Ziel heruntergeladen werden muss entspricht nicht den Anforderungen.

2. Verwenden Sie die Rückruffunktion des Curl-Download-Prozesses.

Lesen Sie http://php.net/manual/en/function.curl-setopt-array.php und verwenden Sie abschließend den Parameter CURLOPT_WRITEFUNCTION, um on_curl_write festzulegen. Die Funktion wird alle 1 Sekunden zurückgerufen.

$ch = curl_init();
$options = array(CURLOPT_URL        => 'http://www.php.net/',
CURLOPT_HEADER        => false,
CURLOPT_HEADERFUNCTION    => 'on_curl_header',
CURLOPT_WRITEFUNCTION    => 'on_curl_write'
);
Nach dem Login kopieren

Das letzte Fragment meiner Implementierung:


function on_curl_write($ch, $data)
{    $pid = getmypid();    
$downloadSizeRecorder = DownloadSizeRecorder::getInstance($pid);    
$bytes = strlen($data);    
$downloadSizeRecorder->downloadData .= $data;    
$downloadSizeRecorder->downloadedFileSize += $bytes;
//    error_log(' on_curl_write '.$downloadSizeRecorder->downloadedFileSize." > {$downloadSizeRecorder->maxSize} \n", 3, '/tmp/hyb.log');
    //确保已经下载的内容略大于最大限制
    if (($downloadSizeRecorder->downloadedFileSize - $bytes) > $downloadSizeRecorder->maxSize) {        return false;
    }    return $bytes;  //这个不正确的返回,将会报错,中断下载 "errno":23,"errmsg":"Failed writing body (0 != 16384)"}
Nach dem Login kopieren

DownloadSizeRecorder ist eine Singleton-Modus-Klasse, Curl-Download-Record die Größe zu diesem Zeitpunkt und geben Sie die MD5 des heruntergeladenen Inhalts usw. zurück.


class DownloadSizeRecorder
{    const ERROR_FAILED_WRITING = 23; //Failed writing body
    public $downloadedFileSize;    
    public $maxSize;    
    public $pid;    
    public $hasOverMaxSize;    
    public $fileFullName;    
    public $downloadData;    
    private static $selfInstanceList = array();    
    public static function getInstance($pid)
    {        if(!isset(self::$selfInstanceList[$pid])){
            self::$selfInstanceList[$pid] = new self($pid);
        }        return self::$selfInstanceList[$pid];
    }    private function __construct($pid)
    {        
    $this->pid = $pid;        
    $this->downloadedFileSize = 0;        
    $this->fileFullName = '';        
    $this->hasOverMaxSize = false;        
    $this->downloadData = '';
    }    
    /**
     * 保存文件     
     */
    public function saveMaxSizeData2File(){        
    if(empty($resp_data)){            
    $resp_data = $this->downloadData;
        }        
        $fileFullName = '/tmp/http_'.$this->pid.'_'.time()."_{$this->maxSize}.download";        
        if($resp_data && strlen($resp_data)>0)
        {            
        list($headerOnly, $bodyOnly) = explode("\r\n\r\n", $resp_data, 2);            
        $saveDataLenth = ($this->downloadedFileSize < $this->maxSize) ? $this->downloadedFileSize : $this->maxSize;            
        $needSaveData = substr($bodyOnly, 0, $saveDataLenth);            
        if(empty($needSaveData)){                
        return;
            }            
            file_put_contents($fileFullName, $needSaveData);            
            if(file_exists($fileFullName)){                
            $this->fileFullName = $fileFullName;
            }
        }
    }    
    /**
     * 返回文件的md5
     * @return string     
     */
    public function returnFileMd5(){        
    $md5 = &#39;&#39;;        
    if(file_exists($this->fileFullName)){            
    $md5 = md5_file($this->fileFullName);
        }        
        return $md5;
    }    
    /**
     * 返回已下载的size
     * @return int    
      */
    public function returnSize(){        
    return ($this->downloadedFileSize < $this->maxSize) ? $this->downloadedFileSize : $this->maxSize;
    }    
    /**
     * 删除下载的文件    
      */
    public function deleteFile(){        
    if(file_exists($this->fileFullName)){            
    unlink($this->fileFullName);
        }
    }
}
Nach dem Login kopieren

Im Codebeispiel der Curl-Anfrage ist die Downloadgröße begrenzt

……
curl_setopt($ch, CURLOPT_WRITEFUNCTION, &#39;on_curl_write&#39;);//设置回调函数
……
$pid = getmypid();
$downloadSizeRecorder = DownloadSizeRecorder::getInstance($pid);
$downloadSizeRecorder->maxSize = $size_limit;
……
//发起curl请求
$response = curl_exec($ch);
……
//保存文件,返回md5
$downloadSizeRecorder->saveMaxSizeData2File();  //保存
$downloadFileMd5 = $downloadSizeRecorder->returnFileMd5();
$downloadedfile_size = $downloadSizeRecorder->returnSize();
$downloadSizeRecorder->deleteFile();
Nach dem Login kopieren

Hier bin ich getreten auf einer Grube. Nach dem Hinzufügen von on_curl_write gibt $response true zurück, was beim späteren Abrufen des zurückgegebenen Inhalts eine Ausnahme verursacht. Glücklicherweise wurde die Downloadgröße in Echtzeit begrenzt und downloadData wird zum Aufzeichnen des heruntergeladenen Inhalts verwendet, der direkt verwendet werden kann.

if($response === true){
    $response = $downloadSizeRecorder->downloadData;
}
Nach dem Login kopieren

Das obige ist der detaillierte Inhalt vonBeispiel dafür, wie PHP Curl verwendet, um eine Datei einer bestimmten Größe herunterzuladen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage