【问题标题】:PHP: Recursive htmlspecialchars on objectPHP:对象上的递归htmlspecialchars
【发布时间】:2012-10-03 17:26:48
【问题描述】:

我想为来自各种来源的数据建立一个通用的消毒剂。我的意思是(在这个阶段)将 htmlspecialchars 应用于字符串。现在,来自这些来源的数据可以是任何东西,从对象到数组再到字符串,都是嵌套的(而且很复杂),而且格式总是有点不同。

所以我想到了一个递归的 htmlspecialchars 函数,它将自身应用于数组和对象,并且只将 htmlspecialchars 应用于字符串,但是我如何递归地遍历一个对象呢?

谢谢。

编辑:我想我应该提到这一点 - 我实际上正在构建一个 RIA,它严重依赖 JS 和 JSON 进行客户端-服务器通信。服务器唯一要做的就是从数据库中获取内容并通过 JSON 将其返回给客户端,格式如下:

{"stat":"ok","data":{...}}

现在正如我所说,数据可以是任何东西,不仅来自字符串形式的数据库,还来自 XML 处理 JSON 的工作流程如下:

  1. 从 DB/XML 中获取数据(源编码为 iso-8859-1)
  2. 将它们放入“数据”数组中

  3. 使用递归从 iso-8859-1 转换为 utf-8

    private function utf8_encode_deep(&$input) {
    if (is_string($input)) {
        $input = $this -> str_encode_utf8($input);
    } else if (is_array($input)) {
        foreach ($input as &$value) {
            $this -> utf8_encode_deep($value);
        }
    
        unset($value);
    } else if (is_object($input)) {
        $vars = array_keys(get_object_vars($input));
    
        foreach ($vars as $var) {
            $this -> utf8_encode_deep($input -> $var);
        }
    }
    }
    
  4. 使用PHP的json_encode将数据转换成JSON

  5. 向客户端发送(回显)数据

  6. 使用JS渲染数据(例如放入表格)

在这两者之间的某个地方,应该以某种方式对数据进行清理(在这个阶段只有 htmlspecialchars)。现在的问题应该是:在哪里消毒,使用什么方法?

