Xss::attributes

protected static Xss::attributes($attributes)

Processes a string of HTML attributes.

Parameters

string $attributes: The html attribute to process.

Return value

string Cleaned up version of the HTML attributes.

File

core/lib/Drupal/Component/Utility/Xss.php, line 198

Class

Xss
Provides helper to filter for cross-site scripting.

Namespace

Drupal\Component\Utility

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
protected static function attributes($attributes) {
  $attributes_array = array();
  $mode = 0;
  $attribute_name = '';
  $skip = FALSE;
  $skip_protocol_filtering = FALSE;
 
  while (strlen($attributes) != 0) {
    // Was the last operation successful?
    $working = 0;
 
    switch ($mode) {
      case 0:
        // Attribute name, href for instance.
        if (preg_match('/^([-a-zA-Z][-a-zA-Z0-9]*)/', $attributes, $match)) {
          $attribute_name = strtolower($match[1]);
          $skip = ($attribute_name == 'style' || substr($attribute_name, 0, 2) == 'on');
 
          // Values for attributes of type URI should be filtered for
          // potentially malicious protocols (for example, an href-attribute
          // starting with "javascript:"). However, for some non-URI
          // attributes performing this filtering causes valid and safe data
          // to be mangled. We prevent this by skipping protocol filtering on
          // such attributes.
          // @see \Drupal\Component\Utility\UrlHelper::filterBadProtocol()
          $skip_protocol_filtering = substr($attribute_name, 0, 5) === 'data-' || in_array($attribute_name, array(
            'title',
            'alt',
            'rel',
            'property',
          ));
 
          $working = $mode = 1;
          $attributes = preg_replace('/^[-a-zA-Z][-a-zA-Z0-9]*/', '', $attributes);
        }
        break;
 
      case 1:
        // Equals sign or valueless ("selected").
        if (preg_match('/^\s*=\s*/', $attributes)) {
          $working = 1;
          $mode = 2;
          $attributes = preg_replace('/^\s*=\s*/', '', $attributes);
          break;
        }
 
        if (preg_match('/^\s+/', $attributes)) {
          $working = 1;
          $mode = 0;
          if (!$skip) {
            $attributes_array[] = $attribute_name;
          }
          $attributes = preg_replace('/^\s+/', '', $attributes);
        }
        break;
 
      case 2:
        // Attribute value, a URL after href= for instance.
        if (preg_match('/^"([^"]*)"(\s+|$)/', $attributes, $match)) {
          $thisval = $skip_protocol_filtering ? $match[1] : UrlHelper::filterBadProtocol($match[1]);
 
          if (!$skip) {
            $attributes_array[] = "$attribute_name=\"$thisval\"";
          }
          $working = 1;
          $mode = 0;
          $attributes = preg_replace('/^"[^"]*"(\s+|$)/', '', $attributes);
          break;
        }
 
        if (preg_match("/^'([^']*)'(\s+|$)/", $attributes, $match)) {
          $thisval = $skip_protocol_filtering ? $match[1] : UrlHelper::filterBadProtocol($match[1]);
 
          if (!$skip) {
            $attributes_array[] = "$attribute_name='$thisval'";
          }
          $working = 1;
          $mode = 0;
          $attributes = preg_replace("/^'[^']*'(\s+|$)/", '', $attributes);
          break;
        }
 
        if (preg_match("%^([^\s\"']+)(\s+|$)%", $attributes, $match)) {
          $thisval = $skip_protocol_filtering ? $match[1] : UrlHelper::filterBadProtocol($match[1]);
 
          if (!$skip) {
            $attributes_array[] = "$attribute_name=\"$thisval\"";
          }
          $working = 1;
          $mode = 0;
          $attributes = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attributes);
        }
        break;
    }
 
    if ($working == 0) {
      // Not well formed; remove and try again.
      $attributes = preg_replace('/
          ^
          (
          "[^"]*("|$)     # - a string that starts with a double quote, up until the next double quote or the end of the string
          |               # or
          \'[^\']*(\'|$)| # - a string that starts with a quote, up until the next quote or the end of the string
          |               # or
          \S              # - a non-whitespace character
          )*              # any number of the above three
          \s*             # any number of whitespaces
          /x', '', $attributes);
      $mode = 0;
    }
  }
 
  // The attribute list ends with a valueless attribute like "selected".
  if ($mode == 1 && !$skip) {
    $attributes_array[] = $attribute_name;
  }
  return $attributes_array;
}
doc_Drupal
2025-01-10 15:47:30
Comments
Leave a Comment

Please login to continue.