Compare commits

...

20 Commits

Author SHA1 Message Date
Clemens Schwaighofer
de0ed058ca ErrorMessage: new flag for logging 'error' level to log 2023-09-11 13:35:35 +09:00
Clemens Schwaighofer
f90bd193d9 Change setError to setMessage to make it clear what is the corret name 2023-09-08 18:54:44 +09:00
Clemens Schwaighofer
0e31180868 Rename setErrorMsgLevel to setError for backend calls 2023-09-08 18:47:44 +09:00
Clemens Schwaighofer
68c9164eaa New ErrorMessage class for frontend return error messages 2023-09-08 18:30:05 +09:00
Clemens Schwaighofer
c2389db1c9 Composer updates 2023-09-08 18:30:02 +09:00
Clemens Schwaighofer
f9558cd3aa Fix for the SetVarType / SetVarTypeNull
string: if it is stringable in anyway, set string (it converts)
this is not check IF it is a string value as it was before
int/float: same, if it is numerc it will be convert to int or float
All other stay the same

Note "set ..." imply to set, and not to convert to 0 if it is int
string that can be covnerted to int
2023-09-05 14:26:57 +09:00
Clemens Schwaighofer
ae3011fe22 php unit test fix for DB\IO 2023-09-01 18:29:00 +09:00
Clemens Schwaighofer
9b9dfeac69 phan error supress 2023-09-01 18:21:25 +09:00
Clemens Schwaighofer
33cb05a002 Update to Exceptions: add codes, update phpunit tests
DB Class throws Exception if on init it fails to connect to the DB,
will not throw Exception if failed connection during execution but
will do the normal retry and soft failure run
DB\ArrayIO will throw Exception on missing table array and table name

All Exceptions have a code set
2023-09-01 08:37:15 +09:00
Clemens Schwaighofer
ec110499a8 phan fixs 2023-08-31 19:06:16 +09:00
Clemens Schwaighofer
09839f3451 phpstan fixes 2023-08-31 19:04:45 +09:00
Clemens Schwaighofer
067e0aed5d L10n change Exception to RuntimeException 2023-08-31 18:08:34 +09:00
Clemens Schwaighofer
545de5c4a1 Fixed more Exceptions to be not Errors but Exceptions
DateTime, Session, FileWrite, Image, SymmetricEncryption

phpunit tests updated, run checks added
2023-08-31 18:06:02 +09:00
Clemens Schwaighofer
2fe37bf92a Exceptions change in Check\Colors, add in Cmbined\ArrayHandler
Chech\Colors now throws correct exceptions for wrong values
Combined\ArrayHandler will throw errors and not return false
2023-08-31 12:07:28 +09:00
Clemens Schwaighofer
cd81d15d9a Convert\Color methods will throw Exception instead of false on error
All Color methods will throw Exceptions:
LengthException,
InvalidArgumentException,
UnexpectedValueException

instead of returning bool: false

All methods will return valid color data as expected only
2023-08-31 10:45:33 +09:00
Clemens Schwaighofer
8a33ee5c15 Slight update for ACL\Login class exit codes
exit will add message as first parameter (string) next to code (int)
Log this to info or critical.
3000 -> 100: info
rest >=1000: critical
previous 4000 = 3000 (options not set)

update unit tests for this

Possible change idea: critical abort throw error?
2023-08-31 10:41:44 +09:00
Clemens Schwaighofer
46e1419ef5 phan checks and updates 2023-08-30 19:26:13 +09:00
Clemens Schwaighofer
c441063437 Composer updates 2023-08-30 19:25:48 +09:00
Clemens Schwaighofer
5290d5f351 Update db class tests in admin run 2023-08-28 09:28:17 +09:00
Clemens Schwaighofer
2635ccb82b edit.css: rename animation, Bug fix in DB\IO cursor_ext access and others
Make sure cursor_ext is set before we access it, else return null for
not set yet.
false for errors, else data value

Other class var access checks to be sure to never fail
2023-08-28 07:40:41 +09:00
68 changed files with 2012 additions and 684 deletions

View File

@@ -132,6 +132,8 @@ return [
// start ignore annotations
'PhanUnextractableAnnotationElementName',
'PhanUnextractableAnnotationSuffix',
// enum problems in comments
'PhanCommentObjectInClassConstantType'
],
// Override to hardcode existence and types of (non-builtin) globals in the global scope.

View File

@@ -167,8 +167,10 @@ final class CoreLibsACLLoginTest extends TestCase
// change_password, pw_username, pw_old_password, pw_new_password,
// pw_new_password_confirm
// 3[session]: override session set
// 4[error] : expected error code, 0 for all ok, 3000 for login page view
// note that 1000 (no db), 2000 (no session) must be tested too
// 4[error] : expected error code, 0 for all ok, 100 for login page view
// note that 1000 (no db), 2000 (no session), 3000 (options set error)
// must be tested too
// <1000 info, >=1000 critical error
// 5[return] : expected return array, eg login_error code,
// or other info data to match
$tests = [
@@ -180,7 +182,7 @@ final class CoreLibsACLLoginTest extends TestCase
[],
[],
[],
3000,
100,
[
'login_error' => 0,
'error_string' => 'Success: <b>No error</b>',
@@ -198,7 +200,7 @@ final class CoreLibsACLLoginTest extends TestCase
[],
[],
[],
3000,
100,
[
'login_error' => 0,
'error_string' => 'Success: <b>No error</b>',
@@ -221,7 +223,7 @@ final class CoreLibsACLLoginTest extends TestCase
[],
[],
[],
3000,
100,
[
'login_error' => 0,
'error_string' => 'Success: <b>No error</b>',
@@ -308,7 +310,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => '',
],
[],
3000,
100,
[
'login_error' => 102,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -329,7 +331,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'abc',
],
[],
3000,
100,
[
'login_error' => 102,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -350,7 +352,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => '',
],
[],
3000,
100,
[
'login_error' => 102,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -371,7 +373,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'abc',
],
[],
3000,
100,
[
'login_error' => 1010,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -395,7 +397,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'abc',
],
[],
3000,
100,
[
// default password is plain text
'login_error' => 1012,
@@ -421,7 +423,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin',
],
[],
3000,
100,
[
'login_error' => 106,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -446,7 +448,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin',
],
[],
3000,
100,
[
'login_error' => 104,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -471,7 +473,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin',
],
[],
3000,
100,
[
'login_error' => 105,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -520,7 +522,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin',
],
[],
3000,
100,
[
'login_error' => 107,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -574,7 +576,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin',
],
[],
3000,
100,
[
'login_error' => 107,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -600,7 +602,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin',
],
[],
3000,
100,
[
'login_error' => 107,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -625,7 +627,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin',
],
[],
3000,
100,
[
'login_error' => 108,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -761,7 +763,7 @@ final class CoreLibsACLLoginTest extends TestCase
],
[],
[],
3000,
100,
[
'login_error' => 1010,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -853,7 +855,7 @@ final class CoreLibsACLLoginTest extends TestCase
],
[],
[],
3000,
100,
[
'login_error' => 1101,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -909,7 +911,7 @@ final class CoreLibsACLLoginTest extends TestCase
],
[],
[],
3000,
100,
[
'login_error' => 1102,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -965,7 +967,7 @@ final class CoreLibsACLLoginTest extends TestCase
],
[],
[],
3000,
100,
[
'login_error' => 1102,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -992,7 +994,7 @@ final class CoreLibsACLLoginTest extends TestCase
],
[],
[],
3000,
100,
[
'login_error' => 1102,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -1133,7 +1135,7 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->expects($this->any())
->method('loginTerminate')
->will(
$this->returnCallback(function ($code) {
$this->returnCallback(function ($message, $code) {
throw new \Exception('', $code);
})
);
@@ -1227,7 +1229,11 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->loginSetMaxLoginErrorCount($mock_settings['max_login_error_count']);
// temporary wrong password
$_POST['login_password'] = 'wrong';
for ($run = 1, $max_run = $login_mock->loginGetMaxLoginErrorCount(); $run <= $max_run; $run++) {
for (
$run = 1, $max_run = $login_mock->loginGetMaxLoginErrorCount();
$run <= $max_run;
$run++
) {
try {
$login_mock->loginMainCall();
} catch (\Exception $e) {
@@ -1475,10 +1481,10 @@ final class CoreLibsACLLoginTest extends TestCase
// print "AJAX: " . $login_mock->loginGetAjaxFlag() . "\n";
// print "AJAX GLOBAL: " . ($GLOBALS['AJAX_PAGE'] ?? '{f}') . "\n";
// print "Login error expext: " . ($expected['login_error'] ?? '{0}') . "\n";
// if this is 3000, then we do further error checks
// if this is 100, then we do further error checks
if (
$e->getCode() == 3000 ||
!empty($_POST['login_exit']) && $_POST['login_exit'] == 3000
$e->getCode() == 100 ||
!empty($_POST['login_exit']) && $_POST['login_exit'] == 100
) {
$this->assertEquals(
$expected['login_error'],
@@ -1816,7 +1822,7 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->expects($this->any())
->method('loginTerminate')
->will(
$this->returnCallback(function ($code) {
$this->returnCallback(function ($message, $code) {
throw new \Exception('', $code);
})
);
@@ -1930,7 +1936,7 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->expects($this->any())
->method('loginTerminate')
->will(
$this->returnCallback(function ($code) {
$this->returnCallback(function ($message, $code) {
throw new \Exception('', $code);
})
);
@@ -2018,7 +2024,7 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->expects($this->any())
->method('loginTerminate')
->will(
$this->returnCallback(function ($code) {
$this->returnCallback(function ($message, $code) {
throw new \Exception('', $code);
})
);
@@ -2114,7 +2120,7 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->expects($this->any())
->method('loginTerminate')
->will(
$this->returnCallback(function ($code) {
$this->returnCallback(function ($message, $code) {
throw new \Exception('', $code);
})
);

View File

@@ -13,6 +13,11 @@ use PHPUnit\Framework\TestCase;
*/
final class CoreLibsCheckColorsTest extends TestCase
{
/**
* Undocumented function
*
* @return array<mixed>
*/
public function validateColorProvider(): array
{
/*
@@ -321,7 +326,7 @@ final class CoreLibsCheckColorsTest extends TestCase
*/
public function testValidateColorException(int $flag): void
{
$this->expectException(\Exception::class);
$this->expectException(\UnexpectedValueException::class);
\CoreLibs\Check\Colors::validateColor('#ffffff', $flag);
}
}

View File

@@ -518,17 +518,20 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
return [
// error <2 arguments
'too view arguments' => [
'ArgumentCountError',
'arrayMergeRecursive needs two or more array arguments',
[1]
],
// error <2 arrays
'only one array' => [
'ArgumentCountError',
'arrayMergeRecursive needs two or more array arguments',
[1],
true,
],
// error element is not array
'non array between array' => [
'TypeError',
'arrayMergeRecursive encountered a non array argument',
[1],
'string',
@@ -947,18 +950,20 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
*/
public function testArrayMergeRecursiveWarningA(): void
{
set_error_handler(
static function (int $errno, string $errstr): never {
throw new Exception($errstr, $errno);
},
E_USER_WARNING
);
// set_error_handler(
// static function (int $errno, string $errstr): never {
// throw new Exception($errstr, $errno);
// },
// E_USER_WARNING
// );
$arrays = func_get_args();
// first is expected warning
$exception = array_shift($arrays);
$warning = array_shift($arrays);
// phpunit 10.0 compatible
$this->expectException($exception);
$this->expectExceptionMessage($warning);
\CoreLibs\Combined\ArrayHandler::arrayMergeRecursive(...$arrays);

View File

@@ -309,45 +309,73 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
'2020-12-12',
'2021-12-12',
-1,
null,
null,
],
'dates equal' => [
'2020-12-12',
'2020-12-12',
0,
null,
null,
],
'second date smaller' => [
'2021-12-12',
'2020-12-12',
1
1,
null,
null,
],
'dates equal with different time' => [
'2020-12-12 12:12:12',
'2020-12-12 13:13:13',
0,
null,
null,
],
'invalid dates --' => [
'--',
'--',
false
false,
'UnexpectedValueException',
1,
],
'empty dates' => [
'',
'',
false
false,
'UnexpectedValueException',
1
],
'invalid dates' => [
'not a date',
'not a date either',
false,
'UnexpectedValueException',
2
],
'invalid end date' => [
'1990-01-01',
'not a date either',
false,
'UnexpectedValueException',
3
],
'out of bound dates' => [
'1900-1-1',
'9999-12-31',
-1
-1,
null,
null,
]
];
}
/**
* Undocumented function
*
* @return array<mixed>
*/
public function dateTimeCompareProvider(): array
{
return [
@@ -355,51 +383,85 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
'2020-12-12',
'2021-12-12',
-1,
null,
null,
],
'dates equal no timestamp' => [
'2020-12-12',
'2020-12-12',
0,
null,
null,
],
'second date smaller no timestamp' => [
'2021-12-12',
'2020-12-12',
1
1,
null,
null,
],
'date equal first time smaller' => [
'2020-12-12 12:12:12',
'2020-12-12 13:13:13',
-1,
null,
null,
],
'date equal time equal' => [
'2020-12-12 12:12:12',
'2020-12-12 12:12:12',
0,
null,
null,
],
'date equal second time smaller' => [
'2020-12-12 13:13:13',
'2020-12-12 12:12:12',
1,
null,
null,
],
'valid date invalid time' => [
'2020-12-12 13:99:13',
'2020-12-12 12:12:99',
false,
'UnexpectedValueException',
2
],
'valid date invalid end time' => [
'2020-12-12 13:12:13',
'2020-12-12 12:12:99',
false,
'UnexpectedValueException',
3
],
'invalid datetimes --' => [
'--',
'--',
false,
'UnexpectedValueException',
1
],
'empty datetimess' => [
'',
'',
false,
'UnexpectedValueException',
1
],
'invalid datetimes' => [
'invalid date times' => [
'not a date',
'not a date either',
false,
'UnexpectedValueException',
2
],
'invalid end date time' => [
'1990-01-01 12:12:12',
'not a date either',
false,
'UnexpectedValueException',
3
],
];
}
@@ -614,10 +676,21 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
* @param string $input_a
* @param string $input_b
* @param int|bool $expected
* @param string|null $exception
* @param int|null $exception_code
* @return void
*/
public function testCompareDate(string $input_a, string $input_b, $expected): void
{
public function testCompareDate(
string $input_a,
string $input_b,
int|bool $expected,
?string $exception,
?int $exception_code
): void {
if ($expected === false) {
$this->expectException($exception);
$this->expectExceptionCode($exception_code);
}
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::compareDate($input_a, $input_b)
@@ -634,10 +707,21 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
* @param string $input_a
* @param string $input_b
* @param int|bool $expected
* @param string|null $exception
* @param int|null $exception_code
* @return void
*/
public function testCompareDateTime(string $input_a, string $input_b, $expected): void
{
public function testCompareDateTime(
string $input_a,
string $input_b,
int|bool $expected,
?string $exception,
?int $exception_code
): void {
if ($expected === false) {
$this->expectException($exception);
$this->expectExceptionCode($exception_code);
}
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::compareDateTime($input_a, $input_b)

View File

@@ -59,6 +59,27 @@ final class CoreLibsConvertColorsTest extends TestCase
3 => false,
4 => false
],
'invalid color red ' => [
0 => -12,
1 => 12,
2 => 12,
3 => false,
4 => false
],
'invalid color green ' => [
0 => 12,
1 => -12,
2 => 12,
3 => false,
4 => false
],
'invalid color blue ' => [
0 => 12,
1 => 12,
2 => -12,
3 => false,
4 => false
],
];
}
@@ -150,10 +171,40 @@ final class CoreLibsConvertColorsTest extends TestCase
'valid' => true,
],
// invalid values
'invalid color' => [
'rgb' => [-12, 300, 12],
'hsb' => [-12, 300, 12],
'hsl' => [-12, 300, 12],
'invalid color r/h/h low' => [
'rgb' => [-1, 12, 12],
'hsb' => [-1, 50, 50],
'hsl' => [-1, 50, 50],
'valid' => false,
],
'invalid color r/h/h high' => [
'rgb' => [256, 12, 12],
'hsb' => [361, 50, 50],
'hsl' => [361, 50, 50],
'valid' => false,
],
'invalid color g/s/s low' => [
'rgb' => [12, -1, 12],
'hsb' => [1, -1, 50],
'hsl' => [1, -1, 50],
'valid' => false,
],
'invalid color g/s/s high' => [
'rgb' => [12, 256, 12],
'hsb' => [1, 101, 50],
'hsl' => [1, 101, 50],
'valid' => false,
],
'invalid color b/b/l low' => [
'rgb' => [12, 12, -1],
'hsb' => [1, 50, -1],
'hsl' => [1, 50, -1],
'valid' => false,
],
'invalid color b/b/l high' => [
'rgb' => [12, 12, 256],
'hsb' => [1, 50, 101],
'hsl' => [1, 50, 101],
'valid' => false,
],
];
@@ -246,11 +297,22 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param int $input_r
* @param int $input_g
* @param int $input_b
* @param string|bool $expected_hash
* @param string|bool $expected
* @return void
*/
public function testRgb2hex(int $input_r, int $input_g, int $input_b, $expected_hash, $expected)
{
public function testRgb2hex(
int $input_r,
int $input_g,
int $input_b,
string|bool $expected_hash,
string|bool $expected
) {
// if expected hash is or expected is false, we need to check for
// LengthException
if ($expected_hash === false || $expected === false) {
$this->expectException(\LengthException::class);
}
// with #
$this->assertEquals(
$expected_hash,
@@ -292,11 +354,19 @@ final class CoreLibsConvertColorsTest extends TestCase
*/
public function testHex2rgb(
string $input,
$expected,
$expected_str,
array|bool $expected,
string|bool $expected_str,
string $separator,
$expected_str_sep
string|bool $expected_str_sep
): void {
if ($expected === false || $expected_str === false || $expected_str_sep === false) {
$hex_string = preg_replace("/[^0-9A-Fa-f]/", '', $input);
if (!is_string($hex_string)) {
$this->expectException(\InvalidArgumentException::class);
} else {
$this->expectException(\UnexpectedValueException::class);
}
}
$this->assertEquals(
$expected,
\CoreLibs\Convert\Colors::hex2rgb($input)
@@ -324,8 +394,11 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected
* @return void
*/
public function testRgb2hsb(int $input_r, int $input_g, int $input_b, $expected): void
public function testRgb2hsb(int $input_r, int $input_g, int $input_b, array|bool $expected): void
{
if ($expected === false) {
$this->expectException(\LengthException::class);
}
$this->assertEquals(
$expected,
\CoreLibs\Convert\Colors::rgb2hsb($input_r, $input_g, $input_b)
@@ -345,8 +418,12 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected
* @return void
*/
public function testHsb2rgb(float $input_h, float $input_s, float $input_b, $expected): void
public function testHsb2rgb(float $input_h, float $input_s, float $input_b, array|bool $expected): void
{
if ($expected === false) {
$this->expectException(\LengthException::class);
$expected = [];
}
$this->assertEquals(
$expected,
\CoreLibs\Convert\Colors::hsb2rgb($input_h, $input_s, $input_b)
@@ -366,8 +443,11 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected
* @return void
*/
public function testRgb2hsl(int $input_r, int $input_g, int $input_b, $expected): void
public function testRgb2hsl(int $input_r, int $input_g, int $input_b, array|bool $expected): void
{
if ($expected === false) {
$this->expectException(\LengthException::class);
}
$this->assertEquals(
$expected,
\CoreLibs\Convert\Colors::rgb2hsl($input_r, $input_g, $input_b)
@@ -387,8 +467,11 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected
* @return void
*/
public function testHsl2rgb($input_h, float $input_s, float $input_l, $expected): void
public function testHsl2rgb(int|float $input_h, float $input_s, float $input_l, array|bool $expected): void
{
if ($expected === false) {
$this->expectException(\LengthException::class);
}
$this->assertEquals(
$expected,
\CoreLibs\Convert\Colors::hsl2rgb($input_h, $input_s, $input_l)
@@ -406,11 +489,11 @@ final class CoreLibsConvertColorsTest extends TestCase
*/
public function testHslHsb360hue(): void
{
$this->assertNotFalse(
$this->assertIsArray(
\CoreLibs\Convert\Colors::hsl2rgb(360.0, 90.5, 41.2),
'HSL to RGB with 360 hue'
);
$this->assertNotFalse(
$this->assertIsArray(
\CoreLibs\Convert\Colors::hsb2rgb(360, 95, 78.0),
'HSB to RGB with 360 hue'
);

View File

@@ -43,12 +43,17 @@ final class CoreLibsConvertSetVarTypeNullTest extends TestCase
'int, no override' => [
1,
null,
null
'1'
],
'int, override set' => [
1,
'not int',
'not int'
'1'
],
'array, override set' => [
[1, 2],
null,
null
]
];
}
@@ -201,7 +206,7 @@ final class CoreLibsConvertSetVarTypeNullTest extends TestCase
'float' => [
1.5,
null,
null
1
]
];
}
@@ -349,7 +354,7 @@ final class CoreLibsConvertSetVarTypeNullTest extends TestCase
'int' => [
1,
null,
null
1.0
]
];
}

View File

@@ -43,11 +43,16 @@ final class CoreLibsConvertSetVarTypeTest extends TestCase
'int, no override' => [
1,
null,
''
'1'
],
'int, override set' => [
1,
'not int',
'1'
],
'array, override set' => [
[1, 2],
'not int',
'not int'
]
];
@@ -189,7 +194,7 @@ final class CoreLibsConvertSetVarTypeTest extends TestCase
'float' => [
1.5,
null,
0
1
]
];
}
@@ -330,7 +335,7 @@ final class CoreLibsConvertSetVarTypeTest extends TestCase
'int' => [
1,
null,
0.0
1.0
]
];
}
@@ -341,7 +346,7 @@ final class CoreLibsConvertSetVarTypeTest extends TestCase
* @dataProvider varSetTypeFloatProvider
* @testdox setFloat $input with override $default will be $expected [$_dataName]
*
* @param mixed $input
* @param mixed $input
* @param float|null $default
* @param float $expected
* @return void

View File

@@ -30,8 +30,10 @@ final class CoreLibsCreateSessionTest extends TestCase
// setSessionName: true/false,
// checkActiveSession: true/false, [1st call, 2nd call]
// getSessionId: string or false
// 3: exepcted name (session)
// 4: expected error string
// 3: exepcted name (session)]
// 4: Exception thrown on error
// 5: exception code, null for none
// 6: expected error string
return [
'session parameter' => [
'sessionNameParameter',
@@ -44,7 +46,9 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567'
],
'sessionNameParameter',
''
null,
null,
'',
],
'session globals' => [
'sessionNameGlobals',
@@ -57,7 +61,9 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567'
],
'sessionNameGlobals',
''
null,
null,
'',
],
'session name default' => [
'',
@@ -70,7 +76,9 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567'
],
'',
''
null,
null,
'',
],
// error checks
// 1: we are in cli
@@ -85,6 +93,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567'
],
'',
'RuntimeException',
1,
'[SESSION] No sessions in php cli'
],
// 2: session disabled
@@ -99,6 +109,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567'
],
'',
'RuntimeException',
2,
'[SESSION] Sessions are disabled'
],
// 3: invalid session name: string
@@ -113,6 +125,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567'
],
'',
'UnexpectedValueException',
3,
'[SESSION] Invalid session name: 1invalid$session#;'
],
// 3: invalid session name: only numbers
@@ -127,6 +141,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567'
],
'',
'UnexpectedValueException',
3,
'[SESSION] Invalid session name: 123'
],
// 3: invalid session name: invalid name short
@@ -143,6 +159,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567'
],
'',
'RuntimeException',
4,
'[SESSION] Failed to activate session'
],
// 5: get session id return false
@@ -157,6 +175,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => false
],
'',
'UnexpectedValueException',
5,
'[SESSION] getSessionId did not return a session id'
],
];
@@ -173,6 +193,7 @@ final class CoreLibsCreateSessionTest extends TestCase
* @param string $type
* @param array<mixed> $mock_data
* @param string $expected
* @param string|null $exception
* @param string $expected_error
* @return void
*/
@@ -181,6 +202,8 @@ final class CoreLibsCreateSessionTest extends TestCase
string $type,
array $mock_data,
string $expected,
?string $exception,
?int $exception_code,
string $expected_error
): void {
// override expected
@@ -224,6 +247,11 @@ final class CoreLibsCreateSessionTest extends TestCase
// regex for session id
$ression_id_regex = "/^\w+$/";
if ($exception !== null) {
$this->expectException($exception);
$this->expectExceptionCode($exception_code);
}
unset($GLOBALS['SET_SESSION_NAME']);
$session_id = '';
switch ($type) {
@@ -253,13 +281,6 @@ final class CoreLibsCreateSessionTest extends TestCase
$expected,
$session_mock->getSessionName()
);
} else {
// false checks
$this->assertEquals(
$expected_error,
$session_mock->getErrorStr(),
'error assert'
);
}
}

View File

@@ -445,12 +445,14 @@ final class CoreLibsDBIOTest extends TestCase
{
// 0: connection array
// 1: status after connection
// 2: exception name
// 2: info string
// 3: ???
return [
'invalid connection' => [
self::$db_config['invalid'],
false,
'RuntimeException',
"-DB-info-> Connected to db '' with schema 'public' as user "
. "'' at host '' on port '5432' with ssl mode 'allow' **** "
. "-DB-info-> DB IO Class debug output: Yes **** ",
@@ -459,6 +461,7 @@ final class CoreLibsDBIOTest extends TestCase
'valid connection' => [
self::$db_config['valid'],
true,
'',
"-DB-info-> Connected to db 'corelibs_db_io_test' with "
. "schema 'public' as user 'corelibs_db_io_test' at host "
. "'localhost' on port '5432' with ssl mode 'allow' **** "
@@ -475,13 +478,21 @@ final class CoreLibsDBIOTest extends TestCase
* @dataProvider connectionProvider
* @testdox Connection will be $expected [$_dataName]
*
* @param array $connection
* @param bool $expected_status
* @param string $exception
* @param string $expected_string
* @return void
*/
public function testConnection(
array $connection,
bool $expected_status,
string $exception,
string $expected_string
): void {
if ($expected_status === false) {
$this->expectException($exception);
}
$db = new \CoreLibs\DB\IO(
$connection,
self::$log
@@ -722,6 +733,10 @@ final class CoreLibsDBIOTest extends TestCase
*/
public function testGetSetting(string $connection, array $settings): void
{
// if settings are all empty -> assume exception
if (empty($settings['db_name']) && empty($settings['db_user'])) {
$this->expectException('RuntimeException');
}
$db = new \CoreLibs\DB\IO(
self::$db_config[$connection],
self::$log

View File

@@ -0,0 +1,343 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Logging\Logger\Level;
/**
* Test class for Logging
* @coversDefaultClass \CoreLibs\Logging\ErrorMessages
* @testdox \CoreLibs\Logging\ErrorMEssages method tests
*/
final class CoreLibsLoggingErrorMessagesTest extends TestCase
{
private const LOG_FOLDER = __DIR__ . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR;
/**
* tear down and remove log data
*
* @return void
*/
public static function tearDownAfterClass(): void
{
array_map('unlink', glob(self::LOG_FOLDER . '*.log'));
}
/**
* for checking level only
*
* @return array
*/
public function providerErrorMessageLevel(): array
{
return [
'ok' => [
'level' => 'ok',
'str' => 'OK',
'expected' => 'ok',
],
'info' => [
'level' => 'info',
'str' => 'INFO',
'expected' => 'info',
],
'warn' => [
'level' => 'warn',
'str' => 'WARN',
'expected' => 'warn'
],
'warning' => [
'level' => 'warning',
'str' => 'WARN',
'expected' => 'warn'
],
'error' => [
'level' => 'error',
'str' => 'ERROR',
'expected' => 'error'
],
'abort' => [
'level' => 'abort',
'str' => 'ABORT',
'expected' => 'abort'
],
'crash' => [
'level' => 'crash',
'str' => 'CRASH',
'expected' => 'crash'
],
'wrong level' => [
'level' => 'wrong',
'str' => 'WRONG',
'expected' => 'unknown'
]
];
}
/**
* Undocumented function
*
* @dataProvider providerErrorMessageLevel
* @testdox error message level: $level will be $expected [$_dataName]
*
* @param string $level
* @param string $str
* @param string $expected
* @return void
*/
public function testErrorMessageLevelOk(string $level, string $str, string $expected): void
{
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testErrorMessages',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Debug,
]);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setMessage(
$level,
$str
);
$this->assertEquals(
[
'level' => $expected,
'str' => $str,
'id' => '',
'target' => '',
'highlight' => [],
],
$em->getLastErrorMsg()
);
}
/**
* Undocumented function
*
* @testdox Test of all methods for n messages [$_dataName]
*
* @return void
*/
public function testErrorMessageOk(): void
{
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testErrorMessages',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Debug
]);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setErrorMsg(
'100',
'info',
'INFO MESSAGE'
);
$this->assertEquals(
[
'id' => '100',
'level' => 'info',
'str' => 'INFO MESSAGE',
'target' => '',
'highlight' => [],
],
$em->getLastErrorMsg()
);
$this->assertEquals(
['100'],
$em->getErrorIds()
);
$this->assertEquals(
[
[
'id' => '100',
'level' => 'info',
'str' => 'INFO MESSAGE',
'target' => '',
'highlight' => [],
]
],
$em->getErrorMsg()
);
$em->setErrorMsg(
'200',
'error',
'ERROR MESSAGE'
);
$this->assertEquals(
[
'id' => '200',
'level' => 'error',
'str' => 'ERROR MESSAGE',
'target' => '',
'highlight' => [],
],
$em->getLastErrorMsg()
);
$this->assertEquals(
['100', '200'],
$em->getErrorIds()
);
$this->assertEquals(
[
[
'id' => '100',
'level' => 'info',
'str' => 'INFO MESSAGE',
'target' => '',
'highlight' => [],
],
[
'id' => '200',
'level' => 'error',
'str' => 'ERROR MESSAGE',
'target' => '',
'highlight' => [],
]
],
$em->getErrorMsg()
);
}
/**
* Undocumented function
*
* @return array
*/
public function providerErrorMessageLog(): array
{
return [
'error, not logged' => [
'id' => '200',
'level' => 'error',
'str' => 'ERROR MESSAGE',
'message' => null,
'log_error' => null,
'expected' => '<ERROR> ERROR MESSAGE',
],
'error, logged' => [
'id' => '200',
'level' => 'error',
'str' => 'ERROR MESSAGE',
'message' => null,
'log_error' => true,
'expected' => '<ERROR> ERROR MESSAGE',
],
'error, logged, message' => [
'id' => '200',
'level' => 'error',
'str' => 'ERROR MESSAGE',
'message' => 'OTHER ERROR MESSAGE',
'log_error' => true,
'expected' => '<ERROR> OTHER ERROR MESSAGE',
],
'crash' => [
'id' => '300',
'level' => 'crash',
'str' => 'CRASH MESSAGE',
'message' => null,
'log_error' => null,
'expected' => '<ALERT> CRASH MESSAGE',
],
'crash, message' => [
'id' => '300',
'level' => 'crash',
'str' => 'CRASH MESSAGE',
'message' => 'OTHER CRASH MESSAGE',
'log_error' => null,
'expected' => '<ALERT> OTHER CRASH MESSAGE',
],
'abort' => [
'id' => '200',
'level' => 'abort',
'str' => 'ABORT MESSAGE',
'message' => null,
'log_error' => null,
'expected' => '<CRITICAL> ABORT MESSAGE',
],
'abort, message' => [
'id' => '200',
'level' => 'abort',
'str' => 'ABORT MESSAGE',
'message' => 'OTHER ABORT MESSAGE',
'log_error' => null,
'expected' => '<CRITICAL> OTHER ABORT MESSAGE',
],
'unknown' => [
'id' => '400',
'level' => 'wrong level',
'str' => 'WRONG LEVEL MESSAGE',
'message' => null,
'log_error' => null,
'expected' => '<EMERGENCY> WRONG LEVEL MESSAGE',
],
'unknown, message' => [
'id' => '400',
'level' => 'wrong level',
'str' => 'WRONG LEVEL MESSAGE',
'message' => 'OTHER WRONG LEVEL MESSAGE',
'log_error' => null,
'expected' => '<EMERGENCY> OTHER WRONG LEVEL MESSAGE',
],
];
}
/**
* Undocumented function
*
* @dataProvider providerErrorMessageLog
* @testdox Test Log writing [$_dataName]
*
* @param string $id
* @param string $level
* @param string $str
* @param string|null $message
* @param bool|null $log_error
* @param string $expected
* @return void
*/
public function testErrorMessageLog(
string $id,
string $level,
string $str,
?string $message,
?bool $log_error,
string $expected
): void {
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testErrorMessages',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Debug,
'log_per_run' => true
]);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setErrorMsg(
$id,
$level,
$str,
message: $message,
log_error: $log_error
);
$file_content = '';
if (is_file($log->getLogFolder() . $log->getLogFile())) {
$file_content = file_get_contents(
$log->getLogFolder() . $log->getLogFile()
) ?: '';
}
// if n
if ($level == 'error' && ($log_error === null || $log_error === false)) {
$this->assertStringNotContainsString(
$expected,
$file_content
);
} else {
$this->assertStringContainsString(
$expected,
$file_content
);
}
}
}
// __END__

118
composer.lock generated
View File

@@ -297,16 +297,16 @@
},
{
"name": "composer/semver",
"version": "3.3.2",
"version": "3.4.0",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9"
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9",
"url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32",
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32",
"shasum": ""
},
"require": {
@@ -356,9 +356,9 @@
"versioning"
],
"support": {
"irc": "irc://irc.freenode.org/composer",
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.3.2"
"source": "https://github.com/composer/semver/tree/3.4.0"
},
"funding": [
{
@@ -374,7 +374,7 @@
"type": "tidelift"
}
],
"time": "2022-04-01T19:23:25+00:00"
"time": "2023-08-31T09:50:34+00:00"
},
{
"name": "composer/xdebug-handler",
@@ -1133,16 +1133,16 @@
},
{
"name": "phpstan/phpdoc-parser",
"version": "1.23.1",
"version": "1.24.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "846ae76eef31c6d7790fac9bc399ecee45160b26"
"reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/846ae76eef31c6d7790fac9bc399ecee45160b26",
"reference": "846ae76eef31c6d7790fac9bc399ecee45160b26",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/3510b0a6274cc42f7219367cb3abfc123ffa09d6",
"reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6",
"shasum": ""
},
"require": {
@@ -1174,22 +1174,22 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.23.1"
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.0"
},
"time": "2023-08-03T16:32:59+00:00"
"time": "2023-09-07T20:46:32+00:00"
},
{
"name": "phpstan/phpstan",
"version": "1.10.29",
"version": "1.10.33",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1"
"reference": "03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1",
"reference": "ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1",
"reference": "03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1",
"shasum": ""
},
"require": {
@@ -1238,7 +1238,7 @@
"type": "tidelift"
}
],
"time": "2023-08-14T13:24:11+00:00"
"time": "2023-09-04T12:20:53+00:00"
},
{
"name": "phpstan/phpstan-deprecation-rules",
@@ -1539,16 +1539,16 @@
},
{
"name": "symfony/console",
"version": "v6.3.2",
"version": "v6.3.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898"
"reference": "eca495f2ee845130855ddf1cf18460c38966c8b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/aa5d64ad3f63f2e48964fc81ee45cb318a723898",
"reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898",
"url": "https://api.github.com/repos/symfony/console/zipball/eca495f2ee845130855ddf1cf18460c38966c8b6",
"reference": "eca495f2ee845130855ddf1cf18460c38966c8b6",
"shasum": ""
},
"require": {
@@ -1609,7 +1609,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v6.3.2"
"source": "https://github.com/symfony/console/tree/v6.3.4"
},
"funding": [
{
@@ -1625,7 +1625,7 @@
"type": "tidelift"
}
],
"time": "2023-07-19T20:17:28+00:00"
"time": "2023-08-16T10:10:12+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -1759,16 +1759,16 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"shasum": ""
},
"require": {
@@ -1783,7 +1783,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -1821,7 +1821,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
},
"funding": [
{
@@ -1837,20 +1837,20 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354"
"reference": "875e90aeea2777b6f135677f618529449334a612"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612",
"reference": "875e90aeea2777b6f135677f618529449334a612",
"shasum": ""
},
"require": {
@@ -1862,7 +1862,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -1902,7 +1902,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0"
},
"funding": [
{
@@ -1918,20 +1918,20 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"shasum": ""
},
"require": {
@@ -1943,7 +1943,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -1986,7 +1986,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0"
},
"funding": [
{
@@ -2002,20 +2002,20 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
"reference": "42292d99c55abe617799667f454222c54c60e229"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
"reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": ""
},
"require": {
@@ -2030,7 +2030,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -2069,7 +2069,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
},
"funding": [
{
@@ -2085,20 +2085,20 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-07-28T09:04:16+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"shasum": ""
},
"require": {
@@ -2107,7 +2107,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -2152,7 +2152,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
},
"funding": [
{
@@ -2168,7 +2168,7 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/service-contracts",

View File

@@ -248,17 +248,17 @@
},
{
"name": "composer/semver",
"version": "3.3.2",
"version_normalized": "3.3.2.0",
"version": "3.4.0",
"version_normalized": "3.4.0.0",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9"
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9",
"url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32",
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32",
"shasum": ""
},
"require": {
@@ -268,7 +268,7 @@
"phpstan/phpstan": "^1.4",
"symfony/phpunit-bridge": "^4.2 || ^5"
},
"time": "2022-04-01T19:23:25+00:00",
"time": "2023-08-31T09:50:34+00:00",
"type": "library",
"extra": {
"branch-alias": {
@@ -310,9 +310,9 @@
"versioning"
],
"support": {
"irc": "irc://irc.freenode.org/composer",
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.3.2"
"source": "https://github.com/composer/semver/tree/3.4.0"
},
"funding": [
{
@@ -1129,17 +1129,17 @@
},
{
"name": "phpstan/phpdoc-parser",
"version": "1.23.1",
"version_normalized": "1.23.1.0",
"version": "1.24.0",
"version_normalized": "1.24.0.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "846ae76eef31c6d7790fac9bc399ecee45160b26"
"reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/846ae76eef31c6d7790fac9bc399ecee45160b26",
"reference": "846ae76eef31c6d7790fac9bc399ecee45160b26",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/3510b0a6274cc42f7219367cb3abfc123ffa09d6",
"reference": "3510b0a6274cc42f7219367cb3abfc123ffa09d6",
"shasum": ""
},
"require": {
@@ -1156,7 +1156,7 @@
"phpunit/phpunit": "^9.5",
"symfony/process": "^5.2"
},
"time": "2023-08-03T16:32:59+00:00",
"time": "2023-09-07T20:46:32+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -1173,23 +1173,23 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.23.1"
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.0"
},
"install-path": "../phpstan/phpdoc-parser"
},
{
"name": "phpstan/phpstan",
"version": "1.10.29",
"version_normalized": "1.10.29.0",
"version": "1.10.33",
"version_normalized": "1.10.33.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1"
"reference": "03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1",
"reference": "ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1",
"reference": "03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1",
"shasum": ""
},
"require": {
@@ -1198,7 +1198,7 @@
"conflict": {
"phpstan/phpstan-shim": "*"
},
"time": "2023-08-14T13:24:11+00:00",
"time": "2023-09-04T12:20:53+00:00",
"bin": [
"phpstan",
"phpstan.phar"
@@ -1609,17 +1609,17 @@
},
{
"name": "symfony/console",
"version": "v6.3.2",
"version_normalized": "6.3.2.0",
"version": "v6.3.4",
"version_normalized": "6.3.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898"
"reference": "eca495f2ee845130855ddf1cf18460c38966c8b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/aa5d64ad3f63f2e48964fc81ee45cb318a723898",
"reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898",
"url": "https://api.github.com/repos/symfony/console/zipball/eca495f2ee845130855ddf1cf18460c38966c8b6",
"reference": "eca495f2ee845130855ddf1cf18460c38966c8b6",
"shasum": ""
},
"require": {
@@ -1648,7 +1648,7 @@
"symfony/process": "^5.4|^6.0",
"symfony/var-dumper": "^5.4|^6.0"
},
"time": "2023-07-19T20:17:28+00:00",
"time": "2023-08-16T10:10:12+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -1682,7 +1682,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v6.3.2"
"source": "https://github.com/symfony/console/tree/v6.3.4"
},
"funding": [
{
@@ -1838,17 +1838,17 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.27.0",
"version_normalized": "1.27.0.0",
"version": "v1.28.0",
"version_normalized": "1.28.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"shasum": ""
},
"require": {
@@ -1860,11 +1860,11 @@
"suggest": {
"ext-ctype": "For best performance"
},
"time": "2022-11-03T14:55:06+00:00",
"time": "2023-01-26T09:26:14+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -1903,7 +1903,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
},
"funding": [
{
@@ -1923,17 +1923,17 @@
},
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.27.0",
"version_normalized": "1.27.0.0",
"version": "v1.28.0",
"version_normalized": "1.28.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354"
"reference": "875e90aeea2777b6f135677f618529449334a612"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612",
"reference": "875e90aeea2777b6f135677f618529449334a612",
"shasum": ""
},
"require": {
@@ -1942,11 +1942,11 @@
"suggest": {
"ext-intl": "For best performance"
},
"time": "2022-11-03T14:55:06+00:00",
"time": "2023-01-26T09:26:14+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -1987,7 +1987,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0"
},
"funding": [
{
@@ -2007,17 +2007,17 @@
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.27.0",
"version_normalized": "1.27.0.0",
"version": "v1.28.0",
"version_normalized": "1.28.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"shasum": ""
},
"require": {
@@ -2026,11 +2026,11 @@
"suggest": {
"ext-intl": "For best performance"
},
"time": "2022-11-03T14:55:06+00:00",
"time": "2023-01-26T09:26:14+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -2074,7 +2074,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0"
},
"funding": [
{
@@ -2094,17 +2094,17 @@
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.27.0",
"version_normalized": "1.27.0.0",
"version": "v1.28.0",
"version_normalized": "1.28.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
"reference": "42292d99c55abe617799667f454222c54c60e229"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
"reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": ""
},
"require": {
@@ -2116,11 +2116,11 @@
"suggest": {
"ext-mbstring": "For best performance"
},
"time": "2022-11-03T14:55:06+00:00",
"time": "2023-07-28T09:04:16+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -2160,7 +2160,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
},
"funding": [
{
@@ -2180,27 +2180,27 @@
},
{
"name": "symfony/polyfill-php80",
"version": "v1.27.0",
"version_normalized": "1.27.0.0",
"version": "v1.28.0",
"version_normalized": "1.28.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"time": "2022-11-03T14:55:06+00:00",
"time": "2023-01-26T09:26:14+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -2246,7 +2246,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
},
"funding": [
{

View File

@@ -38,9 +38,9 @@
'dev_requirement' => true,
),
'composer/semver' => array(
'pretty_version' => '3.3.2',
'version' => '3.3.2.0',
'reference' => '3953f23262f2bff1919fc82183ad9acb13ff62c9',
'pretty_version' => '3.4.0',
'version' => '3.4.0.0',
'reference' => '35e8d0af4486141bc745f23a29cc2091eb624a32',
'type' => 'library',
'install_path' => __DIR__ . '/./semver',
'aliases' => array(),
@@ -182,18 +182,18 @@
'dev_requirement' => true,
),
'phpstan/phpdoc-parser' => array(
'pretty_version' => '1.23.1',
'version' => '1.23.1.0',
'reference' => '846ae76eef31c6d7790fac9bc399ecee45160b26',
'pretty_version' => '1.24.0',
'version' => '1.24.0.0',
'reference' => '3510b0a6274cc42f7219367cb3abfc123ffa09d6',
'type' => 'library',
'install_path' => __DIR__ . '/../phpstan/phpdoc-parser',
'aliases' => array(),
'dev_requirement' => true,
),
'phpstan/phpstan' => array(
'pretty_version' => '1.10.29',
'version' => '1.10.29.0',
'reference' => 'ee5d8f2d3977fb09e55603eee6fb53bdd76ee9c1',
'pretty_version' => '1.10.33',
'version' => '1.10.33.0',
'reference' => '03b1cf9f814ba0863c4e9affea49a4d1ed9a2ed1',
'type' => 'library',
'install_path' => __DIR__ . '/../phpstan/phpstan',
'aliases' => array(),
@@ -266,9 +266,9 @@
'dev_requirement' => true,
),
'symfony/console' => array(
'pretty_version' => 'v6.3.2',
'version' => '6.3.2.0',
'reference' => 'aa5d64ad3f63f2e48964fc81ee45cb318a723898',
'pretty_version' => 'v6.3.4',
'version' => '6.3.4.0',
'reference' => 'eca495f2ee845130855ddf1cf18460c38966c8b6',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/console',
'aliases' => array(),
@@ -293,45 +293,45 @@
'dev_requirement' => true,
),
'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '5bbc823adecdae860bb64756d639ecfec17b050a',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => 'ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(),
'dev_requirement' => true,
),
'symfony/polyfill-intl-grapheme' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '511a08c03c1960e08a883f4cffcacd219b758354',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => '875e90aeea2777b6f135677f618529449334a612',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme',
'aliases' => array(),
'dev_requirement' => true,
),
'symfony/polyfill-intl-normalizer' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '19bd1e4fcd5b91116f14d8533c57831ed00571b6',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => '8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
'aliases' => array(),
'dev_requirement' => true,
),
'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '8ad114f6b39e2c98a8b0e3bd907732c207c2b534',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => '42292d99c55abe617799667f454222c54c60e229',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(),
'dev_requirement' => true,
),
'symfony/polyfill-php80' => array(
'pretty_version' => 'v1.27.0',
'version' => '1.27.0.0',
'reference' => '7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936',
'pretty_version' => 'v1.28.0',
'version' => '1.28.0.0',
'reference' => '6caa57379c4aec19c0a12a38b59b26487dcfe4b5',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
'aliases' => array(),

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
### [3.4.0] 2023-08-31
* Support larger major version numbers (#149)
### [3.3.2] 2022-04-01
* Fixed handling of non-string values (#134)
@@ -175,6 +179,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Namespace: `Composer\Test\Package\LinkConstraint` -> `Composer\Test\Semver\Constraint`
* Changed: code style using php-cs-fixer.
[3.4.0]: https://github.com/composer/semver/compare/3.3.2...3.4.0
[3.3.2]: https://github.com/composer/semver/compare/3.3.1...3.3.2
[3.3.1]: https://github.com/composer/semver/compare/3.3.0...3.3.1
[3.3.0]: https://github.com/composer/semver/compare/3.2.9...3.3.0

View File

@@ -6,8 +6,9 @@ Semver (Semantic Versioning) library that offers utilities, version constraint p
Originally written as part of [composer/composer](https://github.com/composer/composer),
now extracted and made available as a stand-alone library.
[![Continuous Integration](https://github.com/composer/semver/workflows/Continuous%20Integration/badge.svg?branch=main)](https://github.com/composer/semver/actions)
[![Continuous Integration](https://github.com/composer/semver/actions/workflows/continuous-integration.yml/badge.svg?branch=main)](https://github.com/composer/semver/actions/workflows/continuous-integration.yml)
[![PHP Lint](https://github.com/composer/semver/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/composer/semver/actions/workflows/lint.yml)
[![PHPStan](https://github.com/composer/semver/actions/workflows/phpstan.yml/badge.svg?branch=main)](https://github.com/composer/semver/actions/workflows/phpstan.yml)
Installation
------------
@@ -15,7 +16,7 @@ Installation
Install the latest version with:
```bash
$ composer require composer/semver
composer require composer/semver
```

View File

@@ -27,7 +27,7 @@
}
],
"support": {
"irc": "irc://irc.freenode.org/composer",
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues"
},
"require": {

View File

@@ -0,0 +1,11 @@
parameters:
ignoreErrors:
-
message: "#^Parameter \\#1 \\$operator of class Composer\\\\Semver\\\\Constraint\\\\Constraint constructor expects '\\!\\='\\|'\\<'\\|'\\<\\='\\|'\\<\\>'\\|'\\='\\|'\\=\\='\\|'\\>'\\|'\\>\\=', non\\-falsy\\-string given\\.$#"
count: 1
path: src/VersionParser.php
-
message: "#^Strict comparison using \\=\\=\\= between null and non\\-empty\\-string will always evaluate to false\\.$#"
count: 2
path: src/VersionParser.php

View File

@@ -134,15 +134,15 @@ class VersionParser
}
// match classical versioning
if (preg_match('{^v?(\d{1,5})(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
if (preg_match('{^v?(\d{1,5}+)(\.\d++)?(\.\d++)?(\.\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
$version = $matches[1]
. (!empty($matches[2]) ? $matches[2] : '.0')
. (!empty($matches[3]) ? $matches[3] : '.0')
. (!empty($matches[4]) ? $matches[4] : '.0');
$index = 5;
// match date(time) based versioning
} elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) {
$version = preg_replace('{\D}', '.', $matches[1]);
} elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3}){0,2})' . self::$modifierRegex . '$}i', $version, $matches)) {
$version = (string) preg_replace('{\D}', '.', $matches[1]);
$index = 2;
}
@@ -260,16 +260,16 @@ class VersionParser
}
$orGroups = array();
foreach ($orConstraints as $constraints) {
$andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints);
foreach ($orConstraints as $orConstraint) {
$andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $orConstraint);
if (false === $andConstraints) {
throw new \RuntimeException('Failed to preg_split string: '.$constraints);
throw new \RuntimeException('Failed to preg_split string: '.$orConstraint);
}
if (\count($andConstraints) > 1) {
$constraintObjects = array();
foreach ($andConstraints as $constraint) {
foreach ($this->parseConstraint($constraint) as $parsedConstraint) {
$constraintObjects[] = $parsedConstraint;
foreach ($andConstraints as $andConstraint) {
foreach ($this->parseConstraint($andConstraint) as $parsedAndConstraint) {
$constraintObjects[] = $parsedAndConstraint;
}
}
} else {
@@ -285,11 +285,11 @@ class VersionParser
$orGroups[] = $constraint;
}
$constraint = MultiConstraint::create($orGroups, false);
$parsedConstraint = MultiConstraint::create($orGroups, false);
$constraint->setPrettyString($prettyConstraint);
$parsedConstraint->setPrettyString($prettyConstraint);
return $constraint;
return $parsedConstraint;
}
/**

View File

@@ -682,24 +682,34 @@ class PhpDocParser
$tokens->dropSavePoint(); // because of ConstFetchNode
}
$exception = new ParserException(
$tokens->currentTokenValue(),
$tokens->currentTokenType(),
$tokens->currentTokenOffset(),
Lexer::TOKEN_IDENTIFIER,
null,
$tokens->currentTokenLine()
);
$currentTokenValue = $tokens->currentTokenValue();
$currentTokenType = $tokens->currentTokenType();
$currentTokenOffset = $tokens->currentTokenOffset();
$currentTokenLine = $tokens->currentTokenLine();
try {
$constExpr = $this->doctrineConstantExprParser->parse($tokens, true);
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
throw $exception;
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
return $constExpr;
} catch (LogicException $e) {
throw $exception;
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
}
@@ -1117,15 +1127,13 @@ class PhpDocParser
{
if ($tokens->isCurrentTokenType(Lexer::TOKEN_THIS_VARIABLE)) {
$parameter = '$this';
$requirePropertyOrMethod = true;
$tokens->next();
} else {
$parameter = $tokens->currentTokenValue();
$requirePropertyOrMethod = false;
$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);
}
if ($requirePropertyOrMethod || $tokens->isCurrentTokenType(Lexer::TOKEN_ARROW)) {
if ($tokens->isCurrentTokenType(Lexer::TOKEN_ARROW)) {
$tokens->consumeTokenType(Lexer::TOKEN_ARROW);
$propertyOrMethod = $tokens->currentTokenValue();

View File

@@ -196,28 +196,45 @@ class TypeParser
$tokens->dropSavePoint(); // because of ConstFetchNode
}
$exception = new ParserException(
$tokens->currentTokenValue(),
$tokens->currentTokenType(),
$tokens->currentTokenOffset(),
Lexer::TOKEN_IDENTIFIER,
null,
$tokens->currentTokenLine()
);
$currentTokenValue = $tokens->currentTokenValue();
$currentTokenType = $tokens->currentTokenType();
$currentTokenOffset = $tokens->currentTokenOffset();
$currentTokenLine = $tokens->currentTokenLine();
if ($this->constExprParser === null) {
throw $exception;
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
try {
$constExpr = $this->constExprParser->parse($tokens, true);
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
throw $exception;
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
return $this->enrichWithAttributes($tokens, new Ast\Type\ConstTypeNode($constExpr), $startLine, $startIndex);
} catch (LogicException $e) {
throw $exception;
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
}
@@ -600,23 +617,33 @@ class TypeParser
}
}
$exception = new ParserException(
$tokens->currentTokenValue(),
$tokens->currentTokenType(),
$tokens->currentTokenOffset(),
Lexer::TOKEN_IDENTIFIER,
null,
$tokens->currentTokenLine()
);
$currentTokenValue = $tokens->currentTokenValue();
$currentTokenType = $tokens->currentTokenType();
$currentTokenOffset = $tokens->currentTokenOffset();
$currentTokenLine = $tokens->currentTokenLine();
if ($this->constExprParser === null) {
throw $exception;
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
try {
$constExpr = $this->constExprParser->parse($tokens, true);
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
throw $exception;
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
$type = new Ast\Type\ConstTypeNode($constExpr);
@@ -631,7 +658,14 @@ class TypeParser
return $type;
} catch (LogicException $e) {
throw $exception;
throw new ParserException(
$currentTokenValue,
$currentTokenType,
$currentTokenOffset,
Lexer::TOKEN_IDENTIFIER,
null,
$currentTokenLine
);
}
}

Binary file not shown.

View File

@@ -1,16 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEynwsejDI6OEnSoR2UcZzBf/C5cAFAmTaKt8ACgkQUcZzBf/C
5cBjcA//TOyzijQKOpxHJ73Y0F9j5169FDZE95exCWDYxOLkFOr8V/lvjZhXESqh
g5qSn93q4BjAq60pjocZe/sBHxPpyxVLmvWzZcwozP0fauZABsPAXuhPrGtuBn7Q
v7ykPPycayBUiCNNcUi00x5d9+5V4Fvd3URDg/eC/rpBb7O3mA2UWcQrR+bx178z
v91dnztyti8U8PL4ol+BZr56g7mm75wy/oFhDgr4h4xtmH6RzDiCa3DUyKyNqUIG
KqAILtxhcSYRFoDWlakwKGY6lGQrrcrcwKZL+d9yEdXxrgsV0qw5y58b3Tmz39vR
A2CapzNmpuUaSIH7jjdiFak6fAKwKsgZysKRilbMLoON2AS+NZmezqMsX2invrPl
QgURzFJZ2iP2i+83Z02nIB3DiHAZOapQwBEfqhdPq6yG5SNFh5ZvLsSPbbEI2jRL
b29ehUYag3ccxe7tvU2nwOWljMg6zKKAVFTxyGRQ7PW5P7FFxYZ6KCW+25wFj2/d
sXfOAnr+TWmftNkCs8HFkKV2EyxPcslHk3hKfBFh+3GqL1UtcvQdM0NxfwQmklG3
FZ5J+P7UmbZhqXdNIXXtxUa9N7pnEJ1b9sL8DpXd0lCSqjiHwH+euXauouiVcLXd
jl2N0U5M/Qc8tIfeGCxEYm81wTzLi44XcHv62yPqST3UzZ0jYEI=
=jF08
iQIzBAABCgAdFiEEynwsejDI6OEnSoR2UcZzBf/C5cAFAmT1y40ACgkQUcZzBf/C
5cDm6Q//VupQizxW3TICxhwzMDz05+nI8d72mn5vd94Niat90L1wPVHSZ9eBQSs3
xMGVKJufB/3tQp6rviYk0aFnTFsKYkgwQYSDk1P9D7VrcJdpB461P3FT4MGsRk8E
SSo55EuMGpiVvgoKbiPXeYV76yEpSMpelbKDNTm7iglLFVQKAnTv17aQv/UdBoYk
t/dOS0ovoWmjkj9837EA5o2FAkhA5njlpvRs1l5Jt/tZsZtJTcDjPYfP5kIGbOwp
V6xKYW7JYht+O0si3GxGmWGOE4VbOHLpUDpLMmVu53njjeGAIkPgX53TqBRbAbVL
FjpDSZYC08lE4WblqXZEP6aKqVqthQ4LcGfyZDvuWDgPGHf86cTvfHQvtqRY45kU
GhFDz6IfVlwBrfpc4hKfbhF6Q3Txm8ZSSfiVHim8JFjCqO+jn4qmaXGaOqbNUfv9
fLgg7Bbnu1tZdMv6JJP5Kmk0x5wp4m2vFxDd6NGfm7uz9182/LtXOjqQ0MuGfL+j
Dw53dl+WdUpr4Xk1m1GkYwDF9zLIwBB7dEghz6c4nbiGvh31MUk6N+4N2eGkjtWW
B1PPORcpxxXSlhtftCwsJVxRFodQu9cmI0qmw4EUEipFrkFuT7a1rNF48NFyfRMh
PcB/UcUHMCL7owhfQEEuPvqIPJS4saesCdFeJAM0MKuXB1nNGTQ=
=HpaR
-----END PGP SIGNATURE-----

View File

@@ -13,6 +13,8 @@ namespace Symfony\Component\Console\Formatter;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use function Symfony\Component\String\b;
/**
* Formatter class for console output.
*
@@ -241,7 +243,7 @@ class OutputFormatter implements WrappableOutputFormatterInterface
}
preg_match('~(\\n)$~', $text, $matches);
$text = $prefix.preg_replace('~([^\\n]{'.$width.'})\\ *~', "\$1\n", $text);
$text = $prefix.$this->addLineBreaks($text, $width);
$text = rtrim($text, "\n").($matches[1] ?? '');
if (!$currentLineLength && '' !== $current && !str_ends_with($current, "\n")) {
@@ -265,4 +267,11 @@ class OutputFormatter implements WrappableOutputFormatterInterface
return implode("\n", $lines);
}
private function addLineBreaks(string $text, int $width): string
{
$encoding = mb_detect_encoding($text, null, true) ?: 'UTF-8';
return b($text)->toCodePointString($encoding)->wordwrap($width, "\n", true)->toByteString($encoding);
}
}

View File

@@ -48,9 +48,9 @@ class ConsoleSectionOutput extends StreamOutput
public function setMaxHeight(int $maxHeight): void
{
// when changing max height, clear output of current section and redraw again with the new height
$existingContent = $this->popStreamContentUntilCurrentSection($this->maxHeight ? min($this->maxHeight, $this->lines) : $this->lines);
$previousMaxHeight = $this->maxHeight;
$this->maxHeight = $maxHeight;
$existingContent = $this->popStreamContentUntilCurrentSection($previousMaxHeight ? min($previousMaxHeight, $this->lines) : $this->lines);
parent::doWrite($this->getVisibleContent(), false);
parent::doWrite($existingContent, false);
@@ -119,8 +119,7 @@ class ConsoleSectionOutput extends StreamOutput
// re-add the line break (that has been removed in the above `explode()` for
// - every line that is not the last line
// - if $newline is required, also add it to the last line
// - if it's not new line, but input ending with `\PHP_EOL`
if ($i < $count || $newline || str_ends_with($input, \PHP_EOL)) {
if ($i < $count || $newline) {
$lineContent .= \PHP_EOL;
}
@@ -168,6 +167,12 @@ class ConsoleSectionOutput extends StreamOutput
*/
protected function doWrite(string $message, bool $newline)
{
// Simulate newline behavior for consistent output formatting, avoiding extra logic
if (!$newline && str_ends_with($message, \PHP_EOL)) {
$message = substr($message, 0, -\strlen(\PHP_EOL));
$newline = true;
}
if (!$this->isDecorated()) {
parent::doWrite($message, $newline);
@@ -213,7 +218,7 @@ class ConsoleSectionOutput extends StreamOutput
break;
}
$numberOfLinesToClear += $section->lines;
$numberOfLinesToClear += $section->maxHeight ? min($section->lines, $section->maxHeight) : $section->lines;
if ('' !== $sectionContent = $section->getVisibleContent()) {
if (!str_ends_with($sectionContent, \PHP_EOL)) {
$sectionContent .= \PHP_EOL;

View File

@@ -1,4 +1,4 @@
Copyright (c) 2018-2019 Fabien Potencier
Copyright (c) 2018-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -31,7 +31,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",

View File

@@ -1,4 +1,4 @@
Copyright (c) 2015-2019 Fabien Potencier
Copyright (c) 2015-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -28,7 +28,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",

View File

@@ -1,4 +1,4 @@
Copyright (c) 2015-2019 Fabien Potencier
Copyright (c) 2015-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -29,7 +29,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",

View File

@@ -1,4 +1,4 @@
Copyright (c) 2015-2019 Fabien Potencier
Copyright (c) 2015-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -69,7 +69,7 @@ final class Mbstring
{
public const MB_CASE_FOLD = \PHP_INT_MAX;
private const CASE_FOLD = [
private const SIMPLE_CASE_FOLD = [
['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"],
['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'],
];
@@ -301,7 +301,11 @@ final class Mbstring
$map = $upper;
} else {
if (self::MB_CASE_FOLD === $mode) {
$s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s);
static $caseFolding = null;
if (null === $caseFolding) {
$caseFolding = self::getData('caseFolding');
}
$s = strtr($s, $caseFolding);
}
static $lower = null;
@@ -406,6 +410,12 @@ final class Mbstring
public static function mb_check_encoding($var = null, $encoding = null)
{
if (PHP_VERSION_ID < 70200 && \is_array($var)) {
trigger_error('mb_check_encoding() expects parameter 1 to be string, array given', \E_USER_WARNING);
return null;
}
if (null === $encoding) {
if (null === $var) {
return false;
@@ -413,7 +423,21 @@ final class Mbstring
$encoding = self::$internalEncoding;
}
return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var);
if (!\is_array($var)) {
return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var);
}
foreach ($var as $key => $value) {
if (!self::mb_check_encoding($key, $encoding)) {
return false;
}
if (!self::mb_check_encoding($value, $encoding)) {
return false;
}
}
return true;
}
public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
@@ -638,8 +662,10 @@ final class Mbstring
public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
{
$haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
$needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
[$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [
self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding),
self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding),
]);
return self::mb_strpos($haystack, $needle, $offset, $encoding);
}
@@ -674,8 +700,11 @@ final class Mbstring
public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
{
$haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
$needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
$haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding);
$needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding);
$haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack);
$needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle);
return self::mb_strrpos($haystack, $needle, $offset, $encoding);
}
@@ -798,6 +827,50 @@ final class Mbstring
return $code;
}
public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, string $encoding = null): string
{
if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) {
throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');
}
if (null === $encoding) {
$encoding = self::mb_internal_encoding();
}
try {
$validEncoding = @self::mb_check_encoding('', $encoding);
} catch (\ValueError $e) {
throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding));
}
// BC for PHP 7.3 and lower
if (!$validEncoding) {
throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding));
}
if (self::mb_strlen($pad_string, $encoding) <= 0) {
throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string');
}
$paddingRequired = $length - self::mb_strlen($string, $encoding);
if ($paddingRequired < 1) {
return $string;
}
switch ($pad_type) {
case \STR_PAD_LEFT:
return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string;
case \STR_PAD_RIGHT:
return $string.self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding);
default:
$leftPaddingLength = floor($paddingRequired / 2);
$rightPaddingLength = $paddingRequired - $leftPaddingLength;
return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding);
}
}
private static function getSubpart($pos, $part, $haystack, $encoding)
{
if (false === $pos) {

View File

@@ -0,0 +1,119 @@
<?php
return [
'İ' => 'i̇',
'µ' => 'μ',
'ſ' => 's',
'ͅ' => 'ι',
'ς' => 'σ',
'ϐ' => 'β',
'ϑ' => 'θ',
'ϕ' => 'φ',
'ϖ' => 'π',
'ϰ' => 'κ',
'ϱ' => 'ρ',
'ϵ' => 'ε',
'ẛ' => 'ṡ',
'' => 'ι',
'ß' => 'ss',
'ʼn' => 'ʼn',
'ǰ' => 'ǰ',
'ΐ' => 'ΐ',
'ΰ' => 'ΰ',
'և' => 'եւ',
'ẖ' => 'ẖ',
'ẗ' => 'ẗ',
'ẘ' => 'ẘ',
'ẙ' => 'ẙ',
'ẚ' => 'aʾ',
'ẞ' => 'ss',
'ὐ' => 'ὐ',
'ὒ' => 'ὒ',
'ὔ' => 'ὔ',
'ὖ' => 'ὖ',
'ᾀ' => 'ἀι',
'ᾁ' => 'ἁι',
'ᾂ' => 'ἂι',
'ᾃ' => 'ἃι',
'ᾄ' => 'ἄι',
'ᾅ' => 'ἅι',
'ᾆ' => 'ἆι',
'ᾇ' => 'ἇι',
'ᾈ' => 'ἀι',
'ᾉ' => 'ἁι',
'ᾊ' => 'ἂι',
'ᾋ' => 'ἃι',
'ᾌ' => 'ἄι',
'ᾍ' => 'ἅι',
'ᾎ' => 'ἆι',
'ᾏ' => 'ἇι',
'ᾐ' => 'ἠι',
'ᾑ' => 'ἡι',
'ᾒ' => 'ἢι',
'ᾓ' => 'ἣι',
'ᾔ' => 'ἤι',
'ᾕ' => 'ἥι',
'ᾖ' => 'ἦι',
'ᾗ' => 'ἧι',
'ᾘ' => 'ἠι',
'ᾙ' => 'ἡι',
'ᾚ' => 'ἢι',
'ᾛ' => 'ἣι',
'ᾜ' => 'ἤι',
'ᾝ' => 'ἥι',
'ᾞ' => 'ἦι',
'ᾟ' => 'ἧι',
'ᾠ' => 'ὠι',
'ᾡ' => 'ὡι',
'ᾢ' => 'ὢι',
'ᾣ' => 'ὣι',
'ᾤ' => 'ὤι',
'ᾥ' => 'ὥι',
'ᾦ' => 'ὦι',
'ᾧ' => 'ὧι',
'ᾨ' => 'ὠι',
'ᾩ' => 'ὡι',
'ᾪ' => 'ὢι',
'ᾫ' => 'ὣι',
'ᾬ' => 'ὤι',
'ᾭ' => 'ὥι',
'ᾮ' => 'ὦι',
'ᾯ' => 'ὧι',
'ᾲ' => 'ὰι',
'ᾳ' => 'αι',
'ᾴ' => 'άι',
'ᾶ' => 'ᾶ',
'ᾷ' => 'ᾶι',
'ᾼ' => 'αι',
'ῂ' => 'ὴι',
'ῃ' => 'ηι',
'ῄ' => 'ήι',
'ῆ' => 'ῆ',
'ῇ' => 'ῆι',
'ῌ' => 'ηι',
'ῒ' => 'ῒ',
'ῖ' => 'ῖ',
'ῗ' => 'ῗ',
'ῢ' => 'ῢ',
'ῤ' => 'ῤ',
'ῦ' => 'ῦ',
'ῧ' => 'ῧ',
'ῲ' => 'ὼι',
'ῳ' => 'ωι',
'ῴ' => 'ώι',
'ῶ' => 'ῶ',
'ῷ' => 'ῶι',
'ῼ' => 'ωι',
'ff' => 'ff',
'fi' => 'fi',
'fl' => 'fl',
'ffi' => 'ffi',
'ffl' => 'ffl',
'ſt' => 'st',
'st' => 'st',
'ﬓ' => 'մն',
'ﬔ' => 'մե',
'ﬕ' => 'մի',
'ﬖ' => 'վն',
'ﬗ' => 'մխ',
];

View File

@@ -132,6 +132,10 @@ if (!function_exists('mb_str_split')) {
function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); }
}
if (!function_exists('mb_str_pad')) {
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}
if (extension_loaded('mbstring')) {
return;
}

View File

@@ -128,6 +128,10 @@ if (!function_exists('mb_str_split')) {
function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); }
}
if (!function_exists('mb_str_pad')) {
function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }
}
if (extension_loaded('mbstring')) {
return;
}

View File

@@ -31,7 +31,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",

View File

@@ -1,4 +1,4 @@
Copyright (c) 2020 Fabien Potencier
Copyright (c) 2020-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -30,7 +30,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",

View File

@@ -99,7 +99,7 @@ echo "<hr>";
try {
$check = Colors::validateColor('#ab12cd', 99);
print "No Exception";
} catch (\Exception $e) {
} catch (\UnexpectedValueException $e) {
print "ERROR: " . $e->getCode() . ": " . $e->getMessage() . "<br>";
}

View File

@@ -39,8 +39,18 @@ print '<div><h1>' . $PAGE_NAME . '</h1></div>';
// define a list of from to color sets for conversion test
// A(out of bounds)
print "C::S/COLOR invalid rgb->hex (gray 125): -1, -1, -1: " . CoreLibs\Convert\Colors::rgb2hex(-1, -1, -1) . "<br>";
print "\$C::S/COLOR invalid rgb->hex (gray 125): -1, -1, -1: " . $color_class::rgb2hex(-1, -1, -1) . "<br>";
try {
print "C::S/COLOR invalid rgb->hex (gray 125): -1, -1, -1: "
. CoreLibs\Convert\Colors::rgb2hex(-1, -1, -1) . "<br>";
} catch (\LengthException $e) {
print "*Exception: " . $e->getMessage() . "<br>" . $e . "<br>";
}
try {
print "\$C::S/COLOR invalid rgb->hex (gray 125): -1, -1, -1: "
. $color_class::rgb2hex(-1, -1, -1) . "<br>";
} catch (\LengthException $e) {
print "**Exception: " . $e->getMessage() . "<br><pre>" . print_r($e, true) . "</pre><br>";
}
// B(valid)
$rgb = [10, 20, 30];
$hex = '#0a141e';

View File

@@ -73,6 +73,44 @@ $db->dbSetEncoding('SJIS');
print "ENCODING TEST: " . $db->dbVersionInfo('client_encoding') . "/" . $db->dbGetEncoding() . "<br>";
$db->dbResetEncoding();
// empty calls, none of the below should fail
//
$db->dbGetCursor();
//
$db->dbGetCursorExt();
//
$db->dbGetCursorPos('SELECT foo', ['bar']);
//
$db->dbGetCursorNumRows('SELECT foo', ['bar']);
//
$db->dbGetInsertPKName();
//
$db->dbGetInsertPK();
//
$db->dbGetReturningExt();
$db->dbGetReturningExt('foo');
$db->dbGetReturningExt('foo', 0);
$db->dbGetReturningExt(pos:0);
//
$db->dbGetReturningArray();
//
$db->dbGetNumRows();
//
$db->dbGetNumFields();
//
$db->dbGetFieldNames();
//
$db->dbGetFieldTypes();
//
$db->dbGetFieldNameTypes();
//
$db->dbGetFieldName(0);
//
$db->dbGetFieldType(0);
$db->dbGetFieldType('foo');
//
$db->dbGetPrepareCursorValue('foo', 'bar');
// TEST CACHE READS
$res = $db->dbReturn("SELECT * FROM max_test");

View File

@@ -0,0 +1,53 @@
<?php // phpcs:ignore warning
/**
* @phan-file-suppress PhanTypeSuspiciousStringExpression
*/
declare(strict_types=1);
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start();
// basic class test file
define('USE_DATABASE', false);
// sample config
require 'config.php';
// define log file id
$LOG_FILE_ID = 'classTest-error_msg';
ob_end_flush();
use CoreLibs\Logging\Logger\MessageLevel as ml;
$log = new CoreLibs\Logging\Logging([
'log_folder' => BASE . LOG,
'log_file_id' => $LOG_FILE_ID,
'log_per_date' => true,
]);
$PAGE_NAME = 'TEST CLASS: ERROR MSG';
print "<!DOCTYPE html>";
print "<html><head><title>" . $PAGE_NAME . "</title><head>";
print "<body>";
print '<div><a href="class_test.php">Class Test Master</a></div>';
print '<div><h1>' . $PAGE_NAME . '</h1></div>';
$em = new \CoreLibs\Logging\ErrorMessage($log);
print "FN: " . ml::fromName('Affe')->name . "<br>";
print "NU: " . ml::fromValue(100)->name . "<br>";
print "NU: " . ml::fromValue(1000)->name . "<br>";
$em->setErrorMsg('123', 'error', 'msg this is bad, not logged');
$em->setErrorMsg('123', 'error', 'msg this is bad, logged', log_error:true);
$em->setErrorMsg('1000', 'info', 'This is good');
$em->setErrorMsg('9999', 'abort', 'BAD: This is critical (abort)');
$em->setErrorMsg('10-1000', 'wrong', 'Wrong level: This is emergency');
print "ErrorsLast: <pre>" . $log->prAr($em->getLastErrorMsg()) . "</pre>";
print "ErrorsIds: <pre>" . $log->prAr($em->getErrorIds()) . "</pre>";
print "Errors: <pre>" . $log->prAr($em->getErrorMsg()) . "</pre>";
print "</body></html>";
// __END__

View File

@@ -15,7 +15,7 @@ define('USE_DATABASE', false);
// sample config
require 'config.php';
// define log file id
$LOG_FILE_ID = 'classTest-datetime';
$LOG_FILE_ID = 'classTest-file';
ob_end_flush();
use CoreLibs\Check\File;

View File

@@ -109,6 +109,13 @@ foreach ($images as $image) {
echo "<hr>";
}
// errros
try {
Image::createThumbnailSimple('', $thumb_width, 0, $cache_folder, $web_folder);
} catch (\UnexpectedValueException $e) {
print "Message:<br>" . $e->getMessage() . "<br>" . $e . "<br>";
}
print "</body></html>";
// __END__

View File

@@ -115,6 +115,7 @@ $test_files = [
'class_test.config.link.php' => 'Class Test: CONFIG LINK',
'class_test.config.direct.php' => 'Class Test: CONFIG DIRECT',
'class_test.class-calls.php' => 'Class Test: CLASS CALLS',
'class_test.error_msg.php' => 'Class Test: ERROR MSG',
'subfolder/class_test.config.direct.php' => 'Class Test: CONFIG DIRECT SUB',
];

View File

@@ -78,16 +78,18 @@ if (isset($_SESSION)) {
#
print "[UNSET] To set session name valid: "
. ($session->checkValidSessionName($session_name) ? 'Valid' : 'Invalid') . "<br>";
if (false === ($session_id = $session->startSession($session_name))) {
print "[FAILED] Session start failed: " . $session->getErrorStr() . "<br>";
} else {
try {
$session_id = $session->startSession($session_name);
print "[SET] Current session id: " . $session_id . "<br>";
} catch (\Exception $e) {
print "[FAILED] Session start failed:<br>" . $e->getMessage() . "<br>" . $e . "<br>";
}
// set again
if (false === ($session_id = $session->startSession($session_name))) {
print "[2 FAILED] Session start failed: " . $session->getErrorStr() . "<br>";
} else {
try {
$session_id = $session->startSession($session_name);
print "[2 SET] Current session id: " . $session_id . "<br>";
} catch (\Exception $e) {
print "[2 FAILED] Session start failed:<br>" . $e->getMessage() . "<br>" . $e . "<br>";
}
print "[SET] Current session id: " . $session->getSessionId() . "<br>";
print "[SET] Current session name: " . $session->getSessionName() . "<br>";
@@ -125,10 +127,11 @@ print "[READ MAGIC] unset Isset: " . (isset($session->setwrap) ? 'Yes' : 'No') .
// differnt session name
$session_name = 'class-test-session-ALT';
if (false === ($session_id = $session->startSession($session_name))) {
print "[3 FAILED] Session start failed: " . $session->getErrorStr() . "<br>";
} else {
try {
$session_id = $session->startSession($session_name);
print "[3 SET] Current session id: " . $session_id . "<br>";
} catch (\Exception $e) {
print "[3 FAILED] Session start failed:<br>" . $e->getMessage() . "<br>" . $e . "<br>";
}
print "[SET AGAIN] Current session id: " . $session->getSessionId() . "<br>";
@@ -141,10 +144,11 @@ $_SESSION['will_never_be_written'] = 'empty';
// open again
$session_name = 'class-test-session';
if (false === ($session_id = $session->startSession($session_name))) {
print "[4 FAILED] Session start failed: " . $session->getErrorStr() . "<br>";
} else {
try {
$session_id = $session->startSession($session_name);
print "[4 SET] Current session id: " . $session_id . "<br>";
} catch (\Exception $e) {
print "[4 FAILED] Session start failed:<br>" . $e->getMessage() . "<br>" . $e . "<br>";
}
print "[START AGAIN] Current session id: " . $session->getSessionId() . "<br>";
$_SESSION['will_be_written_again'] = 'Full';
@@ -153,10 +157,11 @@ $_SESSION['will_be_written_again'] = 'Full';
$session->writeClose();
// invalid
$session_name = '123';
if (false === ($session_id = $session->startSession($session_name))) {
print "[5 FAILED] Session start failed: " . $session->getErrorStr() . "<br>";
} else {
try {
$session_id = $session->startSession($session_name);
print "[5 SET] Current session id: " . $session_id . "<br>";
} catch (\Exception $e) {
print "[5 FAILED] Session start failed:<br>" . $e->getMessage() . "<br>" . $e . "<br>";
}
print "[BAD NAME] Current session id: " . $session->getSessionId() . "<br>";
print "[BAD NAME] Current session name: " . $session->getSessionName() . "<br>";

View File

@@ -69,16 +69,18 @@ print "[UNSET] Current session status: " . getSessionStatusString($session->getS
print "[READ] " . $var . ": " . ($_SESSION[$var] ?? '{UNSET}') . "<br>";
// start
if (false === ($session_id = $session->startSession($session_name))) {
print "Session start failed: " . $session->getErrorStr() . "<br>";
} else {
print "Current session id: " . $session_id . "<br>";
try {
$session_id = $session->startSession($session_name);
print "[1] Current session id: " . $session_id . "<br>";
} catch (\Exception $e) {
print "[1] Session start failed:<br>" . $e->getMessage() . "<br>" . $e . "<br>";
}
// set again
if (false === ($session_id = $session->startSession($session_name))) {
print "[2] Session start failed<br>";
} else {
try {
$session_id = $session->startSession($session_name);
print "[2] Current session id: " . $session_id . "<br>";
} catch (\Exception $e) {
print "[2] Session start failed:<br>" . $e->getMessage() . "<br>" . $e . "<br>";
}
print "[SET] Current session id: " . $session->getSessionId() . "<br>";
print "[SET] Current session name: " . $session->getSessionName() . "<br>";

View File

@@ -377,7 +377,7 @@ input[type="text"]:focus, textarea:focus, select:focus {
border-top-color: rgba(3, 155, 229 ,1);
border-radius: 50%;
display: inline-block;
animation: rotate 600ms infinite linear;
animation: progress-move 600ms infinite linear;
/* align */
left: 0;
top: 0;
@@ -385,7 +385,7 @@ input[type="text"]:focus, textarea:focus, select:focus {
z-index: 1000;
}
/* Animation for above progress */
@keyframes rotate {
@keyframes progress-move {
to {
transform: rotate(1turn)
}

View File

@@ -240,7 +240,7 @@ class Login
if (false === $this->loginSetOptions($options)) {
// on failure, exit
echo "<b>Could not set options</b>";
$this->loginTerminate(4000);
$this->loginTerminate('Could not set options', 3000);
}
// string key, msg: string, flag: e (error), o (ok)
@@ -392,11 +392,18 @@ class Login
/**
* Wrapper for exit calls
*
* @param int $code
* @param string $message [='']
* @param int $code [=0]
* @return void
*/
protected function loginTerminate($code = 0): void
protected function loginTerminate(string $message = '', int $code = 0): void
{
// all below 1000 are info end, all above 1000 are critical -> should throw exception?
if ($code < 1000) {
$this->log->info($message, ['code' => $code]);
} else {
$this->log->critical($message, ['code' => $code]);
}
exit($code);
}
@@ -1810,14 +1817,14 @@ HTML;
$this->login_error = 1;
echo 'Could not connect to DB<br>';
// if I can't connect to the DB to auth exit hard. No access allowed
$this->loginTerminate(1000);
$this->loginTerminate('Could not connect to DB', 1000);
}
// initial the session if there is no session running already
// check if session exists and could be created
if ($this->session->checkActiveSession() === false) {
$this->login_error = 2;
echo '<b>No active session found</b>';
$this->loginTerminate(2000);
$this->loginTerminate('No active session found', 2000);
}
// set internal page name
$this->page_name = $this->loginReadPageName();
@@ -1916,7 +1923,7 @@ HTML;
$this->loginPrintLogin();
}
// exit so we don't process anything further, at all
$this->loginTerminate(3000);
$this->loginTerminate('Exit after non ajax page load', 100);
} else {
// if we are on an ajax page reset any POST/GET array data to avoid
// any accidentical processing going on
@@ -1924,7 +1931,7 @@ HTML;
$_GET = [];
// set the action to login so we can trigger special login html return
$_POST['action'] = 'login';
$_POST['login_exit'] = 3000;
$_POST['login_exit'] = 100;
$_POST['login_error'] = $this->loginGetLastErrorCode();
$_POST['login_error_text'] = $this->loginGetErrorMsg(
$this->loginGetLastErrorCode(),

View File

@@ -14,8 +14,6 @@ declare(strict_types=1);
namespace CoreLibs\Check;
use Exception;
class Colors
{
/** @var int 1 for HEX rgb */
@@ -41,6 +39,7 @@ class Colors
* @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
* @throws \UnexpectedValueException 1: cannot extract color from string
*/
private static function rgbHslContentCheck(
string $color,
@@ -52,7 +51,7 @@ class Colors
if (
!is_array($color_list = preg_split("/,\s*/", $matches[1] ?? ''))
) {
throw new \Exception("Could not extract color list from rgg/hsl", 3);
throw new \UnexpectedValueException("Could not extract color list from rgg/hsl", 1);
}
// based on rgb/hsl settings check that entries are valid
// rgb: either 0-255 OR 0-100%
@@ -124,7 +123,8 @@ class Colors
* @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
* @throws \UnexpectedValueException 1: no valid flag set
* @throws \InvalidArgumentException 2: no regex block set
*/
public static function validateColor(string $color, int $flags = self::ALL): bool
{
@@ -152,10 +152,10 @@ class Colors
}
// wrong flag set
if ($flags > self::ALL) {
throw new \Exception("Invalid flags parameter: $flags", 1);
throw new \UnexpectedValueException("Invalid flags parameter: $flags", 1);
}
if (!count($regex_blocks)) {
throw new \Exception("No regex blocks set: $flags", 2);
throw new \InvalidArgumentException("No regex blocks set: $flags", 2);
}
// build regex

View File

@@ -90,27 +90,26 @@ class Encoding
$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 {
if ($string == $compare) {
return false;
}
$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;
}
}

View File

@@ -245,14 +245,13 @@ class ArrayHandler
* bool key flag: true: handle keys as string or int
* default false: all keys are string
*
* @return array<mixed>|false merged array
* @return array<mixed> merged array
*/
public static function arrayMergeRecursive(): array|false
public static function arrayMergeRecursive(): array
{
// croak on not enough arguemnts (we need at least two)
if (func_num_args() < 2) {
trigger_error(__FUNCTION__ . ' needs two or more array arguments', E_USER_WARNING);
return false;
throw new \ArgumentCountError(__FUNCTION__ . ' needs two or more array arguments');
}
// default key is not string
$key_is_string = false;
@@ -265,15 +264,13 @@ class ArrayHandler
}
// check that arrays count is at least two, else we don't have enough to do anything
if (count($arrays) < 2) {
trigger_error(__FUNCTION__ . ' needs two or more array arguments', E_USER_WARNING);
return false;
throw new \ArgumentCountError(__FUNCTION__ . ' needs two or more array arguments');
}
$merged = [];
while ($arrays) {
$array = array_shift($arrays);
if (!is_array($array)) {
trigger_error(__FUNCTION__ . ' encountered a non array argument', E_USER_WARNING);
return false;
throw new \TypeError(__FUNCTION__ . ' encountered a non array argument');
}
if (!$array) {
continue;

View File

@@ -105,49 +105,48 @@ class DateTime
bool $show_micro = true
): string {
// check if the timestamp has any h/m/s/ms inside, if yes skip
if (!preg_match("/(h|m|s|ms)/", (string)$timestamp)) {
list($timestamp, $ms) = array_pad(explode('.', (string)round((float)$timestamp, 4)), 2, null);
// if negative remember
$negative = false;
if ((int)$timestamp < 0) {
$negative = true;
}
$timestamp = abs((float)$timestamp);
$timegroups = [86400, 3600, 60, 1];
$labels = ['d', 'h', 'm', 's'];
$time_string = '';
// if timestamp is zero, return zero string
if ($timestamp == 0) {
$time_string = '0s';
} else {
for ($i = 0, $iMax = count($timegroups); $i < $iMax; $i++) {
$output = floor((float)$timestamp / $timegroups[$i]);
$timestamp = (float)$timestamp % $timegroups[$i];
// output has days|hours|min|sec
if ($output || $time_string) {
$time_string .= $output . $labels[$i] . (($i + 1) != count($timegroups) ? ' ' : '');
}
}
}
// only add ms if we have an ms value
if ($ms !== null) {
// if we have ms and it has leading zeros, remove them, but only if it is nut just 0
$ms = preg_replace("/^0+(\d+)$/", '${1}', $ms);
if (!is_string($ms) || empty($ms)) {
$ms = '0';
}
// add ms if there
if ($show_micro) {
$time_string .= ' ' . $ms . 'ms';
} elseif (!$time_string) {
$time_string .= $ms . 'ms';
}
}
if ($negative) {
$time_string = '-' . $time_string;
}
if (preg_match("/(h|m|s|ms)/", (string)$timestamp)) {
return (string)$timestamp;
}
list($timestamp, $ms) = array_pad(explode('.', (string)round((float)$timestamp, 4)), 2, null);
// if negative remember
$negative = false;
if ((int)$timestamp < 0) {
$negative = true;
}
$timestamp = abs((float)$timestamp);
$timegroups = [86400, 3600, 60, 1];
$labels = ['d', 'h', 'm', 's'];
$time_string = '';
// if timestamp is zero, return zero string
if ($timestamp == 0) {
$time_string = '0s';
} else {
$time_string = $timestamp;
for ($i = 0, $iMax = count($timegroups); $i < $iMax; $i++) {
$output = floor((float)$timestamp / $timegroups[$i]);
$timestamp = (float)$timestamp % $timegroups[$i];
// output has days|hours|min|sec
if ($output || $time_string) {
$time_string .= $output . $labels[$i] . (($i + 1) != count($timegroups) ? ' ' : '');
}
}
}
// only add ms if we have an ms value
if ($ms !== null) {
// if we have ms and it has leading zeros, remove them, but only if it is nut just 0
$ms = preg_replace("/^0+(\d+)$/", '${1}', $ms);
if (!is_string($ms) || empty($ms)) {
$ms = '0';
}
// add ms if there
if ($show_micro) {
$time_string .= ' ' . $ms . 'ms';
} elseif (!$time_string) {
$time_string .= $ms . 'ms';
}
}
if ($negative) {
$time_string = '-' . $time_string;
}
return (string)$time_string;
}
@@ -162,37 +161,36 @@ class DateTime
public static function stringToTime(string|int|float $timestring): string|int|float
{
$timestamp = 0;
if (preg_match("/(d|h|m|s|ms)/", (string)$timestring)) {
$timestring = (string)$timestring;
// pos for preg match read + multiply factor
$timegroups = [2 => 86400, 4 => 3600, 6 => 60, 8 => 1];
$matches = [];
// if start with -, strip and set negative
$negative = false;
if (preg_match("/^-/", $timestring)) {
$negative = true;
$timestring = substr($timestring, 1);
}
// preg match: 0: full string
// 2, 4, 6, 8 are the to need values
preg_match("/^((\d+)d ?)?((\d+)h ?)?((\d+)m ?)?((\d+)s ?)?((\d+)ms)?$/", $timestring, $matches);
// multiply the returned matches and sum them up. the last one (ms) is added with .
foreach ($timegroups as $i => $time_multiply) {
if (isset($matches[$i]) && is_numeric($matches[$i])) {
$timestamp += (float)$matches[$i] * $time_multiply;
}
}
if (isset($matches[10]) && is_numeric($matches[10])) {
$timestamp .= '.' . $matches[10];
}
if ($negative) {
// cast to flaot so we can do a negative multiplication
$timestamp = (float)$timestamp * -1;
}
return $timestamp;
} else {
if (!preg_match("/(d|h|m|s|ms)/", (string)$timestring)) {
return $timestring;
}
$timestring = (string)$timestring;
// pos for preg match read + multiply factor
$timegroups = [2 => 86400, 4 => 3600, 6 => 60, 8 => 1];
$matches = [];
// if start with -, strip and set negative
$negative = false;
if (preg_match("/^-/", $timestring)) {
$negative = true;
$timestring = substr($timestring, 1);
}
// preg match: 0: full string
// 2, 4, 6, 8 are the to need values
preg_match("/^((\d+)d ?)?((\d+)h ?)?((\d+)m ?)?((\d+)s ?)?((\d+)ms)?$/", $timestring, $matches);
// multiply the returned matches and sum them up. the last one (ms) is added with .
foreach ($timegroups as $i => $time_multiply) {
if (isset($matches[$i]) && is_numeric($matches[$i])) {
$timestamp += (float)$matches[$i] * $time_multiply;
}
}
if (isset($matches[10]) && is_numeric($matches[10])) {
$timestamp .= '.' . $matches[10];
}
if ($negative) {
// cast to flaot so we can do a negative multiplication
$timestamp = (float)$timestamp * -1;
}
return $timestamp;
}
/**
@@ -323,36 +321,36 @@ class DateTime
*
* @param string $start_date start date string in YYYY-MM-DD
* @param string $end_date end date string in YYYY-MM-DD
* @return int|bool false on error
* or int -1 (s<e)/0 (s=e)/1 (s>e) as difference
* @return int int -1 (s<e)/0 (s=e)/1 (s>e) as difference
* @throws \UnexpectedValueException On empty start/end values
*/
public static function compareDate(string $start_date, string $end_date): int|bool
public static function compareDate(string $start_date, string $end_date): int
{
// pre check for empty or wrong
if ($start_date == '--' || $end_date == '--' || !$start_date || !$end_date) {
return false;
if ($start_date == '--' || $end_date == '--' || empty($start_date) || empty($end_date)) {
throw new \UnexpectedValueException('Start or End date not set or are just "--"', 1);
}
// if invalid, quit
if (($start_timestamp = strtotime($start_date)) === false) {
return false;
throw new \UnexpectedValueException("Error parsing start date through strtotime()", 2);
}
if (($end_timestamp = strtotime($end_date)) === false) {
return false;
throw new \UnexpectedValueException("Error parsing end date through strtotime()", 3);
}
$comp = 0;
// convert anything to Y-m-d and then to timestamp
// this is to remove any time parts
$start_timestamp = strtotime(date('Y-m-d', $start_timestamp));
$end_timestamp = strtotime(date('Y-m-d', $end_timestamp));
// compare, or end with false
if ($start_timestamp < $end_timestamp) {
return -1;
$comp = -1;
} elseif ($start_timestamp == $end_timestamp) {
return 0;
$comp = 0;
} elseif ($start_timestamp > $end_timestamp) {
return 1;
} else {
return false;
$comp = 1;
}
return $comp;
}
/**
@@ -366,32 +364,32 @@ class DateTime
*
* @param string $start_datetime start date/time in YYYY-MM-DD HH:mm:ss
* @param string $end_datetime end date/time in YYYY-MM-DD HH:mm:ss
* @return int|bool false for error
* or -1 (s<e)/0 (s=e)/1 (s>e) as difference
* @return int -1 (s<e)/0 (s=e)/1 (s>e) as difference
* @throws \UnexpectedValueException On empty start/end values
*/
public static function compareDateTime(string $start_datetime, string $end_datetime): int|bool
public static function compareDateTime(string $start_datetime, string $end_datetime): int
{
// pre check for empty or wrong
if ($start_datetime == '--' || $end_datetime == '--' || !$start_datetime || !$end_datetime) {
return false;
if ($start_datetime == '--' || $end_datetime == '--' || empty($start_datetime) || empty($end_datetime)) {
throw new \UnexpectedValueException('Start or end timestamp not set or are just "--"', 1);
}
// quit if invalid timestamp
if (($start_timestamp = strtotime($start_datetime)) === false) {
return false;
throw new \UnexpectedValueException("Error parsing start timestamp through strtotime()", 2);
}
if (($end_timestamp = strtotime($end_datetime)) === false) {
return false;
throw new \UnexpectedValueException("Error parsing end timestamp through strtotime()", 3);
}
$comp = 0;
// compare, or return false
if ($start_timestamp < $end_timestamp) {
return -1;
$comp = -1;
} elseif ($start_timestamp == $end_timestamp) {
return 0;
$comp = 0;
} elseif ($start_timestamp > $end_timestamp) {
return 1;
} else {
return false;
$comp = 1;
}
return $comp;
}
/**

View File

@@ -28,15 +28,15 @@ class Colors
* @param int $green green 0-255
* @param int $blue blue 0-255
* @param bool $hex_prefix default true, prefix with "#"
* @return string|false rgb in hex values with leading # if set,
* false for invalid color
* @return string rgb in hex values with leading # if set,
* @throws \LengthException If any argument is not in the range of 0~255
*/
public static function rgb2hex(
int $red,
int $green,
int $blue,
bool $hex_prefix = true
): string|false {
): string {
$hex_color = '';
if ($hex_prefix === true) {
$hex_color = '#';
@@ -44,7 +44,8 @@ class Colors
foreach (['red', 'green', 'blue'] as $color) {
// if not valid, abort
if ($$color < 0 || $$color > 255) {
return false;
throw new \LengthException('Argument value ' . $$color . ' for color ' . $color
. ' is not in the range of 0 to 255', 1);
}
// pad left with 0
$hex_color .= str_pad(dechex($$color), 2, '0', STR_PAD_LEFT);
@@ -55,37 +56,39 @@ class Colors
/**
* converts a hex RGB color to the int numbers
*
* @param string $hexStr RGB hexstring
* @param string $hex_string RGB hexstring
* @param bool $return_as_string flag to return as string
* @param string $seperator string seperator: default: ","
* @return string|array<string,float|int>|false false on error or array with RGB
* or a string with the seperator
* @return string|array<string,float|int> array with RGB
* or a string with the seperator
* @throws \InvalidArgumentException if hex string is empty
* @throws \UnexpectedValueException if the hex string value is not valid
*/
public static function hex2rgb(
string $hexStr,
string $hex_string,
bool $return_as_string = false,
string $seperator = ','
): string|array|false {
$hexStr = preg_replace("/[^0-9A-Fa-f]/", '', $hexStr); // Gets a proper hex string
if (!is_string($hexStr)) {
return false;
): string|array {
$hex_string = preg_replace("/[^0-9A-Fa-f]/", '', $hex_string); // Gets a proper hex string
if (!is_string($hex_string)) {
throw new \InvalidArgumentException('hex_string argument cannot be empty', 1);
}
$rgbArray = [];
if (strlen($hexStr) == 6) {
if (strlen($hex_string) == 6) {
// If a proper hex code, convert using bitwise operation.
// No overhead... faster
$colorVal = hexdec($hexStr);
$colorVal = hexdec($hex_string);
$rgbArray['r'] = 0xFF & ($colorVal >> 0x10);
$rgbArray['g'] = 0xFF & ($colorVal >> 0x8);
$rgbArray['b'] = 0xFF & $colorVal;
} elseif (strlen($hexStr) == 3) {
} elseif (strlen($hex_string) == 3) {
// If shorthand notation, need some string manipulations
$rgbArray['r'] = hexdec(str_repeat(substr($hexStr, 0, 1), 2));
$rgbArray['g'] = hexdec(str_repeat(substr($hexStr, 1, 1), 2));
$rgbArray['b'] = hexdec(str_repeat(substr($hexStr, 2, 1), 2));
$rgbArray['r'] = hexdec(str_repeat(substr($hex_string, 0, 1), 2));
$rgbArray['g'] = hexdec(str_repeat(substr($hex_string, 1, 1), 2));
$rgbArray['b'] = hexdec(str_repeat(substr($hex_string, 2, 1), 2));
} else {
// Invalid hex color code
return false;
throw new \UnexpectedValueException('Invalid hex_string: ' . $hex_string, 2);
}
// returns the rgb string or the associative array
return $return_as_string ? implode($seperator, $rgbArray) : $rgbArray;
@@ -97,20 +100,21 @@ class Colors
* returns:
* array with hue (0-360), sat (0-100%), brightness/value (0-100%)
*
* @param int $red red 0-255
* @param int $green green 0-255
* @param int $blue blue 0-255
* @return array<int|float>|false Hue, Sat, Brightness/Value
* false for input value error
* @param int $red red 0-255
* @param int $green green 0-255
* @param int $blue blue 0-255
* @return array<int|float> Hue, Sat, Brightness/Value
* @throws \LengthException If any argument is not in the range of 0~255
*/
public static function rgb2hsb(int $red, int $green, int $blue): array|false
public static function rgb2hsb(int $red, int $green, int $blue): array
{
// check that rgb is from 0 to 255
foreach (['red', 'green', 'blue'] as $c) {
if ($$c < 0 || $$c > 255) {
return false;
foreach (['red', 'green', 'blue'] as $color) {
if ($$color < 0 || $$color > 255) {
throw new \LengthException('Argument value ' . $$color . ' for color ' . $color
. ' is not in the range of 0 to 255', 1);
}
$$c = $$c / 255;
$$color = $$color / 255;
}
$MAX = max($red, $green, $blue);
@@ -144,13 +148,13 @@ class Colors
* converts HSB/V to RGB values RGB is full INT
* if HSB/V value is invalid, sets this value to 0
*
* @param float $H hue 0-360 (int)
* @param float $S saturation 0-100 (int)
* @param float $V brightness/value 0-100 (int)
* @return array<int>|false 0 red/1 green/2 blue array as 0-255
* false for input value error
* @param float $H hue 0-360 (int)
* @param float $S saturation 0-100 (int)
* @param float $V brightness/value 0-100 (int)
* @return array<int> 0 red/1 green/2 blue array as 0-255
* @throws \LengthException If any argument is not in the valid range
*/
public static function hsb2rgb(float $H, float $S, float $V): array|false
public static function hsb2rgb(float $H, float $S, float $V): array
{
// check that H is 0 to 359, 360 = 0
// and S and V are 0 to 1
@@ -158,13 +162,13 @@ class Colors
$H = 0;
}
if ($H < 0 || $H > 359) {
return false;
throw new \LengthException('Argument value ' . $H . ' for hue is not in the range of 0 to 359', 1);
}
if ($S < 0 || $S > 100) {
return false;
throw new \LengthException('Argument value ' . $S . ' for saturation is not in the range of 0 to 100', 2);
}
if ($V < 0 || $V > 100) {
return false;
throw new \LengthException('Argument value ' . $V . ' for brightness is not in the range of 0 to 100', 3);
}
// convert to internal 0-1 format
$S /= 100;
@@ -230,20 +234,21 @@ class Colors
* return:
* array with hue (0-360), saturation (0-100%) and luminance (0-100%)
*
* @param int $red red 0-255
* @param int $green green 0-255
* @param int $blue blue 0-255
* @return array<float>|false hue/sat/luminance
* false for input value error
* @param int $red red 0-255
* @param int $green green 0-255
* @param int $blue blue 0-255
* @return array<float> hue/sat/luminance
* @throws \LengthException If any argument is not in the range of 0~255
*/
public static function rgb2hsl(int $red, int $green, int $blue): array|false
public static function rgb2hsl(int $red, int $green, int $blue): array
{
// check that rgb is from 0 to 255
foreach (['red', 'green', 'blue'] as $c) {
if ($$c < 0 || $$c > 255) {
return false;
foreach (['red', 'green', 'blue'] as $color) {
if ($$color < 0 || $$color > 255) {
throw new \LengthException('Argument value ' . $$color . ' for color ' . $color
. ' is not in the range of 0 to 255', 1);
}
$$c = $$c / 255;
$$color = $$color / 255;
}
$min = min($red, $green, $blue);
@@ -284,24 +289,25 @@ class Colors
* converts an HSL to RGB
* if HSL value is invalid, set this value to 0
*
* @param float $hue hue: 0-360 (degrees)
* @param float $sat saturation: 0-100
* @param float $lum luminance: 0-100
* @return array<int,float|int>|false red/blue/green 0-255 each
* @param float $hue hue: 0-360 (degrees)
* @param float $sat saturation: 0-100
* @param float $lum luminance: 0-100
* @return array<int,float|int> red/blue/green 0-255 each
* @throws \LengthException If any argument is not in the valid range
*/
public static function hsl2rgb(float $hue, float $sat, float $lum): array|false
public static function hsl2rgb(float $hue, float $sat, float $lum): array
{
if ($hue == 360) {
$hue = 0;
}
if ($hue < 0 || $hue > 359) {
return false;
throw new \LengthException('Argument value ' . $hue . ' for hue is not in the range of 0 to 359', 1);
}
if ($sat < 0 || $sat > 100) {
return false;
throw new \LengthException('Argument value ' . $sat . ' for saturation is not in the range of 0 to 100', 2);
}
if ($lum < 0 || $lum > 100) {
return false;
throw new \LengthException('Argument value ' . $lum . ' for luminance is not in the range of 0 to 100', 3);
}
// calc to internal convert value for hue
$hue = (1 / 360) * $hue;

View File

@@ -26,8 +26,12 @@ class SetVarTypeMain
?string $default = null,
bool $to_null = false
): ?string {
if (is_string($val)) {
return $val;
if (
$val === null ||
is_scalar($val) ||
$val instanceof \Stringable
) {
return (string)$val;
}
if ($to_null === false) {
return (string)$default;
@@ -39,6 +43,7 @@ class SetVarTypeMain
* Will convert input data to string if possible.
* Runs for string/int/float/bool/null
* Will skip array/object/resource/callable/etc and use default for that
* Note: this is pretty much the same as setStrMain because string is easy
*
* @param mixed $val Input variable
* @param string|null $default Default value
@@ -71,6 +76,7 @@ class SetVarTypeMain
/**
* If input variable is int, return it, else return default value. If to_null
* is true then null as return is allowed, else only int is returned
* Note, if float is sent in, int is returned
*
* @param mixed $val Input variable
* @param int|null $default Default value
@@ -82,8 +88,8 @@ class SetVarTypeMain
?int $default = null,
bool $to_null = false
): ?int {
if (is_int($val)) {
return $val;
if (is_numeric($val)) {
return (int)$val;
}
if ($to_null === false) {
return (int)$default;
@@ -129,6 +135,7 @@ class SetVarTypeMain
/**
* If input is float return it, else set to default value. If to_null is set
* to true, allow null return
* Note if an int is sent in, float is returned
*
* @param mixed $val Input variable
* @param float|null $default Default value
@@ -140,8 +147,8 @@ class SetVarTypeMain
?float $default = null,
bool $to_null = false
): ?float {
if (is_float($val)) {
return $val;
if (is_numeric($val)) {
return (float)$val;
}
if ($to_null === false) {
return (float)$default;

View File

@@ -15,9 +15,6 @@ namespace CoreLibs\Create;
class Session
{
/** @var string list for errors */
private string $session_intern_error_str = '';
/**
* init a session, if array is empty or array does not have session_name set
* then no auto init is run
@@ -71,17 +68,6 @@ class Session
return true;
}
/**
* Return set error string, empty if none set
* Error strings are only set in the startSession method
*
* @return string Last error string
*/
public function getErrorStr(): string
{
return $this->session_intern_error_str;
}
/**
* check if session name is valid
*
@@ -120,13 +106,11 @@ class Session
{
// we can't start sessions on command line
if ($this->checkCliStatus()) {
$this->session_intern_error_str = '[SESSION] No sessions in php cli';
return false;
throw new \RuntimeException('[SESSION] No sessions in php cli', 1);
}
// if session are OFF
if ($this->getSessionStatus() === PHP_SESSION_DISABLED) {
$this->session_intern_error_str = '[SESSION] Sessions are disabled';
return false;
throw new \RuntimeException('[SESSION] Sessions are disabled', 2);
}
// session_status
// initial the session if there is no session running already
@@ -139,8 +123,7 @@ class Session
if (!empty($session_name)) {
// invalid session name, abort
if (!$this->checkValidSessionName($session_name)) {
$this->session_intern_error_str = '[SESSION] Invalid session name: ' . $session_name;
return false;
throw new \UnexpectedValueException('[SESSION] Invalid session name: ' . $session_name, 3);
}
$this->setSessionName($session_name);
}
@@ -149,11 +132,10 @@ class Session
}
// if we still have no active session
if (!$this->checkActiveSession()) {
$this->session_intern_error_str = '[SESSION] Failed to activate session';
return false;
throw new \RuntimeException('[SESSION] Failed to activate session', 4);
}
if (false === ($session_id = $this->getSessionId())) {
$this->session_intern_error_str = '[SESSION] getSessionId did not return a session id';
throw new \UnexpectedValueException('[SESSION] getSessionId did not return a session id', 5);
}
return $session_id;
}

View File

@@ -61,6 +61,7 @@ class ArrayIO extends \CoreLibs\DB\IO
* @param \CoreLibs\Logging\Logging $log Logging class
* @param int $base_acl_level Set base acl level, if needed
* @param int $acl_admin Flag if this is an admin ACL access level
* @throws \RuntimeException Missing table array or table name entry
*/
public function __construct(
array $db_config,
@@ -83,6 +84,7 @@ class ArrayIO extends \CoreLibs\DB\IO
// error abort if no table array or no table name
if (empty($table_array) || empty($table_name)) {
$this->__dbError(1999, false, 'MAJOR ERROR: Core settings missing');
throw new \RuntimeException('MAJOR ERROR: Core settings missing', 1999);
}
// set primary key for given table_array

View File

@@ -302,9 +302,9 @@ class IO
/** @var string */
private string $to_encoding = '';
/** @var string the query string at the moment */
private string $query;
private string $query = '';
/** @var array<mixed> current params for query */
private array $params;
private array $params = [];
// only inside
// basic vars
// the dbh handler, if disconnected by command is null, bool:false on error,
@@ -340,11 +340,12 @@ class IO
// 4: convert numeric/floatN to float (CONVERT_NUMERIC)
// 8: convert bytea to string data (CONVERT_BYTEA)
/** @var int type settings as bit mask, 0 for off, anything >2 will aways set 1 too */
/** @phan-suppress-next-line PhanInvalidConstantExpression, PhanUndeclaredClassConstant */
private int $convert_type = Convert::off->value;
// FOR BELOW: (This should be private and only readable through some method)
// cursor array for cached readings
/** @var array<string,mixed> extended cursoers string index with content */
private array $cursor_ext;
private array $cursor_ext = [];
// per query vars
/** @var \PgSql\Result|false actual cursor (DBH) */
private \PgSql\Result|false $cursor;
@@ -401,7 +402,7 @@ class IO
/** @var bool if we use RETURNING in the INSERT call */
private bool $returning_id = false;
/** @var string if a sync is running holds the hash key of the query */
private string $async_running;
private string $async_running = '';
// logging class, must be public so settings can be changed
/** @var \CoreLibs\Logging\Logging */
public \CoreLibs\Logging\Logging $log;
@@ -413,6 +414,7 @@ class IO
* phpcs:ignore
* @param array{db_name:string,db_user:string,db_pass:string,db_host:string,db_port:int,db_schema:string,db_encoding:string,db_type:string,db_ssl:string,db_convert_type?:string[]} $db_config DB configuration array
* @param \CoreLibs\Logging\Logging $log Logging class
* @throws \RuntimeException If no DB connection can be established on launch
*/
public function __construct(
array $db_config,
@@ -491,6 +493,7 @@ class IO
if (!$this->__connectToDB()) {
$this->__dbError(16);
$this->db_connection_closed = true;
throw new \RuntimeException('INIT: No DB Handler found / connect or reconnect failed', 16);
}
}
@@ -973,9 +976,9 @@ class IO
/**
* write an error
*
* @param integer $error_id Any Error ID, used in debug message string
* @param integer $error_id Any Error ID, used in debug message string
* @param \PgSql\Result|false $cursor Optional cursor, passed on to preprocessor
* @param string $msg optional message added to debug
* @param string $msg optional message added to debug
* @return void
*/
protected function __dbError(
@@ -2687,7 +2690,7 @@ class IO
*/
public function dbGetCursor(): \PgSql\Result|false
{
return $this->cursor;
return $this->cursor ?? false;
}
// ***************************
@@ -2744,7 +2747,7 @@ class IO
}
$query_hash = $this->dbGetQueryHash($query, $params);
if (
is_array($this->cursor_ext) &&
!empty($this->cursor_ext) &&
isset($this->cursor_ext[$query_hash])
) {
if (empty($query_field)) {
@@ -2763,9 +2766,9 @@ class IO
* @param string $query Query to find in cursor_ext
* @param array<mixed> $params If the query is params type we need params
* data to create a unique call one, optional
* @return int|false query position (row pos), false on error
* @return int|false|null query position (row pos), false on error
*/
public function dbGetCursorPos(string $query, array $params = []): int|false
public function dbGetCursorPos(string $query, array $params = []): int|false|null
{
$this->__dbErrorReset();
if (!$query) {
@@ -2773,7 +2776,14 @@ class IO
return false;
}
$query_hash = $this->dbGetQueryHash($query, $params);
return (int)$this->cursor_ext[$query_hash]['pos'];
if (
!empty($this->cursor_ext) &&
isset($this->cursor_ext[$query_hash])
) {
return (int)$this->cursor_ext[$query_hash]['pos'];
} else {
return null;
}
}
/**
@@ -2782,9 +2792,9 @@ class IO
* @param string $query Query to find in cursor_ext
* @param array<mixed> $params If the query is params type we need params
* data to create a unique call one, optional
* @return int|false numer of rows returned, false on error
* @return int|false|null numer of rows returned, false on error
*/
public function dbGetCursorNumRows(string $query, array $params = []): int|false
public function dbGetCursorNumRows(string $query, array $params = []): int|false|null
{
$this->__dbErrorReset();
if (!$query) {
@@ -2792,7 +2802,14 @@ class IO
return false;
}
$query_hash = $this->dbGetQueryHash($query, $params);
return (int)$this->cursor_ext[$query_hash]['num_rows'];
if (
!empty($this->cursor_ext) &&
isset($this->cursor_ext[$query_hash])
) {
return (int)$this->cursor_ext[$query_hash]['num_rows'];
} else {
return null;
}
}
// ***************************
@@ -3194,7 +3211,7 @@ class IO
/**
* Returns the current async running query hash
*
* @return string Current async running query hash
* @return string Current async running query hash, empty string for nothing
*/
public function dbGetAsyncRunning(): string
{
@@ -3829,7 +3846,7 @@ class IO
*/
public function dbGetNumRows(): ?int
{
return $this->num_rows;
return $this->num_rows ?? null;
}
/**
@@ -3839,10 +3856,7 @@ class IO
*/
public function dbGetNumFields(): ?int
{
if (!isset($this->num_fields)) {
return null;
}
return $this->num_fields;
return $this->num_fields ?? null;
}
/**

View File

@@ -63,7 +63,7 @@ class FileWriter
*
* @param string $string string to write to the file
* @param boolean $enter default true, if set adds a linebreak \n at the end
* @return bool True for log written, false for not wirrten
* @return bool True for log written, false for not written
*/
public static function fdebug(string $string, bool $enter = true): bool
{
@@ -75,7 +75,7 @@ class FileWriter
empty(self::$debug_folder) &&
defined('BASE') && defined('LOG')
) {
/** @deprecated Do not use this anymore, define path with fsetFolder */
/** @deprecated Do not use this anymore, define path with festFolder */
trigger_error(
'fsetFolder must be set first. Setting via LOG_FILE_ID and LOG constants is deprecated',
E_USER_DEPRECATED

View File

@@ -254,7 +254,7 @@ class L10n
}
// if this is still null here, we abort
if ($this->l10n === null) {
throw new \Exception(
throw new \RuntimeException(
"Could not create CoreLibs\Language\Core\GetTextReader object",
E_USER_ERROR
);

View File

@@ -0,0 +1,220 @@
<?php
/**
* AUTOR: Clemens Schwaighofer
* CREATED: 2023/9/7
* DESCRIPTION:
* General error collection class for output to frontend or to log
*/
declare(strict_types=1);
namespace CoreLibs\Logging;
use CoreLibs\Logging\Logger\MessageLevel;
class ErrorMessage
{
/** @var array<int,array{id:string,level:string,str:string,target:string,highlight:string[]}> */
private array $error_str = [];
/** @var \CoreLibs\Logging\Logging $log */
public \CoreLibs\Logging\Logging $log;
/** @var bool $log_error global flag to log error level message */
private bool $log_error = false;
/**
* init ErrorMessage
*
* @param \CoreLibs\Logging\Logging $log
* @param bool $log_error [=false]
*/
public function __construct(
\CoreLibs\Logging\Logging $log,
bool $log_error = false
) {
$this->log = $log;
$this->log_error = $log_error;
}
/**
* pushes new error message into the error_str array
* error_id: internal Error ID (should be unique)
* level: error level, can only be ok, info, warn, error, abort, crash
* ok and info are positive response: success
* warn: success, but there might be some things that are not 100% ok
* error: input error or error in executing request
* abort: an internal error happened as mandatory information that normally is
* there is missing, or the ACL level that should normally match does not
* will be logged to "critical"
* crash: system failure or critical system problems (db connection failure)
* will be logged as "alert"
* not set: unkown, will be logged as "emergency"
* target/highlight: id target name for frontend where to attach this message
* highlight is a list of other target points to highlight
*
* @param string $error_id Any internal error ID for this error
* @param string $level Error level in ok/info/warn/error
* @param string $str Error message (out)
* @param string $target alternate attachment point for this error message
* @param array<string> $highlight Any additional error data as error OR
* highlight points for field highlights
* @param string|null $message If abort/crash, non localized $str
* @param array<mixed> $context Additionl info for abort/crash messages
* @param bool|null $log_error [=null] log level 'error' to error, if null use global,
* else set for this call only
*/
public function setErrorMsg(
string $error_id,
string $level,
string $str,
string $target = '',
array $highlight = [],
?string $message = null,
array $context = [],
?bool $log_error = null,
): void {
if ($log_error === null) {
$log_error = $this->log_error;
}
$original_level = $level;
$level = MessageLevel::fromName($level)->name;
// if not string set, write message string if set, else level/error id
if (empty($str)) {
$str = $message ?? 'L:' . $level . '|E:' . $error_id;
}
$this->error_str[] = [
'id' => $error_id,
'level' => $level,
'str' => $str,
'target' => $target,
'highlight' => $highlight,
];
// write to log for abort/crash
switch ($level) {
case 'error':
if ($log_error) {
$this->log->error($message ?? $str, array_merge([
'id' => $error_id,
'level' => $original_level,
], $context));
}
break;
case 'abort':
$this->log->critical($message ?? $str, array_merge([
'id' => $error_id,
'level' => $original_level,
], $context));
break;
case 'crash':
$this->log->alert($message ?? $str, array_merge([
'id' => $error_id,
'level' => $original_level,
], $context));
break;
case 'unknown':
$this->log->emergency($message ?? $str, array_merge([
'id' => $error_id,
'level' => $original_level,
], $context));
break;
}
}
/**
* pushes new error message into the error_str array
* Note, the parameter order is different and does not need an error id
* This is for backend alerts
*
* @param string $level error level (ok/warn/info/error)
* @param string $str error string
* @param string|null $error_id optional error id for precise error lookup
* @param string $target Alternate id name for output target on frontend
* @param array<string> $highlight Any additional error data as error OR
* highlight points for field highlights
* @param string|null $message If abort/crash, non localized $str
* @param array<mixed> $context Additionl info for abort/crash messages
* @param bool|null $log_error [=null] log level 'error' to error, if null use global,
* else set for this call only
*/
public function setMessage(
string $level,
string $str,
?string $error_id = null,
string $target = '',
array $highlight = [],
?string $message = null,
array $context = [],
?bool $log_error = null,
): void {
$this->setErrorMsg($error_id ?? '', $level, $str, $target, $highlight, $message, $context, $log_error);
}
// *********************************************************************
// GETTERS
// *********************************************************************
/**
* Returns the current set error content from setErrorMsg method
*
* @return array<int,array{id:string,level:string,str:string,target:string,highlight:string[]}> Error messages array
*/
public function getErrorMsg(): array
{
return $this->error_str;
}
/**
* Current set error ids
*
* @return array<string>
*/
public function getErrorIds(): array
{
return array_column($this->error_str, 'id');
}
/**
* Gets the LAST entry in the array list.
* If nothing found returns empty array set
*
* @return array{id:string,level:string,str:string,target:string,highlight:string[]} Error block
*/
public function getLastErrorMsg(): array
{
return $this->error_str[array_key_last($this->error_str)] ?? [
'level' => '',
'str' => '',
'id' => '',
'target' => '',
'highlight' => [],
];
}
// *********************************************************************
// FLAG SETTERS
// *********************************************************************
/**
* Set the log error flag
*
* @param bool $flag True to log level error too, False for do not (Default)
* @return void
*/
public function setFlagLogError(bool $flag): void
{
$this->log_error = $flag;
}
/**
* Get the current log error flag
*
* @return bool
*/
public function getFlagLogError(): bool
{
return $this->log_error;
}
}
// __END__

View File

@@ -113,17 +113,32 @@ enum Level: int
/**
* Returns true if the passed $level is higher or equal to $this
*
* @param Level $level
* @return bool
*/
public function includes(Level $level): bool
{
return $this->value <= $level->value;
}
/**
* If level is higher than set one
*
* @param Level $level
* @return bool
*/
public function isHigherThan(Level $level): bool
{
return $this->value > $level->value;
}
/**
* if level is lower than set one
*
* @param Level $level
* @return bool
*/
public function isLowerThan(Level $level): bool
{
return $this->value < $level->value;

View File

@@ -0,0 +1,84 @@
<?php // phpcs:disable Generic.Files.LineLength
/**
* AUTOR: Clemens Schwaighofer
* CREATED: 2023-09-08
* DESCRIPTION:
* Error message return levels
*/
declare(strict_types=1);
namespace CoreLibs\Logging\Logger;
enum MessageLevel: int
{
case ok = 100;
case info = 200;
case warn = 300;
case error = 400;
case abort = 500;
case crash = 550;
case unknown = 600;
/**
* @param string $name any string name, if not matching use unkown
* @return static
*/
public static function fromName(string $name): self
{
return match (strtolower($name)) {
'ok' => self::ok,
'info' => self::info,
'warn', 'warning' => self::warn,
'error' => self::error,
'abort' => self::abort,
'crash' => self::crash,
default => self::unknown,
};
}
/**
* @param int $value
* @return static
*/
public static function fromValue(int $value): self
{
return self::tryFrom($value) ?? self::unknown;
}
/**
* Returns true if the passed $level is higher or equal to $this
*
* @param MessageLevel $level
* @return bool
*/
public function includes(MessageLevel $level): bool
{
return $this->value <= $level->value;
}
/**
* If level is higher than set one
*
* @param MessageLevel $level
* @return bool
*/
public function isHigherThan(MessageLevel $level): bool
{
return $this->value > $level->value;
}
/**
* if level is lower than set one
*
* @param MessageLevel $level
* @return bool
*/
public function isLowerThan(MessageLevel $level): bool
{
return $this->value < $level->value;
}
}
// __END__

View File

@@ -23,7 +23,8 @@ class Image
* if empty ROOT is choosen
* @param string $cache_source cache path, if not given TMP is used
* @param bool $clear_cache if set to true, will create thumb all the tame
* @return string|false thumbnail name, or false for error
* @return string thumbnail name
* @throws \RuntimeException no ImageMagick convert command found
*/
public static function createThumbnail(
string $pic,
@@ -33,7 +34,7 @@ class Image
string $path = '',
string $cache_source = '',
bool $clear_cache = false
): string|false {
): string {
// get image type flags
$image_types = [
0 => 'UNKOWN-IMAGE',
@@ -41,7 +42,7 @@ class Image
2 => 'jpg',
3 => 'png'
];
$return_data = false;
$return_data = '';
$CONVERT = '';
// if CONVERT is not defined, abort
/** @phan-suppress-next-line PhanUndeclaredConstant */
@@ -49,7 +50,7 @@ class Image
/** @phan-suppress-next-line PhanUndeclaredConstant */
$CONVERT = CONVERT;
} else {
return $return_data;
throw new \RuntimeException('CONVERT set binary is not executable or CONVERT is not defined');
}
if (!empty($cache_source)) {
$tmp_src = $cache_source;
@@ -69,72 +70,7 @@ class Image
$pic = $tmp[(count($tmp) - 1)];
}
// does this picture exist and is it a picture
if (file_exists($filename) && is_file($filename)) {
[$width, $height, $type] = getimagesize($filename) ?: [0, 0, 0];
$convert_prefix = '';
$create_file = false;
$delete_filename = '';
// check if we can skip the PDF creation: if we have size, if do not have type, we assume type png
if (!$type) {
$check_thumb = $tmp_src . 'thumb_' . $pic . '_' . $size_x . 'x' . $size_y . '.' . $image_types[3];
if (!is_file($check_thumb)) {
$create_file = true;
} else {
$type = 3;
}
}
// if type is not in the list, but returns as PDF, we need to convert to JPEG before
if (!$type) {
$output = [];
$return = null;
// is this a PDF, if no, return from here with nothing
$convert_prefix = 'png:';
# TEMP convert to PNG, we then override the file name
$convert_string = $CONVERT . ' ' . $filename . ' ' . $convert_prefix . $filename . '_TEMP';
$status = exec($convert_string, $output, $return);
$filename .= '_TEMP';
// for delete, in case we need to glob
$delete_filename = $filename;
// find file, if we can't find base name, use -0 as the first one (ignore other pages in multiple ones)
if (!is_file($filename)) {
$filename .= '-0';
}
[$width, $height, $type] = getimagesize($filename) ?: [0, 0, 0];
}
// if no size given, set size to original
if (!$size_x || $size_x < 1) {
$size_x = $width;
}
if (!$size_y || $size_y < 1) {
$size_y = $height;
}
$thumb = 'thumb_' . $pic . '_' . $size_x . 'x' . $size_y . '.' . $image_types[$type];
$thumbnail = $tmp_src . $thumb;
// check if we already have this picture converted
if (!is_file($thumbnail) || $clear_cache == true) {
// convert the picture
if ($width > $size_x) {
$convert_string = $CONVERT . ' -geometry ' . $size_x . 'x ' . $filename . ' ' . $thumbnail;
$status = exec($convert_string, $output, $return);
// get the size of the converted data, if converted
if (is_file($thumbnail)) {
[$width, $height, $type] = getimagesize($thumbnail) ?: [0, 0, 0];
}
}
if ($height > $size_y) {
$convert_string = $CONVERT . ' -geometry x' . $size_y . ' ' . $filename . ' ' . $thumbnail;
$status = exec($convert_string, $output, $return);
}
}
if (!is_file($thumbnail)) {
copy($filename, $thumbnail);
}
$return_data = $thumb;
// if we have a delete filename, delete here with glob
if ($delete_filename) {
array_map('unlink', glob($delete_filename . '*') ?: []);
}
} else {
if (!file_exists($filename) || !is_file($filename)) {
if (!empty($dummy) && strstr($dummy, '/') === false) {
// check if we have the "dummy" image flag set
$filename = PICTURES . ICONS . strtoupper($dummy) . ".png";
@@ -142,11 +78,77 @@ class Image
if (!empty($dummy) && file_exists($filename) && is_file($filename)) {
$return_data = $filename;
} else {
$return_data = false;
throw new \Exception('Could not set dummy return file: ' . $dummy . ' in ' . $filename);
}
} else {
$filename = $dummy;
$return_data = $dummy;
}
return $return_data;
}
// resize image
[$width, $height, $type] = getimagesize($filename) ?: [0, 0, 0];
$convert_prefix = '';
$create_file = false;
$delete_filename = '';
// check if we can skip the PDF creation: if we have size, if do not have type, we assume type png
if (!$type) {
$check_thumb = $tmp_src . 'thumb_' . $pic . '_' . $size_x . 'x' . $size_y . '.' . $image_types[3];
if (!is_file($check_thumb)) {
$create_file = true;
} else {
$type = 3;
}
}
// if type is not in the list, but returns as PDF, we need to convert to JPEG before
if (!$type) {
$output = [];
$return = null;
// is this a PDF, if no, return from here with nothing
$convert_prefix = 'png:';
# TEMP convert to PNG, we then override the file name
$convert_string = $CONVERT . ' ' . $filename . ' ' . $convert_prefix . $filename . '_TEMP';
$status = exec($convert_string, $output, $return);
$filename .= '_TEMP';
// for delete, in case we need to glob
$delete_filename = $filename;
// find file, if we can't find base name, use -0 as the first one (ignore other pages in multiple ones)
if (!is_file($filename)) {
$filename .= '-0';
}
[$width, $height, $type] = getimagesize($filename) ?: [0, 0, 0];
}
// if no size given, set size to original
if (!$size_x || $size_x < 1) {
$size_x = $width;
}
if (!$size_y || $size_y < 1) {
$size_y = $height;
}
$thumb = 'thumb_' . $pic . '_' . $size_x . 'x' . $size_y . '.' . $image_types[$type];
$thumbnail = $tmp_src . $thumb;
// check if we already have this picture converted
if (!is_file($thumbnail) || $clear_cache == true) {
// convert the picture
if ($width > $size_x) {
$convert_string = $CONVERT . ' -geometry ' . $size_x . 'x ' . $filename . ' ' . $thumbnail;
$status = exec($convert_string, $output, $return);
// get the size of the converted data, if converted
if (is_file($thumbnail)) {
[$width, $height, $type] = getimagesize($thumbnail) ?: [0, 0, 0];
}
}
if ($height > $size_y) {
$convert_string = $CONVERT . ' -geometry x' . $size_y . ' ' . $filename . ' ' . $thumbnail;
$status = exec($convert_string, $output, $return);
}
}
if (!is_file($thumbnail)) {
copy($filename, $thumbnail);
}
$return_data = $thumb;
// if we have a delete filename, delete here with glob
if ($delete_filename) {
array_map('unlink', glob($delete_filename . '*') ?: []);
}
return $return_data;
}
@@ -173,7 +175,9 @@ class Image
* set to false to not use (default true)
* to use quick but less nice version
* @param int $jpeg_quality default 80, set image quality for jpeg only
* @return string|false thumbnail with path
* @return string thumbnail with path
* @throws \UnexpectedValueException input values for filename or cache_folder are wrong
* @throws \RuntimeException convert (gd) failed
*/
public static function createThumbnailSimple(
string $filename,
@@ -185,8 +189,9 @@ class Image
bool $use_cache = true,
bool $high_quality = true,
int $jpeg_quality = 80
): string|false {
): string {
$thumbnail = false;
$exception_message = 'Could not create thumbnail';
// $this->debug('IMAGE PREPARE', "FILE: $filename (exists "
// .(string)file_exists($filename)."), WIDTH: $thumb_width, HEIGHT: $thumb_height");
if (
@@ -210,12 +215,17 @@ class Image
}
// check that input image exists and is either jpeg or png
// also fail if the basic CACHE folder does not exist at all
if (
!file_exists($filename) ||
!is_dir($cache_folder) ||
!is_writable($cache_folder)
) {
return $thumbnail;
if (!file_exists($filename)) {
// return $thumbnail;
throw new \UnexpectedValueException('Missing image file: ' . $filename);
}
if (!is_dir($cache_folder)) {
// return $thumbnail;
throw new \UnexpectedValueException('Cache folder is not a directory: ' . $cache_folder);
}
if (!is_writable($cache_folder)) {
// return $thumbnail;
throw new \UnexpectedValueException('Cache folder is not writeable: ' . $cache_folder);
}
// $this->debug('IMAGE PREPARE', "FILENAME OK, THUMB WIDTH/HEIGHT OK");
[$inc_width, $inc_height, $img_type] = getimagesize($filename) ?: [0, 0, null];
@@ -280,12 +290,18 @@ class Image
// image, copy source image, offset in image, source x/y, new size, source image size
$thumb = imagecreatetruecolor($thumb_width_r, $thumb_height_r);
if ($thumb === false) {
return false;
throw new \RuntimeException(
'imagecreatetruecolor failed: ' . $thumbnail . ', ' . $filename,
1
);
}
if ($img_type == IMAGETYPE_PNG) {
$imagecolorallocatealpha = imagecolorallocatealpha($thumb, 0, 0, 0, 127);
if ($imagecolorallocatealpha === false) {
return false;
throw new \RuntimeException(
'imagecolorallocatealpha failed: ' . $thumbnail . ', ' . $filename,
2
);
}
// preservere transaprency
imagecolortransparent(
@@ -347,7 +363,10 @@ class Image
imagedestroy($source);
imagedestroy($thumb);
} else {
$thumbnail = false;
throw new \RuntimeException(
'Invalid source image file. Only JPEG/PNG are allowed: ' . $filename,
3
);
}
}
} else {
@@ -388,14 +407,20 @@ class Image
}
$thumb = imagecreatetruecolor($thumb_width, $thumb_height);
if ($thumb === false) {
return false;
throw new \RuntimeException(
'imagecreatetruecolor dummy failed: ' . $thumbnail . ', ' . $filename,
3
);
}
// add outside border px = 5% (rounded up)
// eg 50px -> 2.5px
$gray = imagecolorallocate($thumb, 200, 200, 200);
$white = imagecolorallocate($thumb, 255, 255, 255);
if ($gray === false || $white === false) {
return false;
throw new \RuntimeException(
'imagecolorallocate/imagecolorallocate dummy failed: ' . $thumbnail . ', ' . $filename,
2
);
}
// fill gray background
imagefill($thumb, 0, 0, $gray);
@@ -430,7 +455,11 @@ class Image
// add web path
$thumbnail = $thumbnail_web_path . $thumbnail;
}
// either return false or the thumbnail name + output path web
// if still false -> throw exception
if ($thumbnail === false) {
throw new \RuntimeException($exception_message);
}
// else return the thumbnail name + output path web
return $thumbnail;
}

View File

@@ -27,6 +27,7 @@ class SymmetricEncryption
* @param string $message Message to encrypt
* @param string $key Encryption key (as hex string)
* @return string
* @throws \Exception
* @throws \RangeException
*/
public static function encrypt(string $message, string $key): string
@@ -34,7 +35,7 @@ class SymmetricEncryption
try {
$key = CreateKey::hex2bin($key);
} catch (SodiumException $e) {
throw new \Exception('Invalid hex key');
throw new \UnexpectedValueException('Invalid hex key');
}
if (mb_strlen($key, '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
throw new \RangeException(
@@ -84,10 +85,10 @@ class SymmetricEncryption
$key
);
} catch (SodiumException $e) {
throw new \Exception('Invalid ciphertext (too short)');
throw new \UnexpectedValueException('Invalid ciphertext (too short)');
}
if (!is_string($plain)) {
throw new \Exception('Invalid Key');
throw new \UnexpectedValueException('Invalid Key');
}
sodium_memzero($ciphertext);
sodium_memzero($key);

View File

@@ -57,8 +57,10 @@ return array(
'CoreLibs\\Language\\Core\\StringReader' => $baseDir . '/lib/CoreLibs/Language/Core/StringReader.php',
'CoreLibs\\Language\\GetLocale' => $baseDir . '/lib/CoreLibs/Language/GetLocale.php',
'CoreLibs\\Language\\L10n' => $baseDir . '/lib/CoreLibs/Language/L10n.php',
'CoreLibs\\Logging\\ErrorMessage' => $baseDir . '/lib/CoreLibs/Logging/ErrorMessage.php',
'CoreLibs\\Logging\\Logger\\Flag' => $baseDir . '/lib/CoreLibs/Logging/Logger/Flag.php',
'CoreLibs\\Logging\\Logger\\Level' => $baseDir . '/lib/CoreLibs/Logging/Logger/Level.php',
'CoreLibs\\Logging\\Logger\\MessageLevel' => $baseDir . '/lib/CoreLibs/Logging/Logger/MessageLevel.php',
'CoreLibs\\Logging\\Logging' => $baseDir . '/lib/CoreLibs/Logging/Logging.php',
'CoreLibs\\Output\\Form\\Elements' => $baseDir . '/lib/CoreLibs/Output/Form/Elements.php',
'CoreLibs\\Output\\Form\\Generate' => $baseDir . '/lib/CoreLibs/Output/Form/Generate.php',

View File

@@ -108,8 +108,10 @@ class ComposerStaticInit10fe8fe2ec4017b8644d2b64bcf398b9
'CoreLibs\\Language\\Core\\StringReader' => __DIR__ . '/../..' . '/lib/CoreLibs/Language/Core/StringReader.php',
'CoreLibs\\Language\\GetLocale' => __DIR__ . '/../..' . '/lib/CoreLibs/Language/GetLocale.php',
'CoreLibs\\Language\\L10n' => __DIR__ . '/../..' . '/lib/CoreLibs/Language/L10n.php',
'CoreLibs\\Logging\\ErrorMessage' => __DIR__ . '/../..' . '/lib/CoreLibs/Logging/ErrorMessage.php',
'CoreLibs\\Logging\\Logger\\Flag' => __DIR__ . '/../..' . '/lib/CoreLibs/Logging/Logger/Flag.php',
'CoreLibs\\Logging\\Logger\\Level' => __DIR__ . '/../..' . '/lib/CoreLibs/Logging/Logger/Level.php',
'CoreLibs\\Logging\\Logger\\MessageLevel' => __DIR__ . '/../..' . '/lib/CoreLibs/Logging/Logger/MessageLevel.php',
'CoreLibs\\Logging\\Logging' => __DIR__ . '/../..' . '/lib/CoreLibs/Logging/Logging.php',
'CoreLibs\\Output\\Form\\Elements' => __DIR__ . '/../..' . '/lib/CoreLibs/Output/Form/Elements.php',
'CoreLibs\\Output\\Form\\Generate' => __DIR__ . '/../..' . '/lib/CoreLibs/Output/Form/Generate.php',