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

spook1's avatar

upload Picture does not work anymore after update..

The apllication used to work, I upgraded recently to laravel 8, and solved many issues. Now, just as I I want to work on css, I get a new problem in the backend...

In the view I use input field to enter a picture. It is not processed anymore, I get no error messages, but no picture saved in the storage either..

I can open the form. I can browse and identify an image. When selected the image name is reflected. After submit, $request->picture_input is empty...

Can anyone see what is wrong? Why this picture is not correctly processed ( it worked in the past, I get no error...??)

I am quite new in the area, did not write the code myself. Maybe the mistake is easy to see for an expert..

View:

    <h5 class="header_dark">{{ __('My Profile') }}</h5>
             <form method='POST' id="account_form" runat="server" action="profile/submit" 
              enctype="multipart/form-data">
                {{ csrf_field() }}

                <p><b>{{ __('Profile photo') }}</b></p>
                <input type='file' id="file_picture_input"/>
                <br>

    <img id="picture_preview" src="{{ url('') }}/images/profile" alt="" style="width:180px; box-shadow: 0px 0px 15px #444;"/>
		        <div id="picture_preview_container"></div>
				<div id="rotateleft" class="btn" style="display: none;">{{ __('Rotate left') }}</div>
				<div id="rotateright" class="btn" style="display: none;">{{ __('Rotate right') }}</div>
		        <input type="hidden" id="picture_input" name="picture_input"/>
		        <p>{!! __('<b>Be aware!</b> Your profile photo needs to be a clear photo of your face, so other players can easily recognize you.') !!}</p>
		    

     <img id="picture_preview" src="{{ url('') }}/images/profile" alt="" style="width:180px; box-shadow: 
      0px 0px 15px #444;"/>
                <div id="picture_preview_container"></div>

After submit the page shows that an image is required. No image was added to the request.. (I dump&died it as you can see)

