Zend解码表单输入元素中的html实体会导致空值

Tom*_*Tom 2 php forms encoding zend-framework zend-form

我有一个表单元素,称为metaDescription:

        //inside the form
        $description = $this    -> createElement('text', 'metaDescription')
                                -> setLabel('Description:')
                                -> setRequired(false)
                                -> addFilter('StringTrim')
                                -> addValidator('StringLength', array(0, 300))
                                -> addErrorMessage('Invalid description.');               
        $this->addElement($description);
Run Code Online (Sandbox Code Playgroud)

无论何时加载此表单,我都会使用从数据库中提取的默认值对其进行初始化:

$form->setDefault('metaDescription', $oldPage->getMetaDescription());
Run Code Online (Sandbox Code Playgroud)

这完全没问题.

但是,htmlencode当有人发送表单和html_entity_decode从数据库中提取的默认值时,我现在想要任何输入描述,以便字符再次以其原始形状显示.

我在处理表单输入时这样做:

//handle post
        if ($request->isPost()) {
            if ($form->isValid($request->getPost())) {
                $page = new Application_Model_PagePainter(array(
                    'metaDescription'   => htmlentities($form->getValue('metaDescription'))
                ));
                $pageMapper->save($page);

                ....
Run Code Online (Sandbox Code Playgroud)

我现在设置默认值,如下所示:

$form->setDefault('metaDescription', html_entity_decode($oldPage->getMetaDescription()));
Run Code Online (Sandbox Code Playgroud)

起初,这似乎也很好.当我发送例如woord1, woord2, me&you描述时,这正确地保存woord1, woord2, me&amp;you在数据库中并再次正确显示为woord1, woord2, me&you.但是,当我设置一个像ó这样的奇怪角色时,例如.wóórd1这被正确地保存在数据库中,w&oacute;&oacute;rd1但随后发生了一些奇怪的事情:当再次显示表单时,默认值为空.当我看到来源时,它确实是空的:<input type="text" name="metaDescription" id="metaDescription" value="" />.

这会让我相信由于某种原因html_entity_decode($oldPage->getMetaKeywords())返回一个空字符串.但是,当我回显它时它返回正确的结果:wóórd1但是setDefault没有效果.当我删除html_entity_decodesetDefault再次正确工作并且值显示在表单中,但没有解码的html实体.

为什么这个html实体解码会导致这些奇怪字符的表单值为空?

回复vstm

出于调试目的,我取消了编码,如下所示:

$this->view->setEscape(array($this, 'myEscape'));

public function myEscape($inputString)
    {
        return $inputString;
    }
Run Code Online (Sandbox Code Playgroud)

不幸的是,问题仍然与前面解释的相同.只是为了澄清,我在将值放入数据库之前对其进行编码,如下所示:

'metaDescription'   => htmlentities($form->getValue('metaDescription'), ENT_COMPAT, 'UTF-8')
Run Code Online (Sandbox Code Playgroud)

我从数据库中取出后将其解码,如下所示:

$form->setDefault('metaDescription', html_entity_decode($oldPage->getMetaDescription(), ENT_COMPAT, 'UTF-8'));
Run Code Online (Sandbox Code Playgroud)

然而,非常有趣的是,它似乎与UTF8编码有关,因为当我将编码更改为

'metaDescription'   => htmlentities($form->getValue('metaDescription'), ENT_COMPAT 'ISO-8859-1') 
Run Code Online (Sandbox Code Playgroud)

在以UTF8保持解码的同时,输入tést将导致输入框显示tést而不是空值,这是将两种方法都设置为UTF8时的情况.

这对你有帮助吗?

vst*_*stm 6

我知道它与Zend框架有关,它使用htmlspecialchars和utf-8 进行自己的转义(除非你用视图setEscape/ setEncoding方法改变它).确实当你这样做时:

$test = "w&oacute;&oacute;rd1";
$test = html_entity_decode($test, ENT_COMPAT, "iso-8859-1");
$test = htmlspecialchars($test, ENT_COMPAT, "utf-8");
Run Code Online (Sandbox Code Playgroud)

$test 最后是空的.

因此,您必须使用"utf-8"调用html_entity_decode或将视图编码更改为"iso-8859-1"(或任何编码).我认为提供"utf-8"是更好的选择.

对编码的战争

发明角色编码的人要么是邪恶的天才,要么是愚蠢的穴居人.

为了完成这项工作,你还要注意浏览器正在使用的编码,否则你要么在数据库中写入垃圾,在输出中渲染垃圾,要么两者兼而有之(或者如果你将错误的字符集交给某些PHP函数则没有) .(忍受我)

首先,您必须确保浏览器使用的编码.这可以通过以下方式实现:

  1. HTTP响应标头
  2. Content-Type元标记(ZF中的主要选项)

因此,请查看HTML输出中的内容类型元标记及其建议的编码.如果没有内容类型元信息或者它不包含字符集信息,那么你应该在你的布局中添加一个,最好是utf-8(如果你现在不使用布局,那么现在就开始使用它了. ).这很重要,否则你不确定输入的编码是什么,或者你必须向浏览器提供什么编码.这意味着类似的东西是在你<head>的应用程序返回的每个页面的打开之后:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
Run Code Online (Sandbox Code Playgroud)

在下面的示例中,我们假设您选择utf-8,但您可以使用任何合适的 - 如果您相应地更改值(即s/UTF-8 /您的编码/ g).

现在,从浏览器中检索数据时,您知道必须为htmlentities呼叫提供哪些字符集(utf-8):

'metaDescription'   => 
    htmlentities($form->getValue('metaDescription'), ENT_COMPAT, 'UTF-8')
Run Code Online (Sandbox Code Playgroud)

这意味着$form->getValue('metaDescription')返回一个utf-8编码的字符串,该字符串必须转换为HTML实体字符串,这正是我们想要的.

所以在数据库中现在是非威胁字符串,没有变音符号,重音符号等等.

现在我们来看看编辑部分.在那里你必须解码HTML实体,这样用户就不能处理它们.输出字符串必须使用我们想要的字符集进行编码(是的,右:utf-8):

$form->setDefault('metaDescription', 
    html_entity_decode($oldPage->getMetaDescription(), ENT_COMPAT, 'UTF-8'));
Run Code Online (Sandbox Code Playgroud)

所以现在你已经分配了返回的utf-8编码字符串html_entity_decode,metaDescription现在我们只需要通过那个htmlspecialchars默认调用的调用,如果有人使用的话$view->escape().

最后一步是要确保Zend_Viewencode是知道我们的编码(这是可选的,如果你使用的是UTF-8,因为这已经是默认值).为控制器中的特定视图设置它,$this->view->setEncoding('UTF-8')或者为:中的所有视图设置它bootstrap.php:

protected function _initView()
{
    $view = new Zend_View();
    $view->setEncoding('UTF-8');
    $viewRenderer =
        Zend_Controller_Action_HelperBroker::getStaticHelper(
            'ViewRenderer'
        );
    $viewRenderer->setView($view);
    return $view;
}
Run Code Online (Sandbox Code Playgroud)

如果有人现在调用$view->escape()它也需要一个utf-8字符串作为输入.您应该能够setEscape使用"null"转义删除该调用.

如果您按照所有这些步骤操作,您现在应该拥有所有特殊字符,其中根据需要恢复变音符号,重音符号和坟墓(或者我现在已经使自己蒙羞).

所以每个函数都接收它期望的编码,否则它返回臭名昭着的空字符串(伪流程图):

  1. 浏览器 - >以UTF-8发送数据
  2. htmlentities($browserData, ,'UTF-8') - >期望UTF-8返回没有变音符号或其他花哨东西的ASCII
  3. 数据库存储ASCII文本
  4. - 时间流逝 -
  5. 编辑时:从数据库加载ASCII
  6. html_entity_decode($dbData, ,'UTF-8') - >要求ASCII,返回UTF-8编码
  7. 通过$view->escape():htmlspecialchars- >期望UTF-8,返回UTF-8
  8. 浏览器 - >期望UTF-8

tl; dr/recap

  • 使用所需的字符集设置内容类型元标记
  • 确保所有编码/解码函数都知道您选择的字符集(这意味着:保持一致)