imageperlimagemagickimage-uploadingperlmagick

Internal server error when trying to write an image & an thumbnail using ImageMagick in Perl


This Perl script uploads an image to server and then saves: - a gallery image that fits in 900x900 px - a square gallery thumbnail 140x140 px - adds a line in a js file with the image and thumbnail names

The problem is, that the script sometimes works, sometimes - not. It works fine in one or two of every ten attempts. When it doesn't work, it usually returns "Internal Server Error" and doesn't create two files, nor adds a line in js. But in some cases it creates the both jpg files and doesn't add a line in js (again returning "Internal Server Error"). Very strange behavior - I've tried various changes with no result. What I do wrong?

#!/usr/bin/perl -w
##
##

use strict;
use CGI;
use CGI::Carp qw ( fatalsToBrowser );
use File::Basename;
use Image::Magick;

$CGI::POST_MAX = 1024 * 70000;
my $safe_filename_characters = "a-zA-Z0-9_.-";
my $pic_upload_dir="../data/photos/gallery";
my $lst_upload_dir="../data";
my $lst_file=$lst_upload_dir."/gallery.js";

my $query=new CGI;

my $PictureIndex=$query->param("Snd_AddPhoto_Idx");
my $photoname=$query->param("AddPhoto");

    #upload photo
    if ( !$photoname ) {  
        print "Content-Type: text/plain\n\n";
        print "\n\nThere was a problem uploading your photo (try a smaller size).\n";
        exit;
    }  

    my ( $phname, $phpath, $phextension ) = fileparse ($photoname, qr/\.[^.]*/);
    $photoname = $phname . $phextension;
    $photoname =~ tr/ /_/;
    $photoname =~ s/[^$safe_filename_characters]//g;

    if ( $photoname =~ /^([$safe_filename_characters]+)$/ ) {  
        $photoname = $1;
    }  
    else {  
        die "Filename contains invalid characters";
    }  

        # force correct filename for temporary file
        $photoname="tempphoto_zmm_gallery_".$PictureIndex.$phextension;

    my $upload_photohandle = $query->upload("AddPhoto");

    open ( UPLOADPHOTO, ">$pic_upload_dir/$photoname" ) or die "$!";
    binmode UPLOADPHOTO;
    while ( <$upload_photohandle> ) {  
        print UPLOADPHOTO;
    }  
    close UPLOADPHOTO;

    # resize photo
    my($photoimage) = Image::Magick->new;
    open(PHOTOIMAGE, "$pic_upload_dir/$photoname") or die "Unable to open temporary image file!\n";
    $photoimage->Read(file=>\*PHOTOIMAGE);
    close(PHOTOIMAGE);

    $photoimage->Resize(geometry=>'900x900', blur=>0.8);
    $photoimage->Set(Quality=>'75%');

    # write ready photo as jpg
    my $readyphotoname="pic".$PictureIndex.".jpg";
    open(READYIMAGE, ">$pic_upload_dir/$readyphotoname") or die "Unable to write ready image file!\n";
    $photoimage->Write(file=>\*READYIMAGE, filename=>$readyphotoname);
    close(READYIMAGE);
    system("chmod 777 $pic_upload_dir/$readyphotoname");

    # resize thumbnail
    my($thumbimage) = Image::Magick->new;
    open(THUMBIMAGE, "$pic_upload_dir/$photoname") or die "Unable to open temporary image file!\n";
    $thumbimage->Read(file=>\*THUMBIMAGE);
    close(THUMBIMAGE);

    $thumbimage->Resize(geometry=>'140x140^', blur=>0.8);
    $thumbimage->Set(gravity=>'Center');
    $thumbimage->Crop(geometry=>'140x140+0+0');
    $thumbimage->Set(Quality=>'30%');

    # write ready thumbnail as jpg
    my $readythumbname="tbn".$PictureIndex.".jpg";
    open(READYTHUMB, ">$pic_upload_dir/$readythumbname") or die "Unable to write ready image file!\n";
    $thumbimage->Write(file=>\*READYTHUMB, filename=>$readythumbname);
    close(READYTHUMB);
    system("chmod 777 $pic_upload_dir/$readythumbname");

    # delete temporary file
    my($temporary_file)=$pic_upload_dir."/".$photoname;
    unlink($temporary_file) == 0;


# add pic in js gallery list

    # prepare new pic record
    my $NewGalRecord="GalleryList.push(new Array(\"pic".$PictureIndex.".jpg\",\"tbn".$PictureIndex.".jpg\",\"\",\"\"));\n";

    # add to file
    open(JS,">>$lst_file") || die "Failed to open $lst_file\n";
    printf JS $NewGalRecord;
    close JS;
    system("chmod 777 $lst_file");

# print confirmation

...
...
...


exit;

Solution

  • I think I've solved the problem. Obviously there's no need to read the temp file twice. After saving the 'big' image, we can continue manipulate it and then save again as thumbnail. Double reading of the temp file apparently causes conflict. Something like 'Sharing violation' - just a shot in the dark. But now the script works fine. Separately, far removed the rows Set(Quality=>). I don't know whether they have anything to do with the problem, but this will be subject to future testing. Here are the changes:

        # resize photo
        my($photoimage) = Image::Magick->new;
        open(PHOTOIMAGE, "$pic_upload_dir/$photoname") or die "Unable to open temporary image file!\n";
        $photoimage->Read(file=>\*PHOTOIMAGE);
        close(PHOTOIMAGE);
    
        $photoimage->Resize(geometry=>'900x900', blur=>0.8);
    
        # write ready photo as jpg
        my $readyphotoname="pic".$PictureIndex.".jpg";
        open(READYIMAGE, ">$pic_upload_dir/$readyphotoname") or die "Unable to write ready image file!\n";
        $photoimage->Write(file=>\*READYIMAGE, filename=>$readyphotoname);
        close(READYIMAGE);
        system("chmod 777 $pic_upload_dir/$readyphotoname");
    
        # resize thumbnail
        $photoimage->Resize(geometry=>'140x140^', blur=>0.8);
        $photoimage->Set(gravity=>'Center');
        $photoimage->Crop(geometry=>'140x140+0+0');
    
        # write ready thumbnail as jpg
        my $readythumbname="tbn".$PictureIndex.".jpg";
        open(READYTHUMB, ">$pic_upload_dir/$readythumbname") or die "Unable to write ready image file!\n";
        $photoimage->Write(file=>\*READYTHUMB, filename=>$readythumbname);
        close(READYTHUMB);
        system("chmod 777 $pic_upload_dir/$readythumbname");
    
        # delete temporary file
        my($temporary_file)=$pic_upload_dir."/".$photoname;
        unlink($temporary_file) == 0;