I am trying to create a simple form that allows a user to upload a profile picture. To avoid having to deal with too much symfony code, I am using picEdit and I embedded the form directly to the appropriate twig template (which links to both picEdit .css and .js files, and jquery). This form is inside a boostrap modal dialog as seen below:
<div class="modal-dialog">
<div class="modal-content animated fadeIn">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<i class="fa fa-upload modal-icon"></i>
<h4 class="modal-title">Profile picture</h4>
<small>Use the options below to upload and edit your profile picture.</small>
</div>
<div class="modal-body" style="text-align: center">
<form action="upload.php" method="post" id="avatarUploadForm" name="avatarUploadForm" enctype="multipart/form-data">
<input type="file" name="avatarImage" id="avatarImage">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-white" data-dismiss="modal">Close</button>
<button type="submit" id="uploadButton" name="uploadButton" class="btn btn-primary">Upload Picture</button>
</form>
</div>
</div>
I also added the following java script function to the template:
<script type="text/javascript">
$(function() {
$('#avatarImage').picEdit();
});
</script>
The form action points to upload.php, shown below (in its simplistic form) and stored in web/upload.php:
<?php
if (isset($_POST['uploadButton'])){
$file = $_FILES['avatarImage']['name'];
move_uploaded_file($file,"/avatars/$file");
}
?>
When I hit the Upload Picture button, I get a success notification as seen below, but the file does not show up in the directory to where it is being sent, and I suspect the upload.php script never really gets triggered. Any suggestions on what I may be doing incorrectly?? *Disclaimer: I'm very new to php/symfony/java script
You are using the wrong key to move. Change upload.php to:
if (isset($_POST['uploadButton'])){
$file = $_FILES['avatarImage']['tmp_name'];
$fileName = $_FILES['avatarImage']['name'];
if(move_uploaded_file($file,"/assets/img/$fileName")){
header('Content-Type','application/json');
echo json_encode(array(
'status' => 'success'
));
}
else{
header('Content-Type','application/json');
echo json_encode(array(
'status' => 'failed'
));
}
}
http://php.net/manual/en/function.move-uploaded-file.php
You should also not rely on the file name of the uploaded file, its a potential for injection. Use some other naming schema or run the name through a scrubber.
Using this particular plugin im also not sure how you plan to tie the image back to the user entity. This plugin seems to only handle upload.
Make sure that you are not getting errors when uploading the file:
$('#image').picEdit({
formSubmitted: function(response){
console.log(response);
}
});
Symfony Approach
Use a form and controller. This will give you access to a lot more and save you a step in updating the users profile image.
We are going to make a few assumptions. First that only the logged in user will be changing their profile. Second that all directories have the proper permissions. And lastly that you are using annotations for routing
//ProfileController
...
/**
* #Route('/upload-profile-image', name="upload_profile_image")
* #Method({"POST"})
*/
public function uploadProfilePictureAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository('UserBundle:User')->findOneById($this->getUser()->getId());
$form = $this->createFormBuilder($user)
->add('avatarImage','file')
->getForm();
$form->handleRequest($request);
if($form->isValid()){
$user->upload();
$em->flush();
return new JsonResponse(array(
'status'=>'success'
));
}
return new JsonResponse(array(
'status' => 'failed',
'message' => $form->getErrors(true)
));
}
Then make sure that you have your user entity setup with the proper functions described here: http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html
Then just change your form to:
<form action="{{ path('upload_profile_image') }}" ...>
Related
I want to have a button where a client can view an applicant's document that the candidate has uploaded, but for some reason I cannot figure out why it doesn't work.
It was working fine offline, but I deployed the site via FTP today and It doesn't want to work.
I am less than a junior developer so please be kind about messy code,
Here is my code for
upload blade:
<form action="{{route('cv')}}" method="POST" enctype="multipart/form-data">#csrf
<div class="card">
<div class="card-header">Update CV</div>
<div class="card-body">
<input type="file" class="form-control" name="cv"><br>
<button class="btn btn-success float-right"
type="submit">Update</button>
#if($errors->has('cv'))
<div class="error" style="color: red;">{{$errors->first('cv')}}</div>
#endif
</div>
</div>
Code for route:
Route::post('user/cv','UserController#cv')->name('cv');
Code for Controller:
public function cv(Request $request){
$user_id = auth()->user()->id;
$cv = $request->file('cv')->store(public_path('storage/files'));
Profile::where('user_id',$user_id)->update(['cv'=>$request->file('cv')->getClientOriginalName()]);
return redirect()->back()->with('message', 'CV Successfully Updated!');
}
Code for viewing the CV :
View my CV
When I click the button I get this url:
cvroad.co.za/storage/Kevin%20Breed.pdf
The name of the file is : Kevin Breed.pdf and that is how it is seen in my database aswell.
but still 404 not found?
Any and all help would be appreciated, thank you!
Instead of hard-coding the file path, use Laravel's storage_path() to get to the right path.
$cv = $request->file('cv')->store(storage_path('files'));
Though if you're using Storage::url(), then it's looking in public/storage, so the proper way to go about it might to use the public_path
$cv = $request->file('cv')->store(public_path('storage/files'));
Also when saving to the database, you're saving the full path, not just the name. You can store just the name like this:
Profile::where('user_id',$user_id)->update(['cv'=>$request->file('cv')->getClientOriginalName()]);
I can't seem to get my app to upload a file when submitting a request in my Laravel 5.8 application. No matter what type of file I upload, hasFile() always returns false.
Form
<form action="{{ route('items.store') }}" method="POST" enctype="multipart/form-data">
#csrf
<div class="form-group py-50">
<input type="file" name="featured_img" value="featured_img" id="featured_img">
</div>
<div class="form-group">
<input type="submit" class="btn btn-primary" value="Upload Image" name="submit">
</div>
</form>
Controller
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//Check if image has been uploaded
if($request->hasFile('featured_img')){
return "True!";
} else {
return "False!";
}
}
dd() Output
array:7 [▼
"_token" => "sREFSO8bs0rWil05AESVrwEl37XtKOJAF2nCkTNR"
"status" => "published"
"featured_img" => "example.jpg"
"submit" => "Upload Image"
]
enctype="multipart/form-data" has been included in my form.
I have tested multiple files which are around 50-80 KB in size
I am running another Laravel app in the same environment without any issues. I also tested uploading the same images to that app without any problems. This leads me to believe this has nothing to do with misconfiguration of php.ini
dd($request->all()); returns a string name for "featured_img" instead of file object
UPDATE
While Making changes to my view I did not realize I had two form actions in place with the same route. Stupid me. Thank you for everyone that helped me troubleshoot.
check try some case:
check max file size upload in php.ini
check exist enctype="multipart/form-data" in tag or not.
check method in tag (must use POST method), and route in Web.php must have post route
I tested in one of my installation with
in web.php
use Illuminate\Http\Request;
Route::get('test', function(){
return view('test');
});
Route::post('test', function(Request $request){
dd($request->hasFile('test'));
})->name('test');
in test.blade.php
<form action="{{ route('test') }}" method="POST" enctype="multipart/form-data">
#csrf
<div class="form-group py-50">
<input type="file" name="test" id="featured_img">
</div>
<div class="form-group">
<input type="submit" class="btn btn-primary" value="Upload Image" name="submit">
</div>
</form>
$request->hasFile('test') returns true, please check with this code in your controller or route file and let me know, if you are getting any issue.
Also
You should use #stack to add script to your blade and not #section
Update
According to your updated view page code, you have two form in your view posting to same route check that and first form is not closed and second is open.
I know that this is generally frowned upon, but for my specific reasons which I'll state below, I need this functionality:
So what we're doing on this website is that we are allowing users to buy "stores" on which they can sell products, and now those users want to add stuff like "Facebook Pixel" to their stores to allow them to track different activities.
Here's my form responsible for the code
<form action="{{ url('vendor/store/settings/analytics/update') }}" method="POST" style="margin-top: 30px;">
{{ csrf_field() }}
<div class="analytics-form">
<div class="col-md-8 col-md-offset-2 analytics-box">
<div class="form-group">
<label for="">Please pick a type of analytics to install:</label>
<select name="analytic_type[]" id="" class="form-control">
#foreach($analytic_types as $type)
<option value="{{ $type }}">{{ ucwords(str_replace('_', ' ', $type)) }}</option>
#endforeach
</select>
<br>
</div>
<div class="form-group">
<label for="">Please type/paste the code for this analytic:</label>
<textarea class="form-control" cols="5" rows="5" name="analytic_code[]" required></textarea>
<br>
</div>
</div>
</div>
<button class="btn btn-primary btn-block" id="applyAnalytics" type="submit" {{ $store->vendor->hasAnalytics() ? '' : 'disabled'}}>Apply Changes</button>
</form>
And here's the controller method I want to "hit":
public function updateAnalytics(Request $request)
{
try {
$store = auth()->user()->store;
auth()->user()->analytics()->delete();
if($request->has('analytic_type')) {
foreach($request->analytic_type as $index => $value) {
Analytics::create([
'user_id' => auth()->user()->id,
'analyticable_id' => $store->id,
'analyticable_type' => get_class($store),
'method_type' => $request->analytic_type[$index],
'method_code' => $request->analytic_code[$index],
]);
}
}
flash(__("Common.Saved_Successfully"));
} catch (\Exception $e) {
session()->flash('title', __("Common.Error"));
session()->flash('message', __("Common.An_Error_Happened"));
session()->flash('message-class', "error");
}
return redirect()->back();
}
This method works fine locally if I enter either normal text or code into the textarea, but if I tried to enter & submit the below block of code everything blows up, this block of code is the one provided by Facebook Pixel to its users, which I want to save in my database:
<!-- Facebook Pixel Code -->
<script>
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '339673053324500');
fbq('track', 'PageView');
</script>
<noscript><img height="1" width="1" style="display:none"
src="https://www.facebook.com/tr?id=339673053324500&ev=PageView&noscript=1"
/></noscript>
<!-- End Facebook Pixel Code -->
If I put the above code into the text area and submit the data to the server, I get this error below:
Forbidden
You don't have permission to access /app/public/vendor/store/settings/analytics/update on this server.
Additionally, a 403 Forbidden error was encountered while trying to
use an ErrorDocument to handle the request.
The server isn't even allowing me to hit the route in question, or any other route from this form as long as I am submitting code.
Note:
This is probably not an actual permission issue but a security related thing, because I've tried changing permissions on the server for all of the involved files from 0644 to 0755 and nothing changed, of course I might have done something wrong along the way, all suggestions are welcome.
I'm trying to use Codeigniter's form validation to check if the text input from a modal window is redundant with what's already in the database. I can't seem to get far enough under the hood the Codeigniter's set_rules to see what's happening. I hope one of you code animals can help me.
Ajax sends text to a function in the Controller which picks it up as $value and then in the Controller I want to check if this string is already in a table.field of the DB and if so (not) send $unique=false (true) back to the jQuery. The problem is the set_rules statement always returns true regardless of what's in the DB.
Here's the Controller:
public function change_options()
{
# Receives and sends back user-entered new option and adds it to database
# Get strings from ajax in view
$value = $_POST['new_option'];
$value_class = $_POST['new_option_class'];
//echo $value_class; die;
#Make array to send to model
$value_array = array('Options' => $value);
# Make sure option is unique
$this->load->library('form_validation');
//$this->form_validation->set_rules('Options', 'Option', 'is_unique['.$value_class.'.Options]');
$this->form_validation->set_rules('add-new-submit', 'Option', 'is_unique['.$value_class.'.Options]'); <---- This is always true
if ($this->form_validation->run() == TRUE) // Only add new option if it is unique
{
# Add new option to dropdown in database
$this->load->model('data_model');
$this->data_model->add_option($value_class, $value_array);
$unique = true;
}
else
{
# Send string back to view via ajax
$unique = false;
}
echo json_encode(array($value, $unique));
}
I've tried everything I can think of for the first slot of set_rules: 'Options', 'add-new-text', 'add-new-submit', (each of these last two are names in the modal html) $value_class (which is the id for form element in question). Here's the modal for completeness:
<!-- add-new field -->
<div class="modal small hide fade" id="add-new" tabindex="-1" role="dialog" aria-labelledby="add-new-fieldLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">√ó</button>
<h3 id="add-new-fieldLabel">Add New Field</h3>
</div>
<div class="modal-body">
<p>Would you like to add a new item?</p>
<input type="text" id="add-new-text" name="add-new-text" placeholder="Type the new option">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" id="add-new-submit" name="add-new-submit"/>Add</button>
</div>
</div><!-- /add-new field -->
Anybody see what's going on?
I figured out how to do this and posted the code in AJAX not posting or receiving apparently. No need to use Form Validation!
I'm currently developing a system with Laravel framework. Though, I'm not very familiar with MVC architecture yet.
When I'm developing the system, I come across a problem which relates with this bootstrap modal that has a form in it. I'd like to put functions in it so that it could be submitted to the database.
I have followed several tutorials, but didn't come up with a solution because they're all using pages instead of modals.
So, here is the HTML of the modal:
<div class="modal hide fade" id="linkSettings">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h3>Add New Link</h3>
</div>
<div class="modal-body">
<div class="control-group">
<label class="control-label" for="focusedInput">Add A Link:</label>
<div class="controls">
<textarea class="autogrow"></textarea>
</div>
</div>
</div>
<div class="modal-footer">
Close
Save changes
</div>
</div>
Here is the Javascript of the above modal:
$('.btn-settingLink').click(function(e){
e.preventDefault();
$('#linkSettings').modal('show');
});
Now, how do I put the function in the Controller so that whenever a user presses Save Changes button, it will store the value in <textarea> into the database? Is there anything to do with the Javascript code? and Do I need to use {{Form::open('main/addLink','POST')}} at the form to pass its values to the controller and model?
Basically, all I ever wanted was to have the CRUD functions by using modal.
First you need to create a form with a route....
<form method="post" action="{{URL::to('Link/addlink')}}>
Or like you showed above, with your Blade {{Form}} ...either way
Then your textarea needs an id and name
<textarea id="mytext" name="mytext"></textarea>
So your HTML becomes...
<form method="post" action="{{URL::to('Link/addlink')}}>
<div class="modal-body">
<div class="control-group">
<label class="control-label" for="focusedInput">Add A Link:</label>
<div class="controls">
<textarea id="mytext" name="mytext" class="autogrow"></textarea>
</div>
</div>
</div>
<div class="modal-footer">
Close
<input type="submit" id="submit" name="submit" class="btn btn-primary">Save changes</input>
</div>
</form>
Then in your Link controller...or wherever you're actually sending this form..no idea what your controllers are named :)
public function addlink(){
$input = Input::all();
//whatever validation you wanna do, with error handling etc...not gonna provide that, thats up to you
$yourmodel = New Model;
$yourmodel->text = $input['mytext'];
$yourmodel->save();
Return Redirect::back();
}
EDIT (for Ajax)
Add this script at the bottom of your page...
<script>
$(document).ready(function(){
$('input#submit').click(function(e){
e.preventDefault();
var text = $('#mytext').val();
var url = 'your url' //we were using Link/addlink in the other example
$.ajax({
type: "POST",
url: url,
data: { mytext: text },
success: function(){
//Probably add the code to close your modal box here if successful
$('#linkSettings').hide();
},
});
});
});
</script>
PS Completely untested....you will need some tweaking, plus the fact that your controller has the Redirect will probably make it not work since this will just be expecting an echoed Json string
But these are the nuts and bolts, and the foundation is there for you to continue on your own I would think...