mirror of
https://github.com/processwire/processwire.git
synced 2025-08-08 07:47:00 +02:00
Move logic for wireBytesStr() function into WireNumberTools class bytesToStr() method, while also making improvements to the method. Also add a strTobytes() method that does the opposite of bytesToStr. This also incorporates the addition of terabytes support submitted in another PR from @matjazpotocnik.
This commit is contained in:
@@ -680,7 +680,7 @@ function wireIconMarkupFile($filename, $class = '') {
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a quantity of bytes (int), return readable string that refers to quantity in bytes, kB, MB, GB, etc.
|
||||
* Given a quantity of bytes (int), return readable string that refers to quantity in bytes, kB, MB, GB and TB
|
||||
*
|
||||
* #pw-group-strings
|
||||
*
|
||||
@@ -690,96 +690,31 @@ function wireIconMarkupFile($filename, $class = '') {
|
||||
* - `1` (int): Same as `true` but with space between number and unit label.
|
||||
* - Or optionally specify the $options argument here if you do not need the $small argument.
|
||||
* @param array|int $options Options to modify default behavior, or if an integer then `decimals` option is assumed:
|
||||
* - `decimals` (int): Number of decimals to use in returned value (default=0).
|
||||
* - `decimals` (int|null): Number of decimals to use in returned value or NULL for auto (default=null).
|
||||
* When null (auto) a decimal value of 1 is used when appropriate, for megabytes and higher (3.0.214+).
|
||||
* - `decimal_point` (string|null): Decimal point character, or null to detect from locale (default=null).
|
||||
* - `thousands_sep` (string|null): Thousands separator, or null to detect from locale (default=null).
|
||||
* - `small` (bool): If no $small argument was specified, you can optionally specify it in this $options array.
|
||||
* - `type` (string): To force return value as specific type, specify one of: bytes, kilobytes, megabytes, gigabytes; or just: b, k, m, g. (3.0.148+ only)
|
||||
* - `type` (string): To force return value as specific type, specify one of: bytes, kilobytes, megabytes,
|
||||
* gigabytes, terabytes; or just: b, k, m, g, t. (3.0.148+ only, terabytes 3.0.214+).
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
function wireBytesStr($bytes, $small = false, $options = array()) {
|
||||
|
||||
$defaults = array(
|
||||
'type' => '',
|
||||
'decimals' => 0,
|
||||
'decimal_point' => null,
|
||||
'thousands_sep' => null,
|
||||
);
|
||||
|
||||
if(is_array($small)) {
|
||||
$options = $small;
|
||||
$small = isset($options['small']) ? $options['small'] : false;
|
||||
}
|
||||
if(!is_array($options)) $options = array('decimals' => (int) $options);
|
||||
if(!is_int($bytes)) $bytes = (int) $bytes;
|
||||
|
||||
$options = array_merge($defaults, $options);
|
||||
$locale = array();
|
||||
$type = empty($options['type']) ? '' : strtolower(substr($options['type'], 0, 1));
|
||||
|
||||
// determine size value and units label
|
||||
if($bytes < 1024 || $type === 'b') {
|
||||
$val = $bytes;
|
||||
if($small) {
|
||||
$label = $val > 0 ? __('B', __FILE__) : ''; // bytes
|
||||
} else if($val == 1) {
|
||||
$label = __('byte', __FILE__); // singular 1-byte
|
||||
if(is_array($small)) $options = $small;
|
||||
if(!is_array($options)) {
|
||||
if(ctype_digit("$options")) {
|
||||
$options = array('decimals' => (int) $options);
|
||||
} else {
|
||||
$label = __('bytes', __FILE__); // plural 2+ bytes (or 0 bytes)
|
||||
}
|
||||
} else if($bytes < 1000000 || $type === 'k') {
|
||||
$val = $bytes / 1024;
|
||||
$label = __('kB', __FILE__); // kilobytes
|
||||
} else if($bytes < 1073741824 || $type === 'm') {
|
||||
$val = $bytes / 1024 / 1024;
|
||||
$label = __('MB', __FILE__); // megabytes
|
||||
} else {
|
||||
$val = $bytes / 1024 / 1024 / 1024;
|
||||
$label = __('GB', __FILE__); // gigabytes
|
||||
}
|
||||
|
||||
// determine decimal point if not specified in $options
|
||||
if($options['decimal_point'] === null) {
|
||||
if($options['decimals'] > 0) {
|
||||
// determine decimal point from locale
|
||||
if(empty($locale)) $locale = localeconv();
|
||||
$options['decimal_point'] = empty($locale['decimal_point']) ? '.' : $locale['decimal_point'];
|
||||
} else {
|
||||
// no decimal point needed (not used)
|
||||
$options['decimal_point'] = '.';
|
||||
$options = array();
|
||||
}
|
||||
}
|
||||
|
||||
// determine thousands separator if not specified in $options
|
||||
if($options['thousands_sep'] === null) {
|
||||
if($small || $val < 1000) {
|
||||
// no thousands separator needed
|
||||
$options['thousands_sep'] = '';
|
||||
} else {
|
||||
// get thousands separator from current locale
|
||||
if(empty($locale)) $locale = localeconv();
|
||||
$options['thousands_sep'] = empty($locale['thousands_sep']) ? '' : $locale['thousands_sep'];
|
||||
if(is_int($small) && !isset($options['decimals'])) {
|
||||
$options['decimals'] = $small;
|
||||
} else if(is_bool($small)) {
|
||||
$options['small'] = $small;
|
||||
}
|
||||
}
|
||||
|
||||
// format number to string
|
||||
$str = number_format($val, $options['decimals'], $options['decimal_point'], $options['thousands_sep']);
|
||||
|
||||
// in small mode remove numbers with decimals that consist only of zeros "0"
|
||||
if($small && $options['decimals'] > 0) {
|
||||
$test = substr($str, -1 * $options['decimals']);
|
||||
if(((int) $test) === 0) {
|
||||
$str = substr($str, 0, strlen($str) - ($options['decimals'] + 1)); // i.e. 123.00 => 123
|
||||
} else {
|
||||
$str = rtrim($str, '0'); // i.e. 123.10 => 123.1
|
||||
}
|
||||
}
|
||||
|
||||
// append units label to number
|
||||
$str .= ($small === true ? '' : ' ') . $label;
|
||||
|
||||
return $str;
|
||||
return wire()->sanitizer->getNumberTools()->bytesToStr($bytes, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1158,7 +1093,7 @@ function wireInstanceOf($instance, $className, $autoload = true) {
|
||||
* @param string|callable $var
|
||||
* @param bool $syntaxOnly
|
||||
* @var string $callableName
|
||||
* @return array
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
function wireIsCallable($var, $syntaxOnly = false, &$callableName = '') {
|
||||
@@ -1184,7 +1119,7 @@ function wireIsCallable($var, $syntaxOnly = false, &$callableName = '') {
|
||||
function wireCount($value) {
|
||||
if($value === null) return 0;
|
||||
if(is_array($value)) return count($value);
|
||||
if(is_object($value) && $value instanceof \Countable) return count($value);
|
||||
if($value instanceof \Countable) return count($value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@@ -165,6 +165,12 @@ class Sanitizer extends Wire {
|
||||
*/
|
||||
protected $textTools = null;
|
||||
|
||||
/**
|
||||
* @var null|WireNumberTools
|
||||
*
|
||||
*/
|
||||
protected $numberTools = null;
|
||||
|
||||
/**
|
||||
* Runtime caches
|
||||
*
|
||||
@@ -5338,6 +5344,24 @@ class Sanitizer extends Wire {
|
||||
return $this->textTools;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get instance of WireNumberTools
|
||||
*
|
||||
* #pw-group-numbers
|
||||
* #pw-group-other
|
||||
*
|
||||
* @return WireNumberTools
|
||||
* @since 3.0.214
|
||||
*
|
||||
*/
|
||||
public function getNumberTools() {
|
||||
if(!$this->numberTools) {
|
||||
$this->numberTools = new WireNumberTools();
|
||||
$this->wire($this->numberTools);
|
||||
}
|
||||
return $this->numberTools;
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************
|
||||
* FILE VALIDATORS
|
||||
*
|
||||
|
@@ -11,6 +11,14 @@
|
||||
*/
|
||||
class WireNumberTools extends Wire {
|
||||
|
||||
/**
|
||||
* Caches for methods in this class
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
*/
|
||||
protected $caches = array();
|
||||
|
||||
/**
|
||||
* Generate and return an installation unique number/ID (integer)
|
||||
*
|
||||
@@ -90,4 +98,208 @@ class WireNumberTools extends Wire {
|
||||
return $uniqueNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a random integer (cryptographically secure when available)
|
||||
*
|
||||
* @param int $min Minimum value (default=0)
|
||||
* @param int $max Maximum value (default=PHP_INT_MAX)
|
||||
* @param bool $throw Throw WireException if we cannot achieve a cryptographically secure random number? (default=false)
|
||||
* @return int
|
||||
* @since 3.0.214
|
||||
*
|
||||
*/
|
||||
public function randomInteger($min, $max, $throw = false) {
|
||||
$rand = new WireRandom();
|
||||
return $rand->integer($min, $max, array('cryptoSecure' => $throw));
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a value like "1M", "2MB", "3 kB", "4 GB", "5tb" etc. return quantity of bytes
|
||||
*
|
||||
* Spaces, commas and case in given value do not matter. Only the first character of the unit is
|
||||
* taken into account, whether it appears in the given value, or is given in the $unit argument.
|
||||
* Meaning a unit like megabytes (for example) can be specified as 'm', 'mb', 'megabytes', etc.
|
||||
*
|
||||
* @param string|int|float $value
|
||||
* @param string|null $unit Optional unit that given value is in (b, kb, mb, gb, tb), or omit to auto-detect
|
||||
* @return int
|
||||
* @since 3.0.214
|
||||
*
|
||||
*/
|
||||
public function strToBytes($value, $unit = null) {
|
||||
|
||||
if(is_int($value) && $unit === null) return $value;
|
||||
|
||||
$value = str_replace(array(' ', ','), '', "$value");
|
||||
|
||||
if(ctype_digit("$value")) {
|
||||
$value = (int) $value;
|
||||
} else {
|
||||
$value = trim("$value");
|
||||
$negative = strpos($value, '-') === 0;
|
||||
if($negative) $value = ltrim($value, '-');
|
||||
if(preg_match('/^([\d.]+)([bkmgt])/i', $value, $matches)) {
|
||||
$value = strpos($matches[1], '.') !== false ? (float) $matches[1] : (int) $matches[1];
|
||||
if($unit === null) $unit = $matches[2];
|
||||
}
|
||||
if($negative) $value *= -1;
|
||||
}
|
||||
|
||||
if(is_string($unit)) switch(substr(strtolower($unit), 0, 1)) {
|
||||
case 'b': $value *= 1; break; // bytes
|
||||
case 'k': $value *= 1024; break; // kilobytes
|
||||
case 'm': $value *= (1024 * 1024); break; // megabytes
|
||||
case 'g': $value *= (1024 * 1024 * 1024); break; // gigabytes
|
||||
case 't': $value *= (1024 * 1024 * 1024 * 1024); break; // terabytes
|
||||
}
|
||||
|
||||
if(is_float($value)) $value = (int) round($value);
|
||||
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a quantity of bytes (int), return readable string that refers to quantity in bytes, kB, MB, GB and TB
|
||||
*
|
||||
* @param int|string $bytes Quantity in bytes (int) or any string accepted by strToBytes method.
|
||||
* @param array|int $options Options to modify default behavior, or if an integer then `decimals` option is assumed:
|
||||
* - `decimals` (int|null): Number of decimals to use in returned value or NULL for auto (default=null).
|
||||
* When null (auto) a decimal value of 1 is used when appropriate, for megabytes and higher (3.0.214+).
|
||||
* - `decimal_point` (string|null): Decimal point character, or null to detect from locale (default=null).
|
||||
* - `thousands_sep` (string|null): Thousands separator, or null to detect from locale (default=null).
|
||||
* - `small` (bool|int): Make returned string as small as possible? false=no, true=yes, 1=yes with space (default=false)
|
||||
* - `labels` (array): Labels to use for units, indexed by: b, byte, bytes, k, m, g, t
|
||||
* - `type` (string): To force return value as specific type, specify one of: bytes, kilobytes, megabytes,
|
||||
* gigabytes, terabytes; or just: b, k, m, g, t. (3.0.148+ only, terabytes 3.0.214+).
|
||||
* @return string
|
||||
* @since 3.0.214 All versions can also use the wireBytesStr() function
|
||||
*
|
||||
*/
|
||||
public function bytesToStr($bytes, $options = array()) {
|
||||
|
||||
$defaults = array(
|
||||
'type' => '',
|
||||
'small' => false,
|
||||
'decimals' => null,
|
||||
'decimal_point' => null,
|
||||
'thousands_sep' => null,
|
||||
'labels' => array(),
|
||||
);
|
||||
|
||||
if(is_string($bytes) && !ctype_digit($bytes)) {
|
||||
$bytes = $this->strToBytes($bytes);
|
||||
}
|
||||
|
||||
$bytes = (int) $bytes;
|
||||
$options = array_merge($defaults, $options);
|
||||
$type = empty($options['type']) ? '' : strtolower(substr($options['type'], 0, 1));
|
||||
$small = isset($options['small']) ? $options['small'] : false;
|
||||
$labels = $options['labels'];
|
||||
|
||||
if($options['decimals'] === null) {
|
||||
if($bytes > 1024 && empty($options['type'])) {
|
||||
// auto decimals (use 1 decimal for megabytes and higher)
|
||||
$options['decimals'] = 1;
|
||||
} else {
|
||||
$options['decimals'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// determine size value and units label
|
||||
if($bytes < 1024 || $type === 'b') {
|
||||
// bytes
|
||||
$val = $bytes;
|
||||
if($small) {
|
||||
$label = $val > 0 ? (isset($labels['b']) ? $labels['b'] : $this->_('B')) : ''; // bytes
|
||||
} else if($val == 1) {
|
||||
$label = isset($labels['byte']) ? $labels['byte'] : $this->_('byte'); // singular 1-byte
|
||||
} else {
|
||||
$label = isset($labels['bytes']) ? $labels['bytes'] : $this->_('bytes'); // plural 2+ bytes (or 0 bytes)
|
||||
}
|
||||
} else if($bytes < 1000000 || $type === 'k') {
|
||||
// kilobytes
|
||||
$val = $bytes / 1024;
|
||||
$label = isset($labels['k']) ? $labels['k'] : $this->_('kB');
|
||||
} else if($bytes < 1073741824 || $type === 'm') {
|
||||
// megabytes
|
||||
$val = $bytes / 1024 / 1024;
|
||||
$label = isset($labels['m']) ? $labels['m'] : $this->_('MB');
|
||||
} else if($bytes < 1099511627776 || $type === 'g') {
|
||||
// gigabytes
|
||||
$val = $bytes / 1024 / 1024 / 1024;
|
||||
$label = isset($labels['g']) ? $labels['g'] : $this->_('GB');
|
||||
} else {
|
||||
// terabytes
|
||||
$val = $bytes / 1024 / 1024 / 1024 / 1024;
|
||||
$label = isset($labels['t']) ? $labels['t'] : $this->_('TB');
|
||||
}
|
||||
|
||||
// determine decimal point if not specified in $options
|
||||
if($options['decimal_point'] === null) {
|
||||
if($options['decimals'] > 0) {
|
||||
$options['decimal_point'] = $this->locale('decimal_point');
|
||||
} else {
|
||||
// no decimal point needed (not used)
|
||||
$options['decimal_point'] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
// determine thousands separator if not specified in $options
|
||||
if($options['thousands_sep'] === null) {
|
||||
if($small || $val < 1000) {
|
||||
// no thousands separator needed
|
||||
$options['thousands_sep'] = '';
|
||||
} else {
|
||||
$options['thousands_sep'] = $this->locale('thousands_sep');
|
||||
}
|
||||
}
|
||||
|
||||
// format number to string
|
||||
$str = number_format($val, $options['decimals'], $options['decimal_point'], $options['thousands_sep']);
|
||||
|
||||
// in small mode remove numbers with decimals that consist only of zeros "0"
|
||||
if($small && $options['decimals'] > 0) {
|
||||
$test = substr($str, -1 * $options['decimals']);
|
||||
if(((int) $test) === 0) {
|
||||
$str = substr($str, 0, strlen($str) - ($options['decimals'] + 1)); // i.e. 123.00 => 123
|
||||
} else {
|
||||
$str = rtrim($str, '0'); // i.e. 123.10 => 123.1
|
||||
}
|
||||
}
|
||||
|
||||
// append units label to number
|
||||
$str .= ($small === true ? '' : ' ') . $label;
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a number formatting property from current locale
|
||||
*
|
||||
* In multi-language environments, this method’s return values are affected by the
|
||||
* current language locale.
|
||||
*
|
||||
* @param string $key Property to get or omit to get all properties. Properties include:
|
||||
* - `decimal_point`: Decimal point character
|
||||
* - `thousands_sep`: Thousands separator
|
||||
* - `currency_symbol`: Local currency symbol (i.e. $)
|
||||
* - `int_curr_symbol`: International currency symbol (i.e. USD)
|
||||
* - `mon_decimal_point`: Monetary decimal point character
|
||||
* - `mon_thousands_sep`: Monetary thousands separator
|
||||
* - `positive_sign`: Sign for positive values
|
||||
* - `negative_sign`: Sign for negative values
|
||||
* - `clear`: Clear any cached values for current language/locale.
|
||||
* - See <https://www.php.net/manual/en/function.localeconv.php> for more.
|
||||
* @return array|string|int|null
|
||||
*
|
||||
*/
|
||||
public function locale($key = '') {
|
||||
$lang = $this->wire()->languages ? $this->wire()->user->language->id : '';
|
||||
$locale = "locale$lang";
|
||||
if($key === 'clear') unset($this->caches[$locale]);
|
||||
if(empty($this->caches[$locale])) $this->caches[$locale] = localeconv();
|
||||
if($key === '') return $this->caches[$locale];
|
||||
return isset($this->caches[$locale][$key]) ? $this->caches[$locale][$key] : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -398,7 +398,6 @@ class WireRandom extends Wire {
|
||||
$count = count($a);
|
||||
$keys = array_keys($a);
|
||||
$items = array();
|
||||
$item = null;
|
||||
$keepKeys = true;
|
||||
|
||||
// if getArray option not specified, auto determine from qty
|
||||
@@ -475,7 +474,6 @@ class WireRandom extends Wire {
|
||||
*
|
||||
*/
|
||||
public function arrayKey(array $a) {
|
||||
$options['getKey'] = true;
|
||||
return $this->arrayItem($a, array('getKey' => true));
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user