Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.11% covered (success)
98.11%
52 / 53
90.91% covered (success)
90.91%
10 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
Text
98.11% covered (success)
98.11%
52 / 53
90.91% covered (success)
90.91%
10 / 11
37
0.00% covered (danger)
0.00%
0 / 1
 buildControlCharacters
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
5
 controlCharacterPHP2OOXML
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 numberFormat
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 chr
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
5
 controlCharacterOOXML2PHP
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 isUTF8
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
3
 toUTF8
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
4
 toUnicode
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 utf8ToUnicode
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
7
 unicodeToEntities
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
4
 removeUnderscorePrefix
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2/**
3 * This file is part of PHPWord - A pure PHP library for reading and writing
4 * word processing documents.
5 *
6 * PHPWord is free software distributed under the terms of the GNU Lesser
7 * General Public License version 3 as published by the Free Software Foundation.
8 *
9 * For the full copyright and license information, please read the LICENSE
10 * file that was distributed with this source code. For the full list of
11 * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
12 *
13 * @see         https://github.com/PHPOffice/PHPWord
14 *
15 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
16 */
17
18namespace PhpOffice\PhpWord\Shared;
19
20/**
21 * Text.
22 */
23class Text
24{
25    /**
26     * Control characters array.
27     *
28     * @var string[]
29     */
30    private static $controlCharacters = [];
31
32    /**
33     * Build control characters array.
34     */
35    private static function buildControlCharacters(): void
36    {
37        for ($i = 0; $i <= 19; ++$i) {
38            if ($i != 9 && $i != 10 && $i != 13) {
39                $find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_';
40                $replace = chr($i);
41                self::$controlCharacters[$find] = $replace;
42            }
43        }
44    }
45
46    /**
47     * Convert from PHP control character to OpenXML escaped control character.
48     *
49     * Excel 2007 team:
50     * ----------------
51     * That's correct, control characters are stored directly in the shared-strings table.
52     * We do encode characters that cannot be represented in XML using the following escape sequence:
53     * _xHHHH_ where H represents a hexadecimal character in the character's value...
54     * So you could end up with something like _x0008_ in a string (either in a cell value (<v>)
55     * element or in the shared string <t> element.
56     *
57     * @param  string $value Value to escape
58     *
59     * @return string
60     */
61    public static function controlCharacterPHP2OOXML($value = '')
62    {
63        if (empty(self::$controlCharacters)) {
64            self::buildControlCharacters();
65        }
66
67        return str_replace(array_values(self::$controlCharacters), array_keys(self::$controlCharacters), $value);
68    }
69
70    /**
71     * Return a number formatted for being integrated in xml files.
72     *
73     * @param float $number
74     * @param int $decimals
75     *
76     * @return string
77     */
78    public static function numberFormat($number, $decimals)
79    {
80        return number_format($number, $decimals, '.', '');
81    }
82
83    /**
84     * @param int $dec
85     *
86     * @see http://stackoverflow.com/a/7153133/2235790
87     *
88     * @author velcrow
89     *
90     * @return string
91     */
92    public static function chr($dec)
93    {
94        if ($dec <= 0x7F) {
95            return chr($dec);
96        }
97        if ($dec <= 0x7FF) {
98            return chr(($dec >> 6) + 192) . chr(($dec & 63) + 128);
99        }
100        if ($dec <= 0xFFFF) {
101            return chr(($dec >> 12) + 224) . chr((($dec >> 6) & 63) + 128) . chr(($dec & 63) + 128);
102        }
103        if ($dec <= 0x1FFFFF) {
104            return chr(($dec >> 18) + 240) . chr((($dec >> 12) & 63) + 128) . chr((($dec >> 6) & 63) + 128) . chr(($dec & 63) + 128);
105        }
106
107        return '';
108    }
109
110    /**
111     * Convert from OpenXML escaped control character to PHP control character.
112     *
113     * @param string $value Value to unescape
114     *
115     * @return string
116     */
117    public static function controlCharacterOOXML2PHP($value = '')
118    {
119        if (empty(self::$controlCharacters)) {
120            self::buildControlCharacters();
121        }
122
123        return str_replace(array_keys(self::$controlCharacters), array_values(self::$controlCharacters), $value);
124    }
125
126    /**
127     * Check if a string contains UTF-8 data.
128     *
129     * @param string $value
130     *
131     * @return bool
132     */
133    public static function isUTF8($value = '')
134    {
135        return is_string($value) && ($value === '' || preg_match('/^./su', $value) == 1);
136    }
137
138    /**
139     * Return UTF8 encoded value.
140     *
141     * @param null|string $value
142     *
143     * @return ?string
144     */
145    public static function toUTF8($value = '')
146    {
147        if (null !== $value && !self::isUTF8($value)) {
148            // PHP8.2 : utf8_encode is deprecated, but mb_convert_encoding always usable
149            $value = (function_exists('mb_convert_encoding')) ? mb_convert_encoding($value, 'UTF-8', 'ISO-8859-1') : utf8_encode($value);
150        }
151
152        return $value;
153    }
154
155    /**
156     * Returns unicode from UTF8 text.
157     *
158     * The function is splitted to reduce cyclomatic complexity
159     *
160     * @param string $text UTF8 text
161     *
162     * @return string Unicode text
163     *
164     * @since 0.11.0
165     */
166    public static function toUnicode($text)
167    {
168        return self::unicodeToEntities(self::utf8ToUnicode($text));
169    }
170
171    /**
172     * Returns unicode array from UTF8 text.
173     *
174     * @param string $text UTF8 text
175     *
176     * @return array
177     *
178     * @since 0.11.0
179     * @see http://www.randomchaos.com/documents/?source=php_and_unicode
180     */
181    public static function utf8ToUnicode($text)
182    {
183        $unicode = [];
184        $values = [];
185        $lookingFor = 1;
186
187        // Gets unicode for each character
188        for ($i = 0; $i < strlen($text); ++$i) {
189            $thisValue = ord($text[$i]);
190            if ($thisValue < 128) {
191                $unicode[] = $thisValue;
192            } else {
193                if (count($values) == 0) {
194                    $lookingFor = $thisValue < 224 ? 2 : 3;
195                }
196                $values[] = $thisValue;
197                if (count($values) == $lookingFor) {
198                    if ($lookingFor == 3) {
199                        $number = (($values[0] % 16) * 4096) + (($values[1] % 64) * 64) + ($values[2] % 64);
200                    } else {
201                        $number = (($values[0] % 32) * 64) + ($values[1] % 64);
202                    }
203                    $unicode[] = $number;
204                    $values = [];
205                    $lookingFor = 1;
206                }
207            }
208        }
209
210        return $unicode;
211    }
212
213    /**
214     * Returns entites from unicode array.
215     *
216     * @param array $unicode
217     *
218     * @return string
219     *
220     * @since 0.11.0
221     * @see http://www.randomchaos.com/documents/?source=php_and_unicode
222     */
223    private static function unicodeToEntities($unicode)
224    {
225        $entities = '';
226
227        foreach ($unicode as $value) {
228            if ($value != 65279) {
229                $entities .= $value > 127 ? '\uc0{\u' . $value . '}' : chr($value);
230            }
231        }
232
233        return $entities;
234    }
235
236    /**
237     * Return name without underscore for < 0.10.0 variable name compatibility.
238     *
239     * @param string $value
240     *
241     * @return string
242     */
243    public static function removeUnderscorePrefix($value)
244    {
245        if (null !== $value) {
246            if (substr($value, 0, 1) == '_') {
247                $value = substr($value, 1);
248            }
249        }
250
251        return $value;
252    }
253}