Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * File size admin setting.
  19   *
  20   * @package    core_admin
  21   * @copyright  2019 Shamim Rezaie <shamim@moodle.com>
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace core_admin\local\settings;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  require_once($CFG->libdir . '/adminlib.php');
  30  
  31  /**
  32   * An admin setting to support entering and displaying of file sizes in Bytes, KB, MB or GB.
  33   *
  34   * @copyright   2019 Shamim Rezaie <shamim@moodle.com>
  35   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  36   */
  37  class filesize extends \admin_setting {
  38  
  39      /** @var int The byte unit. Number of bytes in a byte */
  40      const UNIT_B = 1;
  41  
  42      /** @var int The kilobyte unit (number of bytes in a kilobyte) */
  43      const UNIT_KB = 1024;
  44  
  45      /** @var int The megabyte unit (number of bytes in a megabyte) */
  46      const UNIT_MB = 1048576;
  47  
  48      /** @var int The gigabyte unit (number of bytes in a gigabyte) */
  49      const UNIT_GB = 1073741824;
  50  
  51      /** @var int default size unit */
  52      protected $defaultunit;
  53  
  54      /**
  55       * Constructor
  56       *
  57       * @param string    $name           unique ascii name, either 'mysetting' for settings that in config,
  58       *                                  or 'myplugin/mysetting' for ones in config_plugins.
  59       * @param string    $visiblename    localised name
  60       * @param string    $description    localised long description
  61       * @param int|null  $defaultvalue   Value of the settings in bytes
  62       * @param int|null  $defaultunit    GB, MB, etc. (in bytes)
  63       */
  64      public function __construct(string $name, string $visiblename, string $description,
  65              int $defaultvalue = null, int $defaultunit = null) {
  66  
  67          $defaultsetting = self::parse_bytes($defaultvalue);
  68  
  69          if ($defaultunit && array_key_exists($defaultunit, self::get_units())) {
  70              $this->defaultunit = $defaultunit;
  71          } else {
  72              $this->defaultunit = self::UNIT_MB;
  73          }
  74          parent::__construct($name, $visiblename, $description, $defaultsetting);
  75      }
  76  
  77      /**
  78       * Returns selectable units.
  79       *
  80       * @return  array
  81       */
  82      protected static function get_units(): array {
  83          return [
  84              self::UNIT_GB => get_string('sizegb'),
  85              self::UNIT_MB => get_string('sizemb'),
  86              self::UNIT_KB => get_string('sizekb'),
  87              self::UNIT_B  => get_string('sizeb'),
  88          ];
  89      }
  90  
  91      /**
  92       * Converts bytes to some more user friendly string.
  93       *
  94       * @param   int     $bytes  The number of bytes we want to convert from
  95       * @return  string
  96       */
  97      protected static function get_size_text(int $bytes): string {
  98          if (empty($bytes)) {
  99              return get_string('none');
 100          }
 101          return display_size($bytes, 0);
 102      }
 103  
 104      /**
 105       * Finds suitable units for given file size.
 106       *
 107       * @param   int     $bytes  The number of bytes
 108       * @return  array           Parsed file size in the format of ['v' => value, 'u' => unit]
 109       */
 110      protected static function parse_bytes(int $bytes): array {
 111          foreach (self::get_units() as $unit => $unused) {
 112              if ($bytes % $unit === 0) {
 113                  return ['v' => (int)($bytes / $unit), 'u' => $unit];
 114              }
 115          }
 116          return ['v' => (int)$bytes, 'u' => self::UNIT_B];
 117      }
 118  
 119      /**
 120       * Get the selected file size as array.
 121       *
 122       * @return  array|null  An array containing 'v' => xx, 'u' => xx, or null if not set
 123       */
 124      public function get_setting(): ?array {
 125          $bytes = $this->config_read($this->name);
 126          if (is_null($bytes)) {
 127              return null;
 128          }
 129          $bytes = intval($bytes);
 130  
 131          return self::parse_bytes($bytes);
 132      }
 133  
 134      /**
 135       * Store the file size as bytes.
 136       *
 137       * @param   array   $data   Must be form 'h' => xx, 'm' => xx
 138       * @return  string          The error string if any
 139       */
 140      public function write_setting($data): string {
 141          if (!is_array($data)) {
 142              return '';
 143          }
 144  
 145          if (!is_numeric($data['v']) || $data['v'] < 0) {
 146              return get_string('errorsetting', 'admin');
 147          }
 148  
 149          // Calculate size in bytes, ensuring we don't overflow PHP_INT_MAX.
 150          $bytes = $data['v'] * $data['u'];
 151          $result = (is_int($bytes) && $this->config_write($this->name, $bytes));
 152  
 153          return ($result ? '' : get_string('errorsetting', 'admin'));
 154      }
 155  
 156      /**
 157       * Returns file size text+select fields.
 158       *
 159       * @param   array   $data   The current setting value. Must be form 'v' => xx, 'u' => xx.
 160       * @param   string  $query  Admin search query to be highlighted.
 161       * @return  string          File size text+select fields and wrapping div(s).
 162       */
 163      public function output_html($data, $query = ''): string {
 164          global $OUTPUT;
 165  
 166          $default = $this->get_defaultsetting();
 167          if (is_number($default)) {
 168              $defaultinfo = self::get_size_text($default);
 169          } else if (is_array($default)) {
 170              $defaultinfo = self::get_size_text($default['v'] * $default['u']);
 171          } else {
 172              $defaultinfo = null;
 173          }
 174  
 175          $inputid = $this->get_id() . 'v';
 176          $units = self::get_units();
 177          $defaultunit = $this->defaultunit;
 178  
 179          $context = (object) [
 180              'id' => $this->get_id(),
 181              'name' => $this->get_full_name(),
 182              'value' => $data['v'],
 183              'readonly' => $this->is_readonly(),
 184              'options' => array_map(function($unit, $title) use ($data, $defaultunit) {
 185                  return [
 186                      'value' => $unit,
 187                      'name' => $title,
 188                      'selected' => ($data['v'] == 0 && $unit == $defaultunit) || $unit == $data['u']
 189                  ];
 190              }, array_keys($units), $units)
 191          ];
 192  
 193          $element = $OUTPUT->render_from_template('core_admin/setting_configfilesize', $context);
 194  
 195          return format_admin_setting($this, $this->visiblename, $element, $this->description, $inputid, '', $defaultinfo, $query);
 196      }
 197  }