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

theUnforgiven's avatar

Signature Pad

I'm using this package - https://github.com/szimek/signature_pad

Which allows drawing on screen for signatures etc, it all works, but the file_put_contents() is placing the file in the public directory. But I don't want this I want store it in public/uploads/signatures for example.

$data_uri = $request->signature;
        $encoded_image = explode(",", $data_uri)[1];
        $decoded_image = base64_decode($encoded_image);

        $contents = file_put_contents(sha1($request->session()->get('user.first_name').$request->session()->get('user.last_name')) . "_signature.png", $decoded_image);

The above is what I have currently which obviously return a base64 png file/image but I want to move to the public/uploads/signatures directory then remove from the public directory so I don't have duplicates.

How can one achieve this? I have tried the rename() & move_uploaded_file() functions to no avail.

0 likes
46 replies
ejdelmonico's avatar

Well, I am not sure but what I would have attempted is to follow that path that was designed into Laravel. That is, storing the file in the local storage and linking to public for availability. You can use any disk or directories you want and it has utility methods.

https://laravel.com/docs/5.3/filesystem#directories

1 like
theUnforgiven's avatar

Using the Storage facade I'm getting all kinds of errors like File not found at path:

ejdelmonico's avatar

Did you run the artisan command to link to public? php artisan storage:link

theUnforgiven's avatar

Still errors:

I'm using the Storage::move() facade to move it, is that right?

ejdelmonico's avatar

The way it works is that you store the file in local storage (storage folder) Laravel stores it under /storage/app/thefile or you can define that custom directory. After linking for public availability, you can access the file by url. You can use a temp directory and then move/rename the file as needed.

To move you would Storage::move('old/file', 'new/file'). The docs are pretty good for examples.

theUnforgiven's avatar

The file_put_contents() is just storing it within the app/public directory, and I want to move it to app/public/uploads for example

ejdelmonico's avatar

To originally store the file its Storage::put() or one of the other helper methods. That will save it in your local storage and then you can move it.

1 like
theUnforgiven's avatar

Keep getting other errors like: file_put_contents(/Users/lee/code/hns/storage/app/public/): failed to open stream: Is a directory

theUnforgiven's avatar

Current code based on my last two replies:

$data_uri = $request->signature;
        $encoded_image = explode(",", $data_uri)[1];
        $decoded_image = base64_decode($encoded_image);

        $sig = $request->session()->get('user.first_name').$request->session()->get('user.last_name') . "_signature.png";
        $contents = file_put_contents(sha1($request->session()->get('user.first_name').$request->session()->get('user.last_name')) . "_signature.png", $decoded_image);
        Storage::put($contents,$sig);

The one in red b95eaeeb... is the actual image that gets stored, but I just want to move that to the uploads/signatures directory

nikocraft's avatar

what is the use of linking public/storage to storage/app/public? Why would we want to store files in storage/app/public instead of public/storage or public/uploads?

1 like
theUnforgiven's avatar

I dont want to do that I just want to store within public/uploads

nikocraft's avatar

how hard could it be to store in public/uploads? I allways store there and it's easy

theUnforgiven's avatar

$contents = file_put_contents(.... is storing in public like the screen shot I posted the b95eaeeb.. red text but I want to move that to the uploads directory.

nikocraft's avatar

here is my code that works

        if($request->hasFile('file')) {
            $album->save();
            Session::push('album.hash', $album->hash);
            $order = 1;
            foreach($request->file('file') as $file){
                $rules = array('file' => 'required|mimes:png,gif,jpeg,jpg'); //'mimes:png,gif,jpeg,txt,pdf,doc'
                $validator = Validator::make(array('file'=> $file), $rules);

                if($validator->passes()){
                    do{
                        $imageHash = str_random(7);
                    } while (Image::where('hash', $imageHash)->withTrashed()->first() != null);

                    $current = Carbon::now();
                    $year = $current->year;
                    $month = $current->month;
                    $day = $current->day;
                    $hour = $current->hour;
                    $folder = 'uploads/'.$year.'/'.$month.'/'.$day.'/'.$hour;

                    if( ! file_exists($folder)) {
                        $oldmask = umask(0);
                        mkdir($folder, 0775, true);
                        mkdir($folder . '/thumb/', 0775, true);
                        umask($oldmask);
                    }

                    $name = $imageHash .'.'. strtolower($file->getClientOriginalExtension());

                    $file->move($folder, $name);

take what you need. you do not need file_put_contents, use file->move

1 like
theUnforgiven's avatar

ok, so I've been having a play around with this:

The image show whats happening: I click that file and it shows this b95eaeeb833a39258fc1c07149d8e4438f71f224_signature.png not the actual image.

The following is the code I have now:

$sig = sha1($request->session()->get('user.first_name').$request->session()->get('user.last_name')) . "_signature.png";
$folder = 'uploads/signatures/';

Storage::put($folder, $sig);

So it's just saving the filename rather than the actual file :( I'm lost....

LeandritGo's avatar

Hi @theUnforgiven can you share the code you used to implement the whole Signature Pad feature? From the front end to the controller if you don't mind.

I am stuck with the front end still. Thanks

theUnforgiven's avatar

Controller:

/**
     * Save Signature
     *
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function saveSignature(Request $request)
    {
        $user = $request->session()->get('user');

        $signature = new Signature;
        $signature->user_id = $request->session()->get('user.id');
        $signature->position = $request->position;

        $data_uri = $request->signature;
        $encoded_image = explode(",", $data_uri)[1];
        //$decoded_image = base64_decode($encoded_image);

        $sig = sha1($request->session()->get('user.first_name').$request->session()->get('user.last_name')) . "_signature.png";
        $folder = '/uploads/signatures/';

        Storage::put($folder, $sig);

        $signature->signature = $encoded_image;
        $signature->save();

        $request->session()->put('user', $user->load('account', 'signature'));
        return back();
    }

JS:

$(function () {

            $.ajaxSetup({
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                }
            });

            var signaturePad = new SignaturePad(document.getElementById('signature-pad'), {
                backgroundColor: 'rgba(255, 255, 255, 0)',
                penColor: 'rgb(0, 0, 0)'
            });
            var saveButton = document.getElementById('save');
            var cancelButton = document.getElementById('clear');


            saveButton.addEventListener('click', function (event) {
                if (signaturePad.isEmpty()) {
                    sweetAlert("Oops...", "Please provide signature first.", "error");
                } else {

                    // do ajax to post it
                    $.ajax({
                        url : '/assessments/signature',
                        type: 'POST',
                        data : {
                            signature: signaturePad.toDataURL('image/png'),
                            position: $('#position').val()
                        },
                        success: function(response)
                        {
                            sweetAlert("Success!", "Good stuff! Your signature is now saved", "success");
                            setTimeout(function () {
                                location.reload();
                            }, 3000);
                            //data - response from server
                        },
                        error: function(response)
                        {
                            sweetAlert("Oops...", "Sorry, something went wrong! We will investigate as soon as possible.", "error");
                            console.log(response);
                        }
                    });
                }

            });

            cancelButton.addEventListener('click', function (event) {
                signaturePad.clear();
            });

        });

Make sure to import the signature JS file before this script.

1 like
LeandritGo's avatar

@theUnforgiven here is my code if you ever want to save the image in your server... As I can see you are saving it in bits in the database.

    $data_uri = $request->signature;
    $encoded_image = explode(",", $data_uri)[1];
    $decoded_image = base64_decode($encoded_image);

    $user = Sentinel::getUser();

    $url = 'Signature' . '-id-' . $user->id . '-Name' . $user->first_name . '-' . $user->last_name .'-Rand-' . rand(111,9999).'.png';

    $name = 'ID' . $user->id . '-Rand-' . rand(111,9999) . '-' . rand(111,9999) . '-' . rand(111,9999);
    $user_id = $user->id;

    $data=array(
        'user_id' => $user_id,
        'name' => $name,
        'url' => $url,
    );

    Signature::insert($data);

    file_put_contents('../storage/app/signatures/' . $url, $decoded_image);

Thanks again for your code :) Javascript was a bit painful for me :) :D

Bilou's avatar

Dear sir, i am new in laravel. i want to save signature as png file. Please Guide me

theUnforgiven's avatar

@Bilou, just follow these two pages through and you should be able to get yourself where you need to be.

lawkunchi's avatar

@theUnforgiven

Hey man do you mind helping me out on how you approach storing the image from the signature pad. Thanks!

theUnforgiven's avatar

@lawkunchi - Sorry I'm a little tied up at the minute, feel free to see the above posts on what I did and also post what you have so far on here and I'll try and help.

lawkunchi's avatar

I got this error when I try to save the signature : Undefined offset: 1

referring to this line
 $encoded_image = explode(",", $data_uri)[1];
Next

Please or to participate in this conversation.