Laravel/Guzzle - POST binary file content

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Mastering Binary File Uploads in Laravel and Guzzle: Solving POST Content Type Issues

As a senior developer working with modern PHP frameworks like Laravel, interacting with external APIs often requires handling complex data types, especially binary files. When you transition from testing tools like Postman to programmatic HTTP requests using Guzzle within a Laravel context, subtle differences in how file content is packaged can lead to frustrating validation errors on the receiving end.

This post dives deep into the common pitfall of posting binary file content—specifically PDF or image files—and shows you the robust solution for ensuring your data is recognized correctly by third-party APIs.

The Problem: Binary Data and Content Negotiation

You are attempting to upload a binary file, and while Postman succeeds, your Laravel/Guzzle implementation fails validation from the API. This almost always points to an issue with the Content-Type header or how the raw binary stream is being attached to the request body.

The error message you received—stating that the content type must be one of specific MIME types (like application/pdf, image/jpeg)—confirms that the API expects a standard file upload format, typically handled via multipart/form-data.

Your initial approach using Http::attach('file', file_get_contents($tempfile), 'myfile.pdf') is conceptually correct for multipart uploads, but the exact way raw binary data is passed needs careful handling to satisfy strict API requirements.

Diagnosing the Guzzle/Laravel Interaction

When dealing with files stored on the disk (like in Laravel's storage), we must ensure that what we feed into Guzzle is the actual binary content of the file, not just a string representation, and that the attachment method correctly sets the necessary headers.

The core issue often lies in mixing raw file contents (file_get_contents()) with the attachment mechanism. While this works for simple text or images, APIs handling complex binary types require explicit context.

The Solution: Robust Binary File Posting

The most reliable way to handle file uploads in Laravel is to leverage the framework's built-in storage and ensure Guzzle correctly serializes the request as multipart/form-data. We need to ensure we are reading the raw stream of the file content properly before attaching it.

Here is the corrected, robust approach for posting binary files using Laravel's HTTP facade in conjunction with Guzzle principles:

use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Http;

// Assume $document is an instance of UploadedFile from the request
$file = $request->file('file_input'); // Get the uploaded file object
$disk = 'local';

// 1. Save the file to a temporary location (or ensure it's accessible)
$tempPath = Storage::disk($disk)->putFile('uploads', $file);

// 2. Construct the request using Http::attach() correctly for files
try {
    $response = Http::asMultipart() // Use asMultipart() or attach() carefully
        ->attach('file', Storage::path($tempPath), $file->getClientOriginalName()) // Attach the file path and name
        ->post('example.org')
        ->json();

    // Handle the response
    return $response;

} catch (\Exception $e) {
    // Log the error if the request fails
    \Log::error("File upload failed: " . $e->getMessage());
    return null;
} finally {
    // Clean up temporary files if necessary (good practice!)
    // Storage::disk($disk)->delete('uploads/' . $tempPath);
}

Why this works better:

  1. Leveraging Storage: Instead of manually reading the file content using file_get_contents() on a potentially non-standard path, we use Laravel's Storage facade to reference the file path directly. This keeps file management consistent with how Laravel handles storage, which is crucial when following standards promoted by frameworks like those found at laravelcompany.com.
  2. asMultipart(): Using methods like Http::asMultipart() explicitly tells Guzzle to format the request payload as multipart/form-data, which is the standard required for file uploads.
  3. Attachment Structure: By attaching the file stream or path directly, the HTTP client correctly sets the necessary boundary markers and MIME type headers that the third-party API expects when receiving a binary file payload.

Conclusion

Dealing with binary data across HTTP boundaries requires precision. While the initial instinct to use attach was right, ensuring the underlying data source is managed by your framework (like Laravel's Storage) and using appropriate methods like asMultipart() guarantees that the request sent to external APIs adheres to the necessary content type specifications. By focusing on proper stream handling and utilizing the tools provided by your environment, you can reliably move from successful Postman tests to seamless programmatic file uploads.