XHP:接口

2018-10-17 11:09 更新

有两个重要的接口中XHP,XHPRoot和XHPChild; 在函数中添加类型注释时,您将需要使用这些注释。

XHPRoot

该XHPRoot接口由所有XHP对象实现; 在实践中,这意味着:

  • :x:element 子类 - 这些是重用(并组合)现有XHP类的类
  • :x:primitive子类 - 这些定义基本元素,例如:x:frag和所有基本的HTML元素
  • 所述的实施方式XHPUnsafeRenderable如下所述接口

XHPChild

XHP呈现树结构,该接口定义树的有效子节点; 这包括:

  • 所有的实现 XHPRoot
  • 字符串,整数,浮点数
  • 上述任何一个数组

尽管字符串,整数,浮点数和数组都不是对象,但是类型instanceof检查器和HHVM都认为它们可以实现这个接口 - 无论是对于参数/返回类型还是用于检查。

高级接口

虽然XHP的安全默认功能通常是有益的,但偶尔需要绕过它们; 最常见的情况是:

  • 迁移到XHP时需要嵌入另一个模板系统的输出。
  • 需要从其他来源嵌入HTML,例如Markdown或BBCode渲染器。

XHP通常会阻碍:

  • 转换所有变量,包括您的HTML代码。
  • 执行子关系 - XHP对象不能被标记为允许HTML字符串子对象。

该XHPUnsafeRenderable和XHPAlwaysValidChild接口允许绕过这些安全机制。

XHPUnsafeRenderable

如果您需要渲染原始HTML字符串,请将其包装在实现此接口的类中,并提供一种toHTMLString(): string方法:

<?hh
/* YOU PROBABLY SHOULDN'T DO THIS
 *
 * Even with a scary (and accurate) name, it tends to be over-used.
 * See below for an alternative.
 */
class ExamplePotentialXSSSecurityHole implements XHPUnsafeRenderable {
  public function __construct(
    private string $html,
  ) {
  }

  public function toHTMLString(): string {
    return $this->html;
  }
}

echo (
  <div class="markdown">
    {new ExamplePotentialXSSSecurityHole(
      HHVM\UserDocumentation\XHP\Examples\md_render('Markdown goes here')
    )}
  </div>
)."\n";

我们不提供此接口的实现,因为通用实现往往被过度使用 - 相反,考虑进行更具体的实现:

<?hh
class ExampleMarkdownXHPWrapper implements XHPUnsafeRenderable {
  private string $html;
  public function __construct(
    string $markdown_source,
  ) {
    $this->html = HHVM\UserDocumentation\XHP\Examples\md_render(
      $markdown_source
    );
  }

  public function toHTMLString(): string {
    return $this->html;
  }
}

echo (
  <div class="markdown">
    {new ExampleMarkdownXHPWrapper('Markdown goes here')}
  </div>
)."\n";

XHPAlwaysValidChild

可以通过实现此接口来绕过XHP的子级验证。实现此接口的大多数类也是实现XHPUnsafeRenderable,因为最常见的需求是当另一个渲染或模板系统生成子代时。

这也可以由XHP对象来实现,但这通常表示应该用类别替换子类规范。这个界面是故意打破XHP安全性的一部分,所以应尽量少用。

Example

<?hh
final class XHPUnsafeExample implements XHPUnsafeRenderable {
  public function toHTMLString(): string {
    return '<script>'.$_GET['I_LOVE_XSS'].'</script>';
  }
}

$inputs = Map {
  '<div />' => <div />,
  '<x:frag />' => <x:frag />,
  '"foo"' => 'foo',
  '3' => 3,
  'true' => true,
  'null' => null,
  'new stdClass()' => new stdClass(),
  '[<li />, <li />, <li />]' => [<li />, <li />, <li />],
  'XHPUnsafeExample' => new XHPUnsafeExample(),
};

$max_label_len = max($inputs->mapWithKey(($k, $_) ==> strlen($k)));
print str_repeat(' ', $max_label_len + 1)." | XHPRoot | XHPChild\n";
print str_repeat('-', $max_label_len + 1)."-|---------|----------\n";

foreach ($inputs as $label => $input) {
  printf(
    " %{$max_label_len}s | %-7s | %s\n",
    $label,
    $input instanceof XHPRoot ? 'yes' : 'no',
    $input instanceof XHPChild ? 'yes' : 'no',
  );
}

Output

                          | XHPRoot | XHPChild
--------------------------|---------|----------
                  <div /> | yes     | yes
               <x:frag /> | yes     | yes
                    "foo" | no      | yes
                        3 | no      | yes
                     true | no      | no
                     null | no      | no
           new stdClass() | no      | no
 [<li />, <li />, <li />] | no      | yes
         XHPUnsafeExample | no      | yes
以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号