PHP: обрабатывать память и низкий уровень использования кода - PullRequest
2 голосов
/ 12 ноября 2010

Да, у меня проблема с памятью PHP.Мое предложение хозяина макс.использовать ограничение памяти 64M, и каким-то образом, когда я загружаю + обрезать функции превышает эту память, и я получаю сообщение об ошибке (хотя не всегда, зависит от размера изображения)

Когда я загружаю изображение размером около 1 МБ или ниже, он загружает, и вы можете обрезать и сохранить его.

Но когда я загружаю изображение размером около 2 МБ или выше (мое ограничение на функцию загрузки составляет 6 МБ), оно загружает, а затем, когда вы обрезаете изображениеи хочу сохранить его, я получаю сообщение «ошибка нехватки памяти».

Я попытался imagedestroy () после любой функции в gd, я больше не использую, но это не повлияло на это.Хотя я использую только GDfunctions в кропе

Так есть ли что-нибудь, что я могу освободить из памяти при загрузке кейса?

Или, может быть, вообще, как освободить использование памяти php?

Вот мой сценарий:

switch($action) {

    case 'upload':


    $userid = $USER;
    $user = getUserInfo($userid);
    $lasttime = $user['showURP']["photo_lasttime"];

    $upload_name = "file";
    $max_file_size_in_bytes = 8388608;
    $extension_whitelist = array("jpg", "gif", "png", "jpeg");

    /* checking extensions */
    $path_info = pathinfo($_FILES[$upload_name]['name']);
    $file_extension = $path_info["extension"];
    $is_valid_extension = false;
    foreach ($extension_whitelist as $extension) {
        if (strcasecmp($file_extension, $extension) == 0) {
            $is_valid_extension = true;
            break;
        }
    }
    if (!$is_valid_extension) {
        echo "{";
        echo        "error: 'Filtype not allowed!'\n";
        echo "}";
        exit(0);
    }
    /* checking filetype*/
switch(exif_imagetype($_FILES[$upload_name]['tmp_name'])) {
    case IMAGETYPE_GIF:
    case IMAGETYPE_JPEG:
    case IMAGETYPE_PNG:
        break;
    default:
        echo "{";
        echo        "error: 'This is no real image!'\n";
        echo "}";
        exit(0);
}

    /* file size check */
    $file_size = @filesize($_FILES[$upload_name]["tmp_name"]);
    if (!$file_size || $file_size > $max_file_size_in_bytes) {
        echo "{";
        echo        "error: 'Filesize exceeds the limit: 6MB'\n";
        echo "}";
        exit(0);
    }




    if(isset($_FILES[$upload_name]))
        if ($_FILES[$upload_name]["error"] > 0) {
            echo "Error: " . $_FILES["file"]["error"] . "<br />";
            } else  {
                $userfile = stripslashes($_FILES[$upload_name]['name']);
                $file_size = $_FILES[$upload_name]['size'];
                $file_temp = $_FILES[$upload_name]['tmp_name'];
                $file_type = $_FILES[$upload_name]["type"];
                $file_err = $_FILES[$upload_name]['error'];
                $file_name = $userfile;

                if(move_uploaded_file($file_temp, "images/profilePhoto/".$file_name)) {
                    echo "{";
                    echo        "msg: '".$file_name."'";
                    echo "}";
                }
            }
    break;

    case 'crop':
    if ($_SERVER['REQUEST_METHOD'] == 'POST')   {


        $jpeg_quality = 90;

        $src = "images/profilePhoto/".$_POST['fname'];
        $ext= pathinfo($src, PATHINFO_EXTENSION);


    if($ext == "jpg" OR $ext == "jpeg" OR $ext == "JPG"){
        $img_r = imagecreatefromjpeg($src); // <-- im getting out of memory error on this line

    }elseif($ext == "png" OR $ext == "PNG"){
        $img_r = imagecreatefrompng($src);
    }elseif($ext == "gif" OR $ext == "GIF"){
        $img_r = imagecreatefromgif($src);
    }

        if($_POST['fixed'] == 0) {
           $targ_w = $_POST['w'];
           $targ_h = $_POST['h'];
        }
        else {
            $targ_h = $_POST['sizeh']; 
            $targ_w = $_POST['sizew']; 
        }

        $dst_r = ImageCreateTrueColor( $targ_w, $targ_h );

        imagecopyresampled($dst_r,$img_r,0,0,$_POST['x'],$_POST['y'],
        $targ_w,$targ_h,$_POST['w'],$_POST['h']);
        imagedestroy($img_r); // free memory

    $path_thumbs = "images/profilePhoto/thumbs";
        $filename = $USER . ".jpg";
        $thumb_path = $path_thumbs . '/' . $filename;

        imagejpeg($dst_r,$thumb_path,$jpeg_quality);
        imagedestroy($dst_r); // free memory

        echo json_encode(array(
            'filename'=>$thumb_path
        ));
        unlink($src);       


    }   
    break;
}

