Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mvnobrega's avatar

file_get_contents() and conversion to webp [ SOLVED ]

I have a function to convert images to wepb format which is working as expected when the image is submitted by form. However, now I need to get the image from a url using file_get_contents(), but the function that converts the image doesn't recognize it as an image file.

This is my function:

public function importar()
    {

        function csv_to_array($file_name) {
        $data =  $header = array();
        $i = 0;
        $file = fopen($file_name, 'r');
        while (($line = fgetcsv($file)) !== FALSE) {
            if( $i==0 ) {
                $header = $line;
            } else {
                $data[] = $line;        
            }
            $i++;
        }
        fclose($file);
        foreach ($data as $key => $_value) {
            $new_item = array();
            foreach ($_value as $key => $value) {
                $new_item[ $header[$key] ] =$value;
            }
            $_data[] = $new_item;
        }
        return $_data;
    }

    $csvFile = 'pets.csv';

    $csv = csv_to_array($csvFile);

    $ignoreError = stream_context_create(array(
                    'http' => array('ignore_errors' => true),
                ));

    foreach ($csv as $key => $pet){


        $this->webpConvert2(file_get_contents($pet['imagem']), false, $ignoreError);

        $novo = new Pet;
        $novo->nome_bichinho  = $pet['titulo'];
        $novo->sexo = $pet['sexo'];
        $novo->save();

        }


    }

When it is submitted by form I do it like this and it works as expected: $this->webpConvert2($request->file('image'));

But using file_get_contents() I get false as the function that converts it doesn't understand how an image file.

How can I resolve this?

0 likes
10 replies
Snapey's avatar

how does a csv file contain an image?

if it contain a path to an image, make sure this is a full file path, or a full url

mvnobrega's avatar

@Snapey

Sorry if I expressed myself wrong. But yes it is the URL of the image

rodrigo.pedra's avatar

@mvnobrega after issuing a request to download an image using file_get_contents() you can check the response headers on a global variable provided by PHP called $http_response_header).

If you are trying to download an image that does not exist, or if the download fails for some reason, you can check this variable's contents to see why it failed.

reference: https://www.php.net/manual/en/reserved.variables.httpresponseheader.php

As an example, this is a function from an older project where composer was not available, and actually the client's server had a fairly old PHP version (5.4 or 5.5, can´t remember).

It just checks for 404 responses, as the API's documentation we were checking against only documented 404 as a value with some meaning. But I hope it will give you an idea.

<?php

function hibpClient($url, $headers = [])
{
    $headers[] = 'User-Agent: my-app';

    $options = [
        'http' => [
            'method' => 'GET',
            'header' => implode("\r\n", $headers) . "\r\n",
            'timeout' => 180,
        ],
    ];

    $context = stream_context_create($options);
    $response = @file_get_contents($url, false, $context);
    $isNotFound = preg_grep('~^HTTP/.+? 404 .+$~i', isset($http_response_header) ? $http_response_header : []);

    if (is_array($isNotFound) && count($isNotFound) === 1) {
        return false;
    }

    if ($response === false) {
        return null;
    }

    return $response;
}

Just for curiosity the API is the Have I Been Pwned API. The client wanted to add this check to an older app we were modernizing at the time.

mvnobrega's avatar

@rodrigo.pedra

Sorry, that made me even more confused. I don't know if I understood correctly, but from what I tried, it didn't work. I need to send the downloaded image file via URL by file_get_contents() to my function: $this->webpConvert2()

I tried like this: $this->webpConvert2($http_response_header)

But my webpConvert2() function doesn't understand this as an image file.

it just returns me the headers:

^ array:13 [▼
  0 => "HTTP/1.1 200 OK"
  1 => "Content-Length: 54065"
  2 => "Content-Type: image/jpeg"
  3 => "Content-MD5: PTtvFyr9oUZi96ShlFYF7Q=="
  4 => "Last-Modified: Wed, 14 Feb 2018 01:00:40 GMT"
  5 => "ETag: 0x8D573465DDC7C67"
  6 => "Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0"
  7 => "x-ms-request-id: 489c4d2c-f01e-0066-7362-7c5153000000"
  8 => "x-ms-version: 2009-09-19"
  9 => "x-ms-lease-status: unlocked"
  10 => "x-ms-blob-type: BlockBlob"
  11 => "Date: Fri, 10 Jun 2022 00:41:27 GMT"
  12 => "Connection: close"
]

Then I get the following error in my webpConvert2() function:

file_exists(): Argument #1 ($filename) must be of type string, array given

O qual ocorre no seguinte trecho da função webpConvert2():

// check if file exists

    if (!file_exists($file)) {

        return false;

    }

Sorry, I didn't put the complete function, see:

 function webpConvert2($file, $compression_quality = 20)
    {



    $year = date("Y");   
    $month = date("m"); 

    // check if file exists
    if (!file_exists($file)) {
        return false;
    }


    $file_type = exif_imagetype($file);
    //https://www.php.net/manual/en/function.exif-imagetype.php
    //exif_imagetype($file);
    // 1    IMAGETYPE_GIF
    // 2    IMAGETYPE_JPEG
    // 3    IMAGETYPE_PNG
    // 6    IMAGETYPE_BMP
    // 15   IMAGETYPE_WBMP
    // 16   IMAGETYPE_XBM

    $this->output_file =  str_slug($this->dados->tipo). '-'. str_slug($this->dados->especie) . '-'. str_slug($this->dados->sexo) . '-' . str_slug($this->dados->cidade) . '-'. str_slug($this->dados->estado) . '-' . rand(10000,5000000) . '.webp';


    if (file_exists($this->output_file)) {
        return $this->output_file;
    }
    if (function_exists('imagewebp')) {
        switch ($file_type) {
            case '1': //IMAGETYPE_GIF
                $image = imagecreatefromgif($file);
                break;
            case '2': //IMAGETYPE_JPEG
                $image = imagecreatefromjpeg($file);
                break;
            case '3': //IMAGETYPE_PNG
                    $image = imagecreatefrompng($file);
                    imagepalettetotruecolor($image);
                    imagealphablending($image, true);
                    imagesavealpha($image, true);
                    break;
            case '6': // IMAGETYPE_BMP
                $image = imagecreatefrombmp($file);
                break;
            case '15': //IMAGETYPE_Webp
               return false;
                break;
            case '16': //IMAGETYPE_XBM
                $image = imagecreatefromxbm($file);
                break;
            default:
                return false;
        }
        // Save the image
        if (file_exists('media/pets/'.$year.'/'.$month)) {
            $result = imagewebp($image, 'media/pets/'.$year.'/'.$month.'/'.$this->output_file, $compression_quality);

        }else{
            mkdir('media/pets/'.$year.'/'.$month, 0777, true);
            $result = imagewebp($image, 'media/pets/'.$year.'/'.$month.'/'.$this->output_file, $compression_quality);
        }

        
        if (false === $result) {
            return false;
        }
        // Free up memory
        imagedestroy($image);
        return $this->output_file;
    } elseif (class_exists('Imagick')) {
        $image = new Imagick();
        $image->readImage($file);
        if ($file_type === "3") {
            $image->setImageFormat('webp');
            $image->setImageCompressionQuality($compression_quality);
            $image->setOption('webp:lossless', 'true');
        }
        //$image->writeImage('public_html/media/users/'.$year.'/'.$month.'/'.$this->output_file);
        //return $this->output_file;
    }
    return false;

    
}

rodrigo.pedra's avatar

@mvnobrega

The $http_response_header is to be used when file_get_contents fails, either throw an error (the @ before the file_get_contents() is called the error suppression operator), or if it return false, which signals an error.

In your case I would try something like this:

<?php

$ignoreError = stream_context_create(array(
    'http' => array('ignore_errors' => true),
));

foreach ($csv as $key => $pet) {
    // @ is to suppress any posible errors
    $response = @file_get_contents($pet['imagem'], false, $ignoreError);

    if ($response === false) {
        // image download failed
        // check $http_response_header
        // and log or do something when
        // the download fails
    } else {
        // $response is an string here
        $this->webpConvert2($response);
    }

    $novo = new Pet();
    $novo->nome_bichinho = $pet['titulo'];
    $novo->sexo = $pet['sexo'];
    $novo->save();
}

One question: does your ->webpConvert2() method expects an string?

Also, check your method call, I think you are passing arguments to the wrong method in this line:

$this->webpConvert2(file_get_contents($pet['imagem'], false, $ignoreError));
mvnobrega's avatar

@rodrigo.pedra

It doesn't work, $response doesn't contain the image file, it just contains a bunch of encrypted code. Then when checking if it is a file it returns false:

if (!file_exists($file)) {
        return false;
    }
rodrigo.pedra's avatar
Level 56

@mvnobrega

Sure it will contain a bunch of "encrypted code". It is an image, which is binary encoded, stored on a string, so if you echo it, it will show as a bunch of "encrypted code".

Also the returned string is stored in memory, so is_file(), or file_exists() will both return false, if you didn't store the file locally.

What did you expected it to occur? Were you expecting file_get_contents() to download the image, save it as a file, and return the saved file path?

If you want to save the image, try saving the contents (the response string) on a path you provide. You can use file_put_contents().

<?php

$ignoreError = stream_context_create(array(
    'http' => array('ignore_errors' => true),
));

foreach ($csv as $key => $pet) {
    // @ is to suppress any posible errors
    // file_get_contents will store the "contents"
    // into memory
    $response = @file_get_contents($pet['imagem'], false, $ignoreError);

    if ($response === false) {
        // image download failed
        // check $http_response_header
        // and log or do something when
        // the download fails
    } else {
        $filename = basename($pet['imagem']);
        $filepath = '/path/to/a/writeable/directory/' . $filename;

        // If you are using Laravel, you can use this:
        // $filepath = storage_path('app/' . $filename);

        // $response is a string here
        // file_put_contents will save
        // the "contents" to a file
        file_put_contents($filepath, $response);

        $this->webpConvert2($filepath);
    }

    $novo = new Pet();
    $novo->nome_bichinho = $pet['titulo'];
    $novo->sexo = $pet['sexo'];
    $novo->save();
}
2 likes
mvnobrega's avatar

@rodrigo.pedra

Thank you very much. You don't know how much you helped me. I had tried putting just the image path but it didn't work. But the way you said it worked perfectly.

thank you

:) (Y)

1 like

Please or to participate in this conversation.