From 7567d5445ef4b12ec1bd2a3c832aac52d8553abc Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Sat, 8 Aug 2020 23:28:27 +0100
Subject: [PATCH] =?UTF-8?q?Issue=20#3142934=20by=20jungle,=20mondrake,=20l?=
 =?UTF-8?q?ongwave,=20Krzysztof=20Doma=C5=84ski,=20DevJoJodae,=20Chi,=20xj?=
 =?UTF-8?q?m,=20catch,=20andypost:=20Replace=20\Drupal\Component\Utility\B?=
 =?UTF-8?q?ytes::toInt()=20with=20\Drupal\Component\Utility\Bytes::toNumbe?=
 =?UTF-8?q?r()=20due=20to=20return=20type?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 core/lib/Drupal/Component/Utility/Bytes.php   | 20 ++++++
 .../Drupal/Component/Utility/Environment.php  |  6 +-
 core/modules/color/color.module               |  2 +-
 .../editor/src/Form/EditorImageDialog.php     |  2 +-
 .../src/Plugin/Field/FieldType/FileItem.php   |  8 +--
 .../rest/resource/FileUploadResource.php      |  4 +-
 .../MaximumFileSizeExceededUploadTest.php     |  2 +-
 .../TemporaryJsonapiFileFieldUploader.php     |  4 +-
 .../modules/migrate/src/MigrateExecutable.php |  2 +-
 core/modules/system/system.install            |  2 +-
 .../Tests/Component/Utility/BytesTest.php     | 65 +++++++++++++------
 11 files changed, 82 insertions(+), 35 deletions(-)

