2013-07-23 22 views
6

Durante il trasferimento di un sito Web esistente, stabile a un nuovo server, si è verificato un problema intermittente con un po 'di codice che crea immagini dinamicamente utilizzando Imagick.Creazione di immagini dinamiche/intestazioni Apache utilizzando Imagick

Il codice analizza una query GET (es example.com/image.php?ipid=75 r = 0 & w = 750 & h = 1000) e quindi scala e ruota un'immagine memorizzata sul server e lo serve al cliente.

ipid = id for an image stored on server 
r = degrees of rotation 
w = width to display 
h = height to display. 

Il codice è stato probabilmente utilizzato per almeno 5 anni senza problemi.

Durante il trasferimento a un server nuovo, molto più veloce (da Debian Squeeze a Ubuntu 12.04), si verifica un problema in cui circa il 50% delle volte l'immagine non viene visualizzata e il server invia un "file png" di 0 byte. Non ci sono errori PHP o errori del server.

A seconda che le immagini vengono inviate con successo o no, diverse intestazioni vengono inviati:

successo intestazioni immagine:

Connection: Keep-Alive 
Content-Type: image/png 
Date: Tue, 23 Jul 2013 17:03:32 GMT 
Keep-Alive: timeout=5, max=76 
Server: Apache/2.2.22 (Ubuntu) 
Transfer-Encoding: chunked 
X-Powered-By: PHP/5.3.10-1ubuntu3.7 

falliti immagine intestazioni:

Connection Keep-Alive 
Content-Length 0 
Content-Type image/png 
Date Tue, 23 Jul 2013 17:03:31 GMT 
Keep-Alive timeout=5, max=78 
Server Apache/2.2.22 (Ubuntu) 
X-Powered-By PHP/5.3.10-1ubuntu3.7 

Qualcuno ha qualche idea del perché questo sta accadendo?

C'è un modo per "forzare" le immagini PNG da inviare in blocco, poiché mi chiedo se sia alla radice del problema. Ho provato varie soluzioni alternative in cui invio la dimensione dell'immagine, o "Transfer-Encoding: chunked" come intestazione tramite la funzione header() di PHP, ma non ha funzionato, e in questi casi il browser afferma che l'immagine è corrotta.

<?php 

//Class used to connect to Imagick and do image manipulation: 
class Images 
{ 
    public $image = null; 

    public function loadImage($imagePath){ 

     $this->image = new Imagick(); 
     return $this->image->readImage($imagePath); 
    } 

    public function getImage(){ 

     $this->image->setImageFormat("png8"); 
     $this->image->setImageDepth(5); 
     $this->image->setCompressionQuality(90); 
     return $this->image; 
    } 

    //  Resize an image by given percentage. 
    //  percentage must be set as float between 0.01 and 1 
    public function resizeImage ($percentage = 1, $maxWidth = false, $maxHeight = false) 
    { 
     if(!$this->image){return false;} 
     if($percentage==1 && $maxWidth==false && $maxHeight == false){return true;} 

     $width = $this->image->getImageWidth(); 
     $height = $this->image->getImageHeight(); 

     $newWidth = $width; 
     $newHeight = $height; 

     if($maxHeight && $maxWidth){ 
      if($height > $maxHeight || $width > $maxWidth){ 

       $scale = ($height/$maxHeight > $width/$maxWidth) ? ($height/$maxHeight) : ($width/$maxWidth) ; 
       $newWidth = (int) ($width/$scale); 
       $newHeight = (int) ($height/$scale); 
      } 
     }else{ 

      $newWidth = $width * $percentage; 
      $newHeight = $height * $percentage; 
     } 
     return $this->image->resizeImage($newWidth,$newHeight,Imagick::FILTER_LANCZOS,1); 

    } 

    public function resizeImageByWidth ($newWidth) 
    { 
     if ($newWidth > 3000){ 
      $newWidth = 3000; //Safety measure - don't allow crazy sizes to break server. 
     } 

     if(!$this->image){return false;} 

     return $this->image->resizeImage($newWidth,0,Imagick::FILTER_LANCZOS,1); 

    } 

    public function rotateImage($degrees=0) 
    { 
     if(!$this->image){return false;} 
     return $this->image->rotateImage(new ImagickPixel(), $degrees); 
    } 

} 


//(simplified version of) procedural code that outputs the image to browser: 

