PHP處理高分辨率圖片的問題

今天小夥伴在羣裏問了這麼一個問題:php

v2-c8c5c85a90fbc0926f824720d0ae6ec3_720w.jpg


v2-09268d40f82b099ee97f5e34645990de_720w.jpg


v2-23e155ffaef71293ec14a87eda287577_720w.jpg


v2-fcf30da625b5ba9e10ee83d10d30763d_720w.jpg

出現這種狀況就是由於內存不足, PHP 程序直接退出了,報錯大概以下:前端

v2-59625dfd9294185cf738916dba13862a_720w.jpg

上圖的意思就是說,咱們能使用的內存最大是8M,可是處理這個圖片還須要額外的41bytes,就會致使內存不足,這是一個很嚴重的錯誤。在對圖片進行操做前須要將圖片的全部信息讀入內存中,同時還會使用另外一部份內存同於處理計算並緩存輸出,因此內存大小的使用仍是和圖片的大小有關。git

PHP 中圖片的處理都是使用了 GD 庫,這個庫提供了不少方法讓 PHP 能夠更方便地對圖片進行操做,支持的圖片格式以下:github

v2-77af30e57ae6f4582f07974865686ecb_720w.jpg

回到一開始的問題,那個小夥伴須要處理高分辨的圖片,圖片大小必然很大,因此就會出現內存不夠的狀況,解決方法仍是有不少的。後端

1. 設置圖片最大可上傳的大小

前端上傳前能夠先檢測下大小,若是超過最大值直接就不請求接口,同時爲安全起見,後端接收到請求後也要檢測大小,防止程序異常退出。緩存


2. 壓縮圖片

3. 關閉 memory_limit

羣裏的小夥伴最後使用了一種 簡單粗暴的方式 解決了該問題,直接在PHP中關閉 memory_limit :安全

set_time_limit(0);
@ini_set('memory_limit','-1');複製代碼

這樣雖然解決了問題,但不優雅也不安全,一樣在 php.ini 配置文件中將 memory_limit 的值設置很大也能解決:bash

memory_limit = 256M複製代碼

PHP代碼中也能夠這樣設置:學習

ini_set('memory_limit', '256M');複製代碼

上面咱們將 memory_limit 參數固定了,這就帶來一個弊端,由於大多數狀況下不須要這麼大的內存,有點浪費資源,最好的作法就是根據須要來設置 memory_limit ,我寫了一個以下方法可供參考:測試

public function setMemoryLimit($filename){
    // 控制執行時間
    set_time_limit(50);

    $maxMemoryUsage = 256M;
    $width = 0;
    $height = 0;
    $size = ini_get('memory_limit');

    // 獲取圖片大小
    list($width, $height) = getimagesize($filename);

    // 計算須要的內存,並轉換成'M'單位
    // 4 由於png圖片一個像素有4字節
    // 1.5 是一個調整因子,由於memory_limit不是那麼精確
    // 詳細能夠查看: http://php.net/imagecreatefromjpeg#76968
    $size = $size + floor(($width * $height * 4 * 1.5 + 1048576) / 1048576);

    if ($size > $maxMemoryUsage){
        $size = $maxMemoryUsage;
   }

   // 更新
   ini_set('memory_limit',$size.'M');
}複製代碼

最後說一下,網上說 GD 庫是比較耗內存的,但我這裏沒有作過測試。Github上有個 C 的項目叫 libvips/libvips :

v2-3bf8685b8b4e11eae840784f84b5e09d_720w.jpg


v2-75c07f4b60e490e8c2a2ca6977e6ae42_720w.jpg

能夠在不佔用不少內存的狀況下提升圖片處理的速度,這是地址:https://github.com/libvips/libvips,有時間能夠學習下。複製代碼


attachments-2020-06-p6b9Ofy25eeac9561b60c.jpg

相關文章
相關標籤/搜索