彻底搜索后我没有看到问题 我有一个表单即时提交,它不是一个对象,它只是一个电子邮件形式。我想验证数据。根据文档,替代方法是这样做。
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
$builder
->add('firstName', 'text', array(
'constraints' => new Length(array('min' => 3)),
))
->add('lastName', 'text', array(
'constraints' => array(
new NotBlank(),
new Length(array('min' => 3)),
),
))
;
现在已经完成了,但是我不能以任何形式或形式(双关语)来调用$form->isValid
,因为即使它通过了约束违规,看似不可见的东西仍会导致它返回无效。
我觉得我可能需要首先从帖子中提取表单,并通过isValid()传递,但我无法确定。
继承我的方法代码
/**
* @Route("/share", name="email_share")
* @Method({"POST"})
* @return \Symfony\Component\HttpFoundation\Response
*/
public function shareAction( Request $request, array $lessons){
if(!$lessons || !is_array($lessons))
{
throw new HttpException(404, "Whoops! shareAction didnt get the lessons");
}
//set up our form defaults here
$defaultData = array('comment' => 'Type your comment here');
//build the form here
$form = $this->createFormBuilder($defaultData)
->setAction($this->generateUrl('email_share'))
->add("emails", 'email', array(
'label' => "Recipient's email address (separate with a comma)",
'constraints' => array(
new Length(array('min' => 6, 'max' => 2040)),
new NotBlank(),
),
))
->add('comment', 'textarea', array(
'label' => "Leave a comment",
))
->add('name', 'text', array(
'label' => "Your name",
'constraints' => array(
new Length(array('min' => 3), 'max' => 254)),
new NotBlank(),
),
))
->add('email', 'email', array(
'label' => "Your email address",
'constraints' => array(
new Length(array('min' => 6, 'max' => 254)),
new NotBlank(),
),
))
->add('copy', 'checkbox', array(
'label' => "Send me a copy",
'required' => false,
))
->add('cancel', 'submit', array(
'label' => "Cancel",
))
->add('save', 'submit', array(
'label' => "Email Resources",
))
->getForm();
if ($this->getRequest()->isMethod('POST')) {
//data is already validated by constraints added when the form was created since we are not attaching this particular form to any object
$form->handleRequest($request);
//alternatively (makes no differene from the former)
//$form->submit($request->request->get($form->getName()));
if ($form->isValid())
{
//have YET to see this
echo 'valid';
exit;
}
else{
//echo 'not fuckin valie, WHY?';
//exit;
// get a ConstraintViolationList
$errors = $this->get('validator')->validate( $form );
$result = '';
//nothing returns here when form is valid against constraints, its just empty
echo $errors;
// iterate on it
foreach( $errors as $error )
{
$error->getPropertyPath() : the field that caused the error
$error->getMessage() : the error message
}
}
$data = $form->getData();
return $this->emailUser($data);
}
return $this->render('ResourceBundle:Default:resources.html.twig', array(
'form' => $form->createView(),
));
}
这是我发布数据的方式
function postForm($form, callback) {
/*
* Get all form values
*/
var values = {};
$.each($form.serializeArray(), function (i, field) {
values[field.name] = field.value;
});
/*
* Throw the form values to the server!
*/
$.ajax({
type: 'POST',
url: '/share',
data: values,
success: function (data) {
callback(data);
}
});
}
$(document).ready(function () {
//bind an event to submit on 'email resources' button
$('div#share form').submit(function (e) {
//disable symfonys default submit button hehaviour
e.preventDefault();
postForm($(this), function (response) {
//replace html here
// Is this where im going wrong? Do i need to replace the form here?
});
});
});
编辑:以下是主要模板代码的相关部分,它首先调用操作
<div id="share" class="hidden" >
<h2>Share Resources</h2>
{% render url('email_share') %}
</div>
这里是在shareAction中呈现的表单模板代码(当前是完整的)
{{ form(form) }}
是
{% if form | default %}
{{ form(form) }}
{% endif %}
{% if mail_response | default %}
{{ dump(mail_response) }}
{% endif %}
表单的隐藏令牌输入部分
<input id="form__token" class="form-control" type="hidden" value="8QWLo8xaPZFCKHBJbuc6CGNIcfmpWyT-yFdWScrsiJs" name="form[_token]">
这两个下划线让我有点担忧(form__token)
EDIT2: 问题在于某处的CSRF令牌。它可以是表单输入名称,令牌本身已经过期,或其他东西。
我通过构建我自己的表单模块
来缩小范围 //set up our form defaults here
$defaultData = array('comment' => 'Type your comment here');
$session = new Session();
$secret = '123xyz';
$vendorDir = realpath(__DIR__ . '/../vendor');
$vendorFormDir = $vendorDir . '/symfony/form/Symfony/Component/Form';
$vendorValidatorDir =
$vendorDir . '/symfony/validator/Symfony/Component/Validator';
// create the validator - details will vary
$validator = Validation::createValidator();
$formFactory = Forms::createFormFactoryBuilder()
->addExtension(new HttpFoundationExtension())
//->addExtension(new CsrfExtension(new SessionCsrfProvider($session, $secret)))
->addExtension(new ValidatorExtension($validator))
->getFormFactory();
//build the form here
$form = $formFactory->createBuilder('form', $defaultData)
->setAction($this->generateUrl('email_share'))
->setMethod('POST')
->add("emails", 'email', array(
//......
//same as above for the rest......
表单FINALLY会像这样通过验证,当我取消注释该行时 - &gt; addExtension(new CsrfExtension(new SessionCsrfProvider($ session,$ secret))) 我得到了与之前相同的错误,即CSRF令牌无效。
对我而言,这几乎指向了这个模块中的某个地方,或者我没有调用某些东西,或者正确扩展,或者javascript返回的表单比CSRF模块预期的要早,或者隐藏的令牌形式input的名称不是CSRF模块正在查找的名称。我不太了解symfony的内部故障来诊断这个,这就是我来这里寻求帮助的原因。有人看到了潜在的问题吗?
编辑:3 我觉得我不应该使用isValid(),如上所述,我没有传递一个对象,我传递一个数组。请参阅此网址http://symfony.com/doc/current/book/validation.html#validating-values-and-arrays。我试图弄清楚如何正确检查约束,我认为isValid()毕竟不是去的方式,否则我错过了一些基本的东西..我只是无法想象如果我只检查约束错误,怎么能我仍然使用CSRFprotection,还是只用于对象或东西?我是否需要手动传递此信息,因为我不使用对象?
编辑4: 看起来我可能已经发现问题的关键,但我还无法弄清楚如何解决它。
在此文件上Symfony \ Component \ Form \ Extension \ Csrf \ CsrfProvider \ DefaultCsrfProvider 我放了一些输出来跟踪令牌,似乎令牌正在重新生成以进行比较,这似乎不应该是我希望它会将传递的令牌与内存中的令牌进行比较,但事实上,它被生成两次,一次为表格,然后再次进行比较。
起初我怀疑浏览器和ajax可能是从两个不同的会话运行的,并且可能由于我使用SessionCsrfProvider()
而导致不匹配,但切换到 - &gt; addExtension(新的CsrfExtension(新的DefaultCsrfProvider($ secret)))我遇到了同样的问题。
这是一个错误,我是否疯了,或者我错过了一些简单的形式或形式的形式ID?
下面是代码,以及我从该代码中找到的结果。
//Symfony\Component\Form\Extension\Csrf\CsrfProvider\DefaultCsrfProvider
public function isCsrfTokenValid($intention, $token)
{
echo '<pre>Warning, Symfony\Component\Form\Extension\Csrf\CsrfProvider\isCsrfTokenValid';
echo'<br>, here is out token handed down to compare<br>';
var_dump($token);
echo '<br>the new generated token thats being compared to is<br>';
var_dump($this->generateCsrfToken($intention));
echo '</pre>';
return $token === $this->generateCsrfToken($intention);
}
返回
//表格 array(6){[&#34;电子邮件&#34;] =&gt; string(19)&#34; email@email.net"
[&#34;评价&#34;] =&GT;字符串(2)&#34;哟&#34; [&#34;名称&#34;] =&GT; string(5)&#34; me&#34;
[&#34;电子邮件&#34;] =&GT; string(19)&#34; email@email.net" [&#34;复印&#34;] =&GT;
字符串(1)&#34; 1&#34; [&#34; _token&#34;] =&GT;串(40) &#34; a11e10eb323f7a4d19577e6d07e68be951ceb569&#34; }警告, Symfony \ Component \ Form \ Extension \ Csrf \ CsrfProvider \ isCsrfTokenValid, 这里是令牌传递给比较字符串(40) &#34; a11e10eb323f7a4d19577e6d07e68be951ceb569&#34;
要比较的新生成令牌是字符串(40) &#34; e83cdf94b15e63e822520b62402eb66e0b1f03d3&#34;
The CSRF token is invalid. Please try to resubmit the form.
块引用
编辑5: 问题已经在这里找到了,看看DefaultCsrfProvider中的这段代码
public function generateCsrfToken($intention)
{
return sha1($this->secret.$intention.$this->getSessionId());
}
public function isCsrfTokenValid($intention, $token)
{
return $token === $this->generateCsrfToken($intention);
}
在ajax调用期间,令牌永远不会有效,除非在generateCsrfToken()令牌方法中设置了一个参数,以允许传递会话,您希望通过ajax传递该会话,如此
public function generateCsrfToken($intention, $session)
{
if(!$session)
{
$session = $this->getSessionId()
}
return sha1($this->secret.$intention.$session);
}
我认为首先会完全降低CSRF整体理念的安全性。
是否有另一个提供,我可以在symfony框架内用于ajax调用?如果依赖于sesion,这几乎不会遗漏SessionCsrfProvider类和DefaultCsrfProvider类来处理它,除非我遗漏了一些非常明显的东西......我应该抓住,传递,然后重置ajax调用上的会话? ??
好吧,在我想到这一点之后到目前为止,我刚发现这篇文章Symfony CSRF and Ajax看不清我是否可以从中做出正面或反面。
答案 0 :(得分:2)
要查看错误,您应该呈现该表单。在表单无效的代码中,该方法返回$ this-&gt; emailUser($ data);但它应该呈现形式。试试这个:
if ($this->getRequest()->isMethod('POST')) {
//data is already validated by constraints added when the form was created since we are not attaching this particular form to any object
$form->handleRequest($request);
//alternatively (makes no differene from the former)
//$form->submit($request->request->get($form->getName()));
if ($form->isValid())
{
//have YET to see this
echo 'valid';
//this is the place to process data
//$data = $form->getData();
//return $this->emailUser($data);
exit;
}
}
return $this->render('ResourceBundle:Default:resources.html.twig', array(
'form' => $form->createView(),
));
这应该在提交和显示错误时再次呈现无效表单
你也可以尝试这个
if ($form->isValid())
{
//have YET to see this
echo 'valid';
exit;
}else{
echo '<pre>';
\Doctrine\Common\Util\Debug::dump($form->getErrorsAsString(), 9);
echo '</pre>';
}
如果表单无效,则显示调试样式中的错误。