分享一個PHP下載遠程圖片的函數


由於工作中有一個下載遠程圖片的需求,所以在網上搜索了一下相關方法, 發現網上大多數代碼類似如下:

/* *
 * 抓取遠程圖片
 *
 * @param string $url 遠程圖片路徑
 * @param string $filename 本地存儲文件名
 
*/
function grabImage( $url$filename = '') {
     if( $url == '') {
         return  false// 如果 $url 為空則返回 false;
    }
     $ext_name =  strrchr( $url, '.');  // 獲取圖片的擴展名
     if( $ext_name != '.gif' &&  $ext_name != '.jpg' &&  $ext_name != '.bmp' &&  $ext_name != '.png') {
         return  false// 格式不在允許的范圍
    }
     if( $filename == '') {
         $filename =  time(). $ext_name// 以時間戳另起名
    }
     // 開始捕獲
     ob_start();
     readfile( $url);
     $img_data =  ob_get_contents();
     ob_end_clean();
     $size =  strlen( $img_data);
     $local_file =  fopen( $filename , 'a');
     fwrite( $local_file$img_data);
     fclose( $local_file);
     return  $filename;
}

上面的函數有幾個缺點:

1.不能自動識別圖片后綴名(很多圖片的url並不指向一個靜態圖片地址,而是直接將圖片流輸出到客戶端)

2.不支持圖片url的302跳轉 

這個函數並不符合本人項目的需求,於是花了點時間自己寫了一個下載函數,此函數支持:

1.靜態圖片下載

2.服務端直接輸出圖片流下載

3.服務端使用302跳轉到真實圖片地址的下載(可限定跳轉次數)

函數代碼如下:

     /* *
     * 下載遠程圖片
     * @param string $url 圖片的絕對url
     * @param string $filepath 文件的完整路徑(包括目錄,不包括后綴名,例如/www/images/test) ,此函數會自動根據圖片url和http頭信息確定圖片的后綴名
     * @return mixed 下載成功返回一個描述圖片信息的數組,下載失敗則返回false
     
*/
    function downloadImage( $url$filepath) {
         // 服務器返回的頭信息
         $responseHeaders =  array();
         // 原始圖片名
         $originalfilename = '';
         // 圖片的后綴名
         $ext = '';
         $ch = curl_init( $url);
         // 設置curl_exec返回的值包含Http頭
        curl_setopt( $ch, CURLOPT_HEADER, 1);
         // 設置curl_exec返回的值包含Http內容
        curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1);       
        //設置抓取跳轉(http 301,302)后的頁面

        curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1);
         // 設置最多的HTTP重定向的數量
        curl_setopt( $ch, CURLOPT_MAXREDIRS, 2);

         // 服務器返回的數據(包括http頭信息和內容)
         $html = curl_exec( $ch);
         // 獲取此次抓取的相關信息
         $httpinfo = curl_getinfo( $ch);
        curl_close( $ch);
         if ( $html !==  false) {
             // 分離response的header和body,由於服務器可能使用了302跳轉,所以此處需要將字符串分離為 2+跳轉次數 個子串
             $httpArr =  explode("\r\n\r\n",  $html, 2 +  $httpinfo['redirect_count']);
             // 倒數第二段是服務器最后一次response的http頭
             $header =  $httpArr[ count( $httpArr) - 2];
             // 倒數第一段是服務器最后一次response的內容
             $body =  $httpArr[ count( $httpArr) - 1];
             $header.="\r\n";

             // 獲取最后一次response的header信息
             preg_match_all('/([a-z0-9-_]+):\s*([^\r\n]+)\r\n/i',  $header$matches);
             if (! empty( $matches) &&  count( $matches) == 3 && ! empty( $matches[1]) && ! empty( $matches[1])) {
                 for ( $i = 0;  $i <  count( $matches[1]);  $i++) {
                     if ( array_key_exists( $i$matches[2])) {
                         $responseHeaders[ $matches[1][ $i]] =  $matches[2][ $i];
                    }
                }
            }
             // 獲取圖片后綴名
             if (0 <  preg_match('{(?:[^\/\\\\]+)\.(jpg|jpeg|gif|png|bmp)$}i',  $url$matches)) {
                 $originalfilename =  $matches[0];
                 $ext =  $matches[1];
            }  else {
                 if ( array_key_exists('Content-Type',  $responseHeaders)) {
                     if (0 <  preg_match('{image/(\w+)}i',  $responseHeaders['Content-Type'],  $extmatches)) {
                         $ext =  $extmatches[1];
                    }
                }
            }
             // 保存文件
             if (! empty( $ext)) {
                 $filepath .= ". $ext";
                 // 如果目錄不存在,則先要創建目錄
                CFiles::createDirectory( dirname( $filepath));
                 $local_file =  fopen( $filepath, 'w');
                 if ( false !==  $local_file) {
                     if ( false !==  fwrite( $local_file$body)) {
                         fclose( $local_file);
                         $sizeinfo =  getimagesize( $filepath);
                         return  array('filepath' =>  realpath( $filepath), 'width' =>  $sizeinfo[0], 'height' =>  $sizeinfo[1], 'orginalfilename' =>  $originalfilename, 'filename' =>  pathinfo( $filepath, PATHINFO_BASENAME));
                    }
                }
            }
        }
         return  false;
    }

 經測試,此函數能應付絕大多數類型遠程圖片下載的處理。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM