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