How to Scan and Upload Documents in PHP Laravel Project

Laravel is a PHP Framework. This article shares how to use Dynamic Web TWAIN to scan and upload documents in a Laravel project, enhancing web document management capabilities.


Dynamic Web TWAIN for Laravel

First, create a Laravel project skeleton:

composer create-project --prefer-dist laravel/laravel web-document-scan

Now, let’s enhance the Laravel controller, blade template, and routes.


To create a controller:

php artisan make:controller DWTUploadController

This command generates a new file - app\Http\Controllers\DWTUploadController.php. In this file, add a page() function to render the blade template and an upload() function to save uploaded files to the images folder:


namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Validator;

class DWTUploadController extends Controller
    function page()
     return view('dwt_upload');

    function upload(Request $request)
     $validation = Validator::make($request->all(), [
      'RemoteFile' => 'required'
      $image = $request->file('RemoteFile');
      $image->move(public_path('images'), $image->getClientOriginalName());
      return response()->json([
       'message'   => 'Successfully uploaded.'
      return response()->json([
       'message'   => $validation->errors()->all()


Create a blade template at resources\views\dwt_upload.blade.php. This template file should contain all the web front-end code needed for the document scan and upload functionality:

<!DOCTYPE html>

    <title>Dynamic Web TWAIN for Laravel</title>
    <script src="{{ asset('Resources/dynamsoft.webtwain.initiate.js') }}" ></script>
    <script src="{{ asset('Resources/dynamsoft.webtwain.config.js') }}" ></script>
    <meta name="_token" content="{{csrf_token()}}" />

    <h3>Dynamic Web TWAIN for Laravel</h3>
    <div id="dwtcontrolContainer"></div>
    <input type="button" value="Load Image" onclick="loadImage();" />
    <input type="button" value="Scan Image" onclick="acquireImage();" />
    <input id="btnUpload" type="button" value="Upload Image" onclick="upload()">

        var DWObject;
        var deviceList = [];
        window.onload = function() {
            if (Dynamsoft) {
                Dynamsoft.DWT.AutoLoad = false;
                Dynamsoft.DWT.UseLocalService = true;
                Dynamsoft.DWT.Containers = [{
                    ContainerId: 'dwtcontrolContainer',
                    Width: '640px',
                    Height: '640px'
                Dynamsoft.DWT.RegisterEvent('OnWebTwainReady', Dynamsoft_OnReady);
                Dynamsoft.DWT.ProductKey =
                Dynamsoft.DWT.ResourcesPath = '';
        function Dynamsoft_OnReady() {
            DWObject = Dynamsoft.DWT.GetWebTwain('dwtcontrolContainer');
            var token = document.querySelector("meta[name='_token']").getAttribute("content");
            DWObject.SetHTTPFormField('_token', token);
            let count = DWObject.SourceCount;
            let select = document.getElementById("source");
            DWObject.GetDevicesAsync().then(function(devices) {
                for (var i = 0; i < devices.length; i++) { // Get how many sources are installed in the system
                    let option = document.createElement('option');
                    option.value = devices[i].displayName;
                    option.text = devices[i].displayName;
            }).catch(function(exp) {
        function loadImage() {
            var OnSuccess = function() {};
            var OnFailure = function(errorCode, errorString) {};
            if (DWObject) {
                DWObject.IfShowFileDialog = true;
                DWObject.LoadImageEx("", Dynamsoft.DWT.EnumDWT_ImageType.IT_ALL, OnSuccess, OnFailure);

        function acquireImage() {
            if (DWObject) {
                var sources = document.getElementById('source');
                if (sources) {
                    DWObject.SelectDeviceAsync(deviceList[sources.selectedIndex]).then(function() {
                        return DWObject.AcquireImageAsync({
                            IfShowUI: false,
                            IfCloseSourceAfterAcquire: true
                    }).catch(function(exp) {
        function upload() {
            var OnSuccess = function(httpResponse) {
                alert("Succesfully uploaded");
            var OnFailure = function(errorCode, errorString, httpResponse) {
            var date = new Date();
                "{{ route('dwtupload.upload') }}",
                date.getTime() + ".jpg",
                1, // JPEG
                OnSuccess, OnFailure



Note: Replace the LICENSE-KEY with your own Dynamsoft license key.

Dynamsoft.DWT.ProductKey = "LICENSE-KEY";


Define routes in routes\web.php:

Route::get('/dwt_upload', 'DWTUploadController@page');
Route::post('/dwt_upload/upload', 'DWTUploadController@upload')->name('dwtupload.upload');

To run the web server:

composer update
composer install
php artisan serve

Open in your web browser to start using your web document management application.

Laravel web document scan

Common Errors and Solutions

419 Status Code

If the CSRF token is not set in the header, attempting to send the post request will result in a 419 status code.

Laravel CSRF

500 Status Code

An exception like Symfony\Component\Mime\Exception\LogicException: Unable to guess the MIME type as no guessers are available indicates that the php_fileinfo extension is disabled.

Laravel php fileinfo extension

To resolve this, enable extension=fileinfo in your php.ini file.

php int extension

Source Code