3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
13 * This class captures the encoding practices of CRM-5667 in a reusable
14 * fashion. In this design, all submitted values are partially HTML-encoded
15 * before saving to the database. If a DB reader needs to output in
16 * non-HTML medium, then it should undo the partial HTML encoding.
18 * This class should be short-lived -- 4.3 should introduce an alternative
19 * escaping scheme and consequently remove HTMLInputCoder.
22 * @copyright CiviCRM LLC https://civicrm.org/licensing
24 class CRM_Utils_API_HTMLInputCoder
extends CRM_Utils_API_AbstractFieldCoder
{
25 private $skipFields = NULL;
28 * @var CRM_Utils_API_HTMLInputCoder
30 private static $_singleton = NULL;
33 * @return CRM_Utils_API_HTMLInputCoder
35 public static function singleton() {
36 if (self
::$_singleton === NULL) {
37 self
::$_singleton = new CRM_Utils_API_HTMLInputCoder();
39 return self
::$_singleton;
45 * @return array<string>
48 public function getSkipFields() {
49 if ($this->skipFields
=== NULL) {
64 'thankyou_footer_text',
71 'confirm_footer_text',
80 'premiums_intro_text',
84 // This is needed for FROM Email Address configuration. dgg
86 // This is needed for navigation items urls
89 // message templates’ text versions
91 // (send an) email to contact’s and CiviMail’s text version
93 // data i/p of persistent table
99 // The 'new' text in word replacements
101 // e.g. '"Full Name" <user@example.org>'
106 // CiviCampaign Goal Details
108 // https://lab.civicrm.org/dev/core/issues/1286
110 // https://lab.civicrm.org/dev/core/issues/1286
112 // SavedSearch entity
114 // SearchDisplay entity
117 $custom = CRM_Core_DAO
::executeQuery('SELECT id FROM civicrm_custom_field WHERE html_type = "RichTextEditor"');
118 while ($custom->fetch()) {
119 $this->skipFields
[] = 'custom_' . $custom->id
;
122 return $this->skipFields
;
126 * going to filter the
127 * submitted values across XSS vulnerability.
129 * @param array|string $values
130 * @param bool $castToString
131 * If TRUE, all scalars will be filtered (and therefore cast to strings).
132 * If FALSE, then non-string values will be preserved
134 public function encodeInput(&$values, $castToString = FALSE) {
135 if (is_array($values)) {
136 foreach ($values as &$value) {
137 $this->encodeInput($value, TRUE);
140 elseif ($castToString ||
is_string($values)) {
141 $values = $this->encodeValue($values);
145 public function encodeValue($value) {
146 return str_replace(['<', '>'], ['<', '>'], $value);
150 * Perform in-place decode on strings (in a list of records).
153 * Ex in: $rows[0] = ['first_name' => 'A&W'].
154 * Ex out: $rows[0] = ['first_name' => 'A&W'].
156 public function encodeRows(&$rows) {
157 foreach ($rows as $rid => $row) {
158 $this->encodeRow($rows[$rid]);
163 * Perform in-place encode on strings (in a single record).
166 * Ex in: ['first_name' => 'A&W'].
167 * Ex out: ['first_name' => 'A&W'].
169 public function encodeRow(&$row) {
170 foreach ($row as $k => $v) {
171 if (is_string($v) && !$this->isSkippedField($k)) {
172 $row[$k] = $this->encodeValue($v);
178 * @param array $values
179 * @param bool $castToString
181 public function decodeOutput(&$values, $castToString = FALSE) {
182 if (is_array($values)) {
183 foreach ($values as &$value) {
184 $this->decodeOutput($value, TRUE);
187 elseif ($castToString ||
is_string($values)) {
188 $values = $this->decodeValue($values);
192 public function decodeValue($value) {
193 return str_replace(['<', '>'], ['<', '>'], $value);
197 * Perform in-place decode on strings (in a list of records).
200 * Ex in: $rows[0] = ['first_name' => 'A&W'].
201 * Ex out: $rows[0] = ['first_name' => 'A&W'].
203 public function decodeRows(&$rows) {
204 foreach ($rows as $rid => $row) {
205 $this->decodeRow($rows[$rid]);
210 * Perform in-place decode on strings (in a single record).
213 * Ex in: ['first_name' => 'A&W'].
214 * Ex out: ['first_name' => 'A&W'].
216 public function decodeRow(&$row) {
217 foreach ($row as $k => $v) {
218 if (is_string($v) && !$this->isSkippedField($k)) {
219 $row[$k] = $this->decodeValue($v);