|
| 1 | +Ideally your entire HTML tree should be generated with XHP, however this is |
| 2 | +often impractical when migrating an existing project to XHP. |
| 3 | + |
| 4 | +To work around this, we provide two interfaces that allow you to embed |
| 5 | +arbitrary HTML code at any point in the tree; using these bypasses XHPs |
| 6 | +security and/or correctness checks, so be very careful about using them. For this |
| 7 | +reason, we have only provided interfaces, instead of concrete implementations. |
| 8 | + |
| 9 | +The Interfaces |
| 10 | +============== |
| 11 | + |
| 12 | +XHPUnsafeRenderable |
| 13 | +------------------- |
| 14 | + |
| 15 | +**This is incredibly dangerous!** |
| 16 | + |
| 17 | +```PHP |
| 18 | +interface XHPUnsafeRenderable { |
| 19 | + public function toHTMLString(); |
| 20 | +} |
| 21 | +``` |
| 22 | + |
| 23 | +This marks an object as being able to provide a raw HTML string. It is up to |
| 24 | +you to make sure that the string is safe - eg no XSS vulnerabilties, and so on. |
| 25 | + |
| 26 | +XHPAlwaysValidChild |
| 27 | +------------------- |
| 28 | + |
| 29 | +This makes an object pass any child element validation rules except for |
| 30 | +"no children". While this is less likely to lead to a security issue, it may |
| 31 | +break the assumptions of the parent object, so should be used as little as |
| 32 | +possible. |
| 33 | + |
| 34 | +Usage |
| 35 | +===== |
| 36 | + |
| 37 | +To actually embed arbitrary HTML anywhere: |
| 38 | + |
| 39 | +```PHP |
| 40 | +final class POTENTIAL_XSS_SECURITY_HOLE |
| 41 | + implements XHPAlwaysValidChild, XHPUnsafeRenderable { |
| 42 | + private $html; |
| 43 | + |
| 44 | + public function __construct($html) { |
| 45 | + $this->html = $html; |
| 46 | + } |
| 47 | + |
| 48 | + public function toHTMLString() { |
| 49 | + return $this->html; |
| 50 | + } |
| 51 | +} |
| 52 | + |
| 53 | +// The function previously known as HTML() |
| 54 | +function POTENTIAL_XSS_SECURITY_HOLE($html) { |
| 55 | + return new POTENTIAL_XSS_SECURITY_HOLE($html); |
| 56 | +} |
| 57 | + |
| 58 | +$xhp = |
| 59 | + <div> |
| 60 | + Hello, world! |
| 61 | + {POTENTIAL_XSS_SECURITY_HOLE('<b>herp derp</b>')} |
| 62 | + </div>; |
| 63 | +``` |
| 64 | + |
| 65 | +We **strongly** recommend making much stricter interfaces instead - for example, |
| 66 | +instead of writing: |
| 67 | + |
| 68 | +``` |
| 69 | +POTENTIAL_XSS_SECURITY_HOLE(render_markdown($markdown)); |
| 70 | +``` |
| 71 | + |
| 72 | +We suggest not implementing POTENTIAL_XSS_SECURITY_HOLE at all, and instead |
| 73 | +doing something like the following: |
| 74 | + |
| 75 | +```PHP |
| 76 | +// Probably don't need XHPAlwaysValidChild - this is likely to be in a <div /> |
| 77 | +// or other similarly liberal container |
| 78 | +final class XHPMarkdown implements XHPUnsafeRenderable { |
| 79 | + private $markdown; |
| 80 | + public function __construct($markdown) { |
| 81 | + $this->markdown = $markdown; |
| 82 | + } |
| 83 | + |
| 84 | + public function toHTMLString() { |
| 85 | + return render_markdown($this->markdown); |
| 86 | + } |
| 87 | +} |
| 88 | + |
| 89 | +function xhp_markdown($markdown) { |
| 90 | + return new XHPMarkdown($markdown); |
| 91 | +} |
| 92 | +``` |
0 commit comments