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

黄舟
Libérer: 2023-03-16 16:40:01
original
2123 Les gens l'ont consulté

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;
}
Copier après la connexion

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'
);
Copier après la connexion

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)"}
Copier après la connexion

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);
        }
    }
}
Copier après la connexion

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();
Copier après la connexion

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;
}
Copier après la connexion

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal