How can I properly sanitize integer fields in Symfony2 forms?

时间:2015-07-31 19:23:57

标签: php symfony

Under perfect circumstances, a user submits only numbers - no commas, periods, or letters. This is fine for Chrome because Chrome doesn't allow these characters in an integer input. But what about browsers that don't prevent this? If a user decides to put a comma in, Symfony gets unexpected results.

Example of a good input: enter image description here

Example of a bad input: enter image description here

public function Debug4Action(Request $request){

        $inquiry = new Inquiry();

        $form = $this->createFormBuilder($inquiry)
            ->add('revenueMin', 'integer');

        $form = $form->getForm();

        $form->handleRequest($request);

        if ($form->isValid()) {
            var_dump($form->getData()->getRevenueMin());
            return new Response('');
        }

        return $this->render('render_form.html.twig', array(
            'form' => $form->createView(),
        ));
    }

When a user submits the bad input into this var_dump($form->getData()->getRevenueMin()); outputs NULL.

The Symfony docs describe a process of transforming data after submission by using the addModalTransformer() method. This seems like it would be a perfect fit for this use case. I have tried to manually scrub out any non numeric characters and continue processing the input.

public function Debug5Action(Request $request){

        $inquiry = new Inquiry();

        $form = $this->createFormBuilder($inquiry)
            ->add('revenueMin', 'integer');

        /*
         * Symfony2 docs recommend using a this to transform the data into something usable.
         * More info: http://symfony.com/doc/current/cookbook/form/data_transformers.html
         */
        $form->get('revenueMin')->addModelTransformer(new CallbackTransformer(
            function($originalInput){
                //As far as I know, this isn't relevant, but CallbackTransformer requires two anonymous functions.
                return $originalInput;
            },
            function($submittedValue){
                //I don't know if this works on integers - but let's see what happens.
                $submittedValue = preg_replace("/[^0-9]/", "", $submittedValue);
                return $submittedValue;
            }
        ));

        $form = $form->getForm();

        $form->handleRequest($request);

        if ($form->isValid()) {
            var_dump($form->getData()->getRevenueMin());
            return new Response('');
        }

        return $this->render('render_form.html.twig', array(
            'form' => $form->createView(),
        ));
    }

However, now we get slightly different results. var_dump($form->getData()->getRevenueMin()); now outputs an empty string. I would guess that this occurs because preg_replace() returns an empty sting with being used on NULL.

The final attempt changes the field type to a text input.

 public function Debug6Action(Request $request){

        $inquiry = new Inquiry();

        $form = $this->createFormBuilder($inquiry)
            //Notice that the form input is now text.
            ->add('revenueMin', 'text');

        $form->get('revenueMin')->addModelTransformer(new CallbackTransformer(
            function($originalInput){
                return $originalInput;
            },
            function($submittedValue){
                $submittedValue = preg_replace("/[^0-9]/", "", $submittedValue);
                //Cast the string into an int for processing.
                return (integer) $submittedValue;
            }
        ));

        $form = $form->getForm();

        $form->handleRequest($request);

        if ($form->isValid()) {
            var_dump($form->getData()->getRevenueMin());
            return new Response('');
        }

        return $this->render('render_form.html.twig', array(
            'form' => $form->createView(),
        ));
    }

This last attempt returns exactly what I need to process the submission! var_dump($form->getData()->getRevenueMin()); outputs int(1234). However, because I've rendered the form as text instead of integer, I am missing out on some of the HTML5 form elements that would have been built had I built the form with an integer type.

How can I display an integer form input to users but continue to get sanitized integers to process?

1 个答案:

答案 0 :(得分:1)

Upon further research it looks like some browsers (I'm working with Safari) will not send anything in a field if the input requires an integer value and an integer is not provided.

Consider the following code:

<!--test.html-->
<form name="form" method="post" action="test2.php">
    <label>revenueMin</label>
    <input type="number" id="form_revenueMin" name="form[revenueMin]"/><br />
    <input type="submit" />
</form>

<?php
    //test2.php
    var_dump($_POST);
?>

Inputting 1,234 results in:

array(1) { ["form"]=> array(1) { ["revenueMin"]=> string(0) "" } }

Inputting 1234 results in:

array(1) { ["form"]=> array(1) { ["revenueMin"]=> string(4) "1234" } }

Because this is a browser issue and not a Symfony issue, the only solution is the third solution provided in the question.

Also worth noting, the second input still gets sent as a string, so casting it as an integer manually is still required.