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

时间:2011-07-26 12:12:54

标签: php forms zend-framework encoding 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);

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

$form->setDefault('metaDescription', $oldPage->getMetaDescription());

这完全没问题。

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

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

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

                ....

我现在设置默认值:

$form->setDefault('metaDescription', html_entity_decode($oldPage->getMetaDescription()));

起初,这似乎也很好。当我发送例如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_decode时,setDefault再次正确工作并且值显示在表单中,但没有解码的html实体。

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

回复vstm

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

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

public function myEscape($inputString)
    {
        return $inputString;
    }

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

'metaDescription'   => htmlentities($form->getValue('metaDescription'), ENT_COMPAT, 'UTF-8')

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

$form->setDefault('metaDescription', html_entity_decode($oldPage->getMetaDescription(), ENT_COMPAT, 'UTF-8'));

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

'metaDescription'   => htmlentities($form->getValue('metaDescription'), ENT_COMPAT 'ISO-8859-1') 

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

这对你有帮助吗?

2 个答案:

答案 0 :(得分:5)

我知道这与Zend框架使用htmlspecialchars和utf-8做自己的escaping有关(除非你用视图setEscape / setEncoding方法改变它)。事实上当你这样做时:

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

$test在结尾处是空的。

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

对编码的战争

  发明角色编码的人无论是邪恶的天才还是邪恶的天才   愚蠢的穴居人。

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

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

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

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    

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

    现在,从浏览器检索数据时,您知道必须为htmlentities调用提供什么字符集(utf-8):

    'metaDescription'   => 
        htmlentities($form->getValue('metaDescription'), ENT_COMPAT, 'UTF-8')
    

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

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

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

    $form->setDefault('metaDescription', 
        html_entity_decode($oldPage->getMetaDescription(), ENT_COMPAT, 'UTF-8'));
    

    现在您已将html_entity_decode返回的utf-8编码字符串分配给metaDescription,现在我们只需要通过htmlspecialchars调用,默认情况下,如果有人使用{ {1}}。

    最后一步是确保$view->escape()的{​​{1}}知道我们的编码(如果你使用utf-8,这是可选的,因为这已经是默认值)。使用Zend_View为控制器中的特定视图设置它,或者为encode中的所有视图设置它:

    $this->view->setEncoding('UTF-8')

    如果有人现在调用bootstrap.php,它还需要输入utf-8字符串。您应该可以使用“null”转义删除protected function _initView() { $view = new Zend_View(); $view->setEncoding('UTF-8'); $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper( 'ViewRenderer' ); $viewRenderer->setView($view); return $view; } 调用。

    如果您按照所有这些步骤进行操作,现在应该根据需要恢复所有特殊字符,同时修复变音符号,重音符号和坟墓(或者我现在自己已经羞辱了)。

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

    1. 浏览器 - &gt;以UTF-8
    2. 发送数据
    3. $view->escape() - &gt;期望UTF-8返回没有变音符号或其他花哨东西的ASCII
    4. 数据库存储ASCII文本
    5. - 时间过去了 -
    6. 然后编辑时:从数据库加载ASCII
    7. setEscape - &gt;期望ASCII,返回UTF-8编码
    8. 通过htmlentities($browserData, ,'UTF-8')html_entity_decode($dbData, ,'UTF-8') - &gt;期望UTF-8,返回UTF-8
    9. 浏览器 - &gt;期待UTF-8
    10. tl; dr / recap

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

答案 1 :(得分:1)

您也可以使用Zend_Filter_HtmlEntities()代替php函数。它不仅仅是PHP函数,但它将保证整个表单中的持久编码。