XHP介紹

2018-10-19 11:18 更新

XHP提供您的輸出(通常為HTML)的本機(jī)XML樣表示。這樣可以對(duì)您的UI代碼進(jìn)行類(lèi)型檢查,并自動(dòng)避免多個(gè)常見(jiàn)問(wèn)題,如跨站點(diǎn)腳本(XSS)和雙重轉(zhuǎn)義。它還應(yīng)用其他驗(yàn)證規(guī)則,例如<head>必須包含<title>。

使用傳統(tǒng)插值,一個(gè)簡(jiǎn)單的頁(yè)面可能如下所示:

<?hh 
$ user_name  =  'Fred' ; 
echo  “<tt> Hello <strong> $ user_name </ strong> </ tt>” ;

然而,使用XHP,它看起來(lái)像這樣:

<?hh 
$ user_name  =  'Fred' ; 
echo  < tt > Hello  < strong > { $ user_name } </ strong > </ tt > ;

第一個(gè)例子使用字符串插值來(lái)輸出HTML,而第二個(gè)例子沒(méi)有引號(hào),這意味著Hack完全可以理解語(yǔ)法 - 但這并不意味著你需要做的只是刪除引號(hào)。所需的其他步驟包括:

  • 使用花括號(hào)包括變量 - 例如"<a>$foo</a>"變成<a>{$foo}</a>。
  • 由于XHP是象XML,所有的元素都必須關(guān)閉-例如,"<br>"成為<br />。
  • 確保您的HTML已正確嵌套。
  • 刪除所有的HTML /屬性轉(zhuǎn)義 - 例如,您不需要htmlspecialchars()在XHP輸出中包含一個(gè)變量之前調(diào)用; 如果你這樣做,它將被雙重轉(zhuǎn)義。

關(guān)于Namespaces

XHP目前有幾個(gè)命名空間的問(wèn)題; 我們建議:

  • XHP類(lèi)沒(méi)有在命名空間中聲明
  • 使用XHP類(lèi)的代碼沒(méi)有命名空間。

我們計(jì)劃在未來(lái)支持namespaces。

XHP-Lib庫(kù)

雖然XHP語(yǔ)法是Hack的一部分,但很大一部分實(shí)現(xiàn)是在一個(gè)名為XHP-Lib的普通庫(kù)中,需要通過(guò)編寫(xiě)器來(lái)安裝:

“require”:{ 
  “facebook / xhp-lib”:“?2.2” 
}

這包括基類(lèi)和接口以及標(biāo)準(zhǔn)HTML元素的定義。

為什么要使用XHP?

大多數(shù)用戶的初始原因是因?yàn)樗恰澳J(rèn)安全”:所有變量都以上下文相適應(yīng)的方式自動(dòng)轉(zhuǎn)義(例如,有不同的轉(zhuǎn)義屬性值與文本節(jié)點(diǎn)的規(guī)則)。另外,XHP被類(lèi)型檢查器理解,確保不傳遞屬性值。一個(gè)常見(jiàn)的例子是border="3",但是border是一個(gè)on / off屬性,所以3的值沒(méi)有意義。

對(duì)于XHP經(jīng)驗(yàn)豐富的用戶來(lái)說(shuō),最大的優(yōu)點(diǎn)是可以輕松地添加自定義的“元素”,使用自己的行為,然后可以像純HTML元素一樣使用。例如,該網(wǎng)站定義<a:post>了與標(biāo)準(zhǔn)<a>標(biāo)簽具有相同接口的標(biāo)簽,但是使用POST請(qǐng)求而不是GET請(qǐng)求:

<?hh // strict

final class :a:post extends :x:element {
  attribute :a;

  use XHPHelpers;

  protected function render(): XHPRoot {
    $id = $this->getID();

    $anchor = <a>{$this->getChildren()}</a>;
    $form = (
      <form
        id={$id}
        method="post"
        action={$this->:href}
        target={$this->:target}
        class="postLink"
      >{$anchor}</form>
    );

    $this->transferAllAttributes($anchor);
    $anchor->setAttribute(
      'onclick',
      'document.getElementById("'.$id.'").submit(); return false;',
    );
    $anchor->setAttribute('href', '#');

    return $form;
  }
}

需要一點(diǎn)CSS,以便<form>不創(chuàng)建塊元素:

form.postLink { 
  display:inline; 
}

在這一點(diǎn)上,新元素可以像任何內(nèi)置元素一樣使用:

<?hh
function intro_examples_a_a_post() {
  $get_link =
   <a  rel="external nofollow" target="_blank"  rel="external nofollow" target="_blank"  rel="external nofollow" target="_blank" >I'm a normal link</a>;
  $post_link =
    <a:post  rel="external nofollow" target="_blank"  rel="external nofollow" target="_blank"  rel="external nofollow" target="_blank" >I make a POST REQUEST</a:post>;

  echo $get_link;
  echo "\n";
  echo $post_link;
}

