2014-03-30 71 views
1

我一直在尝试提交一个表单,它将一个Question对象添加到数据库中。表单提交出错:CSRF令牌无效。请尝试重新提交表格

但每次我这样做,错误“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 
     ); 
    } 

我做了一个数据转换器用于其原来的输入标签为标签的对象我的标签字段。

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; 
     } 
    }); 
}); 

回答

5

你错过了

{{ form_rest(form) }} 

Symfony2中有一种机制,有助于防止跨站点脚本:它们产生具有用于表单验证一个CSRF令牌。在这里,在你的例子中,你不显示(所以不提交)form_rest(form)。基本上form_rest(form)将“渲染”你以前没有渲染过但包含在你传递给视图的表单对象中的每个字段。 CSRF令牌就是其中的一个值。

+0

嘿,这工作。谢谢! – schizoskmrkxx

+0

不客气:) – DonCallisto

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. 
相关问题