Controller:


    public function submit(Request $request)
    {
        $profile = Profile::getProfile();
        $user = GameUser::getCurrentUser();
        $invitation = new Invitation();

        $this->validate($request, [
                'first_name' => 'required|regex:/^[\pL\s\-]+$/u',
                'last_name' => 'required|regex:/^[\pL\s\-]+$/u',
                'email' => 'required|email',
        ]);
        
        dd($request) ;

        if ($profile->picture == "#")
        {
            $this->validate($request, ['picture_input' => 'required']);
        }

        if ($request->picture_input){
            $profile->savePicture($request->picture_input);
        }

dd shows:


Illuminate\Http\Request {#43 ▼
  #json: null
  #convertedFiles: []
  #userResolver: Closure($guard = null) {#113 ▶}
  #routeResolver: Closure() {#1325 ▶}
  +attributes: Symfony\Component\HttpFoundation\ParameterBag {#45 ▶}
  +request: Symfony\Component\HttpFoundation\ParameterBag {#44 ▼
    #parameters: array:5 [▼
      "_token" => "dzcE1cdTU5QT2j8VEP18PPbbHaQ1G3SGT1hQ5xy6"
      "picture_input" => ""
      "first_name" => "Jan"
      "last_name" => "Jansen"
      "email" => "[email protected]"
    ]
  }
  +query: Symfony\Component\HttpFoundation\InputBag {#51 ▶}
0 likes
22 replies
MichalOravec's avatar

You file input doesn't have a name attribute.

<input type="file" id="file_picture_input" name="picture_input">

and remove this hidden input.

<input type="hidden" id="picture_input" name="picture_input">
spook1's avatar

but it did work before.. Something else must have changed

spook1's avatar

I dug into it further, it seems to have to do with croppie.js running and acting upon button clicks.

spook1's avatar

That seems to work as a workaround, but I need the preview... The real problem is that that does not work... Something goes wrong in this previewpart I assume

also I run the next error : Undefined Offset: 1

in the savePicture method of my Profile model.

public function savePicture($picture_input){

		list($type, $data) = explode(';', $picture_input);   << error mentioned for this line>>

		list(, $data)      = explode(',', $data);

		$data = base64_decode($data);

 
spook1's avatar

I am learning. Got this app from a developer who stopped maintenance. It worked fine before, so I do not expect errors.

I checked the upgrade documentation and read the Laravel book on fileiploads. I am aware that I lack experience ..:(

Snapey's avatar

probably you have a javascript error which has stopped croppie from working. It sounds like it takes the file input then puts the file in the hidden input field.

You should check the browser console for javascript errors

johnDoe220's avatar

for show image in view :: and for upload use this $image = $resquest->image->store('uploads');

note ; image = your input file name store ; add image method uploads = directory upload

Post::create({ 'image' => $image });

because before this work add (FILESYSTEM_DRIVER=public) in .env file and run this command = php artisan storage:link

johnDoe220's avatar

< img src = " {{ asset('storage/'.$post->image); }} " > this for show image in laravel8

spook1's avatar

Doesn't asset refer to the public folder? My storage dir is a subdirectory of the resources directory

Indeed, I used to spin up with

php artisan storage:link

here is the whole savePicture method ( a profile method, called from the profileController)

	public function savePicture($picture_input){
		list($type, $data) = explode(';', $picture_input);
		list(, $data)      = explode(',', $data);
		$data = base64_decode($data);
		 
		$image = $data;//$request->file('picture_input');
		$image_name = time().Str::random(5).'.png';
		 
		$path = storage_path('app/pictures/'.$image_name);
		 
		$img = Image::make($image);
		$img->resize(250, 250, function ($constraint) {
			$constraint->aspectRatio();
		})->save($path);
		
		if($this->picture){
			Storage::delete($this->picture);
		}
		$this->update(["picture" => 'pictures'.'/'.$image_name]);
	}

` ``

I do  not see exactly where to make changes :(

But I am very happy that someone recognizes that this could have worked before :)
I keep on puzzling ...
johnDoe220's avatar
look,There is no need to do anything special, if you do the steps like this, the upload will be done without additional coding 
step1 = add this code in .env file FILESYSTEM_DRIVER=public 
step2 = run this command = php artisan storage:link with do work connect storage folder with public folder and auto make storage folder in public folder ok? 
step3 = then you need input with type file in blade and botton with submit type and give name for input file 
make PostsController example and define store method, 
public function store(Request $request){

$image = $request->image->store->('uploads'); // uploads folder auto make in public->storage->uploads ok?

Post::create({
 'image' => $image, 'name' =>$request->name, 'family' = $request->family 
 })

}
spook1's avatar

Thank you so much for helping me.

Indeed I found two error in the browser console:

_small.png:1 Failed to load resource: the server responded with a status of 404 (Not Found)

cropimage.js:4 Uncaught ReferenceError: $ is not defined at cropimage.js:4 

I am still

spook1's avatar

No, only these two:

cropimage.js line 4 :


var uploadCroppie;
var globalFileURL;

$(function() { //shorthand document.ready function
	$('#submit_button').on('click', function(e) { //use on if jQuery 1.7+
	    e.preventDefault();  //prevent form from submitting
	
	    if(uploadCroppie){
	        uploadCroppie.croppie('result', {
	            type: 'base64',
	            size: {
					width: 250,

and an alert:

DevTools failed to load SourceMap: Could not load content for http://localhost:8000/js/bootstrap.esm.js.map: HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE 

spook1's avatar

Just realize that croppie implementation maybe not standard... :

The complete code for the blade referring to cropimage.js:

 @extends('layout')

@section('header')
	@include('includes.basic_header')
@stop

@section('content')
	<div class="container center account-container">
		<div>
			@if (!$valid)
				<p><b>{{ __('Welcome at Detective Collective!') }}</b><p>
				<p>{{ __('Before you begin with solving crimes, you first need to finish your profile.') }}</p>
			@endif
			<h5 class="header_dark">{{ __('My Profile') }}</h5>
			 <form method='POST' id="account_form" runat="server" action="profile/submit" enctype="multipart/form-data">
			 	{{ csrf_field() }}
			 	@foreach ($errors->all() as $error)
		        	<h6 class="red">{{ $error }}</h6>
		        @endforeach
			 	<p><b>{{ __('Profile photo') }}</b></p>
		        <input type='file' id="file_picture_input"/>
		        <br>
		        <img id="picture_preview" src="{{ url('') }}/images/profile" alt="" style="width:180px; box-shadow: 0px 0px 15px #444;"/>
		        <div id="picture_preview_container"></div>
				<div id="rotateleft" class="btn" style="display: none;">{{ __('Rotate left') }}</div>
				<div id="rotateright" class="btn" style="display: none;">{{ __('Rotate right') }}</div>
		        <input type="hidden" id="picture_input" name="picture_input"/> 
		        <p>{!! __('<b>Be aware!</b> Your profile photo needs to be a clear photo of your face, so other players can easily recognize you.') !!}</p>
		        <p><b>{{ __('First name') }}</b></p>
		        <input type='hidden' placeholder="{{ __('First name') }}" name="first_name" value="{{ $profile->first_name }}"/>
		        <p><b>{{ __('Last name') }}</b></p>
		        <input type='text' placeholder="{{ __('Last name') }}" name="last_name" value="{{ $profile->last_name }}"/>
		        <p><b>{{ __('Email address') }}</b></p>
		        <p>{{ __('Your e-mail address will only be used for this game.') }}</p>
		        <input type='email' placeholder="{{ __('Email address') }}" name="email" value="{{ $email }}"/>
		        @if($game_user_availability->active())
				    <div class="row">
					    <div class="col s12">
						    <div class="card blue-grey darken-1 card-all-white-text">
							    <div class="card-content white-text">
							    <span class="card-title">{{ $availability_main_label }}</span>
							    <div class="row">
							    	<p>{{ $availability_question_days }}</p>
							    </div>
							    <div class="row">
							    	@if($allowed_days['mon'])
							    	<div class="col s4">
									    <input type="checkbox" id="gameuser_availability_mon" value="1" name="gameuser_availability_mon" {{ old('gameuser_availability_mon',$game_user_availability->mon) ? 'checked' : '' }}/>
										<label for="gameuser_availability_mon">{{ __('Mon') }}</label>
									</div>
									@endif
									@if($allowed_days['tue'])
									<div class="col s4">
									    <input type="checkbox" id="gameuser_availability_tue" value="1" name="gameuser_availability_tue" {{ old('gameuser_availability_tue',$game_user_availability->tue) ? 'checked' : '' }}/>
										<label for="gameuser_availability_tue">{{ __('Tue') }}</label>
									</div>
									@endif
									@if($allowed_days['wed'])
									<div class="col s4">
										<input type="checkbox" id="gameuser_availability_wed" value="1" name="gameuser_availability_wed" {{ old('gameuser_availability_wed',$game_user_availability->wed) ? 'checked' : '' }}/>
										<label for="gameuser_availability_wed">{{ __('Wed') }}</label>
									</div>
									@endif
									@if($allowed_days['thu'])
									<div class="col s4">
										<input type="checkbox" id="gameuser_availability_thu" value="1" name="gameuser_availability_thu" {{ old('gameuser_availability_thu',$game_user_availability->thu) ? 'checked' : '' }}/>
										<label for="gameuser_availability_thu">{{ __('Thu') }}</label>
									</div>
									@endif
									@if($allowed_days['fri'])
									<div class="col s4">
										<input type="checkbox" id="gameuser_availability_fri" value="1" name="gameuser_availability_fri" {{ old('gameuser_availability_fri',$game_user_availability->fri) ? 'checked' : '' }}/>
										<label for="gameuser_availability_fri">{{ __('Fri') }}</label>
									</div>
									@endif
									@if($allowed_days['sat'])
									<div class="col s4">
										<input type="checkbox" id="gameuser_availability_sat" value="1" name="gameuser_availability_sat" {{ old('gameuser_availability_sat',$game_user_availability->sat) ? 'checked' : '' }}/>
										<label for="gameuser_availability_sat">{{ __('Sat') }}</label>
									</div>
									@endif
									@if($allowed_days['sun'])
									<div class="col s4">
										<input type="checkbox" id="gameuser_availability_sun" value="1" name="gameuser_availability_sun" {{ old('gameuser_availability_sun',$game_user_availability->sun) ? 'checked' : '' }}/>
										<label for="gameuser_availability_sun">{{ __('Sun') }}</label>
									</div>
									@endif
							    </div>
							    <div class="row">
							   		<p>{{ $availability_question_location }}</p>
							   	</div>
							    <div class="row">
								    <div class="input-field col s12">
									    <select name="location_id">
									      <option value=""  disabled selected>{{ __('Select an option') }}</option>
									      @foreach($locations as $location)
									      <option value="{{ $location->id }}" {{ old('location_id', $game_user_availability->location_id) == $location->id ? 'selected="selected"' : ''}}>{{ $location->label }}</option>
									      @endforeach
									    </select>
								  	</div>
								</div>
								<div class="row">
							    	<p>{{ $availability_question_floor_level }}</p>
							    	@for ($i = 0; $i < 9; $i++)
							    		<div class="col s4">
								    		<input name="floor_level[]" type="checkbox" value="{{ $i + 1 }}" id="floor_level_{{ $i }}" {{ in_array(($i + 1), old('floor_level', $game_user_availability->getAllFloors())) ? 'checked="checked"' : '' }}/>
		      								<label for="floor_level_{{ $i }}">{{ $i + 1 }}</label>
		      							</div>
									@endfor
							    </div>
						    </div>
					    </div>
				    </div>
				   @endif
		        
		        <input class="btn-large" type="submit" id="submit_button" value="{{ __('Finish') }}">
	    	</form>
		</div>
	</div>
	<script src="{{ url('js/cropimage.js') }}"></script>
@stop

and the complete js/cropimage.js that generates the error:

 
var uploadCroppie;
var globalFileURL;

$(function() { //shorthand document.ready function
	$('#submit_button').on('click', function(e) { //use on if jQuery 1.7+
	    e.preventDefault();  //prevent form from submitting
	
	    if(uploadCroppie){
	        uploadCroppie.croppie('result', {
	            type: 'base64',
	            size: {
					width: 250,
				    height: 250 
				} //'viewport'
	        }).then(function (resp) {
	            $('#picture_input').val(resp);
	            $('#account_form').submit();
	        });
	    }else{
	    	$('#account_form').submit();
	    }
	});
	
	$('#rotateleft').click(function(){
		if(uploadCroppie){
			// $(uploadCroppie).croppie('bind', {
				// url: globalFileURL
			// });
			
			$(uploadCroppie).croppie('rotate', -90);
			
			// if (deg === 90 || deg === -270) ornt = 6;
			// if (deg === -90 || deg === 270) ornt = 8;
			// if (deg === 180 || deg === -180) ornt = 3;
		}
	});

	$('#rotateright').click(function(){
		if(uploadCroppie){
			$(uploadCroppie).croppie('rotate', 90);
		}
	});
});

//test if input is a valid image
if (window.File && window.FileReader && window.FormData) {
// 			var $inputField = $('input[name="picture_input"]');
var $inputField = $('#file_picture_input');
$inputField.on('change', function (e) {
	var file = e.target.files[0];
	if (file) {
		if (/^image\//i.test(file.type)) {
			readFile(file);
		} else {
			alert('Not a valid image!');
			}
		}
	});
} else {
	alert("File upload is not supported!");
}

function readFile(file) {
	var reader = new FileReader();
	reader.onloadend = function () {
		processFile(reader.result, file.type);
	}
	reader.onerror = function () {
		alert('There was an error reading the file!');
	}
	reader.readAsDataURL(file);
}

//resize the image
function processFile(dataURL, fileType) {
	var maxWidth = 576;
	var maxHeight = 576;

	var image = new Image();
	image.src = dataURL;

	image.onload = function () {
		var width = image.width;
		var height = image.height;
		var shouldResize = (width > maxWidth) && (height > maxHeight);

// 				if (!shouldResize) {
// 					$('#picture_preview').attr('src', dataURL);
// 					return;
// 				}

// 				var newWidth;
// 				var newHeight;

// 				if (width < height) {
// 					newHeight = height * (maxWidth / width);
// 					newWidth = maxWidth;
// 				} else {
// 					newWidth = width * (maxHeight / height);
// 					newHeight = maxHeight;
// 				}

// 				var canvas = document.createElement('canvas');

// 				canvas.width = newWidth;
// 				canvas.height = newHeight;

// 				var context = canvas.getContext('2d');
// 				context.drawImage(this, 0, 0, newWidth, newHeight);
// 				dataURL = canvas.toDataURL(fileType);
	//$('#picture_preview').attr('src', dataURL);
	$('#picture_preview').hide();
	$('#picture_preview_container').height(300);
	
	globalFileURL = dataURL;
	
	if(uploadCroppie){
		$(uploadCroppie).croppie('destroy');
	}
		uploadCroppie = $('#picture_preview_container').croppie({
			//url: dataURL,
		    viewport: {
		        width: 250,
		        height: 250
		    },
		    // enableExif: true,
		    enableOrientation: true,
		    enableZoom: false,
// 					    update: function (data) {
			    
// 	 			            var result = this.result({
// 								type: 'base64',
// 	 	 			        });

// 				        },
//	 			        result: function (data) {
//	 		          	  console.log(data);
//	 		        	},
		});
		$(uploadCroppie).croppie('bind', {
			url: globalFileURL
		});
	$('#rotateleft').show();
	$('#rotateright').show();
	
	
	//$('#picture_input').attr('value', dataURL);
};

image.onerror = function () {
	alert('There was an error processing your file!');
	};
}
spook1's avatar

Moved the script tags in the edit blade up to the header of the layout, Now all javascript errors are solved.

    <script src="{{ url('js/cropimage.js') }}"></script>

has anyone any suggestions how to proceed?

Snapey's avatar

solve or no longer running, therefore not producing errors? Have you checked that jquery is installed?

spook1's avatar

Hi Snapey,

Thank you for staying with me.

All day long I am trying to solve this.

Just checked:

 npm i jquery

up to date, audited 1327 packages in 8s

101 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities 

spook1's avatar

Not sure about jquery etc though..

In my app/js/ directory I see no jquery files.

Neither in my resources/assets/js

Could this be one of the noob-errors where I is a basic thing?

This afternoon I created a new setup based on this tutorial: https://www.webslesson.info/2020/01/laravel-6-crop-upload-image-using-jquery-with-ajax.html

Finally copy-pasted all the files.

Installed croppie to be sure:

 npm install croppie

added 1 package, and audited 1328 packages in 2s
101 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Here also js errors:

 GET http://localhost:8000/css/bootstrap.min.css net::ERR_ABORTED 404 (Not Found)
image_crop:8 GET http://localhost:8000/css/croppie.min.css net::ERR_ABORTED 404 (Not Found)
image_crop:6 GET http://localhost:8000/js/jquery.min.js net::ERR_ABORTED 404 (Not Found)
image_crop:10 GET http://localhost:8000/js/croppie.min.js net::ERR_ABORTED 404 (Not Found)
image_crop:8 GET http://localhost:8000/css/croppie.min.css net::ERR_ABORTED 404 (Not Found)
image_crop:7 GET http://localhost:8000/css/bootstrap.min.css net::ERR_ABORTED 404 (Not Found)
image_crop:49 Uncaught ReferenceError: $ is not defined
    at image_crop:49

Tried npm run production, hoping that would generate croppie.min.js en jquery.min.js....

Did ot help either..

spook1's avatar

downloaded latest jquery cdn and added to pubic/js and resources/app/js/

<script type="text/javascript" src="{{ URL::asset('js/jquery-3.6.0.js') }}"></script>

to the layout header

Still:

cropimage.js:4 Uncaught ReferenceError: $ is not defined
at cropimage.js:4
spook1's avatar

in the end it turned out that the error was that

require(jquery) was commented in bootstrap.js require('/bootstrap'); was commented in app.js

comments that happened during scss and vue explorations...

christinablankenship's avatar

Hi there,

It sounds like you're facing a challenge with the image upload functionality after updating to Laravel 8. While upgrades can bring about improvements, they sometimes introduce new compatibility issues. Let's try to troubleshoot this together.

Firstly, make sure you have updated the necessary dependencies and libraries related to image processing. Since you mentioned no error messages, it might be helpful to check your server logs for any clues. Ensure that your storage permissions are set correctly, allowing the application to save images.

Additionally, Laravel 8 introduced changes to the filesystem configuration, so it's worth confirming that your storage disk configuration aligns with the new specifications.

If the problem persists, you may want to review your code for the image upload process. Double-check the form's enctype attribute to ensure it supports file uploads:

In the backend, ensure your controller is handling the file upload correctly. You might want to check if there are any changes needed in the validation rules or storage methods due to the Laravel 8 upgrade.

As a final suggestion, if you're still encountering issues, consider visiting Laravel's official documentation or community forums for the most up-to-date solutions. It's possible that others have faced similar challenges and can provide valuable insights.

Best of luck with resolving the image upload problem! If you're looking for a user-friendly photo editor, you might want to explore editing your uploaded images with PicsArt. It offers various tools and features to enhance and customize your pictures effortlessly. Give it a try and see if it fits your needs.

Hope this helps, and feel free to share more details if you need further assistance......... www.picsartgeeks.com

Please or to participate in this conversation.