Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 /*
|
Chris@0
|
4 * This file is part of the Symfony package.
|
Chris@0
|
5 *
|
Chris@0
|
6 * (c) Fabien Potencier <fabien@symfony.com>
|
Chris@0
|
7 *
|
Chris@0
|
8 * For the full copyright and license information, please view the LICENSE
|
Chris@0
|
9 * file that was distributed with this source code.
|
Chris@0
|
10 */
|
Chris@0
|
11
|
Chris@0
|
12 namespace Symfony\Component\HttpKernel;
|
Chris@0
|
13
|
Chris@0
|
14 /**
|
Chris@0
|
15 * Signs URIs.
|
Chris@0
|
16 *
|
Chris@0
|
17 * @author Fabien Potencier <fabien@symfony.com>
|
Chris@0
|
18 */
|
Chris@0
|
19 class UriSigner
|
Chris@0
|
20 {
|
Chris@0
|
21 private $secret;
|
Chris@0
|
22
|
Chris@0
|
23 /**
|
Chris@0
|
24 * Constructor.
|
Chris@0
|
25 *
|
Chris@0
|
26 * @param string $secret A secret
|
Chris@0
|
27 */
|
Chris@0
|
28 public function __construct($secret)
|
Chris@0
|
29 {
|
Chris@0
|
30 $this->secret = $secret;
|
Chris@0
|
31 }
|
Chris@0
|
32
|
Chris@0
|
33 /**
|
Chris@0
|
34 * Signs a URI.
|
Chris@0
|
35 *
|
Chris@0
|
36 * The given URI is signed by adding a _hash query string parameter
|
Chris@0
|
37 * which value depends on the URI and the secret.
|
Chris@0
|
38 *
|
Chris@0
|
39 * @param string $uri A URI to sign
|
Chris@0
|
40 *
|
Chris@0
|
41 * @return string The signed URI
|
Chris@0
|
42 */
|
Chris@0
|
43 public function sign($uri)
|
Chris@0
|
44 {
|
Chris@0
|
45 $url = parse_url($uri);
|
Chris@0
|
46 if (isset($url['query'])) {
|
Chris@0
|
47 parse_str($url['query'], $params);
|
Chris@0
|
48 } else {
|
Chris@0
|
49 $params = array();
|
Chris@0
|
50 }
|
Chris@0
|
51
|
Chris@0
|
52 $uri = $this->buildUrl($url, $params);
|
Chris@0
|
53
|
Chris@0
|
54 return $uri.(false === strpos($uri, '?') ? '?' : '&').'_hash='.$this->computeHash($uri);
|
Chris@0
|
55 }
|
Chris@0
|
56
|
Chris@0
|
57 /**
|
Chris@0
|
58 * Checks that a URI contains the correct hash.
|
Chris@0
|
59 *
|
Chris@0
|
60 * The _hash query string parameter must be the last one
|
Chris@0
|
61 * (as it is generated that way by the sign() method, it should
|
Chris@0
|
62 * never be a problem).
|
Chris@0
|
63 *
|
Chris@0
|
64 * @param string $uri A signed URI
|
Chris@0
|
65 *
|
Chris@0
|
66 * @return bool True if the URI is signed correctly, false otherwise
|
Chris@0
|
67 */
|
Chris@0
|
68 public function check($uri)
|
Chris@0
|
69 {
|
Chris@0
|
70 $url = parse_url($uri);
|
Chris@0
|
71 if (isset($url['query'])) {
|
Chris@0
|
72 parse_str($url['query'], $params);
|
Chris@0
|
73 } else {
|
Chris@0
|
74 $params = array();
|
Chris@0
|
75 }
|
Chris@0
|
76
|
Chris@0
|
77 if (empty($params['_hash'])) {
|
Chris@0
|
78 return false;
|
Chris@0
|
79 }
|
Chris@0
|
80
|
Chris@0
|
81 $hash = urlencode($params['_hash']);
|
Chris@0
|
82 unset($params['_hash']);
|
Chris@0
|
83
|
Chris@0
|
84 return $this->computeHash($this->buildUrl($url, $params)) === $hash;
|
Chris@0
|
85 }
|
Chris@0
|
86
|
Chris@0
|
87 private function computeHash($uri)
|
Chris@0
|
88 {
|
Chris@0
|
89 return urlencode(base64_encode(hash_hmac('sha256', $uri, $this->secret, true)));
|
Chris@0
|
90 }
|
Chris@0
|
91
|
Chris@0
|
92 private function buildUrl(array $url, array $params = array())
|
Chris@0
|
93 {
|
Chris@0
|
94 ksort($params, SORT_STRING);
|
Chris@0
|
95 $url['query'] = http_build_query($params, '', '&');
|
Chris@0
|
96
|
Chris@0
|
97 $scheme = isset($url['scheme']) ? $url['scheme'].'://' : '';
|
Chris@0
|
98 $host = isset($url['host']) ? $url['host'] : '';
|
Chris@0
|
99 $port = isset($url['port']) ? ':'.$url['port'] : '';
|
Chris@0
|
100 $user = isset($url['user']) ? $url['user'] : '';
|
Chris@0
|
101 $pass = isset($url['pass']) ? ':'.$url['pass'] : '';
|
Chris@0
|
102 $pass = ($user || $pass) ? "$pass@" : '';
|
Chris@0
|
103 $path = isset($url['path']) ? $url['path'] : '';
|
Chris@0
|
104 $query = isset($url['query']) && $url['query'] ? '?'.$url['query'] : '';
|
Chris@0
|
105 $fragment = isset($url['fragment']) ? '#'.$url['fragment'] : '';
|
Chris@0
|
106
|
Chris@0
|
107 return $scheme.$user.$pass.$host.$port.$path.$query.$fragment;
|
Chris@0
|
108 }
|
Chris@0
|
109 }
|