• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aimeos / aimeos-base / 444bfe8c-7c5f-4827-929d-1e530918e9c8

27 May 2025 10:04AM UTC coverage: 88.615% (+0.006%) from 88.609%
444bfe8c-7c5f-4827-929d-1e530918e9c8

push

circleci

aimeos
Use correct flag for htmlentities() when encoding for XML

1 of 1 new or added line in 1 file covered. (100.0%)

4 existing lines in 1 file now uncovered.

1689 of 1906 relevant lines covered (88.61%)

11.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.29
/src/Str.php
1
<?php
2

3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2020-2025
6
 * @package Base
7
 */
8

9

10
namespace Aimeos\Base;
11

12

13
/**
14
 * String utility class
15
 *
16
 * @package Base
17
 */
18
class Str
19
{
20
        use \Aimeos\Macro\Macroable;
21

22

23
        private static $node;
24
        private static $seq = 0;
25

26

27
        /**
28
         * Returns the sub-string after the given needle.
29
         *
30
         * @param mixed $str Stringable value
31
         * @param mixed $needles String or strings to search for
32
         * @return string|null Sub-string after the needle or NULL if needle is not part of the string
33
         */
34
        public static function after( $str, $needles ) : ?string
35
        {
36
                $str = (string) $str;
2✔
37

38
                foreach( (array) $needles as $needle )
2✔
39
                {
40
                        $needle = (string) $needle;
2✔
41

42
                        if( ( $len = strlen( $needle ) ) > 0 && ( $pos = strpos( $str, $needle ) ) !== false
2✔
43
                                && ( $result = substr( $str, $pos + $len ) ) !== false
2✔
44
                        ) {
45
                                return $result;
2✔
46
                        }
47
                }
48

49
                return null;
2✔
50
        }
51

52

53
        /**
54
         * Returns the sub-string before the given needle.
55
         *
56
         * @param mixed $str Stringable value
57
         * @param mixed $needles String or strings to search for
58
         * @return string|null Sub-string before the needle or NULL if needle is not part of the string
59
         */
60
        public static function before( $str, $needles ) : ?string
61
        {
62
                $str = (string) $str;
2✔
63

64
                foreach( (array) $needles as $needle )
2✔
65
                {
66
                        $needle = (string) $needle;
2✔
67

68
                        if( $needle !== '' && ( $pos = strpos( $str, $needle ) ) !== false
2✔
69
                                && ( $result = substr( $str, 0, $pos ) ) !== false
2✔
70
                        ) {
71
                                return $result;
2✔
72
                        }
73
                }
74

75
                return null;
2✔
76
        }
77

78

79
        /**
80
         * Replaces special HTML characters by their entities.
81
         *
82
         * @param mixed $str Stringable value
83
         * @param int $flags Which characters to encode
84
         * @return string String which isn't interpreted as HTML and save to include in HTML documents
85
         */
86
        public static function decode( $str, int $flags = ENT_SUBSTITUTE | ENT_QUOTES | ENT_HTML5 ) : string
87
        {
88
                return str_replace( '&#96;', '`', htmlspecialchars_decode( (string) $str, $flags | ENT_QUOTES ) );
2✔
89
        }
90

91

92
        /**
93
         * Tests if the strings ends with the needle.
94
         *
95
         * @param mixed $str Stringable value
96
         * @param array|string|null $needles String/character or list thereof to compare with
97
         * @return bool TRUE if string ends with needle, FALSE if not
98
         */
99
        public static function ends( $str, $needles ) : bool
100
        {
101
                $str = (string) $str;
2✔
102

103
                if( $str === '' || $needles == null ) {
2✔
104
                        return false;
2✔
105
                }
106

107
                foreach( (array) $needles as $needle )
2✔
108
                {
109
                        $needle = (string) $needle;
2✔
110

111
                        if( $needle !== '' && substr_compare( $str, $needle, -strlen( $needle ) ) === 0 ) {
2✔
112
                                return true;
2✔
113
                        }
114
                }
115

116
                return false;
2✔
117
        }
118

119

120
        /**
121
         * Replaces special HTML characters by their entities.
122
         *
123
         * @param mixed $str Stringable value
124
         * @param int $flags Which characters to encode
125
         * @return string String which isn't interpreted as HTML and save to include in HTML documents
126
         */
127
        public static function html( $str, int $flags = ENT_SUBSTITUTE | ENT_QUOTES | ENT_HTML5 ) : string
128
        {
129
                return htmlspecialchars( (string) $str, $flags, 'UTF-8' );
22✔
130
        }
131

132

133
        /**
134
         * Tests if the strings contains all of the needles.
135
         *
136
         * @param mixed $str Stringable value
137
         * @param string|array|null $needles String/character or list thereof to search for
138
         * @return bool TRUE if string contains all needles, FALSE if not
139
         */
140
        public static function in( $str, $needles ) : bool
141
        {
142
                $str = (string) $str;
2✔
143

144
                if( $needles == null ) {
2✔
145
                        return false;
2✔
146
                }
147

148
                foreach( (array) $needles as $needle )
2✔
149
                {
150
                        $needle = (string) $needle;
2✔
151

152
                        if( $needle === '' || strpos( $str, $needle ) === false ) {
2✔
153
                                return false;
2✔
154
                        }
155
                }
156

157
                return true;
2✔
158
        }
159

160

161
        /**
162
         * Transforms the string into a suitable URL segment.
163
         *
164
         * @param mixed $str Stringable value
165
         * @param string $lang Two letter ISO language code
166
         * @param string $sep Separator between the words
167
         * @return string String suitable for an URL segment
168
         */
169
        public static function slug( $str, string $lang = 'en', string $sep = '-' ) : string
170
        {
171
                if( $fcn = static::macro( 'slug' ) ) {
6✔
172
                        return $fcn( $str, $lang, $sep );
4✔
173
                }
174

175
                $str = \voku\helper\ASCII::to_ascii( (string) $str, $lang );
2✔
176
                $str = strtolower( preg_replace( '/[^A-Za-z0-9\_\-\~\.]+/', $sep, $str ) );
2✔
177
                return trim( preg_replace( '/(' . preg_quote( $sep, '/' ) . '){2,}/', $sep, $str ), $sep );
2✔
178
        }
179

180

181
        /**
182
         * Tests if the strings contains at least one of the needles.
183
         *
184
         * @param mixed $str Stringable value
185
         * @param array $needles Strings or characters to search for
186
         * @return bool TRUE if string contains at least one needle, FALSE if it contains none
187
         */
188
        public static function some( $str, array $needles ) : bool
189
        {
190
                $str = (string) $str;
2✔
191

192
                foreach( $needles as $needle )
2✔
193
                {
194
                        $needle = (string) $needle;
2✔
195

196
                        if( $needle !== '' && strpos( $str, $needle ) !== false ) {
2✔
197
                                return true;
2✔
198
                        }
199
                }
200

201
                return false;
2✔
202
        }
203

204

205
        /**
206
         * Tests if the strings starts with the needle.
207
         *
208
         * @param mixed $str Stringable value
209
         * @param array|string|null $needles String/character or list thereof to compare with
210
         * @return bool TRUE if string starts with needle, FALSE if not
211
         */
212
        public static function starts( $str, $needles ) : bool
213
        {
214
                $str = (string) $str;
14✔
215

216
                if( $str === '' || $needles == null ) {
14✔
217
                        return false;
2✔
218
                }
219

220
                foreach( (array) $needles as $needle )
14✔
221
                {
222
                        $needle = (string) $needle;
14✔
223

224
                        if( $needle !== '' && strncmp( $str, $needle, strlen( $needle ) ) === 0 ) {
14✔
225
                                return true;
8✔
226
                        }
227
                }
228

229
                return false;
8✔
230
        }
231

232

233
        /**
234
         * Returns a date formatted according to the given format string.
235
         *
236
         * @param string $format DateTime format string but with format characters preceded by "%"
237
         * @return string String with date/time according to the format string
238
         */
239
        public static function strtime( string $format ) : string
240
        {
241
                $format = str_replace( ['%M', '%S'], ['%i', '%s'], $format );
2✔
242
                return trim( date_create()->format( str_replace( '\\%\\', '', '\\' . join( '\\', str_split( $format ) ) ) ) );
2✔
243
        }
244

245

246
        /**
247
         * Generates a unique ID string suitable as global identifier
248
         *
249
         * The ID is similar to an UUID and is as unique as an UUID but it's human
250
         * readable string is only 20 bytes long. Additionally, the unique ID is
251
         * optimized for being used as primary key in databases.
252
         *
253
         * @return string Global unique ID of 20 bytes length
254
         */
255
        public static function uid() : string
256
        {
257
                if( self::$node === null )
2✔
258
                {
259
                        try {
260
                                self::$node = random_bytes( 6 );
2✔
UNCOV
261
                        } catch( \Throwable $t ) {
×
UNCOV
262
                                if( function_exists( 'openssl_random_pseudo_bytes' ) ) {
×
UNCOV
263
                                        self::$node = openssl_random_pseudo_bytes( 6 );
×
264
                                } else {
UNCOV
265
                                        self::$node = pack( 'n*', rand( 0, 0xffff ), rand( 0, 0xffff ), rand( 0, 0xffff ) );
×
266
                                }
267
                        }
268
                }
269

270
                $time = microtime( true );
2✔
271
                $sec = (int) $time;
2✔
272
                $usec = (int) ( fmod( $time, 1 ) * 1000000 );
2✔
273

274
                self::$seq = self::$seq + 1 & 0xfff; // 20 bits for sequence (1 to 4,095), wraps around
2✔
275

276
                $hsec = ( $sec & 0xff00000000 ) >> 32; // 5th byte from seconds till 1970-01-01T00:00:00 (on 64 bit platforms)
2✔
277
                $lsec = $sec & 0xffffffff; // Lowest 32 bits from seconds till 1970-01-01T00:00:00
2✔
278
                $husec = ( $usec & 0xffff0 ) >> 4; // Highest 16 bits from micro seconds (total 20 bits)
2✔
279
                $mix = ( $usec & 0xf ) << 4 | ( self::$seq & 0xf00 ) >> 8; // Lowest 4 bits (usec) and highest 4 bits (seq)
2✔
280
                $lseq = self::$seq & 0xff; // Lowest 16 bits from sequence
2✔
281

282
                // 5 bytes seconds, 2 byte usec, 1 byte usec+seq, 1 byte seq, 6 bytes node
283
                $uid = base64_encode( pack( 'CNnCC', $hsec, $lsec, $husec, $mix, $lseq ) . self::$node );
2✔
284

285
                return str_replace( ['+', '/'], ['-', '_'], $uid ); // URL safety
2✔
286
        }
287
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc