1: <?php
2:
3: namespace Guzzle\Http;
4:
5: use Guzzle\Common\Exception\InvalidArgumentException;
6: use Guzzle\Parser\ParserRegistry;
7:
8: 9: 10:
11: class Url
12: {
13: protected $scheme;
14: protected $host;
15: protected $port;
16: protected $username;
17: protected $password;
18: protected $path = '';
19: protected $fragment;
20:
21: 22: 23:
24: protected $query;
25:
26: 27: 28: 29: 30: 31: 32:
33: public static function factory($url)
34: {
35: $parts = ParserRegistry::getInstance()->getParser('url')->parseUrl($url);
36:
37:
38: if (0 !== strlen($parts['query'])) {
39: $parts['query'] = QueryString::fromString($parts['query']);
40: }
41:
42: return new self($parts['scheme'], $parts['host'], $parts['user'],
43: $parts['pass'], $parts['port'], $parts['path'], $parts['query'],
44: $parts['fragment']);
45: }
46:
47: 48: 49: 50: 51: 52: 53:
54: public static function buildUrl(array $parts)
55: {
56: $url = $scheme = '';
57:
58: if (isset($parts['scheme'])) {
59: $scheme = $parts['scheme'];
60: $url .= $scheme . ':';
61: }
62:
63: if (isset($parts['host'])) {
64: $url .= '//';
65: if (isset($parts['user'])) {
66: $url .= $parts['user'];
67: if (isset($parts['pass'])) {
68: $url .= ':' . $parts['pass'];
69: }
70: $url .= '@';
71: }
72:
73: $url .= $parts['host'];
74:
75:
76: if (isset($parts['port'])
77: && !(($scheme == 'http' && $parts['port'] == 80) || ($scheme == 'https' && $parts['port'] == 443))
78: ) {
79: $url .= ':' . $parts['port'];
80: }
81: }
82:
83:
84: if (isset($parts['path']) && 0 !== strlen($parts['path'])) {
85:
86: if ($url && $parts['path'][0] != '/' && substr($url, -1) != '/') {
87: $url .= '/';
88: }
89: $url .= $parts['path'];
90: }
91:
92:
93: if (isset($parts['query'])) {
94: $url .= '?' . $parts['query'];
95: }
96:
97:
98: if (isset($parts['fragment'])) {
99: $url .= '#' . $parts['fragment'];
100: }
101:
102: return $url;
103: }
104:
105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116:
117: public function __construct($scheme, $host, $username = null, $password = null, $port = null, $path = null, QueryString $query = null, $fragment = null)
118: {
119: $this->scheme = $scheme;
120: $this->host = $host;
121: $this->port = $port;
122: $this->username = $username;
123: $this->password = $password;
124: $this->fragment = $fragment;
125: if (!$query) {
126: $this->query = new QueryString();
127: } else {
128: $this->setQuery($query);
129: }
130: $this->setPath($path);
131: }
132:
133: 134: 135:
136: public function __clone()
137: {
138: $this->query = clone $this->query;
139: }
140:
141: 142: 143: 144: 145:
146: public function __toString()
147: {
148: return self::buildUrl($this->getParts());
149: }
150:
151: 152: 153: 154: 155:
156: public function getParts()
157: {
158: return array(
159: 'scheme' => $this->scheme,
160: 'user' => $this->username,
161: 'pass' => $this->password,
162: 'host' => $this->host,
163: 'port' => $this->port,
164: 'path' => $this->getPath(),
165: 'query' => (string) $this->query ?: null,
166: 'fragment' => $this->fragment,
167: );
168: }
169:
170: 171: 172: 173: 174: 175: 176:
177: public function setHost($host)
178: {
179: if (strpos($host, ':') === false) {
180: $this->host = $host;
181: } else {
182: list($host, $port) = explode(':', $host);
183: $this->host = $host;
184: $this->setPort($port);
185: }
186:
187: return $this;
188: }
189:
190: 191: 192: 193: 194:
195: public function getHost()
196: {
197: return $this->host;
198: }
199:
200: 201: 202: 203: 204: 205: 206:
207: public function setScheme($scheme)
208: {
209: $this->scheme = $scheme;
210:
211: return $this;
212: }
213:
214: 215: 216: 217: 218:
219: public function getScheme()
220: {
221: return $this->scheme;
222: }
223:
224: 225: 226: 227: 228: 229: 230:
231: public function setPort($port)
232: {
233: $this->port = $port;
234:
235: return $this;
236: }
237:
238: 239: 240: 241: 242:
243: public function getPort()
244: {
245: if ($this->port) {
246: return $this->port;
247: } elseif ($this->scheme == 'http') {
248: return 80;
249: } elseif ($this->scheme == 'https') {
250: return 443;
251: }
252:
253: return null;
254: }
255:
256: 257: 258: 259: 260: 261: 262:
263: public function setPath($path)
264: {
265: if (is_array($path)) {
266: $this->path = '/' . implode('/', $path);
267: } else {
268: $this->path = (string) $path;
269: }
270:
271: return $this;
272: }
273:
274: 275: 276: 277: 278:
279: public function normalizePath()
280: {
281: if (!$this->path || $this->path == '/' || $this->path == '*') {
282: return $this;
283: }
284:
285:
286: $this->path = str_replace(array('/./', '//'), '/', $this->path);
287:
288:
289: if (strpos($this->path, '..') !== false) {
290:
291:
292: $segments = $this->getPathSegments();
293: $last = end($segments);
294: $trailingSlash = false;
295: if ($last === '') {
296: array_pop($segments);
297: $trailingSlash = true;
298: }
299:
300: while ($last == '..' || $last == '.') {
301: if ($last == '..') {
302: array_pop($segments);
303: $last = array_pop($segments);
304: }
305: if ($last == '.' || $last == '') {
306: $last = array_pop($segments);
307: }
308: }
309:
310: $this->path = implode('/', $segments);
311: if ($trailingSlash) {
312: $this->path .= '/';
313: }
314: }
315:
316: return $this;
317: }
318:
319: 320: 321: 322: 323: 324: 325:
326: public function addPath($relativePath)
327: {
328: if (!$relativePath || $relativePath == '/') {
329: return $this;
330: }
331:
332:
333: if ($relativePath[0] != '/') {
334: $relativePath = '/' . $relativePath;
335: }
336:
337: return $this->setPath(str_replace('//', '/', $this->getPath() . $relativePath));
338: }
339:
340: 341: 342: 343: 344:
345: public function getPath()
346: {
347: return $this->path;
348: }
349:
350: 351: 352: 353: 354:
355: public function getPathSegments()
356: {
357: return array_slice(explode('/', $this->getPath()), 1);
358: }
359:
360: 361: 362: 363: 364: 365: 366:
367: public function setPassword($password)
368: {
369: $this->password = $password;
370:
371: return $this;
372: }
373:
374: 375: 376: 377: 378:
379: public function getPassword()
380: {
381: return $this->password;
382: }
383:
384: 385: 386: 387: 388: 389: 390:
391: public function setUsername($username)
392: {
393: $this->username = $username;
394:
395: return $this;
396: }
397:
398: 399: 400: 401: 402:
403: public function getUsername()
404: {
405: return $this->username;
406: }
407:
408: 409: 410: 411: 412:
413: public function getQuery()
414: {
415: return $this->query;
416: }
417:
418: 419: 420: 421: 422: 423: 424:
425: public function setQuery($query)
426: {
427: if (is_string($query)) {
428: $output = null;
429: parse_str($query, $output);
430: $this->query = new QueryString($output);
431: } elseif (is_array($query)) {
432: $this->query = new QueryString($query);
433: } elseif ($query instanceof QueryString) {
434: $this->query = $query;
435: }
436:
437: return $this;
438: }
439:
440: 441: 442: 443: 444:
445: public function getFragment()
446: {
447: return $this->fragment;
448: }
449:
450: 451: 452: 453: 454: 455: 456:
457: public function setFragment($fragment)
458: {
459: $this->fragment = $fragment;
460:
461: return $this;
462: }
463:
464: 465: 466: 467: 468:
469: public function isAbsolute()
470: {
471: return $this->scheme && $this->host;
472: }
473:
474: 475: 476: 477: 478: 479: 480: 481: 482:
483: public function combine($url)
484: {
485: $url = self::factory($url);
486:
487:
488: if (!$this->isAbsolute() && $url->isAbsolute()) {
489: $url = $url->combine($this);
490: }
491:
492:
493: if ($buffer = $url->getScheme()) {
494: $this->scheme = $buffer;
495: $this->host = $url->getHost();
496: $this->port = $url->getPort();
497: $this->username = $url->getUsername();
498: $this->password = $url->getPassword();
499: $this->path = $url->getPath();
500: $this->query = $url->getQuery();
501: $this->fragment = $url->getFragment();
502: return $this;
503: }
504:
505:
506: if ($buffer = $url->getHost()) {
507: $this->host = $buffer;
508: $this->port = $url->getPort();
509: $this->username = $url->getUsername();
510: $this->password = $url->getPassword();
511: $this->path = $url->getPath();
512: $this->fragment = $url->getFragment();
513: return $this;
514: }
515:
516: $path = $url->getPath();
517: $query = $url->getQuery();
518:
519: if (!$path) {
520: if (count($query)) {
521: $this->query = $query;
522: }
523: } else {
524: if ($path[0] == '/') {
525: $this->path = $path;
526: } else {
527: $this->path .= '/' . $path;
528: }
529: $this->normalizePath();
530: $this->query = $query;
531: }
532:
533: $this->fragment = $url->getFragment();
534:
535: return $this;
536: }
537: }
538: