Completed
Push — master ( 542186...fb692e )
by ignace nyamagana
04:16
created

Host::createFromArray()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 18
ccs 9
cts 9
cp 1
rs 9.2
cc 4
eloc 9
nc 4
nop 2
crap 4
1
<?php
2
/**
3
 * League.Uri (http://uri.thephpleague.com)
4
 *
5
 * @package   League.uri
6
 * @author    Ignace Nyamagana Butera <[email protected]>
7
 * @copyright 2013-2015 Ignace Nyamagana Butera
8
 * @license   https://github.com/thephpleague/uri/blob/master/LICENSE (MIT License)
9
 * @version   4.2.0
10
 * @link      https://github.com/thephpleague/uri/
11
 */
12
namespace League\Uri\Components;
13
14
use InvalidArgumentException;
15
use League\Uri\Interfaces\Host as HostInterface;
16
17
/**
18
 * Value object representing a URI host component.
19
 *
20
 * @package League.uri
21
 * @author  Ignace Nyamagana Butera <[email protected]>
22
 * @since   1.0.0
23
 */
24
class Host extends AbstractHierarchicalComponent implements HostInterface
25
{
26
    use HostIpTrait;
27
28
    use HostnameInfoTrait;
29
30
    use HostnameTrait;
31
32
    /**
33
     * HierarchicalComponent delimiter
34
     *
35
     * @var string
36
     */
37
    protected static $separator = '.';
38
39
    /**
40
     * Host literal representation
41
     *
42
     * @var string
43
     */
44
    protected $host;
45
46
    /**
47
     * return a new instance from an array or a traversable object
48
     *
49
     * @param \Traversable|string[] $data The segments list
50
     * @param int                   $type one of the constant IS_ABSOLUTE or IS_RELATIVE
51
     *
52
     * @throws InvalidArgumentException If $type is not a recognized constant
53
     *
54
     * @return static
55
     */
56 162
    public static function createFromArray($data, $type = self::IS_RELATIVE)
57
    {
58 162
        static $type_list = [self::IS_ABSOLUTE => 1, self::IS_RELATIVE => 1];
59
60 162
        if (!isset($type_list[$type])) {
61 3
            throw new InvalidArgumentException('Please verify the submitted constant');
62
        }
63
64 159
        if (empty($data)) {
65 12
            return new static();
66
        }
67
68 147
        if ([''] === $data) {
69 3
            return new static('');
70
        }
71
72 144
        return new static(static::formatComponentString($data, $type));
73
    }
74
75
76
    /**
77
     * New instance
78
     *
79
     * @param null|string $host
80
     */
81 1138
    public function __construct($host = null)
82
    {
83 1138
        $this->data = $this->validate($host);
84 1072
        $this->setLiteral();
85 1072
    }
86
87
    /**
88
     * Returns whether or not the host is an IDN
89
     *
90
     * @return bool
91
     */
92 9
    public function isIdn()
93
    {
94 9
        return $this->isIdn;
95
    }
96
97
    /**
98
     * Returns whether or not the host is an IP address
99
     *
100
     * @return bool
101
     */
102 1072
    public function isIp()
103
    {
104 1072
        return $this->hostAsIpv4 || $this->hostAsIpv6;
105
    }
106
107
    /**
108
     * Returns whether or not the host is an IPv4 address
109
     *
110
     * @return bool
111
     */
112 39
    public function isIpv4()
113
    {
114 39
        return $this->hostAsIpv4;
115
    }
116
117
    /**
118
     * Returns whether or not the host is an IPv6 address
119
     *
120
     * @return bool
121
     */
122 39
    public function isIpv6()
123
    {
124 39
        return $this->hostAsIpv6;
125
    }
126
127
    /**
128
     * Returns whether or not the host has a ZoneIdentifier
129
     *
130
     * @return bool
131
     *
132
     * @see http://tools.ietf.org/html/rfc6874#section-4
133
     */
134 12
    public function hasZoneIdentifier()
135
    {
136 12
        return $this->hasZoneIdentifier;
137
    }
138
139
    /**
140
     * Host literal setter
141
     */
142 1072
    protected function setLiteral()
143
    {
144 1072
        $this->host = !$this->isIp() ? $this->__toString() : $this->data[0];
145 1072
    }
146
147
    /**
148
     * DEPRECATION WARNING! This method will be removed in the next major point release
149
     *
150
     * @deprecated deprecated since version 4.2
151
     *
152
     * Returns the instance literal representation
153
     * without encoding
154
     *
155
     * @return string
156
     */
157
    public function getLiteral()
158
    {
159
        return $this->host;
160
    }
161
162
    /**
163
     * validate the submitted data
164
     *
165
     * @param string $str
166
     *
167
     * @return array
168
     */
169 1138
    protected function validate($str)
170
    {
171 1138
        if (null === $str) {
172 354
            return [];
173
        }
174
175 1018
        $str = $this->validateString($str);
176 1009
        if ('' === $str) {
177 30
            return [''];
178
        }
179
180 1000
        $res = $this->validateIpHost($str);
181 1000
        if (!empty($res)) {
182 120
            return $res;
183
        }
184
185 901
        return $this->validateStringHost($str);
186
    }
187
188
    /**
189
     * Retrieves a single host label.
190
     *
191
     * Retrieves a single host label. If the label offset has not been set,
192
     * returns the default value provided.
193
     *
194
     * @param string $offset  the label offset
195
     * @param mixed  $default Default value to return if the offset does not exist.
196
     *
197
     * @return mixed
198
     */
199 3
    public function getLabel($offset, $default = null)
200
    {
201 3
        if (isset($this->data[$offset])) {
202 3
            return $this->isIdn ? $this->data[$offset] : idn_to_ascii($this->data[$offset]);
203
        }
204
205 3
        return $default;
206
    }
207
208
    /**
209
     * Returns an array representation of the host
210
     *
211
     * @return array
212
     */
213 865
    public function toArray()
214
    {
215 865
        return $this->convertToAscii($this->data, !$this->isIdn);
216
    }
217
218
    /**
219
     * @inheritdoc
220
     */
221 1048
    public function getContent()
222
    {
223 1048
        if ([] === $this->data) {
224 369
            return null;
225
        }
226
227 922
        if ($this->isIp()) {
228 75
            return $this->formatIp($this->data[0]);
229
        }
230
231 859
        return $this->formatComponentString($this->toArray(), $this->isAbsolute);
232
    }
233
234
    /**
235
     * @inheritdoc
236
     */
237 2
    public function __debugInfo()
238
    {
239 2
        return ['host' => $this->__toString()];
240
    }
241
242
    /**
243
     * @inheritdoc
244
     */
245 15
    public static function __set_state(array $properties)
246
    {
247 15
        $host = static::createFromArray($properties['data'], $properties['isAbsolute']);
248 15
        $host->hostnameInfoLoaded = $properties['hostnameInfoLoaded'];
249 15
        $host->hostnameInfo = $properties['hostnameInfo'];
250
251 15
        return $host;
252
    }
253
254
    /**
255
     * Returns a host in his punycode encoded form
256
     *
257
     * This method MUST retain the state of the current instance, and return
258
     * an instance with the host transcoded using to ascii the RFC 3492 rules
259
     *
260
     * @see http://tools.ietf.org/html/rfc3492
261
     *
262
     * @return static
263
     */
264 108
    public function toAscii()
265
    {
266 108
        if ($this->isIp() || !$this->isIdn) {
267 36
            return $this;
268
        }
269
270 75
        return $this->modify($this->formatComponentString(
271 75
            $this->convertToAscii($this->data, $this->isIdn),
272 75
            $this->isAbsolute
273 50
        ));
274
    }
275
276
    /**
277
     * Returns a host in his IDN form
278
     *
279
     * This method MUST retain the state of the current instance, and return
280
     * an instance with the host in its IDN form using RFC 3492 rules
281
     *
282
     * @see http://tools.ietf.org/html/rfc3492
283
     *
284
     * @return static
285
     */
286 81
    public function toUnicode()
287
    {
288 81
        if ($this->isIp() || $this->isIdn) {
289 69
            return $this;
290
        }
291
292 72
        return $this->modify($this->formatComponentString($this->data, $this->isAbsolute));
293
    }
294
295
    /**
296
     * @inheritdoc
297
     */
298 886
    protected static function formatComponentString($data, $type)
299
    {
300 886
        $hostname = implode(static::$separator, array_reverse(static::validateIterator($data)));
301 874
        if (self::IS_ABSOLUTE == $type) {
302 36
            return $hostname.static::$separator;
303
        }
304
305 850
        return $hostname;
306
    }
307
308
    /**
309
     * Return an host without its zone identifier according to RFC6874
310
     *
311
     * This method MUST retain the state of the current instance, and return
312
     * an instance without the host zone identifier according to RFC6874
313
     *
314
     * @see http://tools.ietf.org/html/rfc6874#section-4
315
     *
316
     * @return static
317
     */
318 18
    public function withoutZoneIdentifier()
319
    {
320 18
        if ($this->hasZoneIdentifier) {
321 9
            return $this->modify(substr($this->data[0], 0, strpos($this->data[0], '%')));
322
        }
323
324 9
        return $this;
325
    }
326
327
    /**
328
     * Validated the Host Label Count
329
     *
330
     * @param array $labels Host labels
331
     *
332
     * @throws InvalidArgumentException If the validation fails
333
     */
334 886
    protected function assertLabelsCount(array $labels)
335
    {
336 886
        if (127 <= count(array_merge($this->data, $labels))) {
337 3
            throw new InvalidArgumentException('Invalid Hostname, verify labels count');
338
        }
339 883
    }
340
341
    /**
342
     * set the FQDN property
343
     *
344
     * @param string $str
345
     *
346
     * @return string
347
     */
348 901
    protected function setIsAbsolute($str)
349
    {
350 901
        $this->isAbsolute = self::IS_RELATIVE;
351 901
        if ('.' == mb_substr($str, -1, 1, 'UTF-8')) {
352 42
            $this->isAbsolute = self::IS_ABSOLUTE;
353 42
            $str = mb_substr($str, 0, -1, 'UTF-8');
354 28
        }
355
356 901
        return $str;
357
    }
358
359
    /**
360
     * @inheritdoc
361
     */
362 60
    public function append($component)
363
    {
364 60
        return $this->newCollectionInstance(array_merge(
365 60
            $this->validateComponent($component)->toArray(),
366 60
            $this->toArray()
367 40
        ));
368
    }
369
}
370