PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.5
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.5
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / app / Services / Spout / Common / Escaper / XLSX.php

XLSX.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.5, at app/Services/Spout/Common/Escaper/XLSX.php

186 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Box\Spout\Common\Escaper;
4
5 use Box\Spout\Common\Singleton;
6
7 /**
8 * Class XLSX
9 * Provides functions to escape and unescape data for XLSX files
10 *
11 * @package Box\Spout\Common\Escaper
12 */
13 class XLSX implements EscaperInterface
14 {
15 use Singleton;
16
17 /** @var string Regex pattern to detect control characters that need to be escaped */
18 protected $escapableControlCharactersPattern;
19
20 /** @var string[] Map containing control characters to be escaped (key) and their escaped value (value) */
21 protected $controlCharactersEscapingMap;
22
23 /** @var string[] Map containing control characters to be escaped (value) and their escaped value (key) */
24 protected $controlCharactersEscapingReverseMap;
25
26 /**
27 * Initializes the singleton instance
28 */
29 protected function init()
30 {
31 $this->escapableControlCharactersPattern = $this->getEscapableControlCharactersPattern();
32 $this->controlCharactersEscapingMap = $this->getControlCharactersEscapingMap();
33 $this->controlCharactersEscapingReverseMap = array_flip($this->controlCharactersEscapingMap);
34 }
35
36 /**
37 * Escapes the given string to make it compatible with XLSX
38 *
39 * @param string $string The string to escape
40 * @return string The escaped string
41 */
42 public function escape($string)
43 {
44 $escapedString = $this->escapeControlCharacters($string);
45 // @NOTE: Using ENT_NOQUOTES as only XML entities ('<', '>', '&') need to be encoded.
46 // Single and double quotes can be left as is.
47 $escapedString = htmlspecialchars($escapedString, ENT_NOQUOTES);
48
49 return $escapedString;
50 }
51
52 /**
53 * Unescapes the given string to make it compatible with XLSX
54 *
55 * @param string $string The string to unescape
56 * @return string The unescaped string
57 */
58 public function unescape($string)
59 {
60 // ==============
61 // = WARNING =
62 // ==============
63 // It is assumed that the given string has already had its XML entities decoded.
64 // This is true if the string is coming from a DOMNode (as DOMNode already decode XML entities on creation).
65 // Therefore there is no need to call "htmlspecialchars_decode()".
66 $unescapedString = $this->unescapeControlCharacters($string);
67
68 return $unescapedString;
69 }
70
71 /**
72 * @return string Regex pattern containing all escapable control characters
73 */
74 protected function getEscapableControlCharactersPattern()
75 {
76 // control characters values are from 0 to 1F (hex values) in the ASCII table
77 // some characters should not be escaped though: "\t", "\r" and "\n".
78 return '[\x00-\x08' .
79 // skipping "\t" (0x9) and "\n" (0xA)
80 '\x0B-\x0C' .
81 // skipping "\r" (0xD)
82 '\x0E-\x1F]';
83 }
84
85 /**
86 * Builds the map containing control characters to be escaped
87 * mapped to their escaped values.
88 * "\t", "\r" and "\n" don't need to be escaped.
89 *
90 * NOTE: the logic has been adapted from the XlsxWriter library (BSD License)
91 * @link https://github.com/jmcnamara/XlsxWriter/blob/f1e610f29/xlsxwriter/sharedstrings.py#L89
92 *
93 * @return string[]
94 */
95 protected function getControlCharactersEscapingMap()
96 {
97 $controlCharactersEscapingMap = [];
98
99 // control characters values are from 0 to 1F (hex values) in the ASCII table
100 for ($charValue = 0x00; $charValue <= 0x1F; $charValue++) {
101 $character = chr($charValue);
102 if (preg_match("/{$this->escapableControlCharactersPattern}/", $character)) {
103 $charHexValue = dechex($charValue);
104 $escapedChar = '_x' . sprintf('%04s' , strtoupper($charHexValue)) . '_';
105 $controlCharactersEscapingMap[$escapedChar] = $character;
106 }
107 }
108
109 return $controlCharactersEscapingMap;
110 }
111
112 /**
113 * Converts PHP control characters from the given string to OpenXML escaped control characters
114 *
115 * Excel escapes control characters with _xHHHH_ and also escapes any
116 * literal strings of that type by encoding the leading underscore.
117 * So "\0" -> _x0000_ and "_x0000_" -> _x005F_x0000_.
118 *
119 * NOTE: the logic has been adapted from the XlsxWriter library (BSD License)
120 * @link https://github.com/jmcnamara/XlsxWriter/blob/f1e610f29/xlsxwriter/sharedstrings.py#L89
121 *
122 * @param string $string String to escape
123 * @return string
124 */
125 protected function escapeControlCharacters($string)
126 {
127 $escapedString = $this->escapeEscapeCharacter($string);
128
129 // if no control characters
130 if (!preg_match("/{$this->escapableControlCharactersPattern}/", $escapedString)) {
131 return $escapedString;
132 }
133
134 return preg_replace_callback("/({$this->escapableControlCharactersPattern})/", function($matches) {
135 return $this->controlCharactersEscapingReverseMap[$matches[0]];
136 }, $escapedString);
137 }
138
139 /**
140 * Escapes the escape character: "_x0000_" -> "_x005F_x0000_"
141 *
142 * @param string $string String to escape
143 * @return string The escaped string
144 */
145 protected function escapeEscapeCharacter($string)
146 {
147 return preg_replace('/_(x[\dA-F]{4})_/', '_x005F_$1_', $string);
148 }
149
150 /**
151 * Converts OpenXML escaped control characters from the given string to PHP control characters
152 *
153 * Excel escapes control characters with _xHHHH_ and also escapes any
154 * literal strings of that type by encoding the leading underscore.
155 * So "_x0000_" -> "\0" and "_x005F_x0000_" -> "_x0000_"
156 *
157 * NOTE: the logic has been adapted from the XlsxWriter library (BSD License)
158 * @link https://github.com/jmcnamara/XlsxWriter/blob/f1e610f29/xlsxwriter/sharedstrings.py#L89
159 *
160 * @param string $string String to unescape
161 * @return string
162 */
163 protected function unescapeControlCharacters($string)
164 {
165 $unescapedString = $string;
166
167 foreach ($this->controlCharactersEscapingMap as $escapedCharValue => $charValue) {
168 // only unescape characters that don't contain the escaped escape character for now
169 $unescapedString = preg_replace("/(?<!_x005F)($escapedCharValue)/", $charValue, $unescapedString);
170 }
171
172 return $this->unescapeEscapeCharacter($unescapedString);
173 }
174
175 /**
176 * Unecapes the escape character: "_x005F_x0000_" => "_x0000_"
177 *
178 * @param string $string String to unescape
179 * @return string The unescaped string
180 */
181 protected function unescapeEscapeCharacter($string)
182 {
183 return preg_replace('/_x005F(_x[\dA-F]{4}_)/', '$1', $string);
184 }
185 }
186