Initial xentral_oss_20.3.c9ffacf

This commit is contained in:
Alex
2021-05-21 08:49:41 +02:00
parent 5406e4a551
commit 34e5ac43d9
18884 changed files with 2109867 additions and 0 deletions
+169
View File
@@ -0,0 +1,169 @@
<?php
namespace Xentral\Components\Util;
use Xentral\Components\Util\Exception\InvalidArgumentException;
final class ColorUtil
{
/**
* @example '#369' or '#336699' => array('r' => 51, 'g' => 102, 'b' => 153)
*
* @param string $hexColor
*
* @throws InvalidArgumentException
*
* @return array ['r' => {$red}, 'g' => {$green}, 'b' => {$blue}]
*/
public static function convertHexToRgb($hexColor)
{
self::ensureHexColorFormat($hexColor);
$hexColor = self::normalizeHexColor($hexColor);
$hexColor = str_replace('#', '', $hexColor);
$colorParts = str_split($hexColor, 2);
$red = (int)hexdec($colorParts[0]);
$green = (int)hexdec($colorParts[1]);
$blue = (int)hexdec($colorParts[2]);
return ['r' => $red, 'g' => $green, 'b' => $blue];
}
/**
* @param int $red [0-255]
* @param int $green [0-255]
* @param int $blue [0-255]
*
* @throws InvalidArgumentException
*
* @return string
*/
public static function convertRgbToHex($red, $green, $blue)
{
if ($red < 0 || $red > 255) {
throw new InvalidArgumentException(sprintf(
'Invalid value for color red "%s". Color values must be between 0 and 255.', $red
));
}
if ($green < 0 || $green > 255) {
throw new InvalidArgumentException(sprintf(
'Invalid value for color green "%s". Color values must be between 0 and 255.', $green
));
}
if ($blue < 0 || $blue > 255) {
throw new InvalidArgumentException(sprintf(
'Invalid value for color blue "%s". Color values must be between 0 and 255.', $blue
));
}
$rHex = StringUtil::padLeft(dechex($red), 2, '0');
$gHex = StringUtil::padLeft(dechex($green), 2, '0');
$bHex = StringUtil::padLeft(dechex($blue), 2, '0');
$hexColor = '#' . strtoupper($rHex . $gHex . $bHex);
self::ensureHexColorFormat($hexColor);
return $hexColor;
}
/**
* Normalizes hex colors
*
* - Transforms shorthand hexcolors (e.g. #369) into long hexcolor format (#336699)
* - Long hexcolor format (#336699) will be unchanged
*
* @param string $hexColor
*
* @return string
*/
public static function normalizeHexColor($hexColor)
{
self::ensureHexColorFormat($hexColor);
$hexColor = str_replace('#', '', $hexColor);
if (strlen($hexColor) === 3) {
$red = !empty($hexColor[0]) ? $hexColor[0] : '0';
$green = !empty($hexColor[1]) ? $hexColor[1] : '0';
$blue = !empty($hexColor[2]) ? $hexColor[2] : '0';
$hexColor = $red . $red . $green . $green . $blue . $blue;
}
return '#' . $hexColor;
}
/**
* Calculates the brightness level (YIQ formula); is the given color more darker or lighter?
*
* Result 'dark' means: The given color is more darker than light. When using the given color as
* a background color, then use a light text color for better contrast (and vice versa).
*
* @param int $red [0-255]
* @param int $green [0-255]
* @param int $blue [0-255]
*
* @throws InvalidArgumentException
*
* @return string [dark|light]
*/
public static function calculateBrightnessLevel($red, $green, $blue)
{
if ($red < 0 || $red > 255) {
throw new InvalidArgumentException(sprintf(
'Invalid value for color red "%s". Color values must be between 0 and 255.', $red
));
}
if ($green < 0 || $green > 255) {
throw new InvalidArgumentException(sprintf(
'Invalid value for color green "%s". Color values must be between 0 and 255.', $green
));
}
if ($blue < 0 || $blue > 255) {
throw new InvalidArgumentException(sprintf(
'Invalid value for color blue "%s". Color values must be between 0 and 255.', $blue
));
}
/** @see http://dannyruchtie.com/color-contrast-calculator-with-yiq/ */
$yiqValue = ($red * 299 + $green * 587 + $blue * 114) / 1000;
return $yiqValue >= 128 ? 'light' : 'dark';
}
/**
* @param string $hexColor
*
* @throws InvalidArgumentException
*
* @return void
*/
private static function ensureHexColorFormat($hexColor)
{
if (strpos($hexColor, '#') !== 0) {
throw new InvalidArgumentException(sprintf(
'Invalid format for hex color "%s". Hex color must start with hash char (#).',
$hexColor
));
}
$hexString = substr_replace($hexColor, '', 0, 1);
$hexCleaned = preg_replace('/[^0-9A-Fa-f]/', '', $hexString);
if ($hexString !== $hexCleaned) {
throw new InvalidArgumentException(sprintf(
'Invalid format for hex color "%s". Hex color contains invalid chars. ' .
'Valid chars are: A-F, a-f and 0-9.',
$hexColor
));
}
$hexColorLength = strlen($hexColor);
if ($hexColorLength !== 4 && $hexColorLength !== 7) {
throw new InvalidArgumentException(sprintf(
'Invalid format for hex color "%s". Hex color must be four or seven chars long; ' .
'with leading hash char (#).',
$hexColor
));
}
}
}
@@ -0,0 +1,9 @@
<?php
namespace Xentral\Components\Util\Exception;
use RuntimeException;
class InsecureRandomStringException extends RuntimeException implements UtilExceptionInterface
{
}
@@ -0,0 +1,9 @@
<?php
namespace Xentral\Components\Util\Exception;
use InvalidArgumentException as SplInvalidArgumentException;
class InvalidArgumentException extends SplInvalidArgumentException implements UtilExceptionInterface
{
}
@@ -0,0 +1,9 @@
<?php
namespace Xentral\Components\Util\Exception;
use RuntimeException;
class StringUtilException extends RuntimeException implements UtilExceptionInterface
{
}
@@ -0,0 +1,9 @@
<?php
namespace Xentral\Components\Util\Exception;
use Xentral\Core\Exception\ComponentExceptionInterface;
interface UtilExceptionInterface extends ComponentExceptionInterface
{
}
+407
View File
@@ -0,0 +1,407 @@
<?php
namespace Xentral\Components\Util;
use Exception;
use Xentral\Components\Util\Exception\InsecureRandomStringException;
use Xentral\Components\Util\Exception\InvalidArgumentException;
use Xentral\Components\Util\Exception\StringUtilException;
final class StringUtil
{
/** @var array $translate */
private static $transliteration = [
'/m\x{00B2}/u' => 'qm',
'/m\x{00B3}/u' => 'm3',
'/ä/' => 'ae',
'/ö/' => 'oe',
'/ü/' => 'ue',
'/Ä/' => 'Ae',
'/Ö/' => 'Oe',
'/Ü/' => 'Ue',
'/\x{00DF}/u' => 'ss', //ß
'/\x{20AC}/u' => 'EURO', //€
'/\x{0026}/u' => 'und', //&
];
/**
* Returns true if string starts with needle.
*
* @example startsWith('Apple', 'A') -> true
*
* @param string $haystack
* @param string $needle
*
* @return bool
*/
public static function startsWith($haystack, $needle)
{
self::ensureString($haystack);
self::ensureString($needle);
return $needle === '' || strpos($haystack, $needle) === 0;
}
/**
* Returns true if string ends with needle.
*
* @example endsWith('Apple', 'e') -> true
*
* @param string $haystack
* @param string $needle
*
* @return bool
*/
public static function endsWith($haystack, $needle)
{
self::ensureString($haystack);
self::ensureString($needle);
return $needle === substr($haystack, strlen($haystack) - strlen($needle), strlen($needle));
}
/**
* Returns true if needle appears anywhere in string.
*
* @example contains('Apple', 'pp') -> true
*
* @param string $haystack
* @param string $needle
*
* @return bool
*/
public static function contains($haystack, $needle)
{
self::ensureString($haystack);
self::ensureString($needle);
return $needle === '' || strpos($haystack, $needle) !== false;
}
/**
* Pads a string up to a specific length.
*
* @example padLeft('a', 4, '-') -> '---a'
* @example padLeft('a', 4, '-+') -> '-+-a'
*
* @param string $string
* @param int $length
* @param string $pad
*
* @return string
*/
public static function padLeft($string, $length, $pad = ' ')
{
self::ensureString($string);
self::ensureInteger($length);
self::ensureString($pad);
return self::generatePadding($length - mb_strlen($string), $pad) . $string;
}
/**
* Pads a string up to a specific length.
*
* @example padRight('a', 4, '-') -> 'a---'
* @example padRight('a', 4, '-+') -> 'a-+-'
*
* @param string $string
* @param int $length
* @param string $pad
*
* @return string
*/
public static function padRight($string, $length, $pad = ' ')
{
self::ensureString($string);
self::ensureInteger($length);
self::ensureString($pad);
return $string . self::generatePadding($length - mb_strlen($string), $pad);
}
/**
* Generates a filesystem-friendly (win, mac, linux) file name from a given string
*
* @param string $value
*
* @return string file name
*/
public static function toFilename($value)
{
self::ensureString($value);
$sanitize = [
'/\s+/' => '_', //space
'/:\\\/' => '-', //drive name
'/\\\\\\\/' => '-', //unc path
'/[\\/\\\<>:|]/' => '-', //seperators and reserved
'/"/' => '\'',
'/[\*\?&]+/' => '', //other special chars
'/[\x{0000}-\x{001F}]/u' => '',
'/[\x{0080}-\x{FFFF}]/u' => '', //only ascii
];
$filename = preg_replace(array_keys(self::$transliteration), array_values(self::$transliteration), $value);
$filename = preg_replace(array_keys($sanitize), array_values($sanitize), $filename);
$filename = trim($filename, '.');
if ($filename === '') {
throw new StringUtilException(
sprintf('The specified string "%s" cannot be converted to a valid file name', $value)
);
}
return $filename;
}
/** Deletes all non-ASCII non-printable characters from a string
*
* Only characters between 32 to 127 (inclusive) remain.
*
* @param string $value
*
* @return string empty if whole string was non-ASCII
*/
public static function toAscii($value)
{
self::ensureString($value);
$value = preg_replace(['/[\x{0000}-\x{001F}]/u', '/[\x{0080}-\x{FFFF}]/u'], ['', ''], $value);
return $value;
}
/**
* Transforms a String to Title case.
*
* Use delimiter='' to only capitalize the first character.
*
* @example "foo Bar BaZ" => "Foo Bar Baz"
*
* @param string $value
* @param string $delimiters all characters that seperate words
*
* @return string
*/
public static function toTitleCase($value, $delimiters = '\s\v')
{
self::ensureString($value);
self::ensureString($delimiters);
$inWords = [$value];
$outWords = [];
if ($delimiters !== '') {
$regex = sprintf('/[%s]/', $delimiters);
$inWords = preg_split($regex, $value);
}
foreach ($inWords as $word) {
if ($word !== '') {
$outWords[] = mb_strtoupper(mb_substr($word, 0, 1))
. mb_strtolower(mb_substr($word, 1, mb_strlen($word)));
}
}
return implode(' ', $outWords);
}
/**
* Format a nubmer of Bytes to KB, MB etc.
*
* @example formatBytes(1024, ' ') -> '1,0 KB'
*
* @param integer $bytes
* @param string $separator
*
* @return string
*/
public static function formatBytes($bytes, $separator = '')
{
self::ensureInteger($bytes);
$bytes = (int)$bytes;
if ($bytes <= 0) {
return sprintf('0%sBytes', $separator);
}
$units = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
$exponent = (int)floor(log($bytes) / log(1024));
if ($exponent > count($units) - 1) {
$exponent = count($units) - 1;
}
$size = $bytes / pow(1024, $exponent);
return sprintf('%s%s%s',
number_format($size, 1, ',', '.'),
$separator,
$units[$exponent]
);
}
/**
* Parse PHP byte size Values to number of bytes.
*
* Shorthand Format is used in php_ini (e.g. post_max_size).
*
* @example parsePhpShorthandByte('1M') -> 1048576
*
* @param string $phpSize php shorthand byte format
*
* @return int
*/
public static function parsePhpByteSize($phpSize)
{
self::ensureString($phpSize);
preg_match('/^(\d+)([kKmMgG]?)$/', $phpSize, $matches);
if (empty($matches)) {
throw new InvalidArgumentException(sprintf('"%s" is not a PHP size format.', $phpSize));
}
$sizes = ['' => 0, 'K' => 1, 'M' => 2, 'G' => 3];
$number = (int)$matches[1];
$unit = strtoupper($matches[2]);
$exponent = $sizes[$unit];
$bytes = $number * pow(1024, $exponent);
return (int)$bytes;
}
/**
* Generates a random String with specified length
*
* @param int $length
* @param bool $secure true=create cryptographically secure string
*
* @throws InsecureRandomStringException
*
* @return string
*/
public static function random($length, $secure = false)
{
$random = self::randomByOpenSsl($length, $secure);
if ($random === false) {
$random = self::randomByRandomBytes($length);
}
if ($random !== false) {
return $random;
}
if ($random === false && $secure === true) {
throw new InsecureRandomStringException('Could not generate cryptographically secure random string.');
}
return self::randomByMd5($length);
}
/**
* @param int $length
* @param bool $secure
*
* @return string|false
*/
private static function randomByOpenSsl($length, $secure = false)
{
if (function_exists('openssl_random_pseudo_bytes')) {
$bytes = openssl_random_pseudo_bytes(ceil($length / 2), $cryptoStrong);
if ($bytes === false || ($secure === true && $cryptoStrong === false)) {
return false;
}
return substr(bin2hex($bytes), 0, $length);
}
return false;
}
/**
* random_bytes steht erst ab PHP7 zur Verfügung
*
* @param int $length
*
* @return string|false
*/
private static function randomByRandomBytes($length)
{
$random = false;
if (function_exists('random_bytes')) {
try {
$bytes = random_bytes(ceil($length / 2));
$random = substr(bin2hex($bytes), 0, $length);
} catch (Exception $e) {
}
}
return $random;
}
/**
* @param int $length
*
* @return string|false
*/
private static function randomByMd5($length)
{
$random = '';
for ($i = 0; $i * 32 <= $length; $i++) {
$val = mt_rand();
$random .= md5((string)$val);
}
$random = substr($random, 0, $length);
return $random;
}
/**
* @param int $lengthDelta
* @param string $sequence
*
* @return string
*/
private static function generatePadding($lengthDelta, $sequence)
{
if ($sequence === '' || $lengthDelta < 1) {
return '';
}
$padding = '';
for ($i = 0; $i < $lengthDelta; $i++) {
$delta = $lengthDelta - mb_strlen($padding);
$subSequence = mb_substr($sequence, 0, $delta);
$padding .= $subSequence;
}
return $padding;
}
/**
* @param mixed $value
*
* @throws InvalidArgumentException
*
* @return void
*/
private static function ensureString($value)
{
$type = gettype($value);
if ($type !== 'string') {
throw new InvalidArgumentException(sprintf('Wrong type "%s". Only "string" is allowed.', $type));
}
}
/**
* @param mixed $value
*
* @throws InvalidArgumentException
*
* @return void
*/
private static function ensureInteger($value)
{
$type = gettype($value);
if ($type !== 'integer') {
throw new InvalidArgumentException(sprintf('Wrong type "%s". Only "integer" allowed.', $type));
}
}
}