【问题讨论】:

    标签: php json object recursion


    【解决方案1】:

    您只想在输出到 HTML 时转义。而且你不能将一个完整的数组或对象输出到 HTML 中,所以转义一切似乎是无效的。

    由于您的 JSON 输出,您具有一级间接性。因此,您无法在 PHP 中决定数据用于什么上下文 - JSON 仍然是纯文本,而不是 HTML。

    因此,要决定是否必须为 HTML 转义 JSON 中的任何数据,我们必须知道您的 Javascript 是如何使用 JSON 数据的。

    示例:如果您的 JSON 被视为纯文本,并且包含类似 <b>BOLD</b> 的内容,那么在任何 HTML 中使用时的预期结果就是该文本,包括看起来像 HTML 标记的字符,但没有粗体排版。仅当您的 Javascript 客户端将此测试作为纯文本处理时才会发生这种情况,例如它不使用 innerHTML() 将其放置在页面上,因为这会激活 HTML 标记,但仅使用 innerText()textContent() 或任何其他方便的方法,例如jQuery (.text())。

    另一方面,如果您希望 JSON 包含输入到innerHTML() 的现成 HTML,那么您必须先转义此字符串,然后再将其放入 JSON。但是,只有当您不想为其添加任何格式时,您才必须转义整个字符串。否则,您将处于使用模板将预定义格式与用户内容混合的情况:用户内容在放入 HTML 上下文时必须转义,但结果不能 - 否则 Javascript 无法将其放入 innerHTML() 并启用格式。

    基本上,对数组或对象中的所有内容进行全局转义很可能是错误的,除非您知道 Javascript 将在 HTML 上下文中使用的所有内容。

    【讨论】:

    • 这是一个很好的点,“只在输出时转义”。问题是,我使用的是 JSON 客户端-服务器通信机制,而且.. 啊,我编辑了我的帖子,看看。
    • 谢谢。这为该主题提供了一个很好的一般性答案。在我的应用程序中,模型中的内容永远不会有任何预定义的格式(例如 ),所有的 HTML 结构和语义都将使用 Javascript 完成。所以我需要让模型中的内容没有任何 HTML,因此我认为全局转义是合适的。另外,我基本上从不使用innerHTML(),而是使用new Element('a', { id: 'aSpecialLink', href: '...', text: myJsonObj.linkText})(MooTools 语法)
    【解决方案2】:

    你可以试试下面的

    class MyClass {
        public $var1 = '<b>value 1</b>';
        public $var2 = '<b>value 2</b>';
        public $var3 = array('<b>value 3</b>');
    }
    
    $list = array();
    $list[0]['nice'] = range("A", "C");
    $list[0]['bad'] = array("<div>A</div>","<div>B</div>","<div>C</div>",new MyClass());
    $list["<b>gloo</b>"] = array(new MyClass(),"<b>WOW</b>");
    
    var_dump(__htmlspecialchars($list));
    

    使用的功能

    function __htmlspecialchars($data) {
        if (is_array($data)) {
            foreach ( $data as $key => $value ) {
                $data[htmlspecialchars($key)] = __htmlspecialchars($value);
            }
        } else if (is_object($data)) {
            $values = get_class_vars(get_class($data));
            foreach ( $values as $key => $value ) {
                $data->{htmlspecialchars($key)} = __htmlspecialchars($value);
            }
        } else {
            $data = htmlspecialchars($data);
        }
        return $data;
    }
    

    输出类似的东西

    array
      0 => 
        array
          'nice' => 
            array
              0 => string 'A' (length=1)
              1 => string 'B' (length=1)
              2 => string 'C' (length=1)
          'bad' => 
            array
              0 => string '&lt;div&gt;A&lt;/div&gt;' (length=24)
              1 => string '&lt;div&gt;B&lt;/div&gt;' (length=24)
              2 => string '&lt;div&gt;C&lt;/div&gt;' (length=24)
              3 => 
                object(MyClass)[1]
                  ...
    
    
        array
          0 => 
            object(MyClass)[2]
              public 'var1' => string '&lt;b&gt;value 1&lt;/b&gt;' (length=26)
              public 'var2' => string '&lt;b&gt;value 2&lt;/b&gt;' (length=26)
              public 'var3' => 
                array
                  ...
    

    【讨论】:

    • 密钥也必须被转义。因为是输出。但是对原始数组或对象执行此操作会破坏应用程序的其余部分。所以使用外观对象来解决输出问题确实是更好的选择。
    • @Sven 我的问题是如果密钥被转义.. 访问它们会很困难,比如$list["&lt;b&gt;gloo&lt;/b&gt;" 会变成$list['&amp;lt;b&amp;gt;gloo&amp;lt;/b&amp;gt;'] ;
    • 是的,但这就是转义字符串的重点。你不应该对所有事情都过早地这样做,因为你不知道它将是哪个输出上下文,但只有在你知道上下文时才知道。
    • +1 很好的论据...添加了键转义功能...@Sven
    • 感谢详尽的回答,如果我按照自己的意愿做卫生,我会使用这种方法。但是,通过查看各种 cmets,我的问题实际上已经扩大了。因此,为此,我用我的应用程序中发生的事情编辑了我公认的信息量不大的问题,我希望你现在能更好地理解我真正想要做的事情。
    【解决方案3】:
    function htmlrecursive($data){
        if (is_array($data) && count($data) > 1){
            foreach ($data as &$d){
                $d = htmlrecursive($d);
            }
        } else if (!is_array($data)){
            return htmlspecialchars($data);
        }
        else {
             return htmlspecialchars($data[0])
        }
    }
    
    htmlrecursive($array);
    

    【讨论】:

    • 您的代码在尝试此操作时失败:htmlrecursive(array('foo' => ''));
    • 数组键也需要转义。 htmlrecursive(array('&lt;foo&gt;' =&gt; 'bar'));
    【解决方案4】:

    对于你需要实现The ArrayAccess interface的对象,你可以做一个数组遍历递归

    也检查这个问题Getting an object to work with array_walk_recursive in PHP

    【讨论】:

      猜你喜欢
      • 2011-06-05
      • 1970-01-01
      • 2011-06-14
      • 2015-06-04
      • 2021-04-01
      • 2017-05-14
      • 2023-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多