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

ufodisko's avatar

Upload image with Http Client to API

I'm trying to upload an image to an API with laravel's HTTP Client.

The images exists locally in storage/app/public/6iZLEJmeC6Bb_1.png

My code generates an error Maximum execution time of 60 seconds exceeded when I used the attach() method and another error error 400: bad request when I remove the attach() method.

What am I doing wrong?

This is the cURL request provided by the API

if [ -z "$STABILITY_API_KEY" ]; then
    echo "STABILITY_API_KEY environment variable is not set"
    exit 1
fi

OUTPUT_FILE=./out/v1_upscaled_image.png
BASE_URL=${API_HOST:-https://api.stability.ai}
URL="$BASE_URL/v1/generation/esrgan-v1-x2plus/image-to-image/upscale"

curl -f -sS -X POST "$URL" \
  -H 'Content-Type: multipart/form-data' \
  -H 'Accept: image/png' \
  -H "Authorization: Bearer $STABILITY_API_KEY" \
  -F 'image=@"../init_image.png"' \
  -F 'width=1024' \
  -o "$OUTPUT_FILE"

And this is my code, basically doing the same thing with Http::withHeaders

$upscale = Http::withHeaders([
            'Content-Type' => 'multipart/form-data',
            'Accept' => 'image/png',
            'Authorization' => 'Bearer ' . env('STABILITY_API_KEY')
        ])->attach(file_get_contents('http://127.0.0.1:8000/storage/6iZLEJmeC6Bb_1.png'))
        ->post($upscale_url, [
            'image' => 'http://127.0.0.1:8000/storage/6iZLEJmeC6Bb_1.png',
            'width' => 1024,
        ]);

Storage::disk('local')->put($upscaledFile, $upscale->body());
0 likes
15 replies
LaryAI's avatar
Level 58

The issue with the code is that it is trying to attach a file using the file_get_contents() function, which reads the entire file into memory before attaching it. This can cause memory issues for large files. Instead, the attach() method should be used with the path to the file.

Additionally, the post() method should be called with the URL provided by the API, not the $upscale_url variable.

Here's the updated code:

$upscale = Http::withHeaders([
    'Content-Type' => 'multipart/form-data',
    'Accept' => 'image/png',
    'Authorization' => 'Bearer ' . env('STABILITY_API_KEY')
])->attach(
    'image', // name of the file input field
    storage_path('app/public/6iZLEJmeC6Bb_1.png') // path to the file
)->post('https://api.stability.ai/v1/generation/esrgan-v1-x2plus/image-to-image/upscale', [
    'width' => 1024,
]);

Storage::disk('local')->put($upscaledFile, $upscale->body());
ufodisko's avatar

@LaryAI dd($upscale) returns the following

reasonPhrase: "Bad Request"
statusCode: 400
Snapey's avatar

@ufodisko check that the headers and data correspond with the API

check the headers are ok (don't accidentally post your API key here)

The post body seems ok, however I don't know if at the point we should expect to see the filename or the actual file data.

ufodisko's avatar

@Snapey I checked and everything looks fine and matches the API.

I just tried the cURL command in Git Bash using the local file I have and it worked. So the issue is with the file not being sent/uploaded to the API properly.

Jsanwo64's avatar

@ufodisko It seems like you're trying to upload an image to an API using Laravel's HTTP Client, but encountering two different errors.

Regarding the "Maximum execution time of 60 seconds exceeded" error, it is likely that the HTTP request is taking longer than 60 seconds to complete. This could be due to various reasons, such as slow network connectivity or the API server taking too long to respond. To fix this, you can increase the maximum execution time by modifying the max_execution_time value in your php.ini file or by using the ini_set() function in your PHP code.

Regarding the "error 400: bad request" error, it indicates that the API server was not able to understand or process the request. One possible reason for this error could be that the attach() method is not properly attaching the image file to the request. Instead of using attach(), you can try using the withBody() method to create the multipart/form-data request body manually. Here's an example:


try {
    $url = 'https://api.stability.ai/v1/generation/esrgan-v1-x2plus/image-to-image/upscale';
    $filePath = storage_path('app/public/6iZLEJmeC6Bb_1.png');
    $file = new \Symfony\Component\HttpFoundation\File\File($filePath);
    $payload = [
        'image' => $file,
        'width' => 1024,
    ];
    $headers = [
        'Authorization' => 'Bearer ' . env('STABILITY_API_KEY'),
        'Accept' => 'image/png',
    ];
    $response = Http::withHeaders($headers)->withBody($payload, 'form-data')->post($url);
    $response->throw();
} catch (RequestException $e) {
    dd($e->response->status(), $e->response->body());
}

In this example, we are manually creating the multipart/form-data request body using the withBody() method and passing in an array of key-value pairs representing the form fields and their values. The image field is set to the file object created from the image file path, and the width field is set to 1024. The Authorization and Accept headers are also included. If an exception is thrown, we catch it and dump the response status and body for debugging purposes

ufodisko's avatar

@jsanwo64 Thank you for the reply. Unfortunately, I received this error

Passing in the "body" request option as an array to send a request is not supported. Please use the "form_params" request option to send a application/x-www-form-urlencoded request, or the "multipart" request option to send a multipart/form-data request.

ufodisko's avatar

I finally got it working by doing a pure cURL request.

However, I still need to figure out how to get the file path properly because storage_path() does not work.

        $URL1 = "https://api.stability.ai/v1/generation/esrgan-v1-x2plus/image-to-image/upscale";
        $STABILITY_API_KEY = env('STABILITY_API_KEY');
        $OUTPUT_FILE = storage_path('app/public/output.png');

        $file = "C:\Users\George\Projects\stock\storage\app\publiciZLEJmeC6Bb_1.png";

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $URL1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: multipart/form-data',
            'Accept: image/png',
            'Authorization: Bearer '.$STABILITY_API_KEY
        ));

        $postFields = array(
            'image' => new CURLFile($file),
            'width' => '1024'
        );

        curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);

        $result = curl_exec($ch);

        file_put_contents($OUTPUT_FILE, $result);

        curl_close($ch);