Мой хост поддерживает только GD lib для обрезки изображений, поэтому imagemagick не может быть использован.

И, как я упоминал ранее, мой хост имеетпредел памяти на 64M, который не может быть установлен

Ответы [ 4 ]

4 голосов
/ 12 ноября 2010

К сожалению, вы будете ограничены лимитом памяти. Библиотека GD выглядит так, как будто у нее ужасное управление памятью. Я только что попытался загрузить изображение с размерами 3951x2520, и использование памяти сценариев возросло с 512 КБ до загрузки до примерно 50 МБ после загрузки (PHP 5.3.3, Windows 7 Home x64). Фактическое изображение должно занимать только около 28,49 МБ памяти, так почему же GD почти вдвое увеличивает это количество? Понятия не имею.

Редактировать : На самом деле, похоже, причина в том, что GD хранит изображение во внутреннем формате GD2, который неэффективно использует память.

Edit2 : Похоже, формат GD2 на самом деле раздут только на 67% по сравнению с настоящим растровым растровым изображением. Удивительно, что оригинальный формат GD занимает меньше места, чем само оригинальное изображение или GD2. Я полагаю, что это связано с размыванием, которое заметно на выходе. Единственный способ получить файл, загруженный в исходный формат GD, - это сначала загрузить его, используя функцию изображения (например, imagecreatefromjpeg), а затем сохранить его, используя imagegd (не imagegd2), а затем снова загрузить его с * 1011. *. Это не очень эффективно, и сглаживание определенно происходит.

Окончательное редактирование :

Мне кажется, это лучшая функция, чем та, что была у меня ниже. Вы даете ему имя файла вашего файла вместе с целевой высотой и шириной, и он проверит доступную память и вернет истину или ложь, если у вас достаточно для изменения размера. Если вы предпочитаете просто знать приблизительно, сколько памяти требуется, вы можете передать true в качестве параметра $ returnRequiredMem.

function checkMemAvailbleForResize($filename, $targetX, $targetY,$returnRequiredMem = false, $gdBloat = 1.68) {
    $maxMem = ((int) ini_get('memory_limit') * 1024) * 1024;
    $imageSizeInfo = getimagesize($filename);
    $srcGDBytes = ceil((($imageSizeInfo[0] * $imageSizeInfo[1]) * 3) * $gdBloat);
    $targetGDBytes = ceil((($targetX * $targetY) * 3) * $gdBloat);
    $totalMemRequired = $srcGDBytes + $targetGDBytes + memory_get_usage();
    if ($returnRequiredMem) return $srcGDBytes + $targetGDBytes;
    if ($totalMemRequired > $maxMem) return false;
    return true;
}

Примеры: * 1 021 *

if (!checkMemAvailableForResize('path/to/file.jpg', 640,480)) die('Cannot resize!');

или

$totalBytesNeeded = checkMemAvailableForResize('path/to/file.jpg',640,480,true);

Кроме того, вы можете настроить параметр $ gdBloat в случае, если 68% слишком мало или слишком много накладных расходов:

checkMemAvailableForResize('path/to/file.jpg',640,480,false, 1.69);
1 голос
/ 12 ноября 2010

Имейте в виду, что пока GD манипулирует изображением, оно не сохраняется в сжатом формате.Таким образом, объем памяти, который GD потребуется для работы с изображением, прямо пропорционален его размеру (ширина x высота), тогда как загружаемое изображение, вероятно, сжато и, следовательно, может быть намного меньше на вашем собственном диске.

Например, вы можете загружать файл размером 1 МБ, но этот файл на самом деле имеет размер 1024x1024 пикселей и, следовательно, для загрузки GD потребуется около 4 МБ памяти - или, если он будет еще больше (скажем, 2048x2048), это будетбольше как 16 МБ памяти и т. д.

0 голосов
/ 05 июля 2014

Вы должны изменить размер изображения в браузере клиента, а не на сервере. Это сделано с помощью элемента HTML5 canvas. Вы можете написать свою собственную функцию или использовать плагин. Для этого есть хороший плагин jquery.

Загрузка файла jQuery Blueimp

0 голосов
/ 12 ноября 2010

Размер файла не имеет значения на jpeg, потому что материал сжимается.Если вы работаете с этим изображением, оно сохраняется как растровое изображение в памяти, и я думаю, что это ваша проблема.

Вы можете попробовать ImageMagick, потому что ему не нужно столько памяти, сколько gd!

ImageMagick на php.net

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...