move_uploaded_file problem

Over 90% of uplaoded images work just fine, however from time to time there’s an image which gets uploaded without a warning, yet when I try to open it in the browser I get this error:

The image "http://example.com/uploads/photos/1421.png" cannot be displayed, because it contains errors.

Any ideas where could be the problem?

I’ve been googling a bit and it seems that the problem can arise from the fact that I’m using ASCII transfer mode instead of binary. Is it possible to change the transfer mode to binary in PHP?

Thanks.

Here’s some extraction of my upload code (it is being called by ajax):


<?php

define('BASE_PATH', substr(dirname(dirname(__FILE__)), 0, -22));

if (false === empty($_FILES)) {

    $tempFile = $_FILES['Filedata']['tmp_name'];
    
    // check image dimensions
    $size = getimagesize($tempFile);
    if ($size[0] < 150 || $size[1] < 150) {
        
        echo 'Image too small (minimum 150x150px)';
    
    } else {
    
        $extension = end(explode('.', $_FILES['Filedata']['name']));
    
        // here I do some stuff with the database, I left this out
        // because it's not important
    
        // save the photo
        move_uploaded_file($tempFile,
                           BASE_PATH . '/public/' . $paths[0]);
    
        // create a thumbnail
        include BASE_PATH . '/library/My/PHPThumbnailer/ThumbLib.inc.php';
        $thumb = PhpThumbFactory::create(BASE_PATH . '/public/' . $paths[0]);
        $thumb->adaptiveResize(85, 85);
        $thumb->save(BASE_PATH . '/public/' . $paths[1]);
        // resize the main photo so it's not wider than 800px
        $resized = PhpThumbFactory::create(BASE_PATH . '/public/' . $paths[0]);
        $resized->resize(800, 800);
        $resized->save(BASE_PATH . '/public/' . $paths[0]);
    
        // add watermark to the bottom right corner
        $pathToFullImage = BASE_PATH . '/public/' . $paths[0];
        $size = getimagesize($pathToFullImage);
        switch ($extension) {
            case 'gif':
                $im = imagecreatefromgif($pathToFullImage);
                break;
            case 'jpg':
                $im = imagecreatefromjpeg($pathToFullImage);
                break;
            case 'png':
                $im = imagecreatefrompng($pathToFullImage);
                break;
        }
        if (false !== $im) {
            $white = imagecolorallocate($im, 255, 255, 255);
            $font = BASE_PATH . '/public/fonts/arial.ttf';
            imagefttext($im,
                        13, // font size
                        0, // angle
                        $size[0] - 132, // x axis (top left is [0, 0])
                        $size[1] - 13, // y axis
                        $white,
                        $font,
                        'Example.com');
            switch ($extension) {
                case 'gif':
                    imagegif($im, $pathToFullImage);
                    break;
                case 'jpg':
                    imagejpeg($im, $pathToFullImage, 100);
                    break;
                case 'png':
                    imagepng($im, $pathToFullImage, 0);
                    break;
            }
            imagedestroy($im);
        }
    
        echo "1";
    
    }

}

Does it work without AJAX?

Yes.

Then I would guess, additional data (possibly even whitespace) is being sent along with your AJAX request which corrupts your image.

Inspect the difference between a standard request and an AJAX request.