$img = new Images(); 

$imagePath = '/some/path/returned/by/DB/image.png'; 

if($imagePath){ 
    $img->loadImage($imagePath); 

    $width = $img->image->getImageWidth(); 
    $height = $img->image->getImageHeight(); 

    if (!$img->resizeImageByWidth($newWidth)) 
    { 
     die ("image_error: resizeImage() could not create image."); 
    } 

    if($rotation > 0){ 
     if (!$img->rotateImage($rotation)) 
     { 
      die ("image_error: rotateImage() could not create image."); 
     } 
    } 

}else{ 

    die("image_error: no image path specified"); 
} 

header('Content-type:image/png'); 
echo $img->getImage(); 

exit(0); 
?> 

UPDATE: Nel caso in cui aiuta a identificare la posizione del problema:

Ho creato una soluzione cludgy che funziona in tutti i casi, come un palliativo. Quello che faccio è creare l'immagine, salvarla su disco come un file temporaneo. Aprire il file e inviarlo al client usando passthru() e quindi eliminare il file dal disco. Ingombrante, e preferirei farlo in modo 'ordinato', ma mi suggerisce che il problema è in qualche modo associato a queste due linee: header('Content-type:image/png'); echo $img->getImage(); e un errore da parte di Apache, PHP o Imagick per gestire la risorsa.

+0

lunghezza del contenuto di '0'? La codifica Chunked non dovrebbe essere necessaria. Mostra il codice effettivo che stai utilizzando per generare l'immagine. Le intestazioni da soli sono inutili. –

+0

Il codice corrente: http://phpfiddle.org/main/code/mkd-tjr – fred2

+0

Per chiarire, la stessa immagine apparirà una volta con contenuto-Lunghezza di 0, e la prossima volta con Transfer Encoding: chunked. Sembra essere un comportamento casuale. – fred2

risposta

3

Ho riscontrato un problema molto simile a questo ed era correlato alla seconda richiesta con un'intestazione in avanti con un codice di stato 301 o 302. Alcuni browser non seguono

Sono entrambe le immagini che restituiscono 200 o il fallito che restituisce un reindirizzamento?

+0

Ciao Grazie per la risposta. No scusa. Entrambe le immagini restituiscono 200. – fred2

+0

Puoi inviarmi un link all'immagine? Questo può aiutare a rendere difficile il – exussum

+0

bit, dato che si trova su un sito protetto da password, tuttavia vedrò cosa posso fare se non ricevo altri suggerimenti nell'ora successiva. In sostanza vedresti solo le informazioni nel post originale, credo. – fred2

2

Forse un colpo lungo, ma forse c'è qualche output non intenzionale prima della chiamata di eco $img->getImage()? Ciò corromperà l'immagine di output. Mi sono imbattuto in questo prima con un carattere di nuova riga finale dopo il tag di chiusura ?> in qualche casuale include().

Un test rapido prima di analizzare il codice potrebbe essere quello di utilizzare il buffer di output per eliminare qualsiasi cosa prima che i dati dell'immagine vengano emessi.

<?php 
    ob_start(); //call this before executing ANY other php 
?> 

Qualche tempo dopo ...

<?php 
    ob_clean(); //trash invalid data in the output buffer 
    //set proper headers for image output and browser caching if desired 
    echo $img->getImage(); 
    ob_end_flush(); //send the buffered image data to the browser 
?> 

Certo, si fa parlare di una base di codice stabile, ma diverse versioni web server o php la facoltà di considerare che lo spazio bianco non intenzionale in modo diverso.

EDIT: Un altro pensiero

E 'possibile che il nuovo server è in esecuzione un qualche tipo di meccanismo di php uscita caching. Forse sta provando a ricaricare l'immagine generata di recente da una cache da qualche parte, e quella parte sta fallendo, il che potrebbe essere una spiegazione migliore per una lunghezza del contenuto di 0 byte. Forse il nuovo server manca semplicemente una libreria ... confronta l'output di phpinfo(); su ciascun server.

+0

Spiacente, niente spazi vuoti. La memorizzazione nella cache è stata una buona idea - ho pensato che potrebbe essere prima di ricordare che i nuovi server non hanno ancora alcun caching! – fred2

+0

C'è qualche dipendenza dalla cache nella base di codice? Forse questa è la radice del problema. –

Problemi correlati