diff --git a/composer.json b/composer.json index 2de9a8621d..8747b47e78 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ }, "require-dev": { "satooshi/php-coveralls": "~0.6", - "phpunit/phpunit": "~3.7", + "phpunit/phpunit": "~4.1", "codacy/coverage": "dev-master", "phpunit/phpunit-selenium": "~1.2", "squizlabs/php_codesniffer": "2.*" diff --git a/libraries/Response.php b/libraries/Response.php index dc37f6701f..f66982da3a 100644 --- a/libraries/Response.php +++ b/libraries/Response.php @@ -389,5 +389,24 @@ class Response $buffer->flush(); exit; } -} + /** + * Wrapper around PHP's header() function. + * + * @return void + */ + public function header($text) + { + header($text); + } + + /** + * Wrapper around PHP's headers_sent() function. + * + * @return bool + */ + public function headersSent() + { + return headers_sent(); + } +} diff --git a/libraries/core.lib.php b/libraries/core.lib.php index de55573192..1acd47ffa9 100644 --- a/libraries/core.lib.php +++ b/libraries/core.lib.php @@ -498,21 +498,23 @@ function PMA_sendHeaderLocation($uri, $use_refresh = false) return; } + $response = PMA\libraries\Response::getInstance(); + if (SID) { if (mb_strpos($uri, '?') === false) { - header('Location: ' . $uri . '?' . SID); + $response->header('Location: ' . $uri . '?' . SID); } else { $separator = PMA_URL_getArgSeparator(); - header('Location: ' . $uri . $separator . SID); + $response->header('Location: ' . $uri . $separator . SID); } return; } session_write_close(); - if (headers_sent()) { + if ($response->headersSent()) { if (function_exists('debug_print_backtrace')) { echo '
';
-            debug_print_backtrace();
+#            debug_print_backtrace();
             echo '
'; } trigger_error( @@ -524,9 +526,9 @@ function PMA_sendHeaderLocation($uri, $use_refresh = false) // results in a blank page // but we need it when coming from the cookie login panel) if (PMA_IS_IIS && $use_refresh) { - header('Refresh: 0; ' . $uri); + $response->header('Refresh: 0; ' . $uri); } else { - header('Location: ' . $uri); + $response->header('Location: ' . $uri); } } diff --git a/libraries/plugins/auth/AuthenticationHttp.php b/libraries/plugins/auth/AuthenticationHttp.php index 065b39d405..170d7c1e0e 100644 --- a/libraries/plugins/auth/AuthenticationHttp.php +++ b/libraries/plugins/auth/AuthenticationHttp.php @@ -71,16 +71,18 @@ class AuthenticationHttp extends AuthenticationPlugin } else { $realm_message = $GLOBALS['cfg']['Server']['auth_http_realm']; } + + $response = Response::getInstance(); + // remove non US-ASCII to respect RFC2616 $realm_message = preg_replace('/[^\x20-\x7e]/i', '', $realm_message); - header('WWW-Authenticate: Basic realm="' . $realm_message . '"'); - header('HTTP/1.0 401 Unauthorized'); + $response->header('WWW-Authenticate: Basic realm="' . $realm_message . '"'); + $response->header('HTTP/1.0 401 Unauthorized'); if (php_sapi_name() !== 'cgi-fcgi') { - header('status: 401 Unauthorized'); + $response->header('status: 401 Unauthorized'); } /* HTML header */ - $response = Response::getInstance(); $footer = $response->getFooter(); $footer->setMinimal(); $header = $response->getHeader(); diff --git a/test/classes/plugin/auth/AuthenticationHttpTest.php b/test/classes/plugin/auth/AuthenticationHttpTest.php index 8fe2818a99..20e5b81b33 100644 --- a/test/classes/plugin/auth/AuthenticationHttpTest.php +++ b/test/classes/plugin/auth/AuthenticationHttpTest.php @@ -51,33 +51,8 @@ class AuthenticationHttpTest extends PMATestCase unset($this->object); } - /** - * Test for PMA\libraries\plugins\auth\AuthenticationHttp::auth - * - * @return void - */ - public function testAuth() + public function doMockResponse($set_minimal, $body_id, $set_title) { - if (! defined('PMA_TEST_HEADERS')) { - $this->markTestSkipped( - 'Cannot redefine constant/function - missing runkit extension' - ); - } - - $_REQUEST['old_usr'] = '1'; - $GLOBALS['cfg']['Server']['LogoutURL'] = 'http://phpmyadmin.net/logout'; - - $this->assertFalse( - $this->object->auth() - ); - - $this->assertContains( - 'Location: http://phpmyadmin.net/logout', - $GLOBALS['header'][0] - ); - - // case 2 - $restoreInstance = PMA\libraries\Response::getInstance(); // mock footer @@ -86,7 +61,7 @@ class AuthenticationHttpTest extends PMATestCase ->setMethods(array('setMinimal')) ->getMock(); - $mockFooter->expects($this->once()) + $mockFooter->expects($this->exactly($set_minimal)) ->method('setMinimal') ->with(); @@ -99,35 +74,40 @@ class AuthenticationHttpTest extends PMATestCase ) ->getMock(); - $mockHeader->expects($this->once()) + $mockHeader->expects($this->exactly($body_id)) ->method('setBodyId') ->with('loginform'); - $mockHeader->expects($this->once()) + $mockHeader->expects($this->exactly($set_title)) ->method('setTitle') ->with('Access denied!'); - $mockHeader->expects($this->once()) + $mockHeader->expects($this->exactly($set_title)) ->method('disableMenuAndConsole') ->with(); // set mocked headers and footers $mockResponse = $this->getMockBuilder('PMA\libraries\Response') ->disableOriginalConstructor() - ->setMethods(array('getHeader', 'getFooter', 'addHTML')) + ->setMethods(array('getHeader', 'getFooter', 'addHTML', 'header', 'headersSent')) ->getMock(); - $mockResponse->expects($this->once()) + $mockResponse->expects($this->exactly($set_title)) ->method('getFooter') ->with() ->will($this->returnValue($mockFooter)); - $mockResponse->expects($this->once()) + $mockResponse->expects($this->exactly($set_title)) ->method('getHeader') ->with() ->will($this->returnValue($mockHeader)); - $mockResponse->expects($this->exactly(6)) + $mockResponse->expects($this->any()) + ->method('headersSent') + ->with() + ->will($this->returnValue(false)); + + $mockResponse->expects($this->exactly($set_title * 6)) ->method('addHTML') ->with(); @@ -135,59 +115,73 @@ class AuthenticationHttpTest extends PMATestCase $attrInstance->setAccessible(true); $attrInstance->setValue($mockResponse); - $GLOBALS['header'] = array(); - $_REQUEST['old_usr'] = ''; - $GLOBALS['cfg']['Server']['verbose'] = 'verboseMessagê'; + $headers = array_slice(func_get_args(), 3); + + $header_method = $mockResponse->expects($this->exactly(count($headers))) + ->method('header'); + + call_user_func_array(array($header_method, 'withConsecutive'), $headers); $this->assertFalse( $this->object->auth() ); - $this->assertEquals( - array( - 'WWW-Authenticate: Basic realm="phpMyAdmin verboseMessag"', - 'HTTP/1.0 401 Unauthorized', - 'status: 401 Unauthorized' - ), - $GLOBALS['header'] - ); - $attrInstance->setValue($restoreInstance); + } - // case 3 + /** + * Test for PMA\libraries\plugins\auth\AuthenticationHttp::auth + * + * @return void + */ + public function testAuthLogoutUrl() + { - $GLOBALS['header'] = array(); + $_REQUEST['old_usr'] = '1'; + $GLOBALS['cfg']['Server']['LogoutURL'] = 'http://phpmyadmin.net/logout'; + + $this->doMockResponse( + 0, 0, 0, + array('Location: http://phpmyadmin.net/logout') + ); + } + + public function testAuthVerbose() + { + $_REQUEST['old_usr'] = ''; + $GLOBALS['cfg']['Server']['verbose'] = 'verboseMessagê'; + + $this->doMockResponse( + 1, 1, 1, + array('WWW-Authenticate: Basic realm="phpMyAdmin verboseMessag"'), + array('HTTP/1.0 401 Unauthorized'), + array('status: 401 Unauthorized') + ); + } + + public function testAuthHost() + { $GLOBALS['cfg']['Server']['verbose'] = ''; $GLOBALS['cfg']['Server']['host'] = 'hòst'; - $this->assertFalse( - $this->object->auth() + + $this->doMockResponse( + 1, 1, 1, + array('WWW-Authenticate: Basic realm="phpMyAdmin hst"'), + array('HTTP/1.0 401 Unauthorized'), + array('status: 401 Unauthorized') ); + } - $this->assertEquals( - array( - 'WWW-Authenticate: Basic realm="phpMyAdmin hst"', - 'HTTP/1.0 401 Unauthorized', - 'status: 401 Unauthorized' - ), - $GLOBALS['header'] - ); - - // case 4 - - $GLOBALS['header'] = array(); + public function testAuthRealm() + { $GLOBALS['cfg']['Server']['host'] = ''; $GLOBALS['cfg']['Server']['auth_http_realm'] = 'rêäealmmessage'; - $this->assertFalse( - $this->object->auth() - ); - $this->assertEquals( - array( - 'WWW-Authenticate: Basic realm="realmmessage"', - 'HTTP/1.0 401 Unauthorized', - 'status: 401 Unauthorized' - ), - $GLOBALS['header'] + $this->doMockResponse( + 1, 1, 1, + array('WWW-Authenticate: Basic realm="realmmessage"'), + array('HTTP/1.0 401 Unauthorized'), + array('status: 401 Unauthorized') ); }