From 13f27e4d920a05d53236139e8b07007acd046a46 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Mon, 9 Aug 2021 10:25:36 +0300 Subject: [PATCH] Fix #18817: Use `paragonie/random_compat` for random bytes and int generation --- composer.json | 3 +- composer.lock | 112 +++++----- framework/CHANGELOG.md | 1 + framework/base/Security.php | 89 +------- framework/caching/DbCache.php | 3 +- framework/caching/FileCache.php | 2 +- framework/captcha/CaptchaAction.php | 17 +- framework/composer.json | 3 +- framework/mail/BaseMailer.php | 2 +- tests/framework/base/SecurityTest.php | 191 +----------------- .../validators/FileValidatorTest.php | 4 +- tests/framework/web/UploadedFileTest.php | 11 +- 12 files changed, 85 insertions(+), 353 deletions(-) diff --git a/composer.json b/composer.json index d3065cb66f5..1a0eb701fc6 100644 --- a/composer.json +++ b/composer.json @@ -78,7 +78,8 @@ "bower-asset/jquery": "3.6.*@stable | 3.5.*@stable | 3.4.*@stable | 3.3.*@stable | 3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable", "bower-asset/inputmask": "~3.2.2 | ~3.3.5", "bower-asset/punycode": "1.3.*", - "bower-asset/yii2-pjax": "~2.0.1" + "bower-asset/yii2-pjax": "~2.0.1", + "paragonie/random_compat": ">=1" }, "require-dev": { "cweagans/composer-patches": "^1.7", diff --git a/composer.lock b/composer.lock index f0d91e3aebf..35d4dd11f03 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7e41c6fc0175fd049e0e52c4e8b25e5c", + "content-hash": "8f9a4d7e645592f806605d32d676f54e", "packages": [ { "name": "bower-asset/inputmask", @@ -199,6 +199,60 @@ }, "time": "2020-06-29T00:56:53+00:00" }, + { + "name": "paragonie/random_compat", + "version": "v2.0.20", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "0f1f60250fccffeaf5dda91eea1c018aed1adc2a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/0f1f60250fccffeaf5dda91eea1c018aed1adc2a", + "reference": "0f1f60250fccffeaf5dda91eea1c018aed1adc2a", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2021-04-17T09:33:01+00:00" + }, { "name": "yiisoft/yii2-composer", "version": "2.0.10", @@ -891,60 +945,6 @@ }, "time": "2015-09-13T19:01:00+00:00" }, - { - "name": "paragonie/random_compat", - "version": "v2.0.20", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "0f1f60250fccffeaf5dda91eea1c018aed1adc2a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/0f1f60250fccffeaf5dda91eea1c018aed1adc2a", - "reference": "0f1f60250fccffeaf5dda91eea1c018aed1adc2a", - "shasum": "" - }, - "require": { - "php": ">=5.2.0" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "type": "library", - "autoload": { - "files": [ - "lib/random.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com" - } - ], - "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", - "keywords": [ - "csprng", - "polyfill", - "pseudorandom", - "random" - ], - "support": { - "email": "info@paragonie.com", - "issues": "https://github.com/paragonie/random_compat/issues", - "source": "https://github.com/paragonie/random_compat" - }, - "time": "2021-04-17T09:33:01+00:00" - }, { "name": "phpdocumentor/reflection-docblock", "version": "2.0.5", @@ -2919,5 +2919,5 @@ "platform-overrides": { "php": "5.4" }, - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.1.0" } diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index a1b8cadc880..f3df9a4b2c9 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -4,6 +4,7 @@ Yii Framework 2 Change Log 2.0.43 under development ------------------------ +- Enh #18817: Use `paragonie/random_compat` for random bytes and int generation (samdark) - Bug #14663: Do not convert int to string if database type of a column is numeric (egorrishe) - Bug #18650: Refactor `framework/assets/yii.activeForm.js` arrow function into traditional function for IE11 compatibility (marcovtwout) - Bug #18749: Fix `yii\web\ErrorHandler::encodeHtml()` to support strings with invalid UTF symbols (vjik) diff --git a/framework/base/Security.php b/framework/base/Security.php index e3a2373ab8a..49972d17bde 100644 --- a/framework/base/Security.php +++ b/framework/base/Security.php @@ -116,14 +116,6 @@ protected function shouldUseLibreSSL() return $this->_useLibreSSL; } - /** - * @return bool if operating system is Windows - */ - private function isWindows() - { - return DIRECTORY_SEPARATOR !== '/'; - } - /** * Encrypts data using a password. * Derives keys for encryption and authentication from the password using PBKDF2 and a random salt, @@ -471,8 +463,6 @@ public function validateData($data, $key, $rawHash = false) return false; } - private $_randomFile; - /** * Generates specified number of random bytes. * Note that output may not be ASCII. @@ -493,84 +483,7 @@ public function generateRandomKey($length = 32) throw new InvalidArgumentException('First parameter ($length) must be greater than 0'); } - // always use random_bytes() if it is available - if (function_exists('random_bytes')) { - return random_bytes($length); - } - - // The recent LibreSSL RNGs are faster and likely better than /dev/urandom. - // Since 5.4.0, openssl_random_pseudo_bytes() reads from CryptGenRandom on Windows instead - // of using OpenSSL library. LibreSSL is OK everywhere but don't use OpenSSL on non-Windows. - if (function_exists('openssl_random_pseudo_bytes') - && ($this->shouldUseLibreSSL() || $this->isWindows()) - ) { - $key = openssl_random_pseudo_bytes($length, $cryptoStrong); - if ($cryptoStrong === false) { - throw new Exception( - 'openssl_random_pseudo_bytes() set $crypto_strong false. Your PHP setup is insecure.' - ); - } - if ($key !== false && StringHelper::byteLength($key) === $length) { - return $key; - } - } - - // mcrypt_create_iv() does not use libmcrypt. Since PHP 5.3.7 it directly reads - // CryptGenRandom on Windows. Elsewhere it directly reads /dev/urandom. - if (function_exists('mcrypt_create_iv')) { - $key = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); - if (StringHelper::byteLength($key) === $length) { - return $key; - } - } - - // If not on Windows, try to open a random device. - if ($this->_randomFile === null && !$this->isWindows()) { - // urandom is a symlink to random on FreeBSD. - $device = PHP_OS === 'FreeBSD' ? '/dev/random' : '/dev/urandom'; - // Check random device for special character device protection mode. Use lstat() - // instead of stat() in case an attacker arranges a symlink to a fake device. - $lstat = @lstat($device); - if ($lstat !== false && ($lstat['mode'] & 0170000) === 020000) { - $this->_randomFile = fopen($device, 'rb') ?: null; - - if (is_resource($this->_randomFile)) { - // Reduce PHP stream buffer from default 8192 bytes to optimize data - // transfer from the random device for smaller values of $length. - // This also helps to keep future randoms out of user memory space. - $bufferSize = 8; - - if (function_exists('stream_set_read_buffer')) { - stream_set_read_buffer($this->_randomFile, $bufferSize); - } - // stream_set_read_buffer() isn't implemented on HHVM - if (function_exists('stream_set_chunk_size')) { - stream_set_chunk_size($this->_randomFile, $bufferSize); - } - } - } - } - - if (is_resource($this->_randomFile)) { - $buffer = ''; - $stillNeed = $length; - while ($stillNeed > 0) { - $someBytes = fread($this->_randomFile, $stillNeed); - if ($someBytes === false) { - break; - } - $buffer .= $someBytes; - $stillNeed -= StringHelper::byteLength($someBytes); - if ($stillNeed === 0) { - // Leaving file pointer open in order to make next generation faster by reusing it. - return $buffer; - } - } - fclose($this->_randomFile); - $this->_randomFile = null; - } - - throw new Exception('Unable to generate a random key'); + return random_bytes($length); } /** diff --git a/framework/caching/DbCache.php b/framework/caching/DbCache.php index dc7a1316f06..3cd211ec013 100644 --- a/framework/caching/DbCache.php +++ b/framework/caching/DbCache.php @@ -276,7 +276,8 @@ protected function deleteValue($key) */ public function gc($force = false) { - if ($force || mt_rand(0, 1000000) < $this->gcProbability) { + + if ($force || random_int(0, 1000000) < $this->gcProbability) { $this->db->createCommand() ->delete($this->cacheTable, '[[expire]] > 0 AND [[expire]] < ' . time()) ->execute(); diff --git a/framework/caching/FileCache.php b/framework/caching/FileCache.php index b221998db88..378a84fb736 100644 --- a/framework/caching/FileCache.php +++ b/framework/caching/FileCache.php @@ -245,7 +245,7 @@ protected function flushValues() */ public function gc($force = false, $expiredOnly = true) { - if ($force || mt_rand(0, 1000000) < $this->gcProbability) { + if ($force || random_int(0, 1000000) < $this->gcProbability) { $this->gcRecursive($this->cachePath, $expiredOnly); } } diff --git a/framework/captcha/CaptchaAction.php b/framework/captcha/CaptchaAction.php index 40e1aa03a0a..e61a9ed34ae 100644 --- a/framework/captcha/CaptchaAction.php +++ b/framework/captcha/CaptchaAction.php @@ -214,16 +214,17 @@ protected function generateVerifyCode() if ($this->maxLength > 20) { $this->maxLength = 20; } - $length = mt_rand($this->minLength, $this->maxLength); + + $length = random_int($this->minLength, $this->maxLength); $letters = 'bcdfghjklmnpqrstvwxyz'; $vowels = 'aeiou'; $code = ''; for ($i = 0; $i < $length; ++$i) { - if ($i % 2 && mt_rand(0, 10) > 2 || !($i % 2) && mt_rand(0, 10) > 9) { - $code .= $vowels[mt_rand(0, 4)]; + if ($i % 2 && random_int(0, 10) > 2 || !($i % 2) && random_int(0, 10) > 9) { + $code .= $vowels[random_int(0, 4)]; } else { - $code .= $letters[mt_rand(0, 20)]; + $code .= $letters[random_int(0, 20)]; } } @@ -298,8 +299,8 @@ protected function renderImageByGD($code) $x = 10; $y = round($this->height * 27 / 40); for ($i = 0; $i < $length; ++$i) { - $fontSize = (int) (mt_rand(26, 32) * $scale * 0.8); - $angle = mt_rand(-10, 10); + $fontSize = (int) (random_int(26, 32) * $scale * 0.8); + $angle = random_int(-10, 10); $letter = $code[$i]; $box = imagettftext($image, $fontSize, $angle, $x, $y, $foreColor, $this->fontFile, $letter); $x = $box[2] + $this->offset; @@ -341,9 +342,9 @@ protected function renderImageByImagick($code) for ($i = 0; $i < $length; ++$i) { $draw = new \ImagickDraw(); $draw->setFont($this->fontFile); - $draw->setFontSize((int) (mt_rand(26, 32) * $scale * 0.8)); + $draw->setFontSize((int) (random_int(26, 32) * $scale * 0.8)); $draw->setFillColor($foreColor); - $image->annotateImage($draw, $x, $y, mt_rand(-10, 10), $code[$i]); + $image->annotateImage($draw, $x, $y, random_int(-10, 10), $code[$i]); $fontMetrics = $image->queryFontMetrics($draw, $code[$i]); $x += (int) $fontMetrics['textWidth'] + $this->offset; } diff --git a/framework/composer.json b/framework/composer.json index 8d6105d2627..b211cb5eea3 100644 --- a/framework/composer.json +++ b/framework/composer.json @@ -73,7 +73,8 @@ "bower-asset/jquery": "3.6.*@stable | 3.5.*@stable | 3.4.*@stable | 3.3.*@stable | 3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable", "bower-asset/inputmask": "~3.2.2 | ~3.3.5", "bower-asset/punycode": "1.3.*", - "bower-asset/yii2-pjax": "~2.0.1" + "bower-asset/yii2-pjax": "~2.0.1", + "paragonie/random_compat": ">=1" }, "autoload": { "psr-4": {"yii\\": ""} diff --git a/framework/mail/BaseMailer.php b/framework/mail/BaseMailer.php index c4546fbd1f4..63b6904ee52 100644 --- a/framework/mail/BaseMailer.php +++ b/framework/mail/BaseMailer.php @@ -343,7 +343,7 @@ public function generateMessageFileName() { $time = microtime(true); - return date('Ymd-His-', $time) . sprintf('%04d', (int) (($time - (int) $time) * 10000)) . '-' . sprintf('%04d', mt_rand(0, 10000)) . '.eml'; + return date('Ymd-His-', $time) . sprintf('%04d', (int) (($time - (int) $time) * 10000)) . '-' . sprintf('%04d', random_int(0, 10000)) . '.eml'; } /** diff --git a/tests/framework/base/SecurityTest.php b/tests/framework/base/SecurityTest.php index e84714000e0..215999c12aa 100644 --- a/tests/framework/base/SecurityTest.php +++ b/tests/framework/base/SecurityTest.php @@ -5,53 +5,7 @@ * @license http://www.yiiframework.com/license/ */ -namespace yii\base { - - /** - * emulate availability of functions, to test different branches of Security class - * where different execution paths are chosen based on calling function_exists. - * - * This function overrides function_exists from the root namespace in yii\base. - * @param string $name - */ - function function_exists($name) - { - if (isset(\yiiunit\framework\base\SecurityTest::$functions[$name])) { - return \yiiunit\framework\base\SecurityTest::$functions[$name]; - } - - return \function_exists($name); - } - /** - * Emulate chunked reading of fread(), to test different branches of Security class - * where different execution paths are chosen based on the return value of fopen/fread. - * - * This function overrides fopen and fread from the root namespace in yii\base. - * @param string $filename - * @param mixed $mode - */ - function fopen($filename, $mode) - { - if (\yiiunit\framework\base\SecurityTest::$fopen !== null) { - return \yiiunit\framework\base\SecurityTest::$fopen; - } - - return \fopen($filename, $mode); - } - function fread($handle, $length) - { - if (\yiiunit\framework\base\SecurityTest::$fread !== null) { - return \yiiunit\framework\base\SecurityTest::$fread; - } - if (\yiiunit\framework\base\SecurityTest::$fopen !== null) { - return $length < 8 ? \str_repeat('s', $length) : 'test1234'; - } - - return \fread($handle, $length); - } -} // closing namespace yii\base; - -namespace yiiunit\framework\base { +namespace yiiunit\framework\base; use yii\base\Security; use yiiunit\TestCase; @@ -63,16 +17,6 @@ class SecurityTest extends TestCase { const CRYPT_VECTORS = 'old'; - /** - * @var array set of functions for which a fake return value for `function_exists()` is provided. - */ - public static $functions = []; - /** - * @var resource|false|null fake return value for fopen() in \yii\base namespace. Normal behavior if this is null. - */ - public static $fopen; - public static $fread; - /** * @var ExposedSecurity */ @@ -80,27 +24,11 @@ class SecurityTest extends TestCase protected function setUp() { - static::$functions = []; - static::$fopen = null; - static::$fread = null; parent::setUp(); $this->security = new ExposedSecurity(); $this->security->derivationIterations = 1000; // speed up test running } - protected function tearDown() - { - static::$functions = []; - static::$fopen = null; - static::$fread = null; - parent::tearDown(); - } - - private function isWindows() - { - return DIRECTORY_SEPARATOR !== '/'; - } - // Tests : public function testHashData() @@ -893,76 +821,8 @@ public function testRandomKeyInvalidInput($input) $key1 = $this->security->generateRandomKey($input); } - /** - * Test the case where opening /dev/urandom fails. - */ - public function testRandomKeyNoOptions() - { - static::$functions = ['random_bytes' => false, 'openssl_random_pseudo_bytes' => false, 'mcrypt_create_iv' => false]; - static::$fopen = false; - $this->expectException('yii\base\Exception'); - $this->expectExceptionMessage('Unable to generate a random key'); - - $this->security->generateRandomKey(42); - } - - /** - * Test the case where reading from /dev/urandom fails. - */ - public function testRandomKeyFreadFailure() - { - static::$functions = ['random_bytes' => false, 'openssl_random_pseudo_bytes' => false, 'mcrypt_create_iv' => false]; - static::$fread = false; - $this->expectException('yii\base\Exception'); - $this->expectExceptionMessage('Unable to generate a random key'); - - $this->security->generateRandomKey(42); - } - - /** - * returns a set of different combinations of functions available. - */ - public function randomKeyVariants() + public function testGenerateRandomKey() { - return [ - [['random_bytes' => true, 'openssl_random_pseudo_bytes' => true, 'mcrypt_create_iv' => true]], - [['random_bytes' => true, 'openssl_random_pseudo_bytes' => true, 'mcrypt_create_iv' => false]], - [['random_bytes' => true, 'openssl_random_pseudo_bytes' => false, 'mcrypt_create_iv' => true]], - [['random_bytes' => true, 'openssl_random_pseudo_bytes' => false, 'mcrypt_create_iv' => false]], - [['random_bytes' => false, 'openssl_random_pseudo_bytes' => true, 'mcrypt_create_iv' => true]], - [['random_bytes' => false, 'openssl_random_pseudo_bytes' => true, 'mcrypt_create_iv' => false]], - [['random_bytes' => false, 'openssl_random_pseudo_bytes' => false, 'mcrypt_create_iv' => true]], - [['random_bytes' => false, 'openssl_random_pseudo_bytes' => false, 'mcrypt_create_iv' => false]], - ]; - } - - /** - * @dataProvider randomKeyVariants - * @param array $functions - */ - public function testGenerateRandomKey($functions) - { - foreach ($functions as $fun => $available) { - if ($available && !\function_exists($fun)) { - $this->markTestSkipped("Can not test generateRandomKey() branch that includes $fun, because it is not available on your system."); - } - } - // there is no /dev/urandom on windows so we expect this to fail - if ($this->isWindows() && $functions['random_bytes'] === false && $functions['openssl_random_pseudo_bytes'] === false && $functions['mcrypt_create_iv'] === false) { - $this->expectException('yii\base\Exception'); - $this->expectExceptionMessage('Unable to generate a random key'); - } - // Function mcrypt_create_iv() is deprecated since PHP 7.1 - if (version_compare(PHP_VERSION, '7.1.0alpha', '>=') && $functions['random_bytes'] === false && $functions['mcrypt_create_iv'] === true) { - if ($functions['openssl_random_pseudo_bytes'] === false) { - $this->markTestSkipped('Function mcrypt_create_iv() is deprecated as of PHP 7.1'); - } elseif (!$this->security->shouldUseLibreSSL() && !$this->isWindows()) { - $this->markTestSkipped('Function openssl_random_pseudo_bytes need LibreSSL version >=2.1.5 or Windows system on server'); - } - } - - static::$functions = $functions; - // test various string lengths for ($length = 1; $length < 64; $length++) { $key1 = $this->security->generateRandomKey($length); @@ -985,16 +845,6 @@ public function testGenerateRandomKey($functions) $this->assertInternalType('string', $key2); $this->assertEquals($length, strlen($key2)); $this->assertNotEquals($key1, $key2); - - // force /dev/urandom reading loop to deal with chunked data - // the above test may have read everything in one run. - // not sure if this can happen in real life but if it does - // we should be prepared - static::$fopen = fopen('php://memory', 'rwb'); - $length = 1024 * 1024; - $key1 = $this->security->generateRandomKey($length); - $this->assertInternalType('string', $key1); - $this->assertEquals($length, strlen($key1)); } protected function randTime(Security $security, $count, $length, $message) @@ -1010,42 +860,6 @@ protected function randTime(Security $security, $count, $length, $message) fwrite(STDERR, "$message: $count x $length B = $nbytes B in $milisec ms => $rate MB/s\n"); } - public function testGenerateRandomKeySpeed() - { - self::markTestSkipped('Comment markTestSkipped in testGenerateRandomKeySpeed() in order to get RNG benchmark.'); - $tests = [ - "function_exists('random_bytes')", - "defined('OPENSSL_VERSION_TEXT') ? OPENSSL_VERSION_TEXT : null", - 'PHP_VERSION_ID', - 'PHP_OS', - "function_exists('mcrypt_create_iv') ? bin2hex(mcrypt_create_iv(4, MCRYPT_DEV_URANDOM)) : null", - 'DIRECTORY_SEPARATOR', - "ini_get('open_basedir')", - ]; - if ($this->isWindows()) { - $tests[] = "sprintf('%o', lstat(PHP_OS === 'FreeBSD' ? '/dev/random' : '/dev/urandom')['mode'] & 0170000)"; - $tests[] = "bin2hex(file_get_contents(PHP_OS === 'FreeBSD' ? '/dev/random' : '/dev/urandom', false, null, 0, 8))"; - } - foreach ($tests as $i => $test) { - $result = eval('return ' . $test . ';'); - fwrite(STDERR, sprintf("%2d %s ==> %s\n", $i + 1, $test, var_export($result, true))); - } - - foreach ([16, 2000, 262144] as $block) { - $security = new Security(); - foreach (range(1, 10) as $nth) { - $this->randTime($security, 1, $block, "Call $nth"); - } - unset($security); - } - - $security = new Security(); - $this->randTime($security, 10000, 16, 'Rate test'); - - $security = new Security(); - $this->randTime($security, 10000, 5000, 'Rate test'); - } - public function testGenerateRandomString() { $length = 21; @@ -1305,4 +1119,3 @@ public function maskProvider() ]; } } -} // closing namespace yiiunit\framework\base; diff --git a/tests/framework/validators/FileValidatorTest.php b/tests/framework/validators/FileValidatorTest.php index cbed1fbabf1..2ce3c797ca3 100644 --- a/tests/framework/validators/FileValidatorTest.php +++ b/tests/framework/validators/FileValidatorTest.php @@ -324,7 +324,7 @@ protected function createTestFiles($params = []) $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $randomString = ''; for ($i = 0; $i < $len; $i++) { - $randomString .= $characters[rand(0, strlen($characters) - 1)]; + $randomString .= $characters[random_int(0, strlen($characters) - 1)]; } return $randomString; @@ -340,7 +340,7 @@ protected function createTestFiles($params = []) if (is_readable($tempName)) { $size = filesize($tempName); } else { - $size = isset($param['size']) ? $param['size'] : rand( + $size = isset($param['size']) ? $param['size'] : random_int( 1, $this->sizeToBytes(ini_get('upload_max_filesize')) ); diff --git a/tests/framework/web/UploadedFileTest.php b/tests/framework/web/UploadedFileTest.php index 4702c5adb6e..d374a733335 100644 --- a/tests/framework/web/UploadedFileTest.php +++ b/tests/framework/web/UploadedFileTest.php @@ -7,6 +7,7 @@ namespace yiiunit\framework\web; +use Yii; use yii\web\UploadedFile; use yiiunit\framework\web\mocks\UploadedFileMock; use yiiunit\framework\web\stubs\ModelStub; @@ -28,10 +29,10 @@ protected function setUp() private function generateFakeFileData() { return [ - 'name' => md5(mt_rand()), - 'tmp_name' => md5(mt_rand()), + 'name' => md5(random_int(0, PHP_INT_MAX)), + 'tmp_name' => md5(random_int(0, PHP_INT_MAX)), 'type' => 'image/jpeg', - 'size' => mt_rand(1000, 10000), + 'size' => random_int(1000, 10000), 'error' => '0', ]; } @@ -39,10 +40,10 @@ private function generateFakeFileData() private function generateTempFileData() { return [ - 'name' => md5(mt_rand()), + 'name' => md5(random_int(0, PHP_INT_MAX)), 'tmp_name' => tempnam(sys_get_temp_dir(), ''), 'type' => 'image/jpeg', - 'size' => mt_rand(1000, 10000), + 'size' => random_int(1000, 10000), 'error' => '0', ]; }