Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
| 1 | <?php |
||
| 38 | class WhipTest extends PHPUnit_Framework_TestCase |
||
| 39 | { |
||
| 40 | /** |
||
| 41 | * Tests that an invalid source format is rejected. |
||
| 42 | * @expectedException \InvalidArgumentException |
||
| 43 | */ |
||
| 44 | public function testInvalidSource() |
||
| 48 | /** |
||
| 49 | * Tests that we get back the right IP when there using superglobals. |
||
| 50 | */ |
||
| 51 | public function testSuperglobal() |
||
|
|
|||
| 52 | { |
||
| 53 | $_SERVER = array('REMOTE_ADDR' => '24.24.24.24'); |
||
| 54 | $lookup = new Whip(Whip::REMOTE_ADDR); |
||
| 55 | $this->assertEquals('24.24.24.24', $lookup->getValidIpAddress()); |
||
| 56 | } |
||
| 57 | |||
| 58 | /** |
||
| 59 | * Tests that we get back 127.0.0.1 when there is no superglobal information |
||
| 60 | * at all. |
||
| 61 | */ |
||
| 62 | public function testEmptySuperglobal() |
||
| 63 | { |
||
| 64 | $_SERVER = array(); |
||
| 65 | $lookup = new Whip(); |
||
| 66 | $this->assertFalse($lookup->getIpAddress()); |
||
| 67 | } |
||
| 68 | |||
| 69 | /** |
||
| 70 | * Helper to get a mocked PSR-7 instance. |
||
| 71 | * |
||
| 72 | * @param string $remoteAddr The remote address to mock. |
||
| 73 | * @param string[][] $headers The headers, in the format expected by Psr-7. |
||
| 74 | */ |
||
| 75 | private function getHttpMessageMock($remoteAddr, array $headers = array()) |
||
| 76 | { |
||
| 77 | $stub = $this->getMockBuilder("Psr\Http\Message\ServerRequestInterface") |
||
| 78 | ->getMock(); |
||
| 79 | |||
| 80 | $stub->method('getServerParams') |
||
| 81 | ->willReturn(array('REMOTE_ADDR' => $remoteAddr)); |
||
| 82 | $stub->method('getHeaders') |
||
| 83 | ->willReturn($headers); |
||
| 84 | |||
| 85 | return $stub; |
||
| 86 | } |
||
| 87 | /** |
||
| 88 | * Tests that we can use a PSR-7 ServerRequestInterface compatible class. |
||
| 89 | */ |
||
| 90 | public function testPsr7Request() |
||
| 91 | { |
||
| 92 | $lookup = new Whip( |
||
| 93 | Whip::PROXY_HEADERS, |
||
| 94 | array( |
||
| 95 | Whip::PROXY_HEADERS => array( |
||
| 96 | IpWhitelist::IPV4 => array( |
||
| 97 | '127.0.0.1' |
||
| 98 | ) |
||
| 99 | ) |
||
| 100 | ), |
||
| 101 | $this->getHttpMessageMock("127.0.0.1", array('X-Forwarded-For' => array('192.168.1.1,32.32.32.32'))) |
||
| 102 | ); |
||
| 103 | |||
| 104 | $this->assertEquals('32.32.32.32', $lookup->getIpAddress()); |
||
| 105 | } |
||
| 106 | |||
| 107 | /** |
||
| 108 | * Tests that we get false when no valid IP address could be found. |
||
| 109 | */ |
||
| 110 | public function testNoAddresFoundDueToBitmask() |
||
| 111 | { |
||
| 112 | $lookup = new Whip(Whip::PROXY_HEADERS); |
||
| 113 | $lookup->setSource(array('REMOTE_ADDR' => '127.0.0.1')); |
||
| 114 | $this->assertFalse($lookup->getIpAddress()); |
||
| 115 | } |
||
| 116 | |||
| 117 | /** |
||
| 118 | * Tests the standard REMOTE_ADDR method. |
||
| 119 | */ |
||
| 120 | public function testRemoteAddrMethod() |
||
| 121 | { |
||
| 122 | $lookup = new Whip(Whip::REMOTE_ADDR); |
||
| 123 | $lookup->setSource(array('REMOTE_ADDR' => '24.24.24.24')); |
||
| 124 | $this->assertEquals('24.24.24.24', $lookup->getValidIpAddress()); |
||
| 125 | } |
||
| 126 | |||
| 127 | /** |
||
| 128 | * Tests that an invalid IPv4 address returns false. |
||
| 129 | */ |
||
| 130 | public function testInvalidIPv4Address() |
||
| 131 | { |
||
| 132 | $lookup = new Whip(Whip::REMOTE_ADDR); |
||
| 133 | $lookup->setSource(array('REMOTE_ADDR' => '127.0.0.256')); |
||
| 134 | $this->assertFalse($lookup->getValidIpAddress()); |
||
| 135 | } |
||
| 136 | |||
| 137 | /** |
||
| 138 | * Tests a valid IPv6 address. |
||
| 139 | */ |
||
| 140 | public function testValidIPv6Address() |
||
| 141 | { |
||
| 142 | $lookup = new Whip(Whip::REMOTE_ADDR); |
||
| 143 | $lookup->setSource(array('REMOTE_ADDR' => '::1')); |
||
| 144 | $this->assertEquals('::1', $lookup->getValidIpAddress()); |
||
| 145 | } |
||
| 146 | |||
| 147 | /** |
||
| 148 | * Tests that we accept whitelisted proxy methods when the IP matches, even |
||
| 149 | * if the IP listed is a comma separated list. |
||
| 150 | * |
||
| 151 | * @dataProvider proxyMethodWhitelistProvider |
||
| 152 | */ |
||
| 153 | View Code Duplication | public function testValidWhitelistedProxyMethod($remoteAddr) |
|
| 154 | { |
||
| 155 | $lookup = new Whip( |
||
| 156 | Whip::PROXY_HEADERS, |
||
| 157 | array( |
||
| 158 | Whip::PROXY_HEADERS => array( |
||
| 159 | IpWhitelist::IPV4 => array('127.0.0.1'), |
||
| 160 | IpWhitelist::IPV6 => array('::1') |
||
| 161 | ) |
||
| 162 | ), |
||
| 163 | array( |
||
| 164 | 'REMOTE_ADDR' => $remoteAddr, |
||
| 165 | 'HTTP_X_FORWARDED_FOR' => '192.168.1.1,32.32.32.32' |
||
| 166 | ) |
||
| 167 | ); |
||
| 168 | $this->assertEquals('32.32.32.32', $lookup->getIpAddress()); |
||
| 169 | } |
||
| 170 | |||
| 171 | /** |
||
| 172 | * Repeats the above test twice for ipv4 and ipv6 |
||
| 173 | */ |
||
| 174 | public function proxyMethodWhitelistProvider() |
||
| 175 | { |
||
| 176 | return array( |
||
| 177 | array('127.0.0.1'), |
||
| 178 | array('::1'), |
||
| 179 | ); |
||
| 180 | } |
||
| 181 | |||
| 182 | /** |
||
| 183 | * Tests that we accept proxy method based on a whitelisted IP using the |
||
| 184 | * dashed range notation. |
||
| 185 | */ |
||
| 186 | View Code Duplication | public function testValidWhitelistedProxyMethodWithDashNotation() |
|
| 187 | { |
||
| 188 | $lookup = new Whip( |
||
| 189 | Whip::PROXY_HEADERS, |
||
| 190 | array( |
||
| 191 | Whip::PROXY_HEADERS => array( |
||
| 192 | IpWhitelist::IPV4 => array( |
||
| 193 | '127.0.0.0-127.0.255.255', |
||
| 194 | ), |
||
| 195 | IpWhitelist::IPV6 => array( |
||
| 196 | '::1' |
||
| 197 | ) |
||
| 198 | ) |
||
| 199 | ), |
||
| 200 | array( |
||
| 201 | 'REMOTE_ADDR' => '127.0.0.1', |
||
| 202 | 'HTTP_X_FORWARDED_FOR' => '32.32.32.32' |
||
| 203 | ) |
||
| 204 | ); |
||
| 205 | $this->assertEquals('32.32.32.32', $lookup->getIpAddress()); |
||
| 206 | } |
||
| 207 | |||
| 208 | /** |
||
| 209 | * Tests that we accept proxy method based on a whitelisted IP using the |
||
| 210 | * wildcard asterix notation. |
||
| 211 | */ |
||
| 212 | View Code Duplication | public function testValidWhitelistedProxyMethodWithWildcardNotation() |
|
| 213 | { |
||
| 214 | $lookup = new Whip( |
||
| 215 | Whip::PROXY_HEADERS, |
||
| 216 | array( |
||
| 217 | Whip::PROXY_HEADERS => array( |
||
| 218 | IpWhitelist::IPV4 => array( |
||
| 219 | '127.0.*' |
||
| 220 | ), |
||
| 221 | IpWhitelist::IPV6 => array( |
||
| 222 | '::1' |
||
| 223 | ) |
||
| 224 | ) |
||
| 225 | ), |
||
| 226 | array( |
||
| 227 | 'REMOTE_ADDR' => '127.0.0.1', |
||
| 228 | 'HTTP_X_FORWARDED_FOR' => '32.32.32.32' |
||
| 229 | ) |
||
| 230 | ); |
||
| 231 | $this->assertEquals('32.32.32.32', $lookup->getIpAddress()); |
||
| 232 | } |
||
| 233 | |||
| 234 | /** |
||
| 235 | * Tests that we accept proxy method based on a whitelisted IP using the |
||
| 236 | * CIDR address notation. |
||
| 237 | */ |
||
| 238 | View Code Duplication | public function testValidWhitelistedProxyMethodWithCIDRdNotation() |
|
| 239 | { |
||
| 240 | $lookup = new Whip( |
||
| 241 | Whip::PROXY_HEADERS, |
||
| 242 | array( |
||
| 243 | Whip::PROXY_HEADERS => array( |
||
| 244 | IpWhitelist::IPV4 => array( |
||
| 245 | '127.0.0.0/24' |
||
| 246 | ), |
||
| 247 | IpWhitelist::IPV6 => array( |
||
| 248 | '::1' |
||
| 249 | ) |
||
| 250 | ) |
||
| 251 | ), |
||
| 252 | array( |
||
| 253 | 'REMOTE_ADDR' => '127.0.0.1', |
||
| 254 | 'HTTP_X_FORWARDED_FOR' => '32.32.32.32' |
||
| 255 | ) |
||
| 256 | ); |
||
| 257 | $this->assertEquals('32.32.32.32', $lookup->getIpAddress()); |
||
| 258 | } |
||
| 259 | |||
| 260 | /** |
||
| 261 | * Tests that we get false if there is a valid IP in a proxy header but |
||
| 262 | * we reject it due to REMOTE_ADDR not being in the whitelist. |
||
| 263 | */ |
||
| 264 | View Code Duplication | public function testValidIpRejectedDueToWhitelist() |
|
| 265 | { |
||
| 266 | $lookup = new Whip( |
||
| 267 | Whip::PROXY_HEADERS, |
||
| 268 | array( |
||
| 269 | Whip::PROXY_HEADERS => array( |
||
| 270 | IpWhitelist::IPV4 => array( |
||
| 271 | '127.0.0.1/24' |
||
| 272 | ), |
||
| 273 | IpWhitelist::IPV6 => array( |
||
| 274 | '::1' |
||
| 275 | ) |
||
| 276 | ) |
||
| 277 | ), |
||
| 278 | array( |
||
| 279 | 'REMOTE_ADDR' => '24.24.24.24', |
||
| 280 | 'HTTP_X_FORWARDED_FOR' => '32.32.32.32' |
||
| 281 | ) |
||
| 282 | ); |
||
| 283 | $this->assertFalse($lookup->getIpAddress()); |
||
| 284 | } |
||
| 285 | |||
| 286 | /** |
||
| 287 | * Tests that we reject a proxy listed IPv6 address that does not fall within |
||
| 288 | * the allowed subnet. |
||
| 289 | */ |
||
| 290 | public function testIPv6AddressRejectedDueToWhitelist() |
||
| 291 | { |
||
| 292 | $lookup = new Whip( |
||
| 293 | Whip::PROXY_HEADERS, |
||
| 294 | array( |
||
| 295 | Whip::PROXY_HEADERS => array( |
||
| 296 | IpWhitelist::IPV6 => array( |
||
| 297 | '2400:cb00::/32' |
||
| 298 | ) |
||
| 299 | ) |
||
| 300 | ), |
||
| 301 | array( |
||
| 302 | 'REMOTE_ADDR' => '::1', |
||
| 303 | 'HTTP_X_FORWARDED_FOR' => '::1' |
||
| 304 | ) |
||
| 305 | ); |
||
| 306 | $this->assertFalse($lookup->getIpAddress()); |
||
| 307 | } |
||
| 308 | |||
| 309 | /** |
||
| 310 | * Tests that we reject a proxy listed IPv6 address that does not fall within |
||
| 311 | * the allowed subnet. |
||
| 312 | */ |
||
| 313 | public function testIPv6AddressFoundInWhitelist() |
||
| 314 | { |
||
| 315 | $lookup = new Whip( |
||
| 316 | Whip::PROXY_HEADERS, |
||
| 317 | array( |
||
| 318 | Whip::PROXY_HEADERS => array( |
||
| 319 | IpWhitelist::IPV6 => array( |
||
| 320 | '::1/32' |
||
| 321 | ) |
||
| 322 | ) |
||
| 323 | ), |
||
| 324 | array( |
||
| 325 | 'REMOTE_ADDR' => '::1', |
||
| 326 | 'HTTP_X_FORWARDED_FOR' => '::1' |
||
| 327 | ) |
||
| 328 | ); |
||
| 329 | $this->assertEquals('::1', $lookup->getIpAddress()); |
||
| 330 | } |
||
| 331 | |||
| 332 | /** |
||
| 333 | * Test that an IPv4 address is rejected because the whitelist is empty for |
||
| 334 | * IPv4. |
||
| 335 | */ |
||
| 336 | public function testIPv4AddressRejectedDueToEmptyWhitelist() |
||
| 337 | { |
||
| 338 | $lookup = new Whip( |
||
| 339 | Whip::PROXY_HEADERS, |
||
| 340 | array( |
||
| 341 | Whip::PROXY_HEADERS => array( |
||
| 342 | IpWhitelist::IPV6 => array( |
||
| 343 | '::1/32' |
||
| 344 | ) |
||
| 345 | ) |
||
| 346 | ), |
||
| 347 | array( |
||
| 348 | 'REMOTE_ADDR' => '127.0.0.1', |
||
| 349 | 'HTTP_X_FORWARDED_FOR' => '24.24.24.24' |
||
| 350 | ) |
||
| 351 | ); |
||
| 352 | $this->assertFalse($lookup->getIpAddress()); |
||
| 353 | } |
||
| 354 | |||
| 355 | /** |
||
| 356 | * Test that an IPv6 address is rejected because the whitelist is empty for |
||
| 357 | * IPv6. |
||
| 358 | */ |
||
| 359 | public function testIPv6AddressRejectedDueToEmptyWhitelist() |
||
| 360 | { |
||
| 361 | $lookup = new Whip( |
||
| 362 | Whip::PROXY_HEADERS, |
||
| 363 | array( |
||
| 364 | Whip::PROXY_HEADERS => array( |
||
| 365 | IpWhitelist::IPV4 => array( |
||
| 366 | '127.0.0.0/24' |
||
| 367 | ) |
||
| 368 | ) |
||
| 369 | ), |
||
| 370 | array( |
||
| 371 | 'REMOTE_ADDR' => '::1', |
||
| 372 | 'HTTP_X_FORWARDED_FOR' => '::1' |
||
| 373 | ) |
||
| 374 | ); |
||
| 375 | $this->assertFalse($lookup->getIpAddress()); |
||
| 376 | } |
||
| 377 | |||
| 378 | /** |
||
| 379 | * Test a custom header with a whitelisted IP. |
||
| 380 | */ |
||
| 381 | View Code Duplication | public function testCustomHeader() |
|
| 403 | |||
| 404 | /** |
||
| 405 | * Test HTTP_X_REAL_IP header. |
||
| 406 | */ |
||
| 407 | public function testHttpXRealIpHeader() |
||
| 408 | { |
||
| 409 | $lookup = new Whip( |
||
| 410 | Whip::PROXY_HEADERS | Whip::REMOTE_ADDR, |
||
| 411 | array(), |
||
| 412 | array( |
||
| 413 | 'REMOTE_ADDR' => '127.0.0.1', |
||
| 414 | 'HTTP_X_REAL_IP' => '24.24.24.24' |
||
| 415 | ) |
||
| 416 | ); |
||
| 417 | $this->assertEquals('24.24.24.24', $lookup->getIpAddress()); |
||
| 418 | } |
||
| 419 | |||
| 420 | /** |
||
| 421 | * Tests that if we specify the source array, it overrides any values found |
||
| 422 | * in the $_SERVER array. |
||
| 423 | */ |
||
| 424 | View Code Duplication | public function testSourceArrayOverridesServerSuperglobal() |
|
| 433 | |||
| 434 | /** |
||
| 435 | * Tests that if we specify the source array through Whip::setSource, the |
||
| 436 | * class will override any values found in $_SERVER. |
||
| 437 | */ |
||
| 438 | View Code Duplication | public function testSetSourceArrayOverridesServerSuperglobal() |
|
| 448 | } |
||
| 449 |
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: