表单提交时出错:CSRF令牌无效。请尝试重新提交表单

时间:2014-03-30 07:07:33

标签: forms twitter-bootstrap symfony tag-it pagedown

我一直在尝试提交一个将问题对象添加到数据库中的表单。

但每次我这样做,错误“CSRF令牌无效。请尝试重新提交表单”显示。

在我的表单内容字段中,我附加了this插件,这是一个与Stack Overflow相同的编辑器。

在我的表单标记字段中,我附加了this一个用于标记自动完成。

这是我的控制器代码:

/**
 * Creates a new Question entity.
 *
 * @Route("/ask", name="question_create")
 * @Method("POST")
 * @Template("VerySoftAskMeBundle:Question:ask.html.twig")
 */
public function createAction(Request $request) {
    $entity = new Question();
    $form = $this->createCreateForm($entity);
    $tags = $this->getDoctrine()->getRepository('VerySoftAskMeBundle:Tag')->findAll();
    date_default_timezone_set('Asia/Manila');
    $entity->setDateOfPost(new \DateTime());

    $entity->setOwner($this->getUser());

        $form->handleRequest($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($entity);
            $em->flush();

            return $this->redirect($this->generateUrl('question_show', array('id' => $entity->getId())));
        }


    return array(
        'entity' => $entity,
        'form' => $form->createView(),
        'tags' => $tags
    );
}

/**
 * Creates a form to create a Question entity.
 *
 * @param Question $entity The entity
 *
 * @return Form The form
 */
private function createCreateForm(Question $entity) {
    $form = $this->createForm(new QuestionType(), $entity, array(
        'action' => $this->generateUrl('question_create'),
        'method' => 'POST',
        'em' => $this->getDoctrine()->getEntityManager()
    ));

    $form->add('submit', 'submit', array('label' => 'Ask'));

    return $form;
}

/**
     * 
     * @Route("/ask", name="ask")
     * @Security( "has_role( 'ROLE_USER' )" )
     * @Method("GET")
     * @Template
     */
    public function askAction() {

        $tags = $this->getDoctrine()->getRepository('VerySoftAskMeBundle:Tag')->findAll();
        $entity = new Question();
        $form = $this->createCreateForm($entity);

        return array(
            'entity' => $entity,
            'form' => $form->createView(),
            'tags' => $tags
        );
    }

我为我的标记字段创建了一个Data Transformer,它将输入标记转换为标记对象。

class TagTransFormer implements DataTransformerInterface {

/**
 * @var ObjectManager
 */
private $om;

/**
 * @param ObjectManager $om
 */
public function __construct(ObjectManager $om) {
    $this->om = $om;
}

/**
 * Transforms an object (issue) to a string (number).
 *
 * @return ArrayCollection
 */
public function transform($tags) {

    return $tags;
}

/**
 * Transforms a string (number) to an object (issue).
 *
 * @param  string $number
 *
 * @return ArrayCollection
 *
 * @throws TransformationFailedException if object (issue) is not found.
 */
public function reverseTransform($ids) {

    $tags = array();

    if (!$ids) {
        return null;
    }

    $repo = $this->om
            ->getRepository('VerySoftAskMeBundle:Tag');

    $idsArray = explode(",", $ids);
    foreach ($idsArray as $id) {
        $tags[] = $repo->findOneByName($id);
    }
    return $tags;
}
}

这是我的表单类:

class QuestionType extends AbstractType {

/**
 * @param FormBuilderInterface $builder
 * @param array $options
 */
public function buildForm(FormBuilderInterface $builder, array $options) {

    $entityManager = $options['em'];
    $transformer = new TagTransFormer($entityManager);

    $builder
            ->add('title', 'text')
            ->add('content', 'textarea')
            ->add($builder->create('tags', 'text')
                    ->addModelTransformer($transformer)
    );
}

/**
 * @param OptionsResolverInterface $resolver
 */
public function setDefaultOptions(OptionsResolverInterface $resolver) {
    $resolver->setDefaults(array(
                'data_class' => 'VerySoft\AskMeBundle\Entity\Question'
            ))
            ->setRequired(array(
                'em',
            ))
            ->setAllowedTypes(array(
                'em' => 'Doctrine\Common\Persistence\ObjectManager',
    ));
}

/**
 * @return string
 */
public function getName() {
    return 'verysoft_askmebundle_question';
}
}

我的树枝模板:

<div id="askDiv" style="padding-bottom: 90px;">
        {{ form_start(form, { 'attr' : { 'novalidate' : 'novalidate', 'class' : 'col-md-offset-3 form-control-static col-md-7' } }) }}
<div class="col-lg-12" style="padding: 0px; margin-bottom: 30px;">
    <span class="askLabels col-lg-1 text-left">{{ form_label(form.title) }}</span>
            {{form_widget(form.title, { 'attr' : { 'class' : 'form-control col-lg-11' } })}}
</div>
        {{ form_widget(form.content, { 'attr' : { 'class' : 'col-lg-12' } }) }}
<div class="col-lg-12" style="padding: 0px; margin-top: 20px;">
    <label class="col-lg-1 text-left askLabels" for="tagField">Tags</label>

    <div class="col-lg-8">
        {{ form_widget(form.tags) }}
    </div>
    {% if app.user.reputation >= 100 %}
    <a id="addTag" title="Add New Tag" data-toggle="tooltip modal" data-placement="left" class="col-lg-3" href="#"><i class="fa fa-plus-circle"></i></a>
    <div id="mymodal" class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                    <h4 class="modal-title" id="myModalLabel">Add New Tag</h4>
                </div>
                <div class="modal-body">
                    <label for="tagName">Tag Name: </label>
                    <input id="tagName" class="form-control" type="text"/>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                    <button type="button" class="btn btn-primary">Add Tag</button>
                </div>
            </div>
        </div>
    </div>

    {% endif %}


</div>
<div style="margin-top: 20px; ">
        {{ form_widget(form.submit, { 'attr' : { 'class' : 'col-md-offset-4 col-md-4  btn btn-primary' } }) }}
</div>

<p>
    title error{{ form_errors(form.title) }}
</p>
<p>
    content error{{ form_errors(form.content) }}
</p>
<p>
    tag error{{ form_errors(form.tags) }}
</p>
<p>
    form error{{ form_errors(form) }}
</p>

脚本:

$(document).ready(function(){
$("textarea").pagedownBootstrap();

    var zeTags = ["{{ tags|join('", "')|raw }}"];
    $('#verysoft_askmebundle_question_tags').tagit({
        availableTags: zeTags,
        tagLimit: 5,
        beforeTagAdded: function(event, ui) {
            if ($.inArray(ui.tagLabel, zeTags) == -1)
                return false;
        }
    });
});

2 个答案:

答案 0 :(得分:5)

你错过了

{{ form_rest(form) }}

Symfony2有一种机制可以帮助防止跨站点脚本:它们生成一个必须用于表单验证的CSRF令牌。在您的示例中,您不会使用form_rest(form)显示(因此不提交)它。基本上form_rest(form)将&#34;渲染&#34;您之前未呈现的每个字段,但它包含在您传递给视图的表单对象中。 CSRF令牌是其中一个值。

答案 1 :(得分:3)

对于较新版本的Symonfy,例如2.4+您将使用较新的form_end(form),它会自动呈现所有未呈现的字段以及CSRF令牌。

根据documentation

form_end() - Renders the end tag of the form and any fields that have not yet been rendered. This is useful for rendering hidden fields and taking advantage of the automatic CSRF Protection.