Add src files for CoreLibs composer all package

This commit is contained in:
Clemens Schwaighofer
2023-02-16 12:47:43 +09:00
commit cfcd601b3a
76 changed files with 25404 additions and 0 deletions

187
src/Check/Colors.php Normal file
View File

@@ -0,0 +1,187 @@
<?php
/*
* valid checks for css/html based colors
* # hex
* # hex + alpha
* rgb
* rgba
* hsl
* hsla
*/
declare(strict_types=1);
namespace CoreLibs\Check;
use Exception;
class Colors
{
/** @var int 1 for HEX rgb */
public const HEX_RGB = 1;
/** @var int 2 for HEX rgb with alpha */
public const HEX_RGBA = 2;
/** @var int 4 for rgb() */
public const RGB = 4;
/** @var int 8 for rgba() */
public const RGBA = 8;
/** @var int 16 for hsl() */
public const HSL = 16;
/** @var int 32 for hsla() */
public const HSLA = 32;
/** @var int 63 for all bits set (sum of above) */
public const ALL = 63;
/**
* check rgb/hsl content values in detail
* will abort and return false on first error found
*
* @param string $color html/css tring to check
* @param int|false $rgb_flag flag to check for rgb
* @param int|false $hsl_flag flag to check for hsl type
* @return bool True if no error, False if error
*/
private static function rgbHslContentCheck(string $color, $rgb_flag, $hsl_flag): bool
{
// extract string between () and split into elements
preg_match("/\((.*)\)/", $color, $matches);
if (
!is_array($color_list = preg_split("/,\s*/", $matches[1] ?? ''))
) {
throw new \Exception("Could not extract color list from rgg/hsl", 3);
}
// based on rgb/hsl settings check that entries are valid
// rgb: either 0-255 OR 0-100%
// hsl: first: 0-360
foreach ($color_list as $pos => $color_check) {
if (empty($color_check)) {
return false;
}
$percent_check = false;
if (strrpos($color_check, '%', -1) !== false) {
$percent_check = true;
$color_check = str_replace('%', '', $color_check);
}
// first three normal percent or valid number
if ($rgb_flag !== false) {
if ($percent_check === true) {
// for ALL pos
if ($color_check < 0 || $color_check > 100) {
return false;
}
} elseif (
$pos < 3 &&
($color_check < 0 || $color_check > 255)
) {
return false;
} elseif (
// RGBA set pos 3 if not percent
$pos == 3 &&
($color_check < 0 || $color_check > 1)
) {
return false;
}
} elseif ($hsl_flag !== false) {
// pos 0: 0-360
// pos 1,2: %
// pos 3: % or 0-1 (float)
if (
$pos == 0 &&
($color_check < 0 || $color_check > 360)
) {
return false;
} elseif (
// if pos 1/2 are not percent
($pos == 1 || $pos == 2) &&
($percent_check != true ||
($color_check < 0 || $color_check > 100))
) {
return false;
} elseif (
// 3 is either percent or 0~1
$pos == 3 &&
(
($percent_check == false &&
($color_check < 0 || $color_check > 1)) ||
($percent_check === true &&
($color_check < 0 || $color_check > 100))
)
) {
return false;
}
}
}
return true;
}
/**
* check if html/css color string is valid
* @param string $color A color string of any format
* @param int $flags defaults to ALL, else use | to combined from
* HEX_RGB, HEX_RGBA, RGB, RGBA, HSL, HSLA
* @return bool True if valid, False if not
* @throws Exception 1: no valid flag set
*/
public static function validateColor(string $color, int $flags = self::ALL): bool
{
// blocks for each check
$regex_blocks = [];
// set what to check
if ($flags & self::HEX_RGB) {
$regex_blocks[] = '#[\dA-Fa-f]{6}';
}
if ($flags & self::HEX_RGBA) {
$regex_blocks[] = '#[\dA-Fa-f]{8}';
}
if ($flags & self::RGB) {
$regex_blocks[] = 'rgb\(\d{1,3}%?,\s*\d{1,3}%?,\s*\d{1,3}%?\)';
}
if ($flags & self::RGBA) {
$regex_blocks[] = 'rgba\(\d{1,3}%?,\s*\d{1,3}%?,\s*\d{1,3}%?(,\s*(0\.\d{1,2}|1(\.0)?|\d{1,3}%))?\)';
}
if ($flags & self::HSL) {
$regex_blocks[] = 'hsl\(\d{1,3},\s*\d{1,3}(\.\d{1})?%,\s*\d{1,3}(\.\d{1})?%\)';
}
if ($flags & self::HSLA) {
$regex_blocks[] = 'hsla\(\d{1,3},\s*\d{1,3}(\.\d{1})?%,\s*\d{1,3}'
. '(\.\d{1})?%(,\s*(0\.\d{1,2}|1(\.0)?|\d{1,3}%))?\)';
}
// wrong flag set
if ($flags > self::ALL) {
throw new \Exception("Invalid flags parameter: $flags", 1);
}
if (!count($regex_blocks)) {
throw new \Exception("No regex blocks set: $flags", 2);
}
// build regex
$regex = '^('
. join('|', $regex_blocks)
// close regex
. ')$';
// print "C: $color, F: $flags, R: $regex\n";
if (preg_match("/$regex/", $color)) {
// if valid regex, we now need to check if the content is actually valid
// only for rgb/hsl type
/** @var int|false */
$rgb_flag = strpos($color, 'rgb');
/** @var int|false */
$hsl_flag = strpos($color, 'hsl');
// if both not match, return true
if (
$rgb_flag === false &&
$hsl_flag === false
) {
return true;
}
// run detaul rgb/hsl content check
return self::rgbHslContentCheck($color, $rgb_flag, $hsl_flag);
} else {
return false;
}
}
}
// __END__

265
src/Check/Email.php Normal file
View File

@@ -0,0 +1,265 @@
<?php
declare(strict_types=1);
namespace CoreLibs\Check;
class Email
{
// this is for error check parts in where the email regex failed
/** @var array<int,string> */
private static $email_regex_check = [
0 => "^[A-Za-z0-9!#$%&'*+\-\/=?^_`{|}~][A-Za-z0-9!#$%:\(\)&'*+\-\/=?^_`{|}~\.]{0,63}@"
. "[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]{1,})*\.([a-zA-Z]{2,}){1}$", // MASTER
1 => "@(.*)@(.*)", // double @
2 => "^[A-Za-z0-9!#$%&'*+\-\/=?^_`{|}~][A-Za-z0-9!#$%:\(\)&'*+\-\/=?^_`{|}~\.]{0,63}@", // wrong part before @
3 => "@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]{1,})*\.([a-zA-Z]{2,}){1}$", // wrong part after @
4 => "@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]{1,})*\.", // wrong domain name part
5 => "\.([a-zA-Z]{2,6}){1}$", // wrong top level part
6 => "@(.*)\.{2,}", // double .. in domain name part
7 => "@.*\.$" // ends with a dot, top level, domain missing
];
// for above position, description string below
/** @var array<int,string> */
private static $email_regex_check_message = [
0 => 'Invalid email address',
1 => 'Double @ mark in email address',
2 => 'Invalid email part before @ sign',
3 => 'Invalid domain part after @ sign',
4 => 'Invalid domain name part',
5 => 'Wrong domain top level part',
6 => 'Double consecutive dots in domain name (..)',
7 => 'Domain ends with a dot or is missing top level part'
];
// the array with the mobile types that are valid
/** @var array<string,string> */
private static $mobile_email_type = [
'.*@docomo\.ne\.jp$' => 'keitai_docomo',
// correct are a[2-4], b2, c[1-9], e[2-9], h[2-4], t[1-9]
'.*@([a-z0-9]{2}\.)?ezweb\.ne\.jp$' => 'keitai_kddi_ezweb',
// ez[a-j] or nothing
'.*@(ez[a-j]{1}\.)?ido\.ne\.jp$' => 'keitai_kddi_ido',
// (sky group)
'.*@([a-z]{2}\.)?sky\.tu-ka\.ne\.jp$' => 'keitai_kddi_tu-ka',
// (sky group) [tkk,tkc only]
'.*@([a-z]{2}\.)?sky\.tk[kc]{1}\.ne\.jp$' => 'keitai_kddi_sky',
// dtg (sky group)
'.*@([a-z]{2}\.)?sky\.dtg\.ne\.jp$' => 'keitai_kddi_dtg',
// old vodafone [t,k,d,h,c,r,n,s,q]
'.*@[tkdhcrnsq]{1}\.vodafone\.ne\.jp$' => 'keitai_softbank_vodafone',
// very old j-phone (pre vodafone) [d,h,t,k,r,s,n,q,c]
'.*@jp-[dhtkrsnqc]{1}\.ne\.jp$' => 'keitai_softbank_j-phone',
// add i for iphone also as keitai, others similar to the vodafone group
'.*@([dhtcrknsq]{1}\.)?softbank\.ne\.jp$' => 'keitai_softbank',
// add iPhone also as keitai and not as pc
'.*@i{1}\.softbank(\.ne)?\.jp$' => 'smartphone_softbank_iphone',
'.*@disney\.ne\.jp$' => 'keitai_softbank_disney', // (kids)
'.*@willcom\.ne\.jp$' => 'keitai_willcom',
'.*@willcom\.com$' => 'keitai_willcom', // new for pdx.ne.jp address
'.*@wcm\.ne\.jp$' => 'keitai_willcom', // old willcom wcm.ne.jp
'.*@pdx\.ne\.jp$' => 'keitai_willcom_pdx', // old pdx address for willcom
'.*@bandai\.jp$' => 'keitai_willcom_bandai', // willcom paipo! (kids)
'.*@pipopa\.ne\.jp$' => 'keitai_willcom_pipopa', // willcom paipo! (kids)
// actually only di,dj,dk,wm -> all others are "wrong", but none also allowed?
'.*@([a-z0-9]{2,4}\.)?pdx\.ne\.jp$' => 'keitai_willcom_pdx',
// ymobile, ymobile1 techincally not willcom, but I group them there (softbank sub)
'.*@ymobile([1]{1})?\.ne\.jp$' => 'keitai_willcom_ymobile',
// y-mobile techincally not willcom, but I group them there (softbank sub)
'.*@y-mobile\.ne\.jp$' => 'keitai_willcom_ymobile',
'.*@emnet\.ne\.jp$' => 'keitai_willcom_emnet', // e-mobile, group will willcom
'.*@emobile\.ne\.jp$' => 'keitai_willcom_emnet', // e-mobile, group will willcom
'.*@emobile-s\.ne\.jp$' => 'keitai_willcom_emnet' # e-mobile, group will willcom
];
// short list for mobile email types
/** @var array<string,string> */
private static $mobile_email_type_short = [
'keitai_docomo' => 'docomo',
'keitai_kddi_ezweb' => 'kddi',
'keitai_kddi' => 'kddi',
'keitai_kddi_tu-ka' => 'kddi',
'keitai_kddi_sky' => 'kddi',
'keitai_softbank' => 'softbank',
'smartphone_softbank_iphone' => 'iphone',
'keitai_softbank_disney' => 'softbank',
'keitai_softbank_vodafone' => 'softbank',
'keitai_softbank_j-phone' => 'softbank',
'keitai_willcom' => 'willcom',
'keitai_willcom_pdx' => 'willcom',
'keitai_willcom_bandai' => 'willcom',
'keitai_willcom_pipopa' => 'willcom',
'keitai_willcom_ymobile' => 'willcom',
'keitai_willcom_emnet' => 'willcom',
'pc_html' => 'pc',
// old sets -> to be removed later
'docomo' => 'docomo',
'kddi_ezweb' => 'kddi',
'kddi' => 'kddi',
'kddi_tu-ka' => 'kddi',
'kddi_sky' => 'kddi',
'softbank' => 'softbank',
'keitai_softbank_iphone' => 'iphone',
'softbank_iphone' => 'iphone',
'softbank_disney' => 'softbank',
'softbank_vodafone' => 'softbank',
'softbank_j-phone' => 'softbank',
'willcom' => 'willcom',
'willcom_pdx' => 'willcom',
'willcom_bandai' => 'willcom',
'willcom_pipopa' => 'willcom',
'willcom_ymobile' => 'willcom',
'willcom_emnet' => 'willcom',
'pc' => 'pc'
];
/**
* get one position from the regex check list
*
* @param int $type Which position in the regex list to get
* if not set or not valid get default pos 0
* @return string
*/
public static function getEmailRegex(int $type = 0): string
{
// make sure type is in valid range
if ($type < 0 || $type >= count(self::$email_regex_check)) {
$type = 0;
}
return self::$email_regex_check[$type];
}
/**
* get the full check array, except position 0, but preserve keys
* Currently used to add per error level type from
* getEmailRegex to error reporting
* Might be deprecated at some point
*
* @return array<mixed>
*/
public static function getEmailRegexCheck(): array
{
// return all but the first
return array_slice(
self::$email_regex_check,
1,
count(self::$email_regex_check) - 1,
true
);
}
/**
* Returns error message for email ergex error, or empty string if not set
*
* @param int $error
* @return array<string,string|int> Error message and regex
*/
public static function getEmailRegexErrorMessage(int $error): array
{
// return error message and regex
return [
'error' => $error,
'message' => self::$email_regex_check_message[$error] ?? '',
'regex' => self::$email_regex_check[$error] ?? '',
];
}
/**
* guesses the email type (mostly for mobile) from the domain
* if second is set to true, it will return short naming scheme (only provider)
*
* @param string $email email string
* @param bool $short default false, if true,
* returns only short type (pc instead of pc_html)
* @return string|bool email type, eg "pc", "docomo", etc,
* false for invalid short type
*/
public static function getEmailType(string $email, bool $short = false)
{
// trip if there is no email address
if (!$email) {
return 'invalid';
}
// loop until we match a mobile type, return this first found type
foreach (self::$mobile_email_type as $email_regex => $email_type) {
if (preg_match("/$email_regex/", $email)) {
if ($short) {
return self::getShortEmailType($email_type);
} else {
return $email_type;
}
}
}
// if no previous return we assume this is a pc address
if ($short) {
return 'pc';
} else {
return 'pc_html';
}
}
/**
* gets the short email type from a long email type
*
* @param string $email_type email string
* @return string|bool short string or false for invalid
*/
public static function getShortEmailType(string $email_type)
{
// check if the short email type exists
if (isset(self::$mobile_email_type_short[$email_type])) {
return self::$mobile_email_type_short[$email_type];
} else {
// return false on not found
return false;
}
}
/**
* simple email check with the basic email eregex
*
* @param string $email Email address, will be checkd as lower
* @return bool True if email is ok, or false if regex failed
*/
public static function checkEmail(string $email): bool
{
$email_regex = self::getEmailRegex();
if (!preg_match("/$email_regex/", strtolower($email))) {
return false;
}
return true;
}
/**
* check email with all regex checks possible and return errors as array
*
* @param string $email Email address, will be checkd as lower
* @param bool $error_code_only If this is set to true it will only return
* the error pos, instead of detailed array
* @return array<mixed> Errors as array with message and regex
*/
public static function checkEmailFull(string $email, bool $error_code_only = false): array
{
$errors = [];
foreach (self::$email_regex_check as $pos => $email_regex) {
$match = preg_match("/$email_regex/", strtolower($email));
// if the first does not fail, quit as ok
if ($pos == 0 && $match) {
break;
}
// else do error storage
// not that for 1, 6, 7 the regex is matching
if (
(!$match && in_array($pos, [0, 2, 3, 4, 5])) ||
($match && in_array($pos, [1, 6, 7]))
) {
if ($error_code_only === true) {
$errors[] = $pos;
} else {
$errors[] = self::getEmailRegexErrorMessage($pos);
}
}
}
return $errors;
}
}
// __END__

117
src/Check/Encoding.php Normal file
View File

@@ -0,0 +1,117 @@
<?php
/*
* check if string is valid in target encoding
*/
declare(strict_types=1);
namespace CoreLibs\Check;
class Encoding
{
/** @var int<min, -1>|int<1, max>|string */
private static $mb_error_char = '';
/**
* set error char
*
* @param string|int|null $string The character to use to represent
* error chars
* "long" for long, "none" for none
* or a valid code point in int
* like 0x2234 (8756, ∴)
* default character is ? (63)
* if null is set then "none"
* @return void
*/
public static function setErrorChar($string): void
{
if (empty($string)) {
$string = 'none';
}
// if not special string or char but code point
if (in_array($string, ['none', 'long', 'entity'])) {
self::$mb_error_char = $string;
} else {
// always convert to char for internal use
self::$mb_error_char = \IntlChar::chr($string);
// if string convert to code point
if (is_string($string)) {
$string = \IntlChar::ord($string);
}
}
mb_substitute_character($string);
}
/**
* get the current set error character
*
* @param bool $return_substitute_func if set to true return the set
* character from the php function
* directly
* @return string|int Set error character
*/
public static function getErrorChar(bool $return_substitute_func = false)
{
// return mb_substitute_character();
if ($return_substitute_func === true) {
return mb_substitute_character();
} else {
return self::$mb_error_char;
}
}
/**
* test if a string can be safely convert between encodings.
* mostly utf8 to shift jis
* the default compare has a possibility of failure, especially with windows
* it is recommended to the following in the script which uses this method:
* mb_substitute_character(0x2234);
* $class->mb_error_char = '∴';
* if check to Shift JIS
* if check to ISO-2022-JP
* if check to ISO-2022-JP-MS
* set three dots (∴) as wrong character for correct convert error detect
* (this char is used, because it is one of the least used ones)
*
* @param string $string string to test
* @param string $from_encoding encoding of string to test
* @param string $to_encoding target encoding
* @return bool|array<string> false if no error or
* array with failed characters
*/
public static function checkConvertEncoding(
string $string,
string $from_encoding,
string $to_encoding
) {
// convert to target encoding and convert back
$temp = mb_convert_encoding($string, $to_encoding, $from_encoding);
$compare = mb_convert_encoding($temp, $from_encoding, $to_encoding);
// if string does not match anymore we have a convert problem
if ($string != $compare) {
$failed = [];
// go through each character and find the ones that do not match
for ($i = 0, $iMax = mb_strlen($string, $from_encoding); $i < $iMax; $i++) {
$char = mb_substr($string, $i, 1, $from_encoding);
$r_char = mb_substr($compare, $i, 1, $from_encoding);
// the ord 194 is a hack to fix the IE7/IE8
// bug with line break and illegal character
if (
(($char != $r_char && (!self::$mb_error_char ||
in_array(self::$mb_error_char, ['none', 'long', 'entity']))) ||
($char != $r_char && $r_char == self::$mb_error_char && self::$mb_error_char)) &&
ord($char) != 194
) {
$failed[] = $char;
}
}
return $failed;
} else {
return false;
}
}
}
// __END__

