Completed
Push — master ( 8426c2...c6eb56 )
by Lars
02:23
created

Url::__construct()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 27
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 1

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 27
ccs 22
cts 22
cp 1
rs 8.8571
cc 1
eloc 21
nc 1
nop 2
crap 1
1
<?php
2
3
/*
4
 * This file is part of the Purl package, a project by Jonathan H. Wage.
5
 *
6
 * (c) 2013 Jonathan H. Wage
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Purl;
13
14
use Pdp\Parser as PslParser;
15
use Pdp\PublicSuffixListManager;
16
17
/**
18
 * Url is a simple OO class for manipulating Urls in PHP.
19
 *
20
 * @author      Jonathan H. Wage <[email protected]>
21
 *
22
 * @property string $scheme
23
 * @property string $host
24
 * @property integer $port
25
 * @property string $user
26
 * @property string $pass
27
 * @property \Purl\Path $path
28
 * @property \Purl\Query $query
29
 * @property \Purl\Fragment $fragment
30
 * @property string $publicSuffix
31
 * @property string $registerableDomain
32
 * @property string $subdomain
33
 * @property string $canonical
34
 * @property string $resource
35
 */
36
class Url extends AbstractPart
37
{
38
    /**
39
     * @var string The original url string.
40
     */
41
    private $url;
42
43
    /**
44
     * @var ParserInterface
45
     */
46
    private $parser;
47
48
    /**
49
     * Construct a new Url instance.
50
     *
51
     * @param string $url
52
     * @param ParserInterface $parser
53
     */
54 59
    public function __construct($url = null, ParserInterface $parser = null)
55
    {
56 59
        $this->data = array(
57 59
            'scheme'             => null,
58 59
            'host'               => null,
59 59
            'port'               => null,
60 59
            'user'               => null,
61 59
            'pass'               => null,
62 59
            'path'               => null,
63 59
            'query'              => null,
64 59
            'fragment'           => null,
65 59
            'publicSuffix'       => null,
66 59
            'registerableDomain' => null,
67 59
            'subdomain'          => null,
68 59
            'canonical'          => null,
69
            'resource'           => null
70 59
        );
71
72 59
        $this->partClassMap = array(
73 59
            'path' => 'Purl\Path',
74 59
            'query' => 'Purl\Query',
75
            'fragment' => 'Purl\Fragment'
76 59
        );
77
78 59
        $this->url = $url;
79 59
        $this->parser = $parser;
80 59
    }
81
82
    /**
83
     * Static convenience method for creating a new Url instance.
84
     *
85
     * @param string $url
86
     * @return Url
87
     */
88 3
    public static function parse($url)
89
    {
90 3
        return new self($url);
91
    }
92
93
    /**
94
     * Extracts urls from a string of text.
95
     *
96
     * @param string $string
97
     * @return array $urls
98
     */
99 1
    public static function extract($string)
100
    {
101 1
        $regex = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,}(\/\S*)?/";
102
103 1
        preg_match_all($regex, $string, $matches);
104 1
        $urls = array();
105 1
        foreach ($matches[0] as $url) {
106 1
            $urls[] = self::parse($url);
107 1
        }
108
109 1
        return $urls;
110
    }
111
112
    /**
113
     * Creates an Url instance based on data available on $_SERVER variable.
114
     *
115
     * @return Url
116
     */
117 1
    public static function fromCurrent()
0 ignored issues
show
Coding Style introduced by
fromCurrent uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
118
    {
119 1
        $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) ? 'https' : 'http';
120
121 1
        $host = $_SERVER['HTTP_HOST'];
122 1
        $baseUrl = "$scheme://$host";
123
124 1
        $url = new self($baseUrl);
125
126 1
        if (!empty($_SERVER['REQUEST_URI'])) {
127
128 1
            if (strpos($_SERVER['REQUEST_URI'], '?') !== false) {
129 1
                list($path, $query) = array_pad(explode('?', $_SERVER['REQUEST_URI'], 2), 2, null);
130 1
            } else {
131 1
                $path = $_SERVER['REQUEST_URI'];
132 1
                $query = '';
133
            }
134
135 1
            $url->set('path', $path);
136 1
            $url->set('query', $query);
137 1
        }
138
139
        // Only set port if different from default (80 or 443)
140 1
        if (!empty($_SERVER['SERVER_PORT'])) {
141 1
            $port = $_SERVER['SERVER_PORT'];
142
143
            if (
144 1
                ($scheme == 'http' && $port != 80)
145
                ||
146 1
                ($scheme == 'https' && $port != 443)
147 1
            ) {
148 1
                $url->set('port', $port);
149 1
            }
150 1
        }
151
152
        // Authentication
153 1
        if (!empty($_SERVER['PHP_AUTH_USER'])) {
154 1
            $url->set('user', $_SERVER['PHP_AUTH_USER']);
155 1
            if (!empty($_SERVER['PHP_AUTH_PW'])) {
156 1
                $url->set('pass', $_SERVER['PHP_AUTH_PW']);
157 1
            }
158 1
        }
159
160 1
        return $url;
161
    }
162
163
    /**
164
     * Gets the ParserInterface instance used to parse this Url instance.
165
     *
166
     * @return ParserInterface
167
     */
168 59
    public function getParser()
169
    {
170 59
        if ($this->parser === null) {
171 58
            $this->parser = self::createDefaultParser();
172 58
        }
173
174 59
        return $this->parser;
175
    }
176
177
    /**
178
     * Sets the ParserInterface instance to use to parse this Url instance.
179
     *
180
     * @param ParserInterface $parser
181
     */
182 1
    public function setParser(ParserInterface $parser)
183
    {
184 1
        $this->parser = $parser;
185 1
    }
186
187
    /**
188
     * Join this Url instance together with another Url instance or a string url.
189
     *
190
     * @param Url|string $url
191
     * @return Url
192
     */
193 1
    public function join($url)
194
    {
195 1
        $this->initialize();
196 1
        $parts = $this->getParser()->parseUrl($url);
197
198 1
        foreach ($parts as $partsKey => $partsValue) {
199 1
            if ($partsValue !== null) {
200 1
                $this->data[$partsKey] = $partsValue;
201 1
            }
202 1
        }
203
204 1
        foreach ($this->data as $key => &$value) {
205 1
            $value = $this->preparePartValue($key, $value);
206 1
        }
207
208 1
        return $this;
209
    }
210
211
    /** @noinspection PhpMissingParentCallCommonInspection */
212
    /**
213
     * @inheritDoc
214
     * @override
215
     */
216 8
    public function set($key, $value)
217
    {
218 8
        $this->initialize();
219 8
        $this->data[$key] = $this->preparePartValue($key, $value);
220
221 8
        return $this;
222
    }
223
224
    /**
225
     * @param $string
226
     */
227 1
    public function setPathString($string)
228
    {
229 1
      $this->set('path', $string);
230 1
    }
231
232
    /**
233
     * Set the Path instance.
234
     *
235
     * @param Path $path
236
     *
237
     * @return $this
238
     */
239 1
    public function setPath(Path $path)
240
    {
241 1
        $this->data['path'] = $path;
242
243 1
        return $this;
244
    }
245
246
    /**
247
     * Get the Path instance.
248
     *
249
     * @return Path
250
     */
251
    public function getPath()
252
    {
253
        $this->initialize();
254
        return $this->data['path'];
255
    }
256
257
    /**
258
     * @param $string
259
     */
260 1
    public function setQueryString($string)
261
    {
262 1
      $this->set('query', $string);
263 1
    }
264
265
    /**
266
     * Set the Query instance.
267
     *
268
     * @param Query $query
269
     *
270
     * @return $this
271
     */
272 2
    public function setQuery(Query $query)
273
    {
274 2
        $this->data['query'] = $query;
275
276 2
        return $this;
277
    }
278
279
    /**
280
     * Get the Query instance.
281
     *
282
     * @return Query
283
     */
284
    public function getQuery()
285
    {
286
        $this->initialize();
287
        return $this->data['query'];
288
    }
289
290
    /**
291
     * @param $string
292
     */
293 1
    public function setFragmentString($string)
294
    {
295 1
        $this->set('fragment', $string);
296 1
    }
297
298
    /**
299
     * Set the Fragment instance.
300
     *
301
     * @param Fragment $fragment
302
     *
303
     * @return $this
304
     */
305 2
    public function setFragment(Fragment $fragment)
306
    {
307 2
        $this->data['fragment'] = $fragment;
308
309 2
        return $this;
310
    }
311
312
    /**
313
     * Get the Fragment instance.
314
     *
315
     * @return Fragment
316
     */
317
    public function getFragment()
318
    {
319
        $this->initialize();
320
        return $this->data['fragment'];
321
    }
322
323
    /**
324
     * Gets the netloc part of the Url. It is the user, pass, host and port returned as a string.
325
     *
326
     * @return string
327
     */
328 1
    public function getNetloc()
329
    {
330 1
        $this->initialize();
331
332 1
        return ($this->user && $this->pass
333 1
            ? $this->user.($this->pass
334 1
                ? ':'.$this->pass : '').'@'
335 1
            : '').$this->host.($this->port
336 1
                ? ':'.$this->port : '');
337
    }
338
339
    /**
340
     * Builds a string url from this Url instance internal data and returns it.
341
     *
342
     * @return string
343
     */
344 17
    public function getUrl()
345
    {
346 17
        $this->initialize();
347
348 17
        return self::httpBuildUrl(
349 17
            array_map(
350 17
                function ($value) {
351 17
                  return (string) $value;
352 17
                },
353 17
                $this->data
354 17
            )
355 17
        );
356
    }
357
358
    /**
359
     * Set the string url for this Url instance and sets initialized to false.
360
     *
361
     * @param string
362
     */
363 2
    public function setUrl($url)
364
    {
365 2
        $this->initialized = false;
366 2
        $this->data = array();
367 2
        $this->url = $url;
368 2
    }
369
370
    /**
371
     * Checks if the Url instance is absolute or not.
372
     *
373
     * @return boolean
374
     */
375 1
    public function isAbsolute()
376
    {
377 1
        $this->initialize();
378 1
        return $this->scheme && $this->host;
379
    }
380
381
    /**
382
     * @inheritDoc
383
     */
384 14
    public function __toString()
385
    {
386 14
        return $this->getUrl();
387
    }
388
389
    /**
390
     * @inheritDoc
391
     */
392 58
    protected function doInitialize()
393
    {
394 58
        $parts = $this->getParser()->parseUrl($this->url);
395
396 58
        foreach ($parts as $k => $v) {
397 58
            if (!isset($this->data[$k])) {
398 58
                $this->data[$k] = $v;
399 58
            }
400 58
        }
401
402 58
        foreach ($this->data as $key => &$value) {
403 58
            $value = $this->preparePartValue($key, $value);
404 58
        }
405 58
    }
406
407
    /**
408
     * Reconstructs a string URL from an array of parts.
409
     *
410
     * @param array $parts
411
     * @return string $url
412
     */
413 17
    private static function httpBuildUrl(array $parts)
414
    {
415 17
        $parts['path'] = ltrim($parts['path'], '/');
416
417 17
        return sprintf('%s://%s%s%s/%s%s%s',
418 17
            $parts['scheme'],
419 17
            $parts['user'] ? sprintf('%s%s@', $parts['user'], $parts['pass'] ? sprintf(':%s', $parts['pass']) : '') : '',
420 17
            $parts['host'],
421 17
            $parts['port'] ? sprintf(':%d', $parts['port']) : '',
422 17
            $parts['path'] ? $parts['path'] : '',
423 17
            $parts['query'] ? '?'.$parts['query'] : '',
424 17
            $parts['fragment'] ? '#'.$parts['fragment'] : ''
425 17
        );
426
    }
427
428
    /**
429
     * Creates the default Parser instance to parse urls.
430
     *
431
     * @return Parser
432
     */
433 58
    private static function createDefaultParser()
434
    {
435 58
        $pslManager = new PublicSuffixListManager(dirname(dirname(__DIR__)) . '/data');
436 58
        $pslParser = new PslParser($pslManager->getList());
437
438 58
        return new Parser($pslParser);
439
    }
440
}
441