1<?php
2
3namespace iplx\Http;
4
5use InvalidArgumentException;
6use Psr\Http\Message\UriInterface;
7
8class Uri implements UriInterface
9{
10    protected $scheme;
11
12    protected $host;
13
14    protected $port;
15
16    protected $user;
17
18    protected $pass;
19
20    protected $path;
21
22    protected $query;
23
24    protected $fragment;
25
26    public function __construct($uri = null)
27    {
28        $parts = parse_url($uri);
29
30        if ($parts === false) {
31            throw new InvalidArgumentException();
32        }
33
34        foreach ($parts as $component => $value) {
35            $this->$component = $value;
36        }
37    }
38
39    public function getScheme()
40    {
41        return $this->scheme;
42    }
43
44    public function getAuthority()
45    {
46        // Weak type check to also check null
47        if ($this->host == '') {
48            return '';
49        }
50
51        $authority = $this->host;
52
53        $userInfo = $this->getUserInfo();
54        $port = $this->getPort();
55
56        if ($userInfo) {
57            $authority = "$userInfo@$authority";
58        }
59
60        if ($port !== null) {
61            $authority .= ":$port";
62        }
63
64        return $authority;
65    }
66
67    public function getUserInfo()
68    {
69        $userInfo = $this->user;
70
71        if ($this->pass !== null) {
72            $userInfo .= ":{$this->pass}";
73        }
74
75        return $userInfo;
76    }
77
78    public function getHost()
79    {
80        return $this->host;
81    }
82
83    public function getPort()
84    {
85        return $this->port;
86    }
87
88    public function getPath()
89    {
90        return $this->path;
91    }
92
93    public function getQuery()
94    {
95        return $this->query;
96    }
97
98    public function getFragment()
99    {
100        return $this->fragment;
101    }
102
103    public function withScheme($scheme)
104    {
105        $uri = clone $this;
106        $uri->scheme = $scheme;
107
108        return $uri;
109    }
110
111    public function withUserInfo($user, $password = null)
112    {
113        $uri = clone $this;
114        $uri->user = $user;
115        $uri->pass = $password;
116
117        return $uri;
118    }
119
120    public function withHost($host)
121    {
122        $uri = clone $this;
123        $uri->host = $host;
124
125        return $uri;
126    }
127
128    public function withPort($port)
129    {
130        $uri = clone $this;
131        $uri->port = $port;
132
133        return $uri;
134    }
135
136    public function withPath($path)
137    {
138        $uri = clone $this;
139        $uri->path = $path;
140
141        return $uri;
142    }
143
144    public function withQuery($query)
145    {
146        $uri = clone $this;
147        $uri->query = $query;
148
149        return $uri;
150    }
151
152    public function withFragment($fragment)
153    {
154        $uri = clone $this;
155        $uri->fragment = $fragment;
156
157        return $uri;
158    }
159
160    public function __toString()
161    {
162        $scheme = $this->getScheme();
163        $authority = $this->getAuthority();
164        $path = $this->getPath();
165        $query = $this->getQuery();
166        $fragment = $this->getFragment();
167
168        $uri = '';
169
170        // Weak type checks to also check null
171
172        if ($scheme != '') {
173            $uri = "$scheme:";
174        }
175
176        if ($authority != '') {
177            $uri .= "//$authority";
178        }
179
180        if ($path != '') {
181            if ($path[0] === '/') {
182                if ($authority == '') {
183                    $path = ltrim($path, '/');
184                }
185            } else {
186                $path = "/$path";
187            }
188
189            $uri .= $path;
190        }
191
192        if ($query != '') {
193            $uri .= "?$query";
194        }
195
196        if ($fragment != '') {
197            $uri .= "#$fragment";
198        }
199
200        return $uri;
201    }
202}
203