diff --git a/core/lib/Drupal/Component/Utility/Bytes.php b/core/lib/Drupal/Component/Utility/Bytes.php
index 477e6e48dad7..2dc5c933ef34 100644
--- a/core/lib/Drupal/Component/Utility/Bytes.php
+++ b/core/lib/Drupal/Component/Utility/Bytes.php
@@ -23,8 +23,28 @@ class Bytes {
    *
    * @return int
    *   An integer representation of the size in bytes.
+   *
+   * @deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use \Drupal\Component\Utility\Bytes::toNumber() instead
+   *
+   * @see https://www.drupal.org/node/3162663
    */
   public static function toInt($size) {
+    @trigger_error('\Drupal\Component\Utility\Bytes::toInt() is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use \Drupal\Component\Utility\Bytes::toNumber() instead. See https://www.drupal.org/node/3162663', E_USER_DEPRECATED);
+    return self::toNumber($size);
+  }
+
+  /**
+   * Parses a given byte size.
+   *
+   * @param int|float|string $size
+   *   An integer, float, or string size expressed as a number of bytes with
+   *   optional SI or IEC binary unit prefix (e.g. 2, 2.4, 3K, 5MB, 10G, 6GiB,
+   *   8 bytes, 9mbytes).
+   *
+   * @return float
+   *   The floating point value of the size in bytes.
+   */
+  public static function toNumber($size): float {
     // Remove the non-unit characters from the size.
     $unit = preg_replace('/[^bkmgtpezy]/i', '', $size);
     // Remove the non-numeric characters from the size.
diff --git a/core/lib/Drupal/Component/Utility/Environment.php b/core/lib/Drupal/Component/Utility/Environment.php
index d3fc4623a025..6028183c6f45 100644
--- a/core/lib/Drupal/Component/Utility/Environment.php
+++ b/core/lib/Drupal/Component/Utility/Environment.php
@@ -34,7 +34,7 @@ public static function checkMemoryLimit($required, $memory_limit = NULL) {
     // - The memory limit is set to unlimited (-1).
     // - The memory limit is greater than or equal to the memory required for
     //   the operation.
-    return ((!$memory_limit) || ($memory_limit == -1) || (Bytes::toInt($memory_limit) >= Bytes::toInt($required)));
+    return ((!$memory_limit) || ($memory_limit == -1) || (Bytes::toNumber($memory_limit) >= Bytes::toNumber($required)));
   }
 
   /**
@@ -85,11 +85,11 @@ public static function getUploadMaxSize() {
 
     if ($max_size < 0) {
       // Start with post_max_size.
-      $max_size = Bytes::toInt(ini_get('post_max_size'));
+      $max_size = Bytes::toNumber(ini_get('post_max_size'));
 
       // If upload_max_size is less, then reduce. Except if upload_max_size is
       // zero, which indicates no limit.
-      $upload_max = Bytes::toInt(ini_get('upload_max_filesize'));
+      $upload_max = Bytes::toNumber(ini_get('upload_max_filesize'));
       if ($upload_max > 0 && $upload_max < $max_size) {
         $max_size = $upload_max;
       }
diff --git a/core/modules/color/color.module b/core/modules/color/color.module
index d6399276a800..712d65e7843b 100644
--- a/core/modules/color/color.module
+++ b/core/modules/color/color.module
@@ -398,7 +398,7 @@ function color_scheme_form_submit($form, FormStateInterface $form_state) {
     // scheme change based on a faulty memory calculation.
     $usage = memory_get_usage(TRUE);
     $memory_limit = ini_get('memory_limit');
-    $size = Bytes::toInt($memory_limit);
+    $size = Bytes::toNumber($memory_limit);
     if (!Environment::checkMemoryLimit($usage + $required, $memory_limit)) {
       \Drupal::messenger()->addError(t('There is not enough memory available to PHP to change this theme\'s color scheme. You need at least %size more. Check the <a href="http://php.net/manual/ini.core.php#ini.sect.resource-limits">PHP documentation</a> for more information.', ['%size' => format_size($usage + $required - $size)]));
       return;
diff --git a/core/modules/editor/src/Form/EditorImageDialog.php b/core/modules/editor/src/Form/EditorImageDialog.php
index c125e499a543..489011dfc5b6 100644
--- a/core/modules/editor/src/Form/EditorImageDialog.php
+++ b/core/modules/editor/src/Form/EditorImageDialog.php
@@ -92,7 +92,7 @@ public function buildForm(array $form, FormStateInterface $form_state, Editor $e
     else {
       $max_dimensions = 0;
     }
-    $max_filesize = min(Bytes::toInt($image_upload['max_size']), Environment::getUploadMaxSize());
+    $max_filesize = min(Bytes::toNumber($image_upload['max_size']), Environment::getUploadMaxSize());
     $existing_file = isset($image_element['data-entity-uuid']) ? \Drupal::service('entity.repository')->loadEntityByUuid('file', $image_element['data-entity-uuid']) : NULL;
     $fid = $existing_file ? $existing_file->id() : NULL;
 
diff --git a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
index c8217ba3d208..049144539e6c 100644
--- a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
+++ b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php
@@ -240,13 +240,13 @@ public static function validateExtensions($element, FormStateInterface $form_sta
    * Form API callback.
    *
    * Ensures that a size has been entered and that it can be parsed by
-   * \Drupal\Component\Utility\Bytes::toInt().
+   * \Drupal\Component\Utility\Bytes::toNumber().
    *
    * This function is assigned as an #element_validate callback in
    * fieldSettingsForm().
    */
   public static function validateMaxFilesize($element, FormStateInterface $form_state) {
-    if (!empty($element['#value']) && !is_numeric(Bytes::toInt($element['#value']))) {
+    if (!empty($element['#value']) && !is_numeric(Bytes::toNumber($element['#value']))) {
       $form_state->setError($element, t('The "@name" option must contain a valid value. You may either leave the text field empty or enter a string like "512" (bytes), "80 KB" (kilobytes) or "50 MB" (megabytes).', ['@name' => $element['title']]));
     }
   }
@@ -302,9 +302,9 @@ public function getUploadValidators() {
     $settings = $this->getSettings();
 
     // Cap the upload size according to the PHP limit.
-    $max_filesize = Bytes::toInt(Environment::getUploadMaxSize());
+    $max_filesize = Bytes::toNumber(Environment::getUploadMaxSize());
     if (!empty($settings['max_filesize'])) {
-      $max_filesize = min($max_filesize, Bytes::toInt($settings['max_filesize']));
+      $max_filesize = min($max_filesize, Bytes::toNumber($settings['max_filesize']));
     }
 
     // There is always a file size limit due to the PHP server limit.
diff --git a/core/modules/file/src/Plugin/rest/resource/FileUploadResource.php b/core/modules/file/src/Plugin/rest/resource/FileUploadResource.php
index b46c69294931..9127da760440 100644
--- a/core/modules/file/src/Plugin/rest/resource/FileUploadResource.php
+++ b/core/modules/file/src/Plugin/rest/resource/FileUploadResource.php
@@ -528,9 +528,9 @@ protected function getUploadValidators(FieldDefinitionInterface $field_definitio
     $settings = $field_definition->getSettings();
 
     // Cap the upload size according to the PHP limit.
-    $max_filesize = Bytes::toInt(Environment::getUploadMaxSize());
+    $max_filesize = Bytes::toNumber(Environment::getUploadMaxSize());
     if (!empty($settings['max_filesize'])) {
-      $max_filesize = min($max_filesize, Bytes::toInt($settings['max_filesize']));
+      $max_filesize = min($max_filesize, Bytes::toNumber($settings['max_filesize']));
     }
 
     // There is always a file size limit due to the PHP server limit.
diff --git a/core/modules/file/tests/src/FunctionalJavascript/MaximumFileSizeExceededUploadTest.php b/core/modules/file/tests/src/FunctionalJavascript/MaximumFileSizeExceededUploadTest.php
index 6a7b8db6e861..6b7b7f894ed5 100644
--- a/core/modules/file/tests/src/FunctionalJavascript/MaximumFileSizeExceededUploadTest.php
+++ b/core/modules/file/tests/src/FunctionalJavascript/MaximumFileSizeExceededUploadTest.php
@@ -99,7 +99,7 @@ public function testUploadFileExceedingMaximumFileSize() {
     $session = $this->getSession();
 
     // Create a test file that exceeds the maximum POST size with 1 kilobyte.
-    $post_max_size = Bytes::toInt(ini_get('post_max_size'));
+    $post_max_size = Bytes::toNumber(ini_get('post_max_size'));
     $invalid_file = $this->generateFile('exceeding_post_max_size', ceil(($post_max_size + 1024) / 1024), 1024);
 
     // Go to the node creation form and try to upload the test file.
diff --git a/core/modules/jsonapi/src/Controller/TemporaryJsonapiFileFieldUploader.php b/core/modules/jsonapi/src/Controller/TemporaryJsonapiFileFieldUploader.php
index 2847e17e5361..5d63fb9bbe7f 100644
--- a/core/modules/jsonapi/src/Controller/TemporaryJsonapiFileFieldUploader.php
+++ b/core/modules/jsonapi/src/Controller/TemporaryJsonapiFileFieldUploader.php
@@ -446,9 +446,9 @@ protected function getUploadValidators(FieldDefinitionInterface $field_definitio
     $settings = $field_definition->getSettings();
 
     // Cap the upload size according to the PHP limit.
-    $max_filesize = Bytes::toInt(Environment::getUploadMaxSize());
+    $max_filesize = Bytes::toNumber(Environment::getUploadMaxSize());
     if (!empty($settings['max_filesize'])) {
-      $max_filesize = min($max_filesize, Bytes::toInt($settings['max_filesize']));
+      $max_filesize = min($max_filesize, Bytes::toNumber($settings['max_filesize']));
     }
 
     // There is always a file size limit due to the PHP server limit.
diff --git a/core/modules/migrate/src/MigrateExecutable.php b/core/modules/migrate/src/MigrateExecutable.php
index c8d22c55b9ee..278dd7c8a4b7 100644
--- a/core/modules/migrate/src/MigrateExecutable.php
+++ b/core/modules/migrate/src/MigrateExecutable.php
@@ -113,7 +113,7 @@ public function __construct(MigrationInterface $migration, MigrateMessageInterfa
       $this->memoryLimit = PHP_INT_MAX;
     }
     else {
-      $this->memoryLimit = Bytes::toInt($limit);
+      $this->memoryLimit = Bytes::toNumber($limit);
     }
   }
 
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 4b713531a96d..ff01409dda4c 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -316,7 +316,7 @@ function system_requirements($phase) {
       $apcu_actual_size = format_size($memory_info['seg_size']);
       $apcu_recommended_size = '32 MB';
       $requirements['php_apcu']['value'] = t('Enabled (@size)', ['@size' => $apcu_actual_size]);
-      if (Bytes::toInt($apcu_actual_size) < Bytes::toInt($apcu_recommended_size)) {
+      if (Bytes::toNumber($apcu_actual_size) < Bytes::toNumber($apcu_recommended_size)) {
         $requirements['php_apcu']['severity'] = REQUIREMENT_WARNING;
         $requirements['php_apcu']['description'] = t('Depending on your configuration, Drupal can run with a @apcu_size APCu limit. However, a @apcu_default_size APCu limit (the default) or above is recommended, especially if your site uses additional custom or contributed modules.', [
           '@apcu_size' => $apcu_actual_size,
diff --git a/core/tests/Drupal/Tests/Component/Utility/BytesTest.php b/core/tests/Drupal/Tests/Component/Utility/BytesTest.php
index 0b54a5150240..626fdd6aa2b3 100644
--- a/core/tests/Drupal/Tests/Component/Utility/BytesTest.php
+++ b/core/tests/Drupal/Tests/Component/Utility/BytesTest.php
@@ -5,6 +5,8 @@
 use Drupal\Component\Utility\Bytes;
 use PHPUnit\Framework\TestCase;
 
+// cspell:ignore zettabytes
+
 /**
  * Tests bytes size parsing helper methods.
  *
@@ -24,41 +26,66 @@ class BytesTest extends TestCase {
    *   The expected return value from
    *   \Drupal\Component\Utility\Bytes::toInt().
    *
-   * @dataProvider providerTestToInt
+   * @dataProvider providerTestToNumber
    * @covers ::toInt
+   *
+   * @group legacy
+   * @expectedDeprecation \Drupal\Component\Utility\Bytes::toInt() is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use \Drupal\Component\Utility\Bytes::toNumber() instead. See https://www.drupal.org/node/3162663
    */
   public function testToInt($size, $expected_int) {
     $this->assertEquals($expected_int, Bytes::toInt($size));
   }
 
   /**
-   * Provides data for testToInt.
+   * Tests \Drupal\Component\Utility\Bytes::toNumber().
+   *
+   * @param string $size
+   *   The value for the size argument for
+   *   \Drupal\Component\Utility\Bytes::toNumber().
+   * @param float $expected_number
+   *   The expected return value from
+   *   \Drupal\Component\Utility\Bytes::toNumber().
+   *
+   * @dataProvider providerTestToNumber
+   * @covers ::toNumber
+   */
+  public function testToNumber($size, float $expected_number): void {
+    $this->assertSame($expected_number, Bytes::toNumber($size));
+  }
+
+  /**
+   * Provides data for testToNumber().
    *
    * @return array
    *   An array of arrays, each containing the argument for
-   *   \Drupal\Component\Utility\Bytes::toInt(): size, and the expected return
-   *   value.
+   *   \Drupal\Component\Utility\Bytes::toNumber(): size, and the expected
+   *   return value with the expected type (float).
    */
-  public function providerTestToInt() {
+  public function providerTestToNumber(): array {
     return [
-      ['1', 1],
-      ['1 byte', 1],
-      ['1 KB'  , Bytes::KILOBYTE],
-      ['1 MB'  , pow(Bytes::KILOBYTE, 2)],
-      ['1 GB'  , pow(Bytes::KILOBYTE, 3)],
-      ['1 TB'  , pow(Bytes::KILOBYTE, 4)],
-      ['1 PB'  , pow(Bytes::KILOBYTE, 5)],
-      ['1 EB'  , pow(Bytes::KILOBYTE, 6)],
+      ['1', 1.0],
+      ['1 byte', 1.0],
+      ['1 KB'  , (float) Bytes::KILOBYTE],
+      ['1 MB'  , (float) pow(Bytes::KILOBYTE, 2)],
+      ['1 GB'  , (float) pow(Bytes::KILOBYTE, 3)],
+      ['1 TB'  , (float) pow(Bytes::KILOBYTE, 4)],
+      ['1 PB'  , (float) pow(Bytes::KILOBYTE, 5)],
+      ['1 EB'  , (float) pow(Bytes::KILOBYTE, 6)],
+      // Zettabytes and yottabytes cannot be represented by integers on 64-bit
+      // systems, so pow() returns a float.
       ['1 ZB'  , pow(Bytes::KILOBYTE, 7)],
       ['1 YB'  , pow(Bytes::KILOBYTE, 8)],
-      ['23476892 bytes', 23476892],
+      ['23476892 bytes', 23476892.0],
       // 76 MB.
-      ['76MRandomStringThatShouldBeIgnoredByParseSize.', 79691776],
+      ['76MRandomStringThatShouldBeIgnoredByParseSize.', 79691776.0],
       // 76.24 GB (with typo).
-      ['76.24 Giggabyte', 81862076662],
-      ['1.5', 2],
-      ['2.4', 2],
-      ['', 0],
+      ['76.24 Giggabyte', 81862076662.0],
+      ['1.5', 2.0],
+      [1.5, 2.0],
+      ['2.4', 2.0],
+      [2.4, 2.0],
+      ['', 0.0],
+      ['9223372036854775807', 9223372036854775807.0],
     ];
   }
 
-- 
GitLab