Symfony 3 : password validation - symfony

I use this code to validate user password :
$encoderService = $this->container->get('security.password_encoder');
$match = $encoderService->isPasswordValid($user, $request->query->get('password'));
but it always returns 'false' even the password is correct

You're using the password encoder in the wrong way... Check Symfony doc on security
Here is an example on how to use it.
app/config/security.yml
security:
encoders:
AppBundle\Entity\Security:
algorithm: bcrypt
src/AppBundle/Controller/SecurityController.php
class SecurityController extends Controller {
private $tokenManager;
private $encoder;
public function __construct(CsrfTokenManagerInterface $tokenManager=null, UserPasswordEncoderInterface $encoder) {
$this->tokenManager=$tokenManager;
$this->encoder=$encoder;
}
**[...]**
public function editAction(Security $user) {
if($user->getOldPassword() !== null && $user->getPlainPassword() !== null && $this->encoder->isPasswordValid($user, $user->getOldPassword())) {
$user->setPassword($this->encoder->encodePassword($user, $user->getPlainPassword()));
$em->flush();
}
}
}
Form view
<form action="{{ form.vars.action }}" method="{{ form.vars.method }}" onsubmit="event.preventDefault(); ajaxSubmit($(this));">
<div class="form-section-title">Change password</div>
<div class="form-col-2">
<div class="input-field">
{{ form_label(form.oldPassword, 'Current password') }}
{{ form_widget(form.oldPassword, { 'attr': {'autocomplete': 'off' }}) }}
</div>
<div class="input-field">
</div>
</div>
<div class="form-col-2">
<div class="input-field">
{{ form_label(form.plainPassword.first, 'New password') }}
{{ form_widget(form.plainPassword.first, { 'attr': {'autocomplete': 'off' }}) }}
</div>
<div class="input-field">
{{ form_label(form.plainPassword.second, 'Repeat new password) }}
{{ form_widget(form.plainPassword.second, { 'attr': {'autocomplete': 'off' }}) }}
</div>
</div>
<input name="{{ form._token.vars.full_name }}" type="hidden" value="{{ form._token.vars.value }}">
<div class="input-field submit-container">
<button class="waves-effect waves-light btn btn-2 close_action">Annuler</button>
<button class="waves-effect waves-light btn btn-1" type="submit">Valider</button>
</div>
</form>
Javascript submit function
function ajaxSubmit(node) {
$.ajax({
type: node.attr("method"),
url: node.attr("action"),
enctype: 'multipart/form-data',
data: new FormData(node[0]),
processData: false,
contentType: false,
cache: false
}).done(function(response, status, xhr) {
//Your code here
}).fail(function(request, status, error) {
console.error(request);
console.error(status);
console.error(error);
});
}
Side note: Should be obvious, but you should use POST and not GET with your AJAX query.
First because GET parameters are as clear as day... It's quite dangerous for a password to be changed like that.
Second because, as soon as your site will be in HTTPS, your POST parameters will be encrypted. Making it really hard to read the content for anyone sniffing around.
And last, avoid to post code in comments, edit your question instead... ;)

Related

Empty $request->files (FileBag) when using a custom form (not the built in Type from SF)

I'm having issues with file uploads... I'm adding manually a few inputs within a Symfony form (Offer) to allow the user to create a new Company if he doesn't want to use one that already exists, it works very well for the text/textarea fields, but my file Input doesn't work properly. Its content appears in the request parameters instead of in the files parameters of my Request, see below what I get when I dump($request) :
OfferController.php on line 173:
Request {#86 ▼
+attributes: ParameterBag {#70 ▶}
+request: ParameterBag {#69 ▼
#parameters: array:2 [▼
"offer" => array:15 [▶]
"company" => array:6 [▼
"name" => "entreprise"
"pic_logo" => "ah.png" //THIS SHOULD NOT BE HERE BUT IN THE FILEBAG
"sector" => "2"
"status" => "fdsfds"
"revenues" => "sdfsdf"
"content" => "<p>sdfdsf</p>\r\n"
]
]
}
+query: ParameterBag {#49 ▶}
+server: ServerBag {#73 ▶}
+files: FileBag {#63 ▼
#parameters: [] //NO FILE HERE :'(
}
Here is the code that produces this :
View :
{{ form_start(form) }}
<h2>Employeur</h2>
{{ form_row(form.company) }}
<a class="company-new" href="#" id="toggleCompanyForm">Ajouter une nouvelle entreprise...</a>
<div id="form_company" style="display:none">
<div class="row">
<div class="large-6 small-12">
<label>Nom de l'entreprise</label>
<input type="text" name="company[name]">
</div>
<div class="large-6 small-12">
<label>Logo de l'entreprise</label>
{% for message in app.session.flashBag.get('warning_logo') %}
<div class="alert alert-warning">
{{ message }}
</div>
{% endfor %}
<input type="file" name="company[pic_logo]"> {# MY FILE INPUT #}
</div>
And the controller :
public function createAction(Request $request)
{
$confirmed = false;
$entity = new Offer();
$em = $this->getDoctrine()->getManager();
$sectors = $em->getRepository('ModelBundle:Sector')->findAll();
$form = $this->createForm('ModelBundle\Form\OfferType', $entity);
$session = $request->getSession();
die(dump($request));
To upload a file through HTML form you have to add enctype="multipart/form-data" to the tag:
<form action="..." method="post" enctype="multipart/form-data">
Or change opening form tag in twig:
{{ form_start(form, {'multipart': true}) }}

OneupUploaderBundle and jQuery-File-Upload on symfony 2

I've been trying this but I'm confused since I'm new to Symfony Events and stuff.
This is where I've got so far:
composer bundle installation
AppKernel.php, routing.yml, services.yml, config.yml, UploadListener.php file modifications
And it works, the file I put is actually being uploaded to the folder, and I got the status bar filling... but I need something else:
somehow I need to post (and read) an item id (integer) along with the file (or to be able to set the filename when the file is being copied to the output folder)
if something goes wrong with the upload, how do I send an error message back?
In the example (jQuery-File-Uploader), the code returns the filename of the file that was uploaded, my code doesn't do that, I mean the code is there, but it doesn't work
I'm posting the code I have.
HTML code (here is the piece where I call the jQuery-File-Upload
<tr>
<td>{{ clienteCorporativo.nombreComercial|upper }}</td>
<td>{% if clienteCorporativo.afiliadosUploads|length == 0 %}Nunca{% else %}{{ (clienteCorporativo.afiliadosUploads|last).fecha|date('d/mmm/y') }}{% endif %}</td>
<td>
{% if clienteCorporativo.formatoExcelAfiliados == null %}
<span class="btn btn-success fileinput-button">
<i class="glyphicon glyphicon-upload"></i>
<span>Seleccionar Excel</span>
<input id="fileupload_{{ clienteCorporativo.id }}" class="fileupload" data-id="{{ clienteCorporativo.id }}" type="file" name="files[]" multiple>
</span>
{#<span style="color: #8c8c8c"><span class="glyphicon glyphicon-upload"></span> Seleccionar Excel </span>#}
{% else %}
<input id="fileupload_{{ clienteCorporativo.id }}" class="fileupload" type="file" name="files[]" data-url="{{ oneup_uploader_endpoint('gallery') }}" />
{#<a role="button" data-toggle="modal" data-target="#myModal" data-operation="loadOne" data-id="{{ clienteCorporativo.id }}"><span class="glyphicon glyphicon-upload"></span> Seleccionar Excel</a> #}
{% endif %}
<a role="button" data-toggle="modal" data-target="#myModal" data-operation="defineFormat" data-id="{{ clienteCorporativo.id }}"><span class="glyphicon glyphicon-list-alt"></span> Definir Formato</a>
{% if clienteCorporativo.afiliadosUploads|length == 0 %}
<span style="color: #8c8c8c"><span class="glyphicon glyphicon-repeat"></span> Revertir Última Carga </span>
{% else %}
<a role="button" data-toggle="modal" data-target="#myModal" data-operation="undoLast" data-id="{{ clienteCorporativo.id }}"><span class="glyphicon glyphicon-repeat"></span> Revertir Última Carga</a>
{% endif %}
</td>
<td>
<div id="progress_{{ clienteCorporativo.id }}" class="progress text-center">
<div class="progress-bar progress-bar-success">
<span id="files_{{ clienteCorporativo.id }}"></span>
</div>
</div>
</td>
</tr>
js script (the "each" sentence does nothing)
<script>
/*jslint unparam: true */
/*global window, $ */
var idFile = 0;
$(function () {
'use strict';
// Change this to the location of your server-side upload handler:
$('.fileupload').fileupload({
url: '{{ oneup_uploader_endpoint('xlsfile') }}',
dataType: 'json',
done: function (e, data) {
var eventTrigger = $(this)
idFile = eventTrigger.data('id')
$.each(data.result.files, function (index, file) {
$('#files_'+idFile).html(file.name);
});
},
progressall: function (e, data) {
var eventTrigger = $(this)
idFile = eventTrigger.data('id')
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#progress_'+idFile+' .progress-bar').css(
'width',
progress + '%'
);
},
formData: [ {"id":idFile} ]
}).prop('disabled', !$.support.fileInput)
.parent().addClass($.support.fileInput ? undefined : 'disabled');
//
});
</script>
The other files (AppKernel.php, routing.yml, services.yml, config.yml, UploadListener.php) are just like the OneupUploaderBundle documentation says (I've changed things and then rolled back since I didn't got the results I expected). I think I chew more that I could swallow on this one...
Your form fields will be posted with the file upload. Or you can use the form_data: {} option in your $('#myFile').fileUploader() constructor. But it will submit your form fields by default and you can handle those in the usual way.
$('#myFile').fileupload({
dataType: 'json',
formData: {
'file_id': 1
},
You have to craft your own return response in your UploadListener. Then parse the results on the front-end (Javascript).
$response = $event->getResponse();
$response['success'] = true;
$response['files'] = [
'file' => [
'name' => $event->getFile()->getPathname()
]
];
return $response;

Get selected option and all request data in twig form

I have this form in twig, and I want to get the selected option and the value of the input field from a simple html form:
(PS: Don't say 'You'd better generate a form using the controller!' I know that, but I have a reason why I want to create a form in twig: because that allows me to create as many forms as I want using a for loop.)
I tried to pass arguments in the action path, but that didn't work.
<form action="{{ path('changeProf') }}" method="post" id="form">
<section class="col-lg-9 col-md-9 col-sm-9 col-xs-9" style="position: relative; left: 35%;top: 6vmin">
<label style="display:inline-table;">
<span> <input type="text" value="{{ user.id }}" disabled="true" id="iduser"style="max-width: 18vmin;"/></span>
</label>
</section>
<section class="col-lg-9 col-md-9 col-sm-9 col-xs-9"style="position: relative; left: 35%;top: 6vmin">
<label style="display:inline-table;">
<span>{% set k=1 %}
<select id="profil">
{% for prof in profArr %}
<option value="{{ prof }}"> {{ prof }} </option>
{% endfor %}
</select>
</span>
</label>
</section>
<input type="submit" class="btn btn-info btn-xs" style="position: relative;top:18vmin;left:-28%">
</form>
This is the action that handles the form :
/**
* #Route("/profile/chProf",name="changeProf")
* Method ("POST")
* #Template()
*/
public function changeProfAction(Request $request)
{
$session = new Session();
$session->start();
$search = $session->get('user');
$gestAcces = $session->get('acces');
$gestEtat = $session->get('etatUser');
$gestCont = $session->get('contenu');
$repMsg = $session->get('repMsg');
$gestRec = $session->get('Reclam');
$gestMess = $session->get('gestMess');
$gestMp = $session->get('gestMp');
if ($search == Null) {
return $this->redirectToRoute('empty', array('search' => $search,
'contenu' => $gestCont,
'gestAcces' => $gestAcces,
'gestEtat' => $gestEtat,
'repMsg' => $repMsg,
'gestRec' => $gestRec,
'gestMess' => $gestMess,
'gestMp' => $gestMp,
));
}
$em = $this
->getDoctrine()
->getManager();
$reposit = $em->getRepository("CNAMCMSBundle:userprof");
$rep = $em->getRepository("CNAMCMSBundle:profil");
$userprof=new userprof();
$libprof=$request->request->get('profil');
$iduser=$request->request->get('iduser');
$idprof=$rep->findOneBy(array('libelle'=>$libprof));
$userprof->setIdUser($iduser);
$userprof->setIdProfil($idprof);
$em->persist($userprof);
$em->flush();
return $this->render('CNAMCMSBundle:Default:userProf.html.twig', array(
'search'=>$search,
'contenu'=>$gestCont,
'gestAcces'=>$gestAcces,
'gestEtat'=>$gestEtat,
'repMsg'=>$repMsg,
'gestRec'=>$gestRec,
'gestMess'=>$gestMess,
'gestMp'=>$gestMp,
));
}
I think I found out what caused the error you receive.
$request->request->get('profil'); returns NULL.
This means, the form did not send a profil entry.
Look where is the profil in the form:
<input type="text" value="{{ user.id }}" disabled="true" id="iduser"style="max-width: 18vmin;"/>
There is no name attribute! Which is actually what is sent with the request. The name attribute, not the id. The id is used only for local styles and javascripts.
The solution:
<input type="text" value="{{ user.id }}" disabled="true" id="iduser" name="iduser" style="max-width: 18vmin;"/>
Do the same for profil
Hope this helps.

Symfony2 - Display data on same page

I am having a little trouble displaying data on the same page again. I have a simple view
{% block main %}
<div class="col-md-4">
<section class="panel panel-default">
<div class="panel-body">
<form action="{{ path('NickAlertBundle_tsubmit') }}" method="post" enctype="multipart/form-data" class="terminalForm" id="terminalForm">
<div class="row">
<div class="col-md-12">
<input type="text" class="addMargin" id="terminal_command" name="terminal_command" placeholder=">">
</div>
</div>
<div class="row">
<div class="col-md-8 col-md-offset-4">
<input type="submit" class="btn btn-default" id="terminal_submit" value="Submit">
</div>
</div>
</form>
</div>
</section>
</div>
<div class="col-md-8" id="terminal-window">
</div>
{% endblock %}
So on that view I display a form. The user enters some data and then I want the response display in the terminal-window div. So I have set up routes
NickAlertBundle_terminal:
pattern: /terminal
defaults: { _controller: NickAlertBundle:Alert:terminal }
methods: [GET]
NickAlertBundle_tsubmit:
pattern: /terminal
defaults: { _controller: NickAlertBundle:Alert:tcreate }
methods: [POST]
The GET simply renders the initial page, the POST controller is doing
public function terminalAction()
{
return $this->render('NickAlertBundle:Page:terminal.html.twig');
}
public function tcreateAction(Request $request)
{
try {
$terminal_command = strtoupper($request->get('terminal_command'));
$uapiService = $this->container->get('alert_bundle.api_service');
$commandData = $uapiService->terminalService($terminal_command);
return $this->render('NickAlertBundle:Page:terminal.html.twig', array(
'data' => $commandData,
));
}catch (Exception $e) {
}
}
Is this the correct way to do it? Reason I ask is because if I add the following to my div in the view
{% for d in data %}
{{ d }}
{% endfor %}
I obviously get the following error
Variable "data" does not exist in...
So how can I render the data that is returned from the form submission?
Thanks
This is because Twig expects data to be passed to the template the first time the page is rendered (which is handled by the initial GET controller). To remedy the issue, you need to check to determine if data has been defined.
I would do something like this:
{% if data is defined %}
{% for d in data %}
{{ d }}
{% endfor %}
{% endif %}
Now, when the form initially loads but is empty, Twig first checks to see if the variables was passed to it, and since it doesn't, it just skips the for loop altogether.
The other option would be to simply pass an empty array in your first controller. I would view it as less desirable unless you are persisting data and at that point it would be practical anyway.

Form not valid in Symfony2

I am trying to process a form in Symfony2, I get all the values from it in the controller, but when I call:
$form->isValid()
it returns false. I am trying to process the form in a different Controller.
The form is rendered in two pieces, first some personal data and then some more information, but in the submit event of the form, I join all values serializing the forms. This is how I render the form in the view:
<form id="myform" action="{{ path('_process_my_form') }}" {{ form_enctype(form) }} method="POST">
{{ form_errors(form) }}
{{ form_widget(form._token) }}
{{ form_widget(form.first_name, {'attr': {'class': 'form-control'}} ) }}
... // then I render the rest of the personal information widgets
<button type="submit" class="btn btn-info btn-block">Submit</button>
</form>
<form id="myform2">
{{ form_widget(form.job_name, {'attr': {'class': 'form-control'}} ) }}
... // then I render the rest of the widgets (not personal information)
</form>
Then, in the Ajax request, I join the two forms like this:
$("#my_form").submit(function(e) {
e.preventDefault();
$.ajax({
type: e.target.method,
url: e.target.action,
data: $("#my_form").serialize() + $("#my_form2").serialize(),
beforeSend: function( xhr ) {},
success: function(data) {
//do something...
}
});
});
My _process_my_form rule looks like this:
_process_my_form:
pattern: /ajax/process-my-form
defaults: { _controller: MyBundle:User:processMyForm }
This is the Controller who controls the Ajax request:
public function processMyFormAction(Request $request)
{
if ($request->isMethod('POST'))
{
$myEntity = new myEntity();
$form = $this->container->get('form.factory')->create(new myFormType(), $myEntity);
$form->bind($request);
if ($form->isValid())
{
//Process the form... this code is never excecuted :(
}
}
}
Am I doing something wrong???
Thanks!!!
As of Symfony 2.3 I believe they changed the form handle from
$form->bind($request);
to
$form->handleRequest($request);
However I'm not sure if the former is still supported? As far as I can see, the bind method not longer exists in the Form Interface
You can read more here Symfony Cookbook - Form Direct Submit

Resources