grozavule's avatar

Serialization of 'Illuminate\Http\UploadedFile' is not allowed

I've made a form with a drag-and-drop file upload option. The form submission fails with the error: Serialization of 'Illuminate\Http\UploadedFile' is not allowed

Form

@extends('base')

@section('content')
    @component('components.titlebar', ['title' => $title])
    @endcomponent

    @include('components.notifications')

    <fieldset>
        <form action="{{ route('employee.store') }}" method="post" enctype="multipart/form-data">
            <div class="form-group">
                <label class="form-label" for="first_name">FIRST NAME:</label>
                <input type="text" name="first_name" class="form-control" value="{{ old('first_name') }}" />
            </div>

            <div class="form-group">
                <label class="form-label" for="last_name">LAST NAME:</label>
                <input type="text" name="last_name" class="form-control" value="{{ old('last_name') }}" />
            </div>

            <div class="form-group">
                <label class="form-label" for="department_id">DEPARTMENT:</label>
                <select class="form-control" name="department_id">
                    @foreach($departments as $department)
                        <option value="{{ $department->ID }}">{{ $department->DESCRIPTION }}</option>
                    @endforeach
                </select>
            </div>

            <div class="form-group">
                <label class="form-label" for="email_address">EMAIL ADDRESS:</label>
                <div class="input-group">
                    <input type="text" name="email_address" class="form-control" value="{{ old('email_address') }}" />
                    <div class="input-group-append">
                        <div class="input-group-text">@doublelglobal.com</div>
                    </div>
                </div>
            </div>

            <div class="form-group">
                <label class="form-label" for="mobile_number">MOBILE NUMBER:</label>
                <!-- <input type="tel" name="mobile_number" class="form-control" value="{{ old('mobile_number') }}" /> -->
                <div class="form-row">
                    <div class="col-md-3">
                        <input type="tel" name="area_code" class="form-control" maxlength="3" />
                    </div>
                    <div class="col-md-3">
                        <input type="tel" name="prefix" class="form-control" maxlength="3" />
                    </div>
                    <div class="col-md-6">
                        <input type="tel" name="number" class="form-control" maxlength="4" />
                    </div>
                </div>
            </div>

            <div class="form-group">
                <label class="form-label" for="phone_ext">PHONE EXTENSION:</label>
                <input type="number" name="phone_ext" class="form-control" value="{{ old('phone_ext') }}" maxlength="3" />
            </div>

            <div class="drop-zone">
                <span class="drop-zone-prompt">Drop a photo here or click to browse the computer</span>
                <input type="file" name="employee_photo" class="drop-zone-input"/>
            </div>
            @csrf
            @include('components.button', [
                'classes' => ['btn-submit'],
                'icon' => 'save',
                'label' => 'SAVE'
            ])
        </form>
    </fieldset>
@endsection

Controller

private function cropProfileImage($path)
    {
        $image = Image::make($path)->resize(500,500);
        $image->save($path, 40, 'jpg');
    }

    public function store(Request $request)
    {
        $validInput = $request->validate([
            'first_name' => ['required', 'max:30', 'alpha'],
            'last_name' => ['required', 'max:30', 'alpha_dash'],
            'department_id' => ['required', 'exists:vmfg.DEPARTMENT,ID'],
            'email_address' => ['nullable'],
            'area_code' => ['nullable', 'size:3'],
            'prefix' => ['nullable', 'size:3'],
            'number' => ['nullable', 'size:4'],
            'phone_ext' => ['nullable', 'integer', 'min:100', 'max:210', 'unique:employees,phone_ext' ],
            'employee_photo' => ['required', 'image']
        ]);

        $path = $request->file('employee_photo')->store('employee-photos');
        $this->cropProfileImage($path);

        $employee = new Employee;
        $employee->first_name = $validInput['first_name'];
        $employee->last_name = $validInput['last_name'];
        $employee->department_id = $validInput['department_id'];
        $employee->email_address = $validInput['email_address'] . '@doublelglobal.com';
        $employee->phone_number = '+1' . $validInput['area_code'] . $validInput['prefix'] . $validInput['number'];
        $employee->phone_ext = $validInput['phone_ext'];
        $employee->photo_path = $path;
        $employee->save();

        return redirect()->route('employees.index')->with('success', 'The employee, ' . $employee->first_name . ' ' . $employee->last_name . ', was successfully added!');
    }

What am I doing wrong?

0 likes
7 replies
Sinnbeck's avatar

What line is throwing the error? Check the stack trace in the error

grozavule's avatar

Here is the stack trace (I don't see where it even references any of my files):

Exception: Serialization of 'Illuminate\Http\UploadedFile' is not allowed in file /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Session/Store.php on line 129

#0 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Session/Store.php(129): serialize()
#1 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(170): Illuminate\Session\Store->save()
#2 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(65): Illuminate\Session\Middleware\StartSession->saveSession()
#3 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Session\Middleware\StartSession->handle()
#4 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#5 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse->handle()
#6 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(67): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#7 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Cookie\Middleware\EncryptCookies->handle()
#8 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#9 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Routing/Router.php(683): Illuminate\Pipeline\Pipeline->then()
#10 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\Routing\Router->runRouteWithinStack()
#11 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\Routing\Router->runRoute()
#12 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Routing/Router.php(613): Illuminate\Routing\Router->dispatchToRoute()
#13 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(170): Illuminate\Routing\Router->dispatch()
#14 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(130): Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http\{closure}()
#15 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#16 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle()
#17 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#18 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle()
#19 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#20 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Foundation\Http\Middleware\ValidatePostSize->handle()
#21 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(63): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#22 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode->handle()
#23 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/fideloper/proxy/src/TrustProxies.php(57): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#24 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(171): Fideloper\Proxy\TrustProxies->handle()
#25 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(105): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#26 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(145): Illuminate\Pipeline\Pipeline->then()
#27 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter()
#28 /mnt/c/Users/eric.drake/Documents/Sites/dev.keystone.local/public/index.php(55): Illuminate\Foundation\Http\Kernel->handle()
#29 {main}
Snapey's avatar

Whats in the index method and view?

grozavule's avatar

Here is the full EmployeeController source code:

<?php

namespace App\Http\Controllers;

use App\Visual\Employee as VisualEmployee;
use Illuminate\Http\Request;
use App\Employee;
use Intervention\Image\Facades\Image;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Response;

class EmployeeController extends Controller
{
    public function index()
    {
        return view('employees.index', [
            'title' => 'COMPANY DIRECTORY',
            'employees' => Employee::all()
        ]);
    }

    public function create()
    {
        return view('employees.create', [
            'title' => 'ADD EMPLOYEE',
            'employees' => VisualEmployee::where('ACTIVE', '=', 'Y')->orderBy('LAST_NAME')->orderBy('FIRST_NAME')->get(),
        ]);
    }

    private function cropProfileImage($path)
    {
        $image = Image::make(storage_path($path))->resize(500,500);
        $image->save($path, 40, 'jpg');
    }

    public function store(Request $request)
    {
        try
        {
            $validInput = Validator::make($request->all(), [
                'employee_id' => ['required', 'exists:vmfg.EMPLOYEE,ID'],
                'first_name' => ['required', 'max:30', 'alpha'],
                'last_name' => ['required', 'max:30', 'alpha_dash'],
                'department_id' => ['required', 'exists:vmfg.DEPARTMENT,ID'],
                'email_address' => ['nullable'],
                'area_code' => ['nullable', 'size:3'],
                'prefix' => ['nullable', 'size:3'],
                'number' => ['nullable', 'size:4'],
                'phone_ext' => ['nullable', 'integer', 'min:100', 'max:210', 'unique:employees,phone_ext' ],
                'employee_photo' => ['required', 'image']
            ]);

            if($validInput->fails())
            {
                return Response::json($validInput->errors(), 400);
            }
            $employee = new Employee;
            $employee->id = $request->input('employee_id');
            $employee->first_name = $request->input('first_name');
            $employee->last_name = $request->input('last_name');
            $employee->department_id = $request->input('department_id');
            $employee->email_address = $request->input('email_address') . '@doublelglobal.com';
            $employee->mobile_number = '+1' . $request->input('area_code') . $request->input('prefix') . $request->input('number');
            $employee->phone_ext = $request->input('phone_ext');
            if($request->hasFile('employee_photo'))
            {
                $path = $request->file('employee_photo')->store('employee-photos');
                $this->cropProfileImage($path);
                $employee->photo_path = $path;
            }
            $employee->save();

            //return redirect()->route('employees.index')->with('success', 'The employee, ' . $employee->first_name . ' ' . $employee->last_name . ', was successfully added!');
            return Response::json(['success' => 'The employee, ' . $employee->first_name . ' ' . $employee->last_name . ', was successfully added!'], 200);
        } catch(\Exception $e)
        {
            return Response::json(['danger' => $e->getMessage()], 400);
        }
    }
}

The create.blade.php file is as follows:

@extends('base')

@section('content')
    @component('components.titlebar', ['title' => $title])
    @endcomponent

    @include('components.notifications')

    <fieldset>
        <form id="employee-create" action="{{ route('employee.store') }}" method="post" enctype="multipart/form-data">
            <div class="form-group">
                <label class="form-label" for="employee_id">EMPLOYEE ID:</label>
                <select name="employee_id" class="form-control">
                    <option value="">SELECT AN EMPLOYEE ID</option>
                    @foreach($employees as $employee)
                    <option data-firstname="{{ $employee->FIRST_NAME }}" data-lastname="{{ $employee->LAST_NAME }}" data-department="{{ $employee->DEPARTMENT_ID }}" value="{{ $employee->ID }}">{{ $employee->ID }} - {{ strtoupper($employee->FIRST_NAME) }} {{ strtoupper($employee->LAST_NAME) }}</option>
                    @endforeach
                </select>
            </div>

            <div class="form-group">
                <label class="form-label" for="first_name">FIRST NAME:</label>
                <input type="text" name="first_name" class="form-control" value="{{ old('first_name') }}" readonly />
            </div>

            <div class="form-group">
                <label class="form-label" for="last_name">LAST NAME:</label>
                <input type="text" name="last_name" class="form-control" value="{{ old('last_name') }}" readonly />
            </div>

            <div class="form-group">
                <label class="form-label" for="department_id">DEPARTMENT:</label>
                <input type="text" name="department_id" class="form-control" value="{{ old('department_id') }}" readonly />
            </div>

            <div class="form-group">
                <label class="form-label" for="email_address">EMAIL ADDRESS:</label>
                <div class="input-group">
                    <input type="text" name="email_address" class="form-control" value="{{ old('email_address') }}" />
                    <div class="input-group-append">
                        <div class="input-group-text">@doublelglobal.com</div>
                    </div>
                </div>
            </div>

            <div class="form-group">
                <label class="form-label" for="mobile_number">MOBILE NUMBER:</label>
                <div class="form-row">
                    <div class="col-md-3">
                        <input type="tel" name="area_code" class="form-control" maxlength="3" />
                    </div>
                    <div class="col-md-3">
                        <input type="tel" name="prefix" class="form-control" maxlength="3" />
                    </div>
                    <div class="col-md-6">
                        <input type="tel" name="number" class="form-control" maxlength="4" />
                    </div>
                </div>
            </div>

            <div class="form-group">
                <label class="form-label" for="phone_ext">PHONE EXTENSION:</label>
                <input type="number" name="phone_ext" class="form-control" value="{{ old('phone_ext') }}" maxlength="3" />
            </div>

            <div class="drop-zone">
                <span class="drop-zone-prompt">Drop a photo here or click to browse the computer</span>
                <input type="file" name="employee_photo" class="drop-zone-input"/>
            </div>
            @csrf
            <input type="submit" value="SAVE"/>
        </form>
    </fieldset>
@endsection

Please note that I've changed both files since asking the initial question. When I've used drag-and-drop file uploads in the past, they needed to be submitted via AJAX. I rewrote sections of the code to work better with an AJAX request.

Here is the JS:

//Drag-and-Drop File Uploads
let form = document.querySelector('#employee-create');
let inputElement = document.querySelector('.drop-zone-input');
let prompt = document.querySelector('.drop-zone-prompt');
let ajax = new XMLHttpRequest();
let data = new FormData(form);
let droppedFiles = false;

const dropZoneElement = inputElement.closest(".drop-zone");dropZoneElement.addEventListener("click", (e) => {
    inputElement.click();
});
inputElement.addEventListener("change", (e) => {
    droppedFiles = e.target.files;
    prompt.innerHTML= e.target.files[0].name;
});
dropZoneElement.addEventListener("dragover", (e) => {
    e.preventDefault();
    dropZoneElement.classList.add("drop-zone-over");
});
["dragleave", "dragend"].forEach((type) => {
    dropZoneElement.addEventListener(type, (e) => {
        dropZoneElement.classList.remove("drop-zone-over");
    });
});
dropZoneElement.addEventListener("drop", (e) => {
    e.preventDefault();
    if (e.dataTransfer.files.length) {
        droppedFiles = e.dataTransfer.files;
        inputElement.files = e.dataTransfer.files;
        prompt.innerHTML = e.dataTransfer.files[0].name;
    }
    dropZoneElement.classList.remove("drop-zone-over");
});

form.addEventListener('submit', function(e){
    e.preventDefault();
    console.log("I used the submit event listener!");

   if(droppedFiles)
   {
       console.log(droppedFiles[0]);
       data.append(inputElement.getAttribute('name'), droppedFiles[0]);

       ajax.open(this.getAttribute('method'), this.getAttribute('action'), true);
       ajax.onload = function() {
           if(ajax.status >= 200 && ajax.status < 400)
           {
               let data = JSON.parse(ajax.responseText);
           } else {
               let errors = JSON.parse(ajax.responseText);
           }
       }
       ajax.onerror = function(){
           alert('Please try again!');
       }
       ajax.send(data);
   } else {
       alert('No photos were selected!');
   }
});
Snapey's avatar

Somewhere you are trying to return the uploaded file via the session.

try temporarily removing employee_photo from the validation rules.

grozavule's avatar

If I pull any reference to the employee_photo, the form submission will work.

grozavule's avatar

If I just remove it from the validation rules, I still get the Serialization error. I have to remove the form element, the validation rule, and any references to the uploaded file before the error will go away.

Please or to participate in this conversation.