[ Index ]

PHP Cross Reference of YOURLS

title

Body

[close]

/tests/tests/format/ -> EscTest.php (source)

   1  <?php
   2  
   3  /**
   4   * Escaping formatting functions.
   5   * Note: tests about escaping and sanitizing URLs are in URLTest.php
   6   */
   7  #[\PHPUnit\Framework\Attributes\Group('formatting')]
   8  class EscTest extends PHPUnit\Framework\TestCase {
   9  
  10      /**
  11       * Attributes and how they should be escaped
  12       */
  13      static function html_attributes(): \Iterator
  14      {
  15          yield array(
  16              '"double quotes"',
  17              '&quot;double quotes&quot;',
  18          );
  19          yield array(
  20              "'single quotes'",
  21              '&#039;single quotes&#039;',
  22          );
  23          yield array(
  24              "'mixed' " . '"quotes"',
  25              '&#039;mixed&#039; &quot;quotes&quot;',
  26          );
  27          yield array(
  28              'foo & bar &baz; &apos;',
  29              'foo &amp; bar &amp;baz; &apos;',
  30          );
  31      }
  32  
  33  
  34      /**
  35       * Attribute escaping
  36       */
  37      #[\PHPUnit\Framework\Attributes\DataProvider('html_attributes')]
  38      function test_esc_attr( $attr, $escaped ) {
  39          $this->assertSame( $escaped, yourls_esc_attr( $attr ) );
  40      }
  41  
  42      /**
  43       * Attribute escaping -- escaping twice shouldn't change
  44       */
  45      #[\PHPUnit\Framework\Attributes\DataProvider('html_attributes')]
  46      function test_esc_attr_twice( $attr, $escaped ) {
  47          $this->assertSame( $escaped, yourls_esc_attr( yourls_esc_attr( $attr ) ) );
  48      }
  49  
  50      /**
  51       * HTML string and how they should be escaped
  52       */
  53      static function html_strings(): \Iterator
  54      {
  55          // Simple string
  56          yield array(
  57              'The quick brown fox.',
  58              'The quick brown fox.',
  59          );
  60          // URL with &
  61          yield array(
  62              'https://127.0.0.1/admin/admin-ajax.php?id=y1120844669&action=edit&keyword=1a&nonce=bf3115ac3a',
  63              'https://127.0.0.1/admin/admin-ajax.php?id=y1120844669&amp;action=edit&amp;keyword=1a&amp;nonce=bf3115ac3a',
  64          );
  65          // More ampersands
  66          yield array(
  67              'H&M and Dungeons & Dragons',
  68              'H&amp;M and Dungeons &amp; Dragons',
  69          );
  70          // Simple quotes
  71          yield array(
  72              "SELECT stuff FROM table WHERE blah IN ('omg', 'wtf') AND foo = 1",
  73              'SELECT stuff FROM table WHERE blah IN (&#039;omg&#039;, &#039;wtf&#039;) AND foo = 1',
  74          );
  75          // Double quotes
  76          yield array(
  77              'I am "special"',
  78              'I am &quot;special&quot;',
  79          );
  80          // Greater and less than
  81          yield array(
  82              'this > that < that <randomhtml />',
  83              'this &gt; that &lt; that &lt;randomhtml /&gt;',
  84          );
  85          // Ignore actual entities
  86          yield array(
  87              '&#038; &#x00A3; &#x22; &amp;',
  88              '&amp; &#xA3; &quot; &amp;',
  89          );
  90          // Empty string
  91          yield array(
  92              '',
  93              '',
  94          );
  95      }
  96  
  97      /**
  98       * HTML escaping
  99       */
 100      #[\PHPUnit\Framework\Attributes\DataProvider('html_strings')]
 101      function test_esc_html( $html, $escaped ) {
 102          $this->assertSame( $escaped, yourls_esc_html( $html ) );
 103          // Double escaping shouldn't change
 104          $this->assertSame( $escaped, yourls_esc_html( yourls_esc_html( $html ) ) );
 105      }
 106  
 107      /**
 108       * List of URLs and how they should be escaped
 109       */
 110      static function list_of_URLs(): \Iterator
 111      {
 112          yield array(
 113              'http://example.com/?this=that&that=this',
 114              'http://example.com/?this=that&#038;that=this',
 115          );
 116          yield array(
 117              'http://example.com/?this=that&that="this"',
 118              'http://example.com/?this=that&#038;that=this',
 119          );
 120          yield array(
 121              "http://example.com/?this=that&that='this'",
 122              'http://example.com/?this=that&#038;that=&#039;this&#039;',
 123          );
 124          yield array(
 125              "http://example.com/?this=that&that=<this>",
 126              'http://example.com/?this=that&#038;that=this',
 127          );
 128      }
 129  
 130      /**
 131       * Escape URLs for display
 132       */
 133      #[\PHPUnit\Framework\Attributes\DataProvider('list_of_URLs')]
 134      #[\PHPUnit\Framework\Attributes\Group('url')]
 135      function test_esc_urls( $url, $escaped ) {
 136          $this->assertEquals( $escaped, yourls_esc_url( $url ) );
 137      }
 138  
 139      /**
 140       * Some strings and how they should be escaped in javascript
 141       */
 142      static function list_of_JS(): \Iterator
 143      {
 144          yield array(
 145              'hello world();',
 146              'hello world();',
 147          );
 148          yield array(
 149              'hello("world");',
 150              'hello(&quot;world&quot;);',
 151          );
 152          yield array(
 153              'foo & bar &baz; &apos;',
 154              'foo &amp; bar &amp;baz; &apos;',
 155          );
 156      }
 157  
 158      /**
 159       * Escape JS
 160       */
 161      #[\PHPUnit\Framework\Attributes\DataProvider('list_of_JS')]
 162      function test_esc_js( $js, $escaped ) {
 163          $this->assertEquals( $escaped, yourls_esc_js( $js ) );
 164      }
 165  
 166      /**
 167       * Strings in a textarea and how they should be escaped
 168       */
 169      static function list_of_textarea(): \Iterator
 170      {
 171          yield array(
 172              'hello<br/>world',
 173              'hello&lt;br/&gt;world',
 174          );
 175          yield array(
 176              '"omg"',
 177              '&quot;omg&quot;',
 178          );
 179          yield array(
 180              "'omg'",
 181              '&#039;omg&#039;',
 182          );
 183      }
 184  
 185      /**
 186       * Escape JS
 187       */
 188      #[\PHPUnit\Framework\Attributes\DataProvider('list_of_textarea')]
 189      function test_esc_textarea( $text, $escaped ) {
 190          $this->assertEquals( $escaped, yourls_esc_textarea( $text ) );
 191      }
 192  
 193      /**
 194       * Strings, whitelist of allowed tags/attributes, and expected escaped output
 195       */
 196      static function list_of_whitelisted_html(): \Iterator
 197      {
 198          // yield array( 'string to escape', 'allowed tags/attributes', 'expected escaped output' );
 199  
 200          yield 'empty whitelist escapes everything' => array(
 201              '<b>only</b>',
 202              array(),
 203              '&lt;b&gt;only&lt;/b&gt;',
 204          );
 205          // Allowed tag is un-escaped, the rest stays escaped
 206          yield 'allowed tag, disallowed tag' => array(
 207              '<b>bold</b> <i>x</i>',
 208              array( 'b' => array() ),
 209              '<b>bold</b> &lt;i&gt;x&lt;/i&gt;',
 210          );
 211          // Text content of an allowed tag is still escaped
 212          yield 'text content stays escaped' => array(
 213              '<b>x & y < z</b>',
 214              array( 'b' => array() ),
 215              '<b>x &amp; y &lt; z</b>',
 216          );
 217          // Tag matching is case-insensitive and output is lowercased
 218          yield 'tag name is case-insensitive' => array(
 219              '<B>x</B>',
 220              array( 'b' => array() ),
 221              '<b>x</b>',
 222          );
 223          // An allowed tag with an empty attribute list keeps the tag but strips attributes
 224          yield 'attributes stripped when none allowed' => array(
 225              '<b class="foo">x</b>',
 226              array( 'b' => array() ),
 227              '<b>x</b>',
 228          );
 229          // An allowed attribute is kept...
 230          yield 'allowed attribute kept' => array(
 231              '<a href="http://example.com">link</a>',
 232              array( 'a' => array( 'href' => true ) ),
 233              '<a href="http://example.com">link</a>',
 234          );
 235          // ...while non-whitelisted attributes on the same tag are dropped
 236          yield 'disallowed attribute dropped' => array(
 237              '<a href="http://example.com" onclick="evil()">x</a>',
 238              array( 'a' => array( 'href' => true ) ),
 239              '<a href="http://example.com">x</a>',
 240          );
 241          // Single-quoted attribute values are normalized to double quotes
 242          yield 'single quotes normalized to double quotes' => array(
 243              "<a href='http://example.com'>x</a>",
 244              array( 'a' => array( 'href' => true ) ),
 245              '<a href="http://example.com">x</a>',
 246          );
 247          // The allowed tag/attribute map itself is case-insensitive
 248          yield 'whitelist keys are case-insensitive' => array(
 249              '<A HREF="http://example.com">x</A>',
 250              array( 'A' => array( 'HREF' => true ) ),
 251              '<a href="http://example.com">x</a>',
 252          );
 253          // href values are sanitized: a javascript: scheme is neutralized to an empty URL
 254          yield 'javascript scheme in href is neutralized' => array(
 255              '<a href="javascript:alert(1)">x</a>',
 256              array( 'a' => array( 'href' => true ) ),
 257              '<a href="">x</a>',
 258          );
 259      }
 260  
 261      /**
 262       * Escape HTML but allow a whitelist of tags and attributes
 263       */
 264      #[\PHPUnit\Framework\Attributes\DataProvider('list_of_whitelisted_html')]
 265      function test_esc_html_with_whitelist( $string, $allowed, $escaped ) {
 266          $this->assertSame( $escaped, yourls_esc_html_with_whitelist( $string, $allowed ) );
 267      }
 268  
 269      /**
 270       * With no whitelist argument, yourls_esc_html_with_whitelist() is equivalent to yourls_esc_html()
 271       */
 272      #[\PHPUnit\Framework\Attributes\DataProvider('html_strings')]
 273      function test_esc_html_with_whitelist_defaults_to_esc_html( $html, $escaped ) {
 274          $this->assertSame( yourls_esc_html( $html ), yourls_esc_html_with_whitelist( $html ) );
 275          $this->assertSame( $escaped, yourls_esc_html_with_whitelist( $html ) );
 276      }
 277  
 278  }


Generated: Sat Jun 13 05:10:47 2026 Cross-referenced by PHPXref 0.7.1