While adding entries to the database I have noticed that they are not escaped. I am returning them via ajax/json response.
So what I am doing (in short) is:
$data = $repo->findById(235)
return $this->json($data);
$('#container').append(response.body)
the problem is that it generates a JS script which shows alerts on my website.
The question is: How to escape it so I could safely append it on my website?
my form:
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('body', TextType::class);
//rest of the data I am setting separately in the entity itself
}
my controller:
$em = $this->getDoctrine();
$js = $this->get('jms_serializer');
$thread = new Thread();
$thread->{'set' . $class}($material);
$thread->setAuthor($this->getUser())
->setAuthorName($this->getUser()->getUsername())
->setLastCommentAt(new \DateTime())
->setNumComments(0);
$threadForm = $this->createForm(ThreadType::class, $thread);
$threadForm->submit($request->request->all());
if ($threadForm->isValid()) {
try {
$this->getEntityManager()->persist($thread);
$this->getEntityManager()->flush();
return new JsonResponse($js->serialize($thread, 'json'), 200, [], true);
} catch (\Exception $ex) {
return $this->json([$ex->getMessage()], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
There are multiple ways you could approach this.
Form DataTransformer
You could add a DataTransformer to the form that encodes the input and decodes it in the form field. For that you could use a ViewTransformer:
$builder
->add('body', TextType::class)
->addViewTransformer(new CallbackTransformer(
function ($encodedBody) {
return html_entity_decode($encodedBody);
},
function ($decodedBody) {
return htmlentities($decodedBody);
}
));
I'm not 100% sure about the order, but this way you could handle encoded strings in your application (e.g. "&lgt;script") and your user still sees the decoded string they entered ("
If you want to keep storing the unescaped strings in the database you could write a custom DBAL-type that will escape, e.g. using htmlentities()
when you retrieve the data and decodes whenever you persist data. Whenever your entity contains a text-type that contains data from a user you can mark it as your secured text-type and it will automatically be en-/decoded. This probably makes most sense when you use it with the data transformer in the form.
Dealing with a safe string might now be a bit problematic in the templates as twig autoescapes by default and that might break things, so you end up disabling it, which might not be what you want. Instead you might want touse a JMS Serializer for JSON-serialization and hook up a Handler that pretty much does the same transformation as above (only in one direction). This will only affect your JSON-output to the AJAX call which might be better suited to your needs. If you want to use Symfony's own Serializer you could achieve similar results using a callback on the object's property.
Yesterday I have 'thinking off' mode ;-)
just achive it like this:
/**
* Set body
*
* @param string $body
*
* @return Thread
*/
public function setBody($body)
{
$this->body = htmlspecialchars($body);
return $this;
}