intro_examples_a_a_post();

Output

<a  rel="external nofollow" target="_blank"  rel="external nofollow" target="_blank"  rel="external nofollow" target="_blank" >I'm a normal link</a>
<form id="f20194a67b" method="post" action="http://www.example.com" class="postLink"><a href="#" id="f20194a67b" onclick="document.getElementById("f20194a67b").submit(); return false;">I make a POST REQUEST</a></form>

運(yùn)行時(shí)驗(yàn)證

由于XHP對(duì)象是一流的,而不僅僅是字符串,因此可以進(jìn)行一整套驗(yàn)證,以確保您的UI沒(méi)有細(xì)微的錯(cuò)誤:

<?hh

function intro_examples_tag_matching_validation_using_string(): void {
  echo '<div class="section-header">';
  echo '<a href="#use">You should have used <span class="xhp">XHP</naps></a>';
  echo '</div>';
}

function intro_examples_tag_matching_validation_using_xhp(): void {
  // Typechecker error
  // Fatal syntax error at runtime
  echo
    <div class="section-header">
      <a href="#use">You should have used <span class="xhp">XHP</naps></a>
    </div>;
}

function intro_examples_tag_matching_validation_run(): void {
  intro_examples_tag_matching_validation_using_string();
  intro_examples_tag_matching_validation_using_xhp();
}

intro_examples_tag_matching_validation_run();

Output

Fatal error: XHP: mismatched tag: 'naps' not the same as 'span' in /data/users/joelm/user-documentation/guides/hack/24-XHP/01-introduction-examples/tag-matching-validation.php.type-errors on line 14

上述代碼將不會(huì)進(jìn)行類(lèi)型檢查或運(yùn)行,因?yàn)閄HP驗(yàn)證器將會(huì)看到<span>并且<naps>標(biāo)簽不匹配 - 但是以下代碼將正確鍵入正確但無(wú)法運(yùn)行,因?yàn)樵跇?biāo)記匹配時(shí),它們不能正確嵌套(根據(jù)HTML規(guī)范),并且嵌套驗(yàn)證僅在運(yùn)行時(shí)發(fā)生:

?hh

function intro_examples_allowed_tag_validation_using_string(): void {
  echo '<ul><i>Item 1</i></ul>';
}

function intro_examples_allowed_tag_validation_using_xhp(): void {
  try {
    echo <ul><i>Item 1</i></ul>;
  } catch (\XHPInvalidChildrenException $ex) {
    // We will get here because an <i> cannot be nested directly below a <ul>
    var_dump($ex->getMessage());
  }
}

function intro_examples_allowed_tag_validation_run(): void {
  intro_examples_allowed_tag_validation_using_string();
  echo PHP_EOL . PHP_EOL;
  intro_examples_allowed_tag_validation_using_xhp();
}

intro_examples_allowed_tag_validation_run();

Output

<ul><i>Item 1</i></ul>

string(262) "Element `ul` was rendered with invalid children.

/data/users/joelm/user-documentation/guides/hack/24-XHP/01-introduction-examples/allowed-tag-validation.php:11

Verified 0 children before failing.

Children expected:
(:li)*

Children received:
:i[%flow,%phrase]"

安全

基于字符串的條目和驗(yàn)證是跨站點(diǎn)腳本(XSS)的首選。你可以通過(guò)使用特殊功能來(lái)解決這個(gè)問(wèn)題htmlspecialchars(),但是你必須真正記住使用這些功能。輸出之前,XHP自動(dòng)將保留的HTML字符轉(zhuǎn)義為HTML實(shí)體。

<?hh

function intro_examples_avoid_xss_using_string(string $could_be_bad): void {
  // Could call htmlspecialchars() here
  echo '<html><head/><body> ' . $could_be_bad . '</body></html>';
}

function intro_examples_avoid_xss_using_xhp(string $could_be_bad): void {
  // The string $could_be_bad will be escaped to HTML entities like:
  // <html><head></head><body>&lt;blink&gt;Ugh&lt;/blink&gt;</body></html>
  echo
    <html>
      <head/>
      <body>{$could_be_bad}</body>
    </html>;
}

function intro_examples_avoid_xss_run(string $could_be_bad): void {
  intro_examples_avoid_xss_using_string($could_be_bad);
  echo PHP_EOL . PHP_EOL;
  intro_examples_avoid_xss_using_xhp($could_be_bad);
}

intro_examples_avoid_xss_run('<blink>Ugh</blink>');

Output

<html><head/><body> <blink>Ugh</blink></body></html>

<html><head></head><body>&lt;blink&gt;Ugh&lt;/blink&gt;</body></html>
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)