Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
94.74% covered (success)
94.74%
54 / 57
72.73% covered (warning)
72.73%
8 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
Text
94.74% covered (success)
94.74%
54 / 57
72.73% covered (warning)
72.73%
8 / 11
39.22
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
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
6.03
 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 < 0) {
98            return '';
99        }
100        if ($dec <= 0x7F) {
101            return chr($dec);
102        }
103        if ($dec <= 0x7FF) {
104            return chr(($dec >> 6) + 192) . chr(($dec & 63) + 128);
105        }
106        if ($dec <= 0xFFFF) {
107            return chr(($dec >> 12) + 224) . chr((($dec >> 6) & 63) + 128) . chr(($dec & 63) + 128);
108        }
109        if ($dec <= 0x1FFFFF) {
110            return chr(($dec >> 18) + 240) . chr((($dec >> 12) & 63) + 128) . chr((($dec >> 6) & 63) + 128) . chr(($dec & 63) + 128);
111        }
112
113        return '';
114    }
115
116    /**
117     * Convert from OpenXML escaped control character to PHP control character.
118     *
119     * @param string $value Value to unescape
120     *
121     * @return string
122     */
123    public static function controlCharacterOOXML2PHP($value = '')
124    {
125        if (empty(self::$controlCharacters)) {
126            self::buildControlCharacters();
127        }
128
129        return str_replace(array_keys(self::$controlCharacters), array_values(self::$controlCharacters), $value);
130    }
131
132    /**
133     * Check if a string contains UTF-8 data.
134     *
135     * @param string $value
136     *
137     * @return bool
138     */
139    public static function isUTF8($value = '')
140    {
141        return is_string($value) && ($value === '' || preg_match('/^./su', $value) == 1);
142    }
143
144    /**
145     * Return UTF8 encoded value.
146     *
147     * @param null|string $value
148     *
149     * @return ?string
150     */
151    public static function toUTF8($value = '')
152    {
153        if (null !== $value && !self::isUTF8($value)) {
154            // PHP8.2 : utf8_encode is deprecated, but mb_convert_encoding always usable
155            $value = (function_exists('mb_convert_encoding')) ? mb_convert_encoding($value, 'UTF-8', 'ISO-8859-1') : utf8_encode($value);
156            if ($value === false) {
157                throw new Exception('Unable to convert text to UTF-8');
158            }
159        }
160
161        return $value;
162    }
163
164    /**
165     * Returns unicode from UTF8 text.
166     *
167     * The function is splitted to reduce cyclomatic complexity
168     *
169     * @param string $text UTF8 text
170     *
171     * @return string Unicode text
172     *
173     * @since 0.11.0
174     */
175    public static function toUnicode($text)
176    {
177        return self::unicodeToEntities(self::utf8ToUnicode($text));
178    }
179
180    /**
181     * Returns unicode array from UTF8 text.
182     *
183     * @param string $text UTF8 text
184     *
185     * @return array
186     *
187     * @since 0.11.0
188     * @see http://www.randomchaos.com/documents/?source=php_and_unicode
189     */
190    public static function utf8ToUnicode($text)
191    {
192        $unicode = [];
193        $values = [];
194        $lookingFor = 1;
195
196        // Gets unicode for each character
197        for ($i = 0; $i < strlen($text); ++$i) {
198            $thisValue = ord($text[$i]);
199            if ($thisValue < 128) {
200                $unicode[] = $thisValue;
201            } else {
202                if (count($values) == 0) {
203                    $lookingFor = $thisValue < 224 ? 2 : 3;
204                }
205                $values[] = $thisValue;
206                if (count($values) == $lookingFor) {
207                    if ($lookingFor == 3) {
208                        $number = (($values[0] % 16) * 4096) + (($values[1] % 64) * 64) + ($values[2] % 64);
209                    } else {
210                        $number = (($values[0] % 32) * 64) + ($values[1] % 64);
211                    }
212                    $unicode[] = $number;
213                    $values = [];
214                    $lookingFor = 1;
215                }
216            }
217        }
218
219        return $unicode;
220    }
221
222    /**
223     * Returns entites from unicode array.
224     *
225     * @param array $unicode
226     *
227     * @return string
228     *
229     * @since 0.11.0
230     * @see http://www.randomchaos.com/documents/?source=php_and_unicode
231     */
232    private static function unicodeToEntities($unicode)
233    {
234        $entities = '';
235
236        foreach ($unicode as $value) {
237            if ($value != 65279) {
238                $entities .= $value > 127 ? '\uc0{\u' . $value . '}' : chr($value);
239            }
240        }
241
242        return $entities;
243    }
244
245    /**
246     * Return name without underscore for < 0.10.0 variable name compatibility.
247     *
248     * @param string $value
249     *
250     * @return string
251     */
252    public static function removeUnderscorePrefix($value)
253    {
254        if (null !== $value) {
255            if (substr($value, 0, 1) == '_') {
256                $value = substr($value, 1);
257            }
258        }
259
260        return $value;
261    }
262}