diff --git a/src/Illuminate/Cache/DatabaseStore.php b/src/Illuminate/Cache/DatabaseStore.php index 2306fb06d3f4..dc1241c805ee 100755 --- a/src/Illuminate/Cache/DatabaseStore.php +++ b/src/Illuminate/Cache/DatabaseStore.php @@ -4,8 +4,10 @@ use Closure; use Exception; +use Illuminate\Support\Str; use Illuminate\Contracts\Cache\Store; use Illuminate\Support\InteractsWithTime; +use Illuminate\Database\PostgresConnection; use Illuminate\Database\ConnectionInterface; class DatabaseStore implements Store @@ -78,7 +80,7 @@ public function get($key) return; } - return unserialize($cache->value); + return $this->unserialize($cache->value); } /** @@ -93,7 +95,7 @@ public function put($key, $value, $minutes) { $key = $this->prefix.$key; - $value = serialize($value); + $value = $this->serialize($value); $expiration = $this->getTime() + (int) ($minutes * 60); @@ -157,7 +159,7 @@ protected function incrementOrDecrement($key, $value, Closure $callback) $cache = is_array($cache) ? (object) $cache : $cache; - $current = unserialize($cache->value); + $current = $this->unserialize($cache->value); // Here we'll call this callback function that was given to the function which // is used to either increment or decrement the function. We use a callback @@ -172,7 +174,7 @@ protected function incrementOrDecrement($key, $value, Closure $callback) // since database cache values are encrypted by default with secure storage // that can't be easily read. We will return the new value after storing. $this->table()->where('key', $prefixed)->update([ - 'value' => serialize($new), + 'value' => $this->serialize($new), ]); return $new; @@ -253,4 +255,36 @@ public function getPrefix() { return $this->prefix; } + + /** + * Serialize the given value. + * + * @param mixed $value + * @return string + */ + protected function serialize($value) + { + $result = serialize($value); + + if ($this->connection instanceof PostgresConnection && Str::contains($result, "\0")) { + $result = base64_encode($result); + } + + return $result; + } + + /** + * Unserialize the given value. + * + * @param string $value + * @return mixed + */ + protected function unserialize($value) + { + if ($this->connection instanceof PostgresConnection && ! Str::contains($value, [':', ';'])) { + $value = base64_decode($value); + } + + return unserialize($value); + } } diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index c3077b1035a4..c7e7ae2a4040 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -1149,8 +1149,10 @@ public function auth(array $options = []) $this->post('logout', 'Auth\LoginController@logout')->name('logout'); // Registration Routes... - $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register'); - $this->post('register', 'Auth\RegisterController@register'); + if ($options['register'] ?? true) { + $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register'); + $this->post('register', 'Auth\RegisterController@register'); + } // Password Reset Routes... $this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request'); diff --git a/src/Illuminate/Validation/Concerns/ReplacesAttributes.php b/src/Illuminate/Validation/Concerns/ReplacesAttributes.php index 6ebdfddd7f20..3594dd9b3540 100644 --- a/src/Illuminate/Validation/Concerns/ReplacesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ReplacesAttributes.php @@ -259,7 +259,11 @@ protected function replaceSize($message, $attribute, $rule, $parameters) */ protected function replaceGt($message, $attribute, $rule, $parameters) { - return str_replace(':value', $this->getSize($parameters[0], $this->getValue($parameters[0])), $message); + if (is_null($value = $this->getValue($parameters[0]))) { + return str_replace(':value', $parameters[0], $message); + } + + return str_replace(':value', $this->getSize($attribute, $value), $message); } /** @@ -273,7 +277,11 @@ protected function replaceGt($message, $attribute, $rule, $parameters) */ protected function replaceLt($message, $attribute, $rule, $parameters) { - return str_replace(':value', $this->getSize($parameters[0], $this->getValue($parameters[0])), $message); + if (is_null($value = $this->getValue($parameters[0]))) { + return str_replace(':value', $parameters[0], $message); + } + + return str_replace(':value', $this->getSize($attribute, $value), $message); } /** @@ -287,7 +295,11 @@ protected function replaceLt($message, $attribute, $rule, $parameters) */ protected function replaceGte($message, $attribute, $rule, $parameters) { - return str_replace(':value', $this->getSize($parameters[0], $this->getValue($parameters[0])), $message); + if (is_null($value = $this->getValue($parameters[0]))) { + return str_replace(':value', $parameters[0], $message); + } + + return str_replace(':value', $this->getSize($attribute, $value), $message); } /** @@ -301,7 +313,11 @@ protected function replaceGte($message, $attribute, $rule, $parameters) */ protected function replaceLte($message, $attribute, $rule, $parameters) { - return str_replace(':value', $this->getSize($parameters[0], $this->getValue($parameters[0])), $message); + if (is_null($value = $this->getValue($parameters[0]))) { + return str_replace(':value', $parameters[0], $message); + } + + return str_replace(':value', $this->getSize($attribute, $value), $message); } /** diff --git a/tests/Auth/AuthListenersSendEmailVerificationNotificationHandleFunctionTest.php b/tests/Auth/AuthListenersSendEmailVerificationNotificationHandleFunctionTest.php index 815f0d1d389e..49a681d33fa6 100644 --- a/tests/Auth/AuthListenersSendEmailVerificationNotificationHandleFunctionTest.php +++ b/tests/Auth/AuthListenersSendEmailVerificationNotificationHandleFunctionTest.php @@ -17,7 +17,7 @@ public function testWillExecuted() { $user = $this->getMockBuilder(MustVerifyEmail::class)->getMock(); $user->method('hasVerifiedEmail')->willReturn(false); - $user->expects($this->exactly(1))->method('sendEmailVerificationNotification'); + $user->expects($this->once())->method('sendEmailVerificationNotification'); $listener = new SendEmailVerificationNotification(); @@ -30,7 +30,7 @@ public function testWillExecuted() public function testUserIsNotInstanceOfMustVerifyEmail() { $user = $this->getMockBuilder(User::class)->getMock(); - $user->expects($this->exactly(0))->method('sendEmailVerificationNotification'); + $user->expects($this->never())->method('sendEmailVerificationNotification'); $listener = new SendEmailVerificationNotification(); @@ -44,7 +44,7 @@ public function testHasVerifiedEmailAsTrue() { $user = $this->getMockBuilder(MustVerifyEmail::class)->getMock(); $user->method('hasVerifiedEmail')->willReturn(true); - $user->expects($this->exactly(0))->method('sendEmailVerificationNotification'); + $user->expects($this->never())->method('sendEmailVerificationNotification'); $listener = new SendEmailVerificationNotification(); diff --git a/tests/Cache/CacheDatabaseStoreTest.php b/tests/Cache/CacheDatabaseStoreTest.php index 0069b2437852..9587d8f2ba74 100755 --- a/tests/Cache/CacheDatabaseStoreTest.php +++ b/tests/Cache/CacheDatabaseStoreTest.php @@ -48,6 +48,17 @@ public function testDecryptedValueIsReturnedWhenItemIsValid() $this->assertEquals('bar', $store->get('foo')); } + public function testValueIsReturnedOnPostgres() + { + $store = $this->getPostgresStore(); + $table = m::mock('stdClass'); + $store->getConnection()->shouldReceive('table')->once()->with('table')->andReturn($table); + $table->shouldReceive('where')->once()->with('key', '=', 'prefixfoo')->andReturn($table); + $table->shouldReceive('first')->once()->andReturn((object) ['value' => base64_encode(serialize('bar')), 'expiration' => 999999999999999]); + + $this->assertEquals('bar', $store->get('foo')); + } + public function testValueIsInsertedWhenNoExceptionsAreThrown() { $store = $this->getMockBuilder('Illuminate\Cache\DatabaseStore')->setMethods(['getTime'])->setConstructorArgs($this->getMocks())->getMock(); @@ -74,6 +85,17 @@ public function testValueIsUpdatedWhenInsertThrowsException() $store->put('foo', 'bar', 1); } + public function testValueIsInsertedOnPostgres() + { + $store = $this->getMockBuilder('Illuminate\Cache\DatabaseStore')->setMethods(['getTime'])->setConstructorArgs($this->getPostgresMocks())->getMock(); + $table = m::mock('stdClass'); + $store->getConnection()->shouldReceive('table')->once()->with('table')->andReturn($table); + $store->expects($this->once())->method('getTime')->will($this->returnValue(1)); + $table->shouldReceive('insert')->once()->with(['key' => 'prefixfoo', 'value' => base64_encode(serialize("\0")), 'expiration' => 61]); + + $store->put('foo', "\0", 1); + } + public function testForeverCallsStoreItemWithReallyLongTime() { $store = $this->getMockBuilder('Illuminate\Cache\DatabaseStore')->setMethods(['put'])->setConstructorArgs($this->getMocks())->getMock(); @@ -186,8 +208,18 @@ protected function getStore() return new DatabaseStore(m::mock('Illuminate\Database\Connection'), 'table', 'prefix'); } + protected function getPostgresStore() + { + return new DatabaseStore(m::mock('Illuminate\Database\PostgresConnection'), 'table', 'prefix'); + } + protected function getMocks() { return [m::mock('Illuminate\Database\Connection'), 'table', 'prefix']; } + + protected function getPostgresMocks() + { + return [m::mock('Illuminate\Database\PostgresConnection'), 'table', 'prefix']; + } } diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 98b7fee0c04d..5fa2cda1bb71 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -1533,6 +1533,154 @@ public function testProperMessagesAreReturnedForSizes() $this->assertEquals('file', $v->messages()->first('photo')); } + public function testValidateGtPlaceHolderIsReplacedProperly() + { + $trans = $this->getIlluminateArrayTranslator(); + $trans->addLines([ + 'validation.gt.numeric' => ':value', + 'validation.gt.string' => ':value', + 'validation.gt.file' => ':value', + 'validation.gt.array' => ':value', + ], 'en'); + + $v = new Validator($trans, ['items' => '3'], ['items' => 'gt:4']); + $this->assertFalse($v->passes()); + $this->assertEquals(4, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 3, 'more' => 5], ['items' => 'numeric|gt:more']); + $this->assertFalse($v->passes()); + $this->assertEquals(5, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 'abc', 'more' => 'abcde'], ['items' => 'gt:more']); + $this->assertFalse($v->passes()); + $this->assertEquals(5, $v->messages()->first('items')); + + $file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $biggerFile = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $biggerFile->expects($this->any())->method('getSize')->will($this->returnValue(5120)); + $biggerFile->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $v = new Validator($trans, ['photo' => $file, 'bigger' => $biggerFile], ['photo' => 'file|gt:bigger']); + $this->assertFalse($v->passes()); + $this->assertEquals(5, $v->messages()->first('photo')); + + $v = new Validator($trans, ['items' => [1, 2, 3], 'more' => [0, 1, 2, 3]], ['items' => 'gt:more']); + $this->assertFalse($v->passes()); + $this->assertEquals(4, $v->messages()->first('items')); + } + + public function testValidateLtPlaceHolderIsReplacedProperly() + { + $trans = $this->getIlluminateArrayTranslator(); + $trans->addLines([ + 'validation.lt.numeric' => ':value', + 'validation.lt.string' => ':value', + 'validation.lt.file' => ':value', + 'validation.lt.array' => ':value', + ], 'en'); + + $v = new Validator($trans, ['items' => '3'], ['items' => 'lt:2']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 3, 'less' => 2], ['items' => 'numeric|lt:less']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 'abc', 'less' => 'ab'], ['items' => 'lt:less']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + + $file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $smallerFile = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $smallerFile->expects($this->any())->method('getSize')->will($this->returnValue(2048)); + $smallerFile->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $v = new Validator($trans, ['photo' => $file, 'smaller' => $smallerFile], ['photo' => 'file|lt:smaller']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('photo')); + + $v = new Validator($trans, ['items' => [1, 2, 3], 'less' => [0, 1]], ['items' => 'lt:less']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + } + + public function testValidateGtePlaceHolderIsReplacedProperly() + { + $trans = $this->getIlluminateArrayTranslator(); + $trans->addLines([ + 'validation.gte.numeric' => ':value', + 'validation.gte.string' => ':value', + 'validation.gte.file' => ':value', + 'validation.gte.array' => ':value', + ], 'en'); + + $v = new Validator($trans, ['items' => '3'], ['items' => 'gte:4']); + $this->assertFalse($v->passes()); + $this->assertEquals(4, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 3, 'more' => 5], ['items' => 'numeric|gte:more']); + $this->assertFalse($v->passes()); + $this->assertEquals(5, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 'abc', 'more' => 'abcde'], ['items' => 'gte:more']); + $this->assertFalse($v->passes()); + $this->assertEquals(5, $v->messages()->first('items')); + + $file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $biggerFile = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $biggerFile->expects($this->any())->method('getSize')->will($this->returnValue(5120)); + $biggerFile->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $v = new Validator($trans, ['photo' => $file, 'bigger' => $biggerFile], ['photo' => 'file|gte:bigger']); + $this->assertFalse($v->passes()); + $this->assertEquals(5, $v->messages()->first('photo')); + + $v = new Validator($trans, ['items' => [1, 2, 3], 'more' => [0, 1, 2, 3]], ['items' => 'gte:more']); + $this->assertFalse($v->passes()); + $this->assertEquals(4, $v->messages()->first('items')); + } + + public function testValidateLtePlaceHolderIsReplacedProperly() + { + $trans = $this->getIlluminateArrayTranslator(); + $trans->addLines([ + 'validation.lte.numeric' => ':value', + 'validation.lte.string' => ':value', + 'validation.lte.file' => ':value', + 'validation.lte.array' => ':value', + ], 'en'); + + $v = new Validator($trans, ['items' => '3'], ['items' => 'lte:2']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 3, 'less' => 2], ['items' => 'numeric|lte:less']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 'abc', 'less' => 'ab'], ['items' => 'lte:less']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + + $file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $smallerFile = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $smallerFile->expects($this->any())->method('getSize')->will($this->returnValue(2048)); + $smallerFile->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $v = new Validator($trans, ['photo' => $file, 'smaller' => $smallerFile], ['photo' => 'file|lte:smaller']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('photo')); + + $v = new Validator($trans, ['items' => [1, 2, 3], 'less' => [0, 1]], ['items' => 'lte:less']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + } + public function testValidateIn() { $trans = $this->getIlluminateArrayTranslator();