Merge branch '2.4'

* 2.4:
  [Process] minor fixes
  Improve performance of getNextEmbedBlock by removing unnecessary preg_match and function calls.
  Avoid unnecessary line indentation calculation.
  Optimise Inline::evaluateScalar() for parsing strings.
  fixed CS
  fixed parsing Mongo DSN and added Test for it
  () is also a valid delimiter
  Adding PHP 5.6 to travis-ci tests
  Update BCryptPasswordEncoder.php
  [Validator] Removed PHP <5.3.3 specific code which is not officially supported.
  Fixed wrong redirect url if path contains some query parameters
This commit is contained in:
Fabien Potencier 2014-02-24 17:21:51 +01:00
commit 7baeaa2fd7
11 changed files with 177 additions and 68 deletions

View File

@ -5,6 +5,7 @@ php:
- 5.3
- 5.4
- 5.5
- 5.6
- hhvm
matrix:

View File

@ -100,7 +100,11 @@ class RedirectController extends ContainerAware
$qs = $request->getQueryString();
if ($qs) {
$qs = '?'.$qs;
if (strpos($path, '?') === false) {
$qs = '?'.$qs;
} else {
$qs = '&'.$qs;
}
}
$port = '';

View File

@ -199,7 +199,36 @@ class RedirectControllerTest extends TestCase
$this->assertRedirectUrl($returnValue, $expectedUrl);
}
private function createRequestObject($scheme, $host, $port, $baseUrl)
public function pathQueryParamsProvider()
{
return array(
array('http://www.example.com/base/redirect-path', '/redirect-path', ''),
array('http://www.example.com/base/redirect-path?foo=bar', '/redirect-path?foo=bar', ''),
array('http://www.example.com/base/redirect-path?foo=bar', '/redirect-path', 'foo=bar'),
array('http://www.example.com/base/redirect-path?foo=bar&abc=example', '/redirect-path?foo=bar', 'abc=example'),
array('http://www.example.com/base/redirect-path?foo=bar&abc=example&baz=def', '/redirect-path?foo=bar', 'abc=example&baz=def'),
);
}
/**
* @dataProvider pathQueryParamsProvider
*/
public function testPathQueryParams($expectedUrl, $path, $queryString)
{
$scheme = 'http';
$host = 'www.example.com';
$baseUrl = '/base';
$port = 80;
$request = $this->createRequestObject($scheme, $host, $port, $baseUrl, $queryString);
$controller = $this->createRedirectController();
$returnValue = $controller->urlRedirectAction($request, $path, false, $scheme, $port, null);
$this->assertRedirectUrl($returnValue, $expectedUrl);
}
private function createRequestObject($scheme, $host, $port, $baseUrl, $queryString = '')
{
$request = $this->getMock('Symfony\Component\HttpFoundation\Request');
$request
@ -218,6 +247,10 @@ class RedirectControllerTest extends TestCase
->expects($this->any())
->method('getBaseUrl')
->will($this->returnValue($baseUrl));
$request
->expects($this->any())
->method('getQueryString')
->will($this->returnValue($queryString));
return $request;
}

View File

@ -65,7 +65,11 @@ class Regex implements ValueInterface
$start = substr($m[1], 0, 1);
$end = substr($m[1], -1);
if (($start === $end && !preg_match('/[*?[:alnum:] \\\\]/', $start)) || ($start === '{' && $end === '}')) {
if (
($start === $end && !preg_match('/[*?[:alnum:] \\\\]/', $start))
|| ($start === '{' && $end === '}')
|| ($start === '(' && $end === ')')
) {
return new self(substr($m[1], 1, -1), $m[2], $end);
}
}

View File

@ -99,21 +99,19 @@ class MongoDbProfilerStorage implements ProfilerStorageInterface
*/
protected function getMongo()
{
if ($this->mongo === null) {
if (preg_match('#^(mongodb://.*)/(.*)/(.*)$#', $this->dsn, $matches)) {
$server = $matches[1].(!empty($matches[2]) ? '/'.$matches[2] : '');
$database = $matches[2];
$collection = $matches[3];
$mongoClass = (version_compare(phpversion('mongo'), '1.3.0', '<')) ? '\Mongo' : '\MongoClient';
$mongo = new $mongoClass($server);
$this->mongo = $mongo->selectCollection($database, $collection);
} else {
throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use MongoDB with an invalid dsn "%s". The expected format is "mongodb://[user:pass@]host/database/collection"', $this->dsn));
}
if (null !== $this->mongo) {
return $this->mongo;
}
return $this->mongo;
if (!$parsedDsn = $this->parseDsn($this->dsn)) {
throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use MongoDB with an invalid dsn "%s". The expected format is "mongodb://[user:pass@]host/database/collection"', $this->dsn));
}
list($server, $database, $collection) = $parsedDsn;
$mongoClass = version_compare(phpversion('mongo'), '1.3.0', '<') ? '\Mongo' : '\MongoClient';
$mongo = new $mongoClass($server);
return $this->mongo = $mongo->selectCollection($database, $collection);
}
/**
@ -233,4 +231,27 @@ class MongoDbProfilerStorage implements ProfilerStorageInterface
return $profile;
}
/**
* @param string $dsn
*
* @return null|array Array($server, $database, $collection)
*/
private function parseDsn($dsn)
{
if (!preg_match('#^(mongodb://.*)/(.*)/(.*)$#', $dsn, $matches)) {
return;
}
$server = $matches[1];
$database = $matches[2];
$collection = $matches[3];
preg_match('#^mongodb://(([^:]+):?(.*)(?=@))?@?([^/]*)(.*)$#', $server, $matchesServer);
if ('' == $matchesServer[5] && '' != $matches[2]) {
$server .= '/'.$matches[2];
}
return array($server, $database, $collection);
}
}

View File

@ -71,6 +71,32 @@ class MongoDbProfilerStorageTest extends AbstractProfilerStorageTest
}
}
public function getDsns()
{
return array(
array('mongodb://localhost/symfony_tests/profiler_data', array(
'mongodb://localhost/symfony_tests',
'symfony_tests',
'profiler_data'
)),
array('mongodb://user:password@localhost/symfony_tests/profiler_data', array(
'mongodb://user:password@localhost/symfony_tests',
'symfony_tests',
'profiler_data'
)),
array('mongodb://user:password@localhost/admin/symfony_tests/profiler_data', array(
'mongodb://user:password@localhost/admin',
'symfony_tests',
'profiler_data'
)),
array('mongodb://user:password@localhost:27009,localhost:27010/?replicaSet=rs-name&authSource=admin/symfony_tests/profiler_data', array(
'mongodb://user:password@localhost:27009,localhost:27010/?replicaSet=rs-name&authSource=admin',
'symfony_tests',
'profiler_data'
))
);
}
public function testCleanup()
{
$dt = new \DateTime('-2 day');
@ -87,6 +113,17 @@ class MongoDbProfilerStorageTest extends AbstractProfilerStorageTest
self::$storage->purge();
}
/**
* @dataProvider getDsns
*/
public function testDsnParser($dsn, $expected)
{
$m = new \ReflectionMethod(self::$storage, 'parseDsn');
$m->setAccessible(true);
$this->assertEquals($expected, $m->invoke(self::$storage, $dsn));
}
public function testUtf8()
{
$profile = new Profile('utf8_test_profile');

View File

@ -911,7 +911,9 @@ class Process
public function setEnv(array $env)
{
// Process can not handle env values that are arrays
$env = array_filter($env, function ($value) { if (!is_array($value)) { return true; } });
$env = array_filter($env, function ($value) {
return !is_array($value);
});
$this->env = array();
foreach ($env as $key => $value) {
@ -1190,6 +1192,7 @@ class Process
* Reads pipes, executes callback.
*
* @param Boolean $blocking Whether to use blocking calls or not.
* @param Boolean $close Whether to close file handles or not.
*/
private function readPipes($blocking, $close)
{

View File

@ -79,7 +79,7 @@ class ProcessPipes
public function close()
{
$this->closeUnixPipes();
foreach ($this->fileHandles as $offset => $handle) {
foreach ($this->fileHandles as $handle) {
fclose($handle);
}
$this->fileHandles = array();
@ -227,6 +227,8 @@ class ProcessPipes
/**
* Reads data in file handles.
*
* @param Boolean $close Whether to close file handles or not.
*
* @return array An array of read data indexed by their fd.
*/
private function readFileHandles($close = false)
@ -262,6 +264,7 @@ class ProcessPipes
* Reads data in file pipes streams.
*
* @param Boolean $blocking Whether to use blocking calls or not.
* @param Boolean $close Whether to close file handles or not.
*
* @return array An array of read data indexed by their fd.
*/

View File

@ -29,6 +29,7 @@ class BCryptPasswordEncoder extends BasePasswordEncoder
*
* @param integer $cost The algorithmic cost that should be used
*
* @throws \RuntimeException When no BCrypt encoder is available
* @throws \InvalidArgumentException if cost is out of range
*/
public function __construct($cost)

View File

@ -386,51 +386,55 @@ class Inline
private static function evaluateScalar($scalar)
{
$scalar = trim($scalar);
$scalarLower = strtolower($scalar);
switch (true) {
case 'null' == strtolower($scalar):
case 'null' == $scalarLower:
case '' == $scalar:
case '~' == $scalar:
return null;
case 0 === strpos($scalar, '!str'):
return (string) substr($scalar, 5);
case 0 === strpos($scalar, '! '):
return intval(self::parseScalar(substr($scalar, 2)));
case 0 === strpos($scalar, '!!php/object:'):
if (self::$objectSupport) {
return unserialize(substr($scalar, 13));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException('Object support when parsing a YAML file has been disabled.');
}
return null;
case ctype_digit($scalar):
$raw = $scalar;
$cast = intval($scalar);
return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)):
$raw = $scalar;
$cast = intval($scalar);
return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
case 'true' === strtolower($scalar):
case 'true' === $scalarLower:
return true;
case 'false' === strtolower($scalar):
case 'false' === $scalarLower:
return false;
case is_numeric($scalar):
return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar);
case 0 == strcasecmp($scalar, '.inf'):
case 0 == strcasecmp($scalar, '.NaN'):
return -log(0);
case 0 == strcasecmp($scalar, '-.inf'):
return log(0);
case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
return floatval(str_replace(',', '', $scalar));
case preg_match(self::getTimestampRegex(), $scalar):
return strtotime($scalar);
// Optimise for returning strings.
case $scalar[0] === '+' || $scalar[0] === '-' || $scalar[0] === '.' || $scalar[0] === '!' || is_numeric($scalar[0]):
switch (true) {
case 0 === strpos($scalar, '!str'):
return (string) substr($scalar, 5);
case 0 === strpos($scalar, '! '):
return intval(self::parseScalar(substr($scalar, 2)));
case 0 === strpos($scalar, '!!php/object:'):
if (self::$objectSupport) {
return unserialize(substr($scalar, 13));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException('Object support when parsing a YAML file has been disabled.');
}
return null;
case ctype_digit($scalar):
$raw = $scalar;
$cast = intval($scalar);
return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)):
$raw = $scalar;
$cast = intval($scalar);
return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
case is_numeric($scalar):
return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar);
case 0 == strcasecmp($scalar, '.inf'):
case 0 == strcasecmp($scalar, '.NaN'):
return -log(0);
case 0 == strcasecmp($scalar, '-.inf'):
return log(0);
case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
return floatval(str_replace(',', '', $scalar));
case preg_match(self::getTimestampRegex(), $scalar):
return strtotime($scalar);
}
default:
return (string) $scalar;
}

View File

@ -312,7 +312,9 @@ class Parser
$removeComments = !preg_match($removeCommentsPattern, $this->currentLine);
while ($this->moveToNextLine()) {
if ($this->getCurrentLineIndentation() === $newIndent) {
$indent = $this->getCurrentLineIndentation();
if ($indent === $newIndent) {
$removeComments = !preg_match($removeCommentsPattern, $this->currentLine);
}
@ -321,20 +323,16 @@ class Parser
break;
}
if ($removeComments && $this->isCurrentLineEmpty() || $this->isCurrentLineBlank()) {
if ($this->isCurrentLineBlank()) {
$data[] = substr($this->currentLine, $newIndent);
}
if ($this->isCurrentLineBlank()) {
$data[] = substr($this->currentLine, $newIndent);
continue;
}
$indent = $this->getCurrentLineIndentation();
if ($removeComments && $this->isCurrentLineComment()) {
continue;
}
if (preg_match('#^(?P<text> *)$#', $this->currentLine, $match)) {
// empty line
$data[] = $match['text'];
} elseif ($indent >= $newIndent) {
if ($indent >= $newIndent) {
$data[] = substr($this->currentLine, $newIndent);
} elseif (0 == $indent) {
$this->moveToPreviousLine();