Jsanwo64's avatar

@ufodisko Try this https://laravel.com/docs/10.x/filesystem#the-public-disk

You need to Symlink the storage folder first. if you are using Laravel's default file storage system and you haven't already done so, you'll need to create a symbolic link between the storage folder and the public folder. This will allow files stored in the storage folder to be accessible from the web via the public folder.

To create the symbolic link, run the following command in your terminal from the root of your Laravel project:

php artisan storage:link

This will create a symbolic link named public/storage that points to the storage/app/public directory. With this symbolic link in place, you can use the storage_path() function to generate a path to a file in the public folder like so:

$OUTPUT_FILE = storage_path('app/public/output.png');

1 like
Jsanwo64's avatar

if you are still wondering if the code below is still usable after symlink

$OUTPUT_FILE = public_path('output.png');"

Yes, if you have created a symbolic link between the storage/app/public folder and the public/storage folder using the php artisan storage:link command, you can use the public_path() function to generate a path to a file in the public/storage folder.

Here's an example:

$OUTPUT_FILE = public_path('storage/output.png');

This will generate an absolute path to the file output.png in the public/storage folder of your Laravel application. When you save a file to this path using file_put_contents(), it will be stored in the storage/app/public directory and will be accessible from the web via the public/storage symbolic link.

Note that when you use the public_path() function, you should include the storage directory in the path. This is because the public/storage symbolic link points to the storage/app/public directory, not the storage directory directly.

ufodisko's avatar

@jsanwo64 I've already created the symbolic link. The problem is not with $OUTPUT_FILE it's with $file

As you can, I'm using an absolute system path to point to the image.

However, I just tried $file = storage_path('app/public/6iZLEJmeC6Bb_1.png'); and it worked!

Please or to participate in this conversation.