php - Zend在表单输入元素中解码html实体导致空值

标签 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 是从数据库中提取的默认值,以便字符再次以其原始形状显示。

在处理表单输入时,我是这样做的:
//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 时的情况。

这对你有帮助吗?

最佳答案

我知道它与 Zend 框架使用 htmlspecialchars 和 utf-8 做自己的 escaping 有关系(除非你用 View 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 或将 View 编码更改为“iso-8859-1”(或任何您的编码)。我认为提供“utf-8”是更好的选择。

反对编码的 war

Whoever invented character encodings was either an evil genius or a stupid caveman.



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

所以首先你必须确保浏览器使用的是什么编码。这可以通过以下方式实现:
  • HTTP 响应头
  • Content-Type 元标记(ZF 中的主要选项)

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

    <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-entities 字符串,这正是我们想要的。

    因此,数据库中现在是没有变音、重音或其他任何内容的非威胁字符串。

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

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

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

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

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

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

    如果您遵循所有这些步骤,您现在应该可以根据需要恢复所有带有变音、重音和坟墓的特殊字符(或者我现在已经丢脸了)。

    所以每个函数都会收到它期望的编码,否则它会返回臭名昭著的空字符串(伪流程图):
  • 浏览器 -> 以 UTF-8 格式发送数据
  • htmlentities($browserData, ,'UTF-8') -> 期望 UTF-8 返回 ASCII 没有变音或其他花哨的东西
  • 数据库存储 ASCII 文本
  • -- 时间流逝 --
  • 然后在编辑时:从数据库中加载 ASCII
  • html_entity_decode($dbData, ,'UTF-8') -> 需要 ASCII,返回 UTF-8 编码的
  • 通过 $view->escape() : htmlspecialchars -> 期望 UTF-8,返回 UTF-8
  • 浏览器 -> 期望 UTF-8

  • tl;博士/回顾
  • 使用所需的字符集设置内容类型元标记
  • 确保所有编码/解码功能都知道您选择的字符集(这意味着:保持一致)
  • 关于php - Zend在表单输入元素中解码html实体导致空值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6829820/

    相关文章:

    PHPUnit , PEAR 升级错误

    php - 如何在 PHP 中更改文件内容?

    php - 如何在 PHP 中实现装饰器?

    javascript - 使用单选按钮以订单形式动态增加/减少总价

    php - Zend Framework 1.x 和 2.x,它们的兼容性如何?

    php - 我的 PHP 代码中的参数有问题,参数未定义

    ruby-on-rails - 使用 STI 基类的 Rails form_for

    php - 指定的 Controller 无效(错误)- Zend Framework

    php - 如何将 zend 表单元素添加到 php 中的表单?

    html - 将 enctype ="multipart/form-data"放入每个表单标签中是否不好