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

0xlaradev's avatar

$request->hasFile('file') doesn't detect uploaded file

Hi! I'm trying to figure out why $request->hasFile('file') is not detecting an uploaded file.

I'm sending the file via Javascript using an XMLhttprequest like this:

(function() {
    var HOST = "http://127.0.0.1:8000/storage/"
    var sendRequestUrl = "http://127.0.0.1:8000/api/v1/store-image"
    function createStorageKey(file) {
        var date = new Date();
        var noSpacesName = file.name.replace(/\s/g, '-').toLowerCase();
        var name = date.getTime() + "-" + noSpacesName;
        return name;
      }
      function createFormData(key, file) {
        var data = new FormData()
        data.append("key", key)
        data.append("Content-Type", file.type)
        data.append("file", file)
        return data
      }
    addEventListener("trix-attachment-add", function(event) {
      if (event.attachment.file) {
        uploadFileAttachment(event.attachment)
      }
    })
    // app/javascript/trix-editor-overrides.jslotr
    window.addEventListener("trix-file-accept", function(event) {
        const acceptedTypes = ['image/jpg', 'image/jpeg', 'image/png', 'image/heic']
        if (!acceptedTypes.includes(event.file.type)) {
        event.preventDefault()
        alert("Formato no permitido. Sube una imagen con extensión permitida: jpg, jpeg, png o heic")
        }
    })
    // app/javascript/trix-editor-overrides.js
    window.addEventListener("trix-file-accept", function(event) {
        const maxFileSize = 2048 * 2048 // 4MB 
        if (event.file.size > maxFileSize) {
        event.preventDefault()
        alert("El tamaño máximo permitido es de 4MB")
        }
    })
    function uploadFileAttachment(attachment) {
      uploadFile(attachment.file, setProgress, setAttributes)
      function setProgress(progress) {
        attachment.setUploadProgress(progress)
      }
      function setAttributes(attributes) {
        attachment.setAttributes(attributes)
      }
    }
    function uploadFile(file, progressCallback, successCallback) {
      var key = createStorageKey(file);
      var formData = createFormData(key, file);
      var xhr = new XMLHttpRequest();
      xhr.open("post", sendRequestUrl, true);
      xhr.upload.addEventListener("progress", function(event) {
        var progress = event.loaded / event.total * 100
        progressCallback(progress)
      });
      xhr.addEventListener("load", function(event) {
        if (xhr.status == 204) {
          var attributes = {
            url: HOST + key,
            href: HOST + key + "?content-disposition=attachment"}
          successCallback(attributes)} 
      });
      xhr.send(formData);
    }
})();

The important function, I think, is createFormData() and the last line where i do xhr.send(formdata)

If I inspect the formdata object using:

      for (var pair of formData.entries()) {
        console.log(pair[0]+ ', '+ pair[1]);
      };

before sending formdata I can see this in Chrome console:

key, 1714005757016-ejercicio.png
Content-Type, image/png
file, [object File]

formdata is processed by this part of my APIController.php:


    public function storePostImages(Request $request)
    {
        // Evaluate if method is POST
        if ($request->isMethod('post')) {

            // Evlauate if a file is been uploaded
            if ($request->hasFile('file')) {
                // Assign posted file to variable
                $file = $request->file('file');
                // Evaluate if file is an image
                if (getimagesize($file)) {
                    //
                } else {
                    return response()->json(['error' => 'file type not supported'], 415);
                }
                // Get file name assigned in front end
                $fileName = $_POST['key'];
                // Store image in public folder so that it can be accessible in front end
                Storage::disk('public')->put($fileName, file_get_contents($file));
                
                // Return successful response
                return response()->json(['message' => 'success'], 204);
            }

            return response()->json(['message' => 'No file'], 400);
        } 
        
        return response()->json(['message' => 'error'], 405);
}

And after all of it I get back this response: POST http://127.0.0.1:8000/api/v1/store-image 400 (Bad Request)

Which is an http response I added in APIController.php storePostImages, which means that the conditional statement if ($request->hasFile('file')) is returning false.

So why is $request->hasFile('file') not detecting file if formdata does have a 'file' key and an ObjectFile?

The strange thing is that 2 days ago this was working and I can't seem to find what is going on right now...

0 likes
3 replies
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

It looks like the issue might be related to how the FormData is being constructed and sent with the XMLHttpRequest. Specifically, the Content-Type header might be incorrectly set or not set at all, which can affect how the server interprets the incoming request.

Here are a few steps to troubleshoot and potentially fix the issue:

  1. Ensure the enctype is set correctly in the XMLHttpRequest: When sending files with FormData and XMLHttpRequest, you need to ensure that the Content-Type header is set to multipart/form-data. However, when using FormData with XMLHttpRequest, this should be handled automatically, and you should not set the Content-Type header manually. This allows the browser to set the boundary in the Content-Type which is necessary for parsing the multipart form data on the server.

    Modify your uploadFile function to remove any manual setting of the Content-Type header if present. Here's how you might adjust the function:

    function uploadFile(file, progressCallback, successCallback) {
        var key = createStorageKey(file);
        var formData = createFormData(key, file);
        var xhr = new XMLHttpRequest();
        xhr.open("post", sendRequestUrl, true);
    
        // Do not set Content-Type manually
        // xhr.setRequestHeader('Content-Type', 'multipart/form-data');
    
        xhr.upload.addEventListener("progress", function(event) {
            var progress = event.loaded / event.total * 100;
            progressCallback(progress);
        });
    
        xhr.addEventListener("load", function(event) {
            if (xhr.status == 204) {
                var attributes = {
                    url: HOST + key,
                    href: HOST + key + "?content-disposition=attachment"
                };
                successCallback(attributes);
            }
        });
    
        xhr.send(formData);
    }
    
  2. Check the server-side configuration: Ensure that your Laravel backend is correctly configured to handle file uploads. Check your php.ini settings for file_uploads, upload_max_filesize, post_max_size, and max_file_uploads to ensure they are set to reasonable values.

  3. Debugging the request: Before sending the request, you can log the FormData contents as you've done, but also consider checking the network request in the browser's developer tools to see the actual payload and headers being sent.

  4. Laravel Controller Adjustment: Make sure that your Laravel route handling the file upload is correctly receiving the file. You can debug by returning the entire request object or specific parts of it to see what data is actually making it to the server.

    public function storePostImages(Request $request)
    {
        return response()->json(['request' => $request->all()], 200);
    }
    

By following these steps, you should be able to diagnose why $request->hasFile('file') is returning false and fix the issue accordingly.

1 like
DanteB918's avatar

Can you dump

		$request->all();

in your controller? If your JS says one thing but your controller says another, then it would be helpful to see what your controller has to say about the request.

Might also try Lary's recommendation to use

		xhr.setRequestHeader('Content-Type', 'multipart/form-data');
1 like
0xlaradev's avatar

Thanks! The solution was Lary's second recommendation: check upload_max_filesize. I increased it in php.ini and it worked.

1 like

Please or to participate in this conversation.