56
src/Check/File.php Normal file
View File

@@ -0,0 +1,56 @@
<?php
/*
* various file/file name functions
*/
declare(strict_types=1);
namespace CoreLibs\Check;
class File
{
/**
* quick return the extension of the given file name
*
* @param string $filename file name
* @return string extension of the file name
*/
public static function getFilenameEnding(string $filename): string
{
$page_temp = pathinfo($filename);
return $page_temp['extension'] ?? '';
}
/**
* get lines in a file
*
* @param string $file file for line count read
* @return int number of lines or -1 for non readable file
*/
public static function getLinesFromFile(string $file): int
{
if (
is_file($file) &&
file_exists($file) &&
is_readable($file)
) {
$f = fopen($file, 'rb');
if (!is_resource($f)) {
return 0;
}
$lines = 0;
while (!feof($f)) {
$lines += substr_count(fread($f, 8192) ?: '', "\n");
}
fclose($f);
} else {
// if file does not exist or is not readable, return -1
$lines = -1;
}
// return lines in file
return $lines;
}
}
// __END__

41
src/Check/Jason.php Normal file
View File

@@ -0,0 +1,41 @@
<?php
/*
* DEPRECATED: Use correct Convert\Json:: instead
*/
declare(strict_types=1);
namespace CoreLibs\Check;
use CoreLibs\Convert\Json;
class Jason
{
/**
* @param string|null $json a json string, or null data
* @param bool $override if set to true, then on json error
* set original value as array
* @return array<mixed> returns an array from the json values
* @deprecated Use Json::jsonConvertToArray()
*/
public static function jsonConvertToArray(?string $json, bool $override = false): array
{
return Json::jsonConvertToArray($json, $override);
}
/**
* @param bool|boolean $return_string [default=false] if set to true
* it will return the message string and not
* the error number
* @return int|string Either error number (0 for no error)
* or error string ('' for no error)
* @deprecated Use Json::jsonGetLastError()
*/
public static function jsonGetLastError(bool $return_string = false)
{
return Json::jsonGetLastError($return_string);
}
}
// __END__

59
src/Check/Password.php Normal file
View File

@@ -0,0 +1,59 @@
<?php
/*
* core password set, check and rehash check wrapper functions
*/
declare(strict_types=1);
namespace CoreLibs\Check;
class Password
{
/**
* creates the password hash
*
* @param string $password password
* @return string hashed password
*/
public static function passwordSet(string $password): string
{
// always use the PHP default for the password
// password options ca be set in the password init,
// but should be kept as default
return password_hash($password, PASSWORD_DEFAULT);
}
/**
* checks if the entered password matches the hash
*
* @param string $password password
* @param string $hash password hash
* @return bool true or false
*/
public static function passwordVerify(string $password, string $hash): bool
{
if (password_verify($password, $hash)) {
return true;
} else {
return false;
}
}
/**
* checks if the password needs to be rehashed
*
* @param string $hash password hash
* @return bool true or false
*/
public static function passwordRehashCheck(string $hash): bool
{
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
return true;
} else {
return false;
}
}
}
// __END__

75
src/Check/PhpVersion.php Normal file
View File

@@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
namespace CoreLibs\Check;
class PhpVersion
{
/**
* checks if running PHP version matches given PHP version (min or max)
* if either is empty or null it will be ignored
* if no min version (null or empty)
*
* @param string|null $min_version minimum version as string (x, x.y, x.y.x)
* @param string|null $max_version optional maximum version as string (x, x.y, x.y.x)
* @return bool true if ok, false if not matching version
*/
public static function checkPHPVersion(?string $min_version, ?string $max_version = null): bool
{
// exit with false if the min/max strings are wrong
if (
!empty($min_version) &&
!preg_match("/^\d{1,2}(\.\d{1,2})?(\.\d{1,2})?$/", $min_version)
) {
return false;
}
// max is only chcked if it is set
if (
!empty($max_version) &&
!preg_match("/^\d{1,2}(\.\d{1,2})?(\.\d{1,2})?$/", $max_version)
) {
return false;
}
// split up the version strings to calc the compare number
if (!empty($min_version)) {
$version = explode('.', $min_version);
$min_version = (int)$version[0] * 10000 + (int)($version[1] ?? 0) * 100 + (int)($version[2] ?? 0);
}
if (!empty($max_version)) {
$version = explode('.', $max_version);
$max_version = (int)$version[0] * 10000 + (int)($version[1] ?? 0) * 100 + (int)($version[2] ?? 0);
// drop out if min is bigger max, equal size is okay, that would be only THIS
if (!empty($min_version) && $min_version > $max_version) {
return false;
}
}
// set the php version id
if (!defined('PHP_VERSION_ID')) {
$version = explode('.', phpversion() ?: '');
// creates something like 50107
define('PHP_VERSION_ID', (int)$version[0] * 10000 + (int)$version[1] * 100 + (int)$version[2]);
}
// check if matching for version
if (
!empty($min_version) && empty($max_version) &&
PHP_VERSION_ID >= $min_version
) {
return true;
} elseif (
empty($min_version) && !empty($max_version) &&
PHP_VERSION_ID <= $max_version
) {
return true;
} elseif (
!empty($min_version) && !empty($max_version) &&
PHP_VERSION_ID >= $min_version && PHP_VERSION_ID <= $max_version
) {
return true;
}
// if no previous return, fail
return false;
}
}
// __END__