2014-06-21 6 views
5

मेरे पास एक स्क्रिप्ट है जो छवियों को अपलोड करती है और उन्मुखीकरण के आधार पर उन्हें घुमाती है और मुझे समस्या का सामना करना पड़ रहा है कि जब एक छवि जिसमें EXIF ​​टैग अपलोड होते हैं, तो मुझे एक त्रुटि मिलती है:PHP ने छवि अपलोड रोटेशन पर स्मृति आकार को समाप्त कर दिया

33554432 बाइट्स थक के

अनुमति स्मृति आकार ( 10368 बाइट्स आवंटित करने के लिए करने की कोशिश की।

और फिर लाइन यह त्रुटि लॉग में करने के लिए बात कर रहा है।

मैं नोटिस किया था यह केवल उन छवियों के साथ हो रहा है जिनमें EXIF ​​टैग हैं। यदि फ़ोटोशॉप या कुछ द्वारा जेनरेट की गई सामान्य छवियां अपलोड की जाती हैं, तो यह बिना किसी समस्या के काम करती है।

वास्तविक छवि उन्मुखीकरण कोड है निम्नलिखित:

function correctImageOrientation($fullpath) { 
    if (function_exists('exif_read_data')) { 
    $exif = exif_read_data($fullpath); 
    if($exif && isset($exif['Orientation'])) { 
     $orientation = $exif['Orientation']; 
     if($orientation != 1){ 
     $img = imagecreatefromjpeg($fullpath); 
     $deg = 0; 
     switch ($orientation) { 
      case 3: 
      $deg = 180; 
      break; 
      case 6: 
      $deg = 270; 
      break; 
      case 8: 
      $deg = 90; 
      break; 
     } 
     if ($deg) { 
      $img = imagerotate($img, $deg, 0);   
     } 
     // then rewrite the rotated image back to the disk as $filename 
     imagejpeg($img, $fullpath, 100); 
     } // if there is some rotation necessary 
    } // if have the exif orientation info 
    } // if function exists  
} 

error_log जहां स्मृति समस्या होता है में सही लाइन वास्तव में एक है जहाँ यह कहते हैं:

$img = imagerotate($img, $deg, 0); 

तरह से मैं कर रहा हूँ इसे स्क्रिप्ट में कॉल करना निम्नलिखित है:

$dirname = session::value('user_id'); 
$rotatedfile = '/home/myfolder/public_html/'.$dirname.'/'.$file_name; 
$rotatedfile = $this->correctImageOrientation($rotatedfile); 

मैं मूल रूप से क्या हूं हासिल करने की कोशिश कर रहा है कि घुमावदार छवि मूल फ़ाइल के समान स्थान पर सहेजी जाती है, मूल रूप से इसे बदलती है।

फिर से, यह केवल उन छवियों के साथ हो रहा है जिनमें EXIF ​​जानकारी शामिल है। अन्य सभी समस्याओं के बिना अपलोड कर रहे हैं।

इस स्मृति आवंटन समस्या का कारण क्या हो सकता है?

उत्तर

4

आपका त्रुटि यह है:

33554432 बाइट्स समाप्त की अनुमति स्मृति आकार ( 10368 बाइट्स आवंटित करने के लिए करने की कोशिश की)।

33554432 बाइट 32 मेगाबाइट में परिवर्तित हो जाता है। तो इसका मतलब यह है कि कुछ काम करने की कोशिश करते समय PHP स्मृति से बाहर हो गया।

आप दावा करते हैं कि विफल होने वाली छवियों में EXIF ​​जानकारी है, लेकिन यह मेरे कारण के रूप में मेरे लिए सच नहीं है। बावजूद, आपकी समस्या का समाधान करने के लिए त्वरित, जोड़ने और ini_set लाइन अपने कार्य

उदाहरण के लिए करने के लिए memory_limit से जुड़ा द्वारा अपने कार्य के लिए PHP स्मृति बढ़ाने के लिए उसे यहां जोड़ें आप if (function_exists('exif_read_data')) { जांच के बाद है। मैं इसे 64M पर सेट कर रहा हूं क्योंकि यह इस कार्य को चलाने पर आपकी स्क्रिप्ट मेमोरी क्षमता को प्रभावी ढंग से दोगुना कर देगा। यहाँ कोड:

function correctImageOrientation($fullpath) { 
    if (function_exists('exif_read_data')) { 
    ini_set('memory_limit', '64M'); 
    $exif = exif_read_data($fullpath); 
    if($exif && isset($exif['Orientation'])) { 
     $orientation = $exif['Orientation']; 
     if($orientation != 1){ 
     $img = imagecreatefromjpeg($fullpath); 
     $deg = 0; 
     switch ($orientation) { 
      case 3: 
      $deg = 180; 
      break; 
      case 6: 
      $deg = 270; 
      break; 
      case 8: 
      $deg = 90; 
      break; 
     } 
     if ($deg) { 
      $img = imagerotate($img, $deg, 0);   
     } 
     // then rewrite the rotated image back to the disk as $filename 
     imagejpeg($img, $fullpath, 100); 
     } // if there is some rotation necessary 
    } // if have the exif orientation info 
    } // if function exists  
} 

क्या मैं मूल रूप से प्राप्त करने के लिए कोशिश कर रहा हूँ कि घुमाया छवि मूल फ़ाइल वाले स्थान पर ही बचाया हो जाता है, मूल रूप से यह जगह है।

समस्या आप PHP में जी.डी. पुस्तकालय जो स्मृति खा जब पीएचपी प्रणाली में फाइल लोड और भी अधिक स्मृति को खा जाएगा जब यह छवि को घुमाने के प्रयास कर रहा है का उपयोग कर रहे है।

यह हो सकता है कि EXIF ​​जानकारी वाले चित्रों में मानक 72 डीपीआई की तुलना में अधिक डीपीआई हो। इसलिए जब उनके आयाम EXIF ​​जानकारी के बिना किसी अन्य छवि के रूप में सतही रूप से समान प्रतीत हो सकते हैं, तो एक 300 डीपीआई छवि प्रभावी रूप से 72 डीपीआई छवि की तुलना में आकार में 4 गुना अधिक प्रभावी होगी। सबसे अधिक संभावना है कि वे छवियां क्यों विफल हो रही हैं; EXIF जानकारी नहीं बल्कि समग्र डीपीआई।

अब आप के रूप में पढ़ने वाली रेखा को बदलकर php.ini में मेमोरी सीमा भी बदल सकते हैं। और तकनीकी रूप से यह काम करेगा। लेकिन मैं इस कार्य की एक स्क्रिप्ट के लिए अच्छा अभ्यास नहीं मानता जो असफल रहा है।

ऐसा इसलिए है क्योंकि जब आप php.ini में सेटिंग बदलते हैं तो यह सभी PHP इंटरैक्शन के लिए रैम बढ़ाता है; न केवल समस्या मुद्दा। तो आपका सर्वर अचानक बुनियादी कार्यों के लिए अपाचे (जो PHP चलाता है) के लिए और अधिक रैम खा रहा है, साथ ही साथ ओडबॉल फ़ंक्शन जो अधिक रैम खाता है। मतलब यह है कि यदि इस कोड को केवल दिन में कुछ हद तक एक्सेस किया जाता है, तो बड़े सर्वर को बोझ क्यों करें जो प्रति PHP प्रक्रिया के 32 एम रैम से खुश है? रैम वृद्धि की जरूरतों को अलग करने के लिए ini_set('memory_limit', '64M'); का बेहतर उपयोग करें।

+1

वाह, यह बहुत अजीब है। क्योंकि मैंने वास्तव में इसे स्मृति_लिमिट समस्या माना था और मैंने इसे php.ini में 256MB तक बढ़ा दिया लेकिन यह देखने के बाद कि कोड के आपके टुकड़े ने इसे ठीक किया है, मैंने php.ini पर एक grep किया है (जो मैंने पहले नहीं किया था) और देखा कि 2 अलग स्मृति_limit सेट थे। मैं कितना बेवकूफ हूँ! इसे ठीक करने में आपकी मदद के लिए बहुत बहुत धन्यवाद :) – user1227914

+0

@ user1227914 ग्रेट!साथ ही, कोड के नीचे अपना नवीनतम संपादन देखें जो बताता है कि मुझे क्यों लगता है कि आपकी रैम इतनी ज्यादा खाई जा रही है और 'php.ini' को समायोजित करते समय इस तरह के मामले के लिए एक अच्छा विचार नहीं हो सकता है। – JakeGould

+0

यह समझ में आता है और मैं आपके सुझावों को लागू करूंगा। वास्तव में उपयोगी उत्तर के लिए बहुत बहुत धन्यवाद :) – user1227914

0

imagecreatefromjpeg छवि को असम्पीडित करता है और परिणाम को स्मृति में डाल देता है। यही वजह है कि 3 एमबी जेपीईजी को कभी-कभी 32 एमबी मेमोरी की आवश्यकता होती है (सटीक राशि संकल्प, रंग गहराई, आदि पर निर्भर करती है)।

आप इस परिणाम की जरूरत है, तो आप एक चर के लिए असाइन करें: समस्या

$img = imagecreatefromjpeg($fullpath); 

और अब। imagerotate$img संसाधन का उपयोग करता है, इसे घुमाता है और परिणाम को स्मृति के एक नए क्षेत्र में डालता है क्योंकि यह $img संसाधन को ओवरराइट करने के बजाय एक नया छवि संसाधन डिज़ाइन द्वारा लौटाता है।

$img = imagerotate($img, $deg, 0); 

सबूत::

// our image 
$url = 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/Pluto-01_Stern_03_Pluto_Color_TXT.jpg/1024px-Pluto-01_Stern_03_Pluto_Color_TXT.jpg'; 
file_put_contents('../cache4/' . basename($url), fopen($url, 'r')); 
$filename = '../cache4/' . basename($url); 

echo 'Before imagecreate: ' . round(memory_get_usage()/pow(1024, 2)) . ' MB (Max: ' . round(memory_get_peak_usage()/pow(1024, 2)) . ' MB)<br>' . PHP_EOL; 

// read image into RAM for further usage 
$image = imagecreatefromjpeg($filename); 

echo 'After imagecreate: ' . round(memory_get_usage()/pow(1024, 2)) . ' MB (Max: ' . round(memory_get_peak_usage()/pow(1024, 2)) . ' MB)<br>' . PHP_EOL; 

// rotate image 
$result = imagerotate($image, 180, 0); 

echo 'After imagerotate: ' . round(memory_get_usage()/pow(1024, 2)) . ' MB (Max: ' . round(memory_get_peak_usage()/pow(1024, 2)) . ' MB)<br>' . PHP_EOL; 

// flip image 
imageflip($result, IMG_FLIP_VERTICAL); 

echo 'After imageflip: ' . round(memory_get_usage()/pow(1024, 2)) . ' MB (Max: ' . round(memory_get_peak_usage()/pow(1024, 2)) . ' MB)<br>' . PHP_EOL; 

रिटर्न: तो अंत में आप 64 स्मृति के एमबी की जरूरत

Before imagecreate: 0 MB (Max: 0 MB) 
After imagecreate: 5 MB (Max: 5 MB) 
After imagerotate: 10 MB (Max: 10 MB) 
After imageflip: 10 MB (Max: 10 MB) 

आप देख सकते हैं के बाद imagerotate बुलाया गया है शिखर 10 MB को जन्म देती है, लेकिन imageflip जैसे फ़ंक्शन इस व्यवहार को नहीं दिखाते हैं क्योंकि यह आंतरिक रूप से आपके चर को ओवरराइट करता है।

हो सकता है कि आपको लगता है आप चर ओवरराइट करके कि हल कर सकते हैं:

$image = imagerotate($image, 180, 0); 

लेकिन वह केवल वर्तमान उपयोग कम हो जाएगा:

After imagerotate: 5 MB (Max: 10 MB) 

यह दुख की बात है कि हम can not pass the variable by reference since PHP 5.4:

imagerotate(&$image, 180, 0); 

मैंने bug report खोला ताकि उम्मीद में इसे अनुकूलित किया जा सके भविष्य।

संबंधित मुद्दे