Maison >développement back-end >tutoriel php >Exemple de la façon dont PHP utilise curl pour télécharger un fichier d'une taille spécifiée

Exemple de la façon dont PHP utilise curl pour télécharger un fichier d'une taille spécifiée

黄舟
黄舟original
2017-10-16 09:46:172112parcourir

En utilisant la fonction curl basée sur libcurl en PHP, vous pouvez lancer une requête http vers l'URL cible et obtenir le contenu de la réponse renvoyée. La méthode de requête habituelle est similaire au code suivant :


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;
}

La réponse $ dans le code ci-dessus est la requête http initiée par curl depuis $ Si les données obtenues à partir de l'URL ne spécifient pas la taille à télécharger via la plage de l'en-tête $, quelle que soit la taille de la ressource, le contenu complet de l'URI doit être demandé et renvoyé. Habituellement, curl n'est utilisé que pour demander certaines interfaces ou appeler une fonction à distance pour obtenir des données, le paramètre CURLOPT_TIMEOUT est donc très important dans ce scénario.

Le scénario d'utilisation de curl consiste non seulement à accéder à l'interface de données, mais également à détecter si une ressource URL peut fournir le service http correct. Lorsque l'URL renseignée par l'utilisateur est un fichier de ressources, tel qu'un pdf ou un ppt, si l'état du réseau est mauvais et que curl est utilisé pour demander une ressource plus importante, un délai d'attente se produira inévitablement ou davantage de ressources Internet seront consommées. . La stratégie précédente consistait à télécharger complètement (curl le téléchargera et le stockera en mémoire). Une fois la demande terminée, la taille du contenu sera vérifiée. Lorsque la valeur cible est dépassée, la tâche de surveillance sera suspendue. Cette restriction après l'incident traitait en fait des symptômes plutôt que de la cause première. Finalement, le client a présenté de nouvelles exigences. La tâche n'a pas pu être arrêtée et seul le fichier de la taille spécifiée a été téléchargé et la valeur md5 a été renvoyée au client. vérifier l'exactitude.

Après quelques tentatives, ce problème a été résolu. Le processus d'enregistrement est le suivant.

1. Essayez d'utiliser CURLOPT_MAXFILESIZE.

Il existe des exigences de version pour les versions PHP et libcurl, qui sont entièrement prétraitées. Lorsque la cible s'avère plus grande que le paramètre, une erreur dépassant la limite de taille est directement renvoyée sans télécharger la cible, ce qui. ne répond pas aux exigences.

2. Utilisez la fonction de rappel du processus de téléchargement curl.

Reportez-vous à http://php.net/manual/en/function.curl-setopt-array.php, et enfin utilisez le paramètre CURLOPT_WRITEFUNCTION pour définir on_curl_write La fonction sera rappelée une fois toutes les 1 secondes.

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

Le dernier fragment de mon implémentation :


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)"}

DownloadSizeRecorder est une classe en mode singleton, curl download Record la taille à l'époque, et renvoyer le md5 du contenu téléchargé, etc.


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);
        }
    }
}

Dans l'exemple de code de la requête curl, la taille du téléchargement est limitée

……
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();

Ici, j'ai fait un pas sur une fosse. Après avoir ajouté on_curl_write, $response renverra true, provoquant une exception lors de la récupération ultérieure du contenu renvoyé. Heureusement, la taille du téléchargement a été limitée en temps réel et downloadData est utilisé pour enregistrer le contenu téléchargé, qui peut être utilisé directement.

if($response === true){
    $response = $downloadSizeRecorder->downloadData;
}

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn