These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Copyright 2016 Facebook, Inc. |
||
4 | * |
||
5 | * You are hereby granted a non-exclusive, worldwide, royalty-free license to |
||
6 | * use, copy, modify, and distribute this software in source code or binary |
||
7 | * form for use in connection with the web services and APIs provided by |
||
8 | * Facebook. |
||
9 | * |
||
10 | * As with any software that integrates with the Facebook platform, your use |
||
11 | * of this software is subject to the Facebook Developer Principles and |
||
12 | * Policies [http://developers.facebook.com/policy/]. This copyright notice |
||
13 | * shall be included in all copies or substantial portions of the software. |
||
14 | * |
||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||
21 | * DEALINGS IN THE SOFTWARE. |
||
22 | * |
||
23 | */ |
||
24 | namespace Facebook\Url; |
||
25 | |||
26 | /** |
||
27 | * Class FacebookUrlDetectionHandler |
||
28 | * |
||
29 | * @package Facebook |
||
30 | */ |
||
31 | class FacebookUrlDetectionHandler implements UrlDetectionInterface |
||
32 | { |
||
33 | /** |
||
34 | * @inheritdoc |
||
35 | */ |
||
36 | public function getCurrentUrl() |
||
37 | { |
||
38 | return $this->getHttpScheme() . '://' . $this->getHostName() . $this->getServerVar('REQUEST_URI'); |
||
39 | } |
||
40 | |||
41 | /** |
||
42 | * Get the currently active URL scheme. |
||
43 | * |
||
44 | * @return string |
||
45 | */ |
||
46 | protected function getHttpScheme() |
||
47 | { |
||
48 | return $this->isBehindSsl() ? 'https' : 'http'; |
||
49 | } |
||
50 | |||
51 | /** |
||
52 | * Tries to detect if the server is running behind an SSL. |
||
53 | * |
||
54 | * @return boolean |
||
55 | */ |
||
56 | protected function isBehindSsl() |
||
57 | { |
||
58 | // Check for proxy first |
||
59 | $protocol = $this->getHeader('X_FORWARDED_PROTO'); |
||
60 | if ($protocol) { |
||
61 | return $this->protocolWithActiveSsl($protocol); |
||
62 | } |
||
63 | |||
64 | $protocol = $this->getServerVar('HTTPS'); |
||
65 | if ($protocol) { |
||
66 | return $this->protocolWithActiveSsl($protocol); |
||
67 | } |
||
68 | |||
69 | return (string)$this->getServerVar('SERVER_PORT') === '443'; |
||
70 | } |
||
71 | |||
72 | /** |
||
73 | * Detects an active SSL protocol value. |
||
74 | * |
||
75 | * @param string $protocol |
||
76 | * |
||
77 | * @return boolean |
||
78 | */ |
||
79 | protected function protocolWithActiveSsl($protocol) |
||
80 | { |
||
81 | $protocol = strtolower((string)$protocol); |
||
82 | |||
83 | return in_array($protocol, ['on', '1', 'https', 'ssl'], true); |
||
84 | } |
||
85 | |||
86 | /** |
||
87 | * Tries to detect the host name of the server. |
||
88 | * |
||
89 | * Some elements adapted from |
||
90 | * |
||
91 | * @see https://github.com/symfony/HttpFoundation/blob/master/Request.php |
||
92 | * |
||
93 | * @return string |
||
94 | */ |
||
95 | protected function getHostName() |
||
96 | { |
||
97 | // Check for proxy first |
||
98 | if ($header = $this->getHeader('X_FORWARDED_HOST') && $this->isValidForwardedHost($header)) { |
||
0 ignored issues
–
show
|
|||
99 | $elements = explode(',', $header); |
||
100 | $host = $elements[count($elements) - 1]; |
||
101 | } elseif (!$host = $this->getHeader('HOST')) { |
||
102 | if (!$host = $this->getServerVar('SERVER_NAME')) { |
||
103 | $host = $this->getServerVar('SERVER_ADDR'); |
||
104 | } |
||
105 | } |
||
106 | |||
107 | // trim and remove port number from host |
||
108 | // host is lowercase as per RFC 952/2181 |
||
109 | $host = strtolower(preg_replace('/:\d+$/', '', trim($host))); |
||
110 | |||
111 | // Port number |
||
112 | $scheme = $this->getHttpScheme(); |
||
113 | $port = $this->getCurrentPort(); |
||
114 | $appendPort = ':' . $port; |
||
115 | |||
116 | // Don't append port number if a normal port. |
||
117 | if (($scheme == 'http' && $port == '80') || ($scheme == 'https' && $port == '443')) { |
||
118 | $appendPort = ''; |
||
119 | } |
||
120 | |||
121 | return $host . $appendPort; |
||
122 | } |
||
123 | |||
124 | protected function getCurrentPort() |
||
125 | { |
||
126 | // Check for proxy first |
||
127 | $port = $this->getHeader('X_FORWARDED_PORT'); |
||
128 | if ($port) { |
||
129 | return (string)$port; |
||
130 | } |
||
131 | |||
132 | $protocol = (string)$this->getHeader('X_FORWARDED_PROTO'); |
||
133 | if ($protocol === 'https') { |
||
134 | return '443'; |
||
135 | } |
||
136 | |||
137 | return (string)$this->getServerVar('SERVER_PORT'); |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * Returns the a value from the $_SERVER super global. |
||
142 | * |
||
143 | * @param string $key |
||
144 | * |
||
145 | * @return string |
||
146 | */ |
||
147 | protected function getServerVar($key) |
||
148 | { |
||
149 | return isset($_SERVER[$key]) ? $_SERVER[$key] : ''; |
||
150 | } |
||
151 | |||
152 | /** |
||
153 | * Gets a value from the HTTP request headers. |
||
154 | * |
||
155 | * @param string $key |
||
156 | * |
||
157 | * @return string |
||
158 | */ |
||
159 | protected function getHeader($key) |
||
160 | { |
||
161 | return $this->getServerVar('HTTP_' . $key); |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Checks if the value in X_FORWARDED_HOST is a valid hostname |
||
166 | * Could prevent unintended redirections |
||
167 | * |
||
168 | * @param string $header |
||
169 | * |
||
170 | * @return boolean |
||
171 | */ |
||
172 | protected function isValidForwardedHost($header) |
||
173 | { |
||
174 | $elements = explode(',', $header); |
||
175 | $host = $elements[count($elements) - 1]; |
||
176 | |||
177 | return preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $host) //valid chars check |
||
178 | && 0 < strlen($host) && strlen($host) < 254 //overall length check |
||
179 | && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $host); //length of each label |
||
180 | } |
||
181 | } |
||
182 |
This error can happen if you refactor code and forget to move the variable initialization.
Let’s take a look at a simple example:
The above code is perfectly fine. Now imagine that we re-order the statements:
In that case,
$x
would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.