From 018b9ce98156ee87d49ff796b949cbbd25261376 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sun, 10 Sep 2023 18:58:35 +0000 Subject: [PATCH] update --- Algorithm/Clustering/DBSCAN.php | 19 +- Algorithm/Clustering/MeanShift.php | 4 +- Algorithm/Clustering/PointInterface.php | 5 +- Algorithm/Frequency/Apriori.php | 2 +- Algorithm/Graph/MarkovChain.php | 29 +++ .../Optimization/GeneticOptimization.php | 4 +- Algorithm/Optimization/TabuSearch.php | 2 +- Algorithm/Rating/BradleyTerry.php | 2 +- Algorithm/Rating/Glicko1.php | 7 +- Algorithm/Rating/Glicko2.php | 6 +- Api/CreditRating/CreditSafe.php | 4 +- .../BayesianPersonalizedRanking.php | 11 +- DataStorage/Session/JWT.php | 22 +- Event/EventManager.php | 10 +- Localization/ISO3166Trait.php | 1 + Math/Matrix/Vector.php | 4 +- Math/Topology/MetricsND.php | 6 +- Message/ResponseAbstract.php | 223 +++++++++++++++++- Module/ModuleAbstract.php | 142 +++++------ System/File/FileUtils.php | 4 +- Utils/ArrayUtils.php | 4 +- Utils/Formatter/HtmlFormatter.php | 4 +- Utils/ImageUtils.php | 6 +- 23 files changed, 388 insertions(+), 133 deletions(-) diff --git a/Algorithm/Clustering/DBSCAN.php b/Algorithm/Clustering/DBSCAN.php index 72f3a82fb..09f011ef9 100644 --- a/Algorithm/Clustering/DBSCAN.php +++ b/Algorithm/Clustering/DBSCAN.php @@ -166,8 +166,8 @@ final class DBSCAN /** * Find neighbors of a point * - * @param PointInterface $point Base point for potential neighbors - * @param float $epsion Max distance to neighbor + * @param PointInterface $point Base point for potential neighbors + * @param float $epsilon Max distance to neighbor * * @return array * @@ -210,6 +210,7 @@ final class DBSCAN } } + /** @var float[] $distances */ return $distances; } @@ -228,10 +229,7 @@ final class DBSCAN foreach ($this->clusters as $c => $cluster) { $points = []; foreach ($cluster as $p) { - $points[] = [ - 'x' => \reset($p->coordinates), - 'y' => \end($p->coordinates), - ]; + $points[] = $p->coordinates; } $this->convexHulls[$c] = MonotoneChain::createConvexHull($points); @@ -239,14 +237,7 @@ final class DBSCAN } foreach ($this->convexHulls as $c => $hull) { - if (Polygon::isPointInPolygon( - [ - 'x' => \reset($point->coordinates), - 'y' => \end($point->coordinates), - ], - $hull - ) <= 0 - ) { + if (Polygon::isPointInPolygon($point->coordinates, $hull) <= 0) { return $c; } } diff --git a/Algorithm/Clustering/MeanShift.php b/Algorithm/Clustering/MeanShift.php index e299e27be..3db459b0c 100644 --- a/Algorithm/Clustering/MeanShift.php +++ b/Algorithm/Clustering/MeanShift.php @@ -239,8 +239,8 @@ final class MeanShift /** * Find the closest cluster/group of a point * - * @param PointInterface $point Point to find the cluster for - * @param PointInterface[] $group Clusters + * @param PointInterface $point Point to find the cluster for + * @param array $groups Clusters * * @return int * diff --git a/Algorithm/Clustering/PointInterface.php b/Algorithm/Clustering/PointInterface.php index 83d20e1d2..666aa0ff0 100755 --- a/Algorithm/Clustering/PointInterface.php +++ b/Algorithm/Clustering/PointInterface.php @@ -18,8 +18,9 @@ namespace phpOMS\Algorithm\Clustering; /** * Point interface. * - * @property int $group Group - * @property string $name Name + * @property int $group Group + * @property string $name Name + * @property array $coordinates Coordinates * * @package phpOMS\Algorithm\Clustering; * @license OMS License 2.0 diff --git a/Algorithm/Frequency/Apriori.php b/Algorithm/Frequency/Apriori.php index 3a524ca2b..3a4749ab4 100644 --- a/Algorithm/Frequency/Apriori.php +++ b/Algorithm/Frequency/Apriori.php @@ -72,7 +72,7 @@ final class Apriori * * @param array $sets Sets of a set (e.g. [[1,2,3,4], [1,2], [1]]) * - * @return array + * @return array * * @since 1.0.0 */ diff --git a/Algorithm/Graph/MarkovChain.php b/Algorithm/Graph/MarkovChain.php index e69de29bb..4c986055e 100644 --- a/Algorithm/Graph/MarkovChain.php +++ b/Algorithm/Graph/MarkovChain.php @@ -0,0 +1,29 @@ + $parameters) { + $fitnesses[$key] = ($fitness)($parameters); } \asort($fitnesses); diff --git a/Algorithm/Optimization/TabuSearch.php b/Algorithm/Optimization/TabuSearch.php index 669e4c101..9c92098f8 100644 --- a/Algorithm/Optimization/TabuSearch.php +++ b/Algorithm/Optimization/TabuSearch.php @@ -81,7 +81,7 @@ class TabuSearch for ($i = 0; $i < $iterations; ++$i) { $neighbors = []; - for ($i = 0; $i < $tabuListSize; ++$i) { + for ($j = 0; $j < $tabuListSize; ++$j) { $neighbor = ($neighbor)($currentSolution); $neighbors[] = $neighbor; } diff --git a/Algorithm/Rating/BradleyTerry.php b/Algorithm/Rating/BradleyTerry.php index ed3ab4db1..816c518f7 100644 --- a/Algorithm/Rating/BradleyTerry.php +++ b/Algorithm/Rating/BradleyTerry.php @@ -20,8 +20,8 @@ namespace phpOMS\Algorithm\Rating; * @package phpOMS\Algorithm\Rating * @license OMS License 2.0 * @link https://jingga.app - * @since 1.0.0 * @see https://en.wikipedia.org/wiki/Bradley%E2%80%93Terry_model + * @since 1.0.0 */ final class BradleyTerry { diff --git a/Algorithm/Rating/Glicko1.php b/Algorithm/Rating/Glicko1.php index 7fdc7ba47..1c01ce197 100644 --- a/Algorithm/Rating/Glicko1.php +++ b/Algorithm/Rating/Glicko1.php @@ -61,7 +61,7 @@ final class Glicko1 * * @see calculateC(); * - * @var int + * @var float * @since 1.0.0 */ public float $DEFAULT_C = 34.6; @@ -127,7 +127,6 @@ final class Glicko1 ) : array { // Step 1: - $s = []; $E = []; $gRD = []; @@ -145,8 +144,8 @@ final class Glicko1 // Step 2: foreach ($oElo as $id => $e) { $gRD_t = 1 / (\sqrt(1 + 3 * self::Q * self::Q * $oRd[$id] * $oRd[$id] / (\M_PI * \M_PI))); - $gRD[] = $gRD_t; - $E[] = 1 / (1 + \pow(10, $gRD_t * ($elo - $e) / -400)); + $gRD[$id] = $gRD_t; + $E[$id] = 1 / (1 + \pow(10, $gRD_t * ($elo - $e) / -400)); } $d = 0; diff --git a/Algorithm/Rating/Glicko2.php b/Algorithm/Rating/Glicko2.php index 5f2144947..1abea5668 100644 --- a/Algorithm/Rating/Glicko2.php +++ b/Algorithm/Rating/Glicko2.php @@ -123,13 +123,13 @@ final class Glicko2 // Step 1: $g = []; - foreach ($oRd as $rd) { - $g[] = 1 / \sqrt(1 + 3 * $rd * $rd / (\M_PI * \M_PI)); + foreach ($oRd as $idx => $rd) { + $g[$idx] = 1 / \sqrt(1 + 3 * $rd * $rd / (\M_PI * \M_PI)); } $E = []; foreach ($oElo as $idx => $elo) { - $E[] = 1 / (1 + \exp(-$g[$idx] * ($elo - $elo))); + $E[$idx] = 1 / (1 + \exp(-$g[$idx] * ($elo - $elo))); } $v = 0; diff --git a/Api/CreditRating/CreditSafe.php b/Api/CreditRating/CreditSafe.php index bd2b6df77..0361402d1 100644 --- a/Api/CreditRating/CreditSafe.php +++ b/Api/CreditRating/CreditSafe.php @@ -51,7 +51,7 @@ final class CreditSafe implements CreditRatingInterface $response = Rest::request($request); return $response->header->status === 200 - ? ($response->get('token') ?? '') + ? ($response->getDataString('token') ?? '') : ''; } @@ -212,7 +212,7 @@ final class CreditSafe implements CreditRatingInterface $response = Rest::request($request); - return $response->get('orderID') ?? ''; + return $response->getDataString('orderID') ?? ''; } /** diff --git a/Business/Recommendation/BayesianPersonalizedRanking.php b/Business/Recommendation/BayesianPersonalizedRanking.php index 8ad29da1a..93d5e6d33 100644 --- a/Business/Recommendation/BayesianPersonalizedRanking.php +++ b/Business/Recommendation/BayesianPersonalizedRanking.php @@ -20,8 +20,8 @@ namespace phpOMS\Business\Recommendation; * @package phpOMS\Business\Recommendation * @license OMS License 2.0 * @link https://jingga.app - * @since 1.0.0 * @see https://arxiv.org/ftp/arxiv/papers/1205/1205.2618.pdf + * @since 1.0.0 * * @todo Implement, current implementation probably wrong */ @@ -40,13 +40,15 @@ final class BayesianPersonalizedRanking // num_factors determines the dimensionality of the latent factor space. // learning_rate controls the step size for updating the latent factors during optimization. // regularization prevents overfitting by adding a penalty for large parameter values. - public function __construct(int $numFactors, float $learningRate, float $regularization) { + public function __construct(int $numFactors, float $learningRate, float $regularization) + { $this->numFactors = $numFactors; $this->learningRate = $learningRate; $this->regularization = $regularization; } - private function generateRandomFactors() { + private function generateRandomFactors() + { $factors = []; for ($i = 0; $i < $this->numFactors; ++$i) { $factors[$i] = \mt_rand() / \mt_getrandmax(); @@ -67,7 +69,8 @@ final class BayesianPersonalizedRanking return $score; } - public function updateFactors($userId, $posItemId, $negItemId) : void { + public function updateFactors($userId, $posItemId, $negItemId) : void + { if (!isset($this->userFactors[$userId])) { $this->userFactors[$userId] = $this->generateRandomFactors(); } diff --git a/DataStorage/Session/JWT.php b/DataStorage/Session/JWT.php index 01f2e2dec..f629efde9 100644 --- a/DataStorage/Session/JWT.php +++ b/DataStorage/Session/JWT.php @@ -35,8 +35,8 @@ final class JWT /** * Create JWT signature part * - * @param string $secret Secret (at least 256 bit) - * @param array{alg:string, typ:string} $header Header + * @param string $secret Secret (at least 256 bit) + * @param array{alg:string, typ:string} $header Header * @param array{sub:string, ?uid:string, ?name:string, iat:string} $payload Payload * * @return string hmac(Header64 . Payload64, secret) @@ -60,15 +60,15 @@ final class JWT /** * Create JWT token * - * @param string $secret Secret (at least 256 bit) - * @param array{alg:string, typ:string} $header Header + * @param string $secret Secret (at least 256 bit) + * @param array{alg:string, typ:string} $header Header * @param array{sub:string, ?uid:string, ?name:string, iat:string} $payload Payload * * @return string Header64 . Payload64 . hmac(Header64 . Payload64, secret) * * @since 1.0.0 */ - public static function createJWT(string $secret, array $header = [], array $payload = []) : string + public static function createJWT(string $secret, array $header, array $payload) : string { $header64 = Base64Url::encode(\json_encode($header)); $payload64 = Base64Url::encode(\json_encode($payload)); @@ -94,11 +94,7 @@ final class JWT return []; } - try { - return \json_decode(Base64Url::decode($explode[0]), true); - } catch (\Throwable $_) { - return []; - } + return \json_decode(Base64Url::decode($explode[0]), true); } /** @@ -118,11 +114,7 @@ final class JWT return []; } - try { - return \json_decode(Base64Url::decode($explode[1]), true); - } catch (\Throwable $_) { - return []; - } + return \json_decode(Base64Url::decode($explode[1]), true); } /** diff --git a/Event/EventManager.php b/Event/EventManager.php index ac9cf84e2..164e43fab 100755 --- a/Event/EventManager.php +++ b/Event/EventManager.php @@ -171,11 +171,15 @@ final class EventManager implements \Countable */ public function triggerSimilar(string $group, string $id = '', mixed $data = null) : bool { + if (empty($this->callbacks)) { + return false; + } + $groupIsRegex = \stripos($group, '/') === 0; $idIsRegex = \stripos($id, '/') === 0; $groups = []; - foreach ($this->groups as $groupName => $value) { + foreach ($this->groups as $groupName => $_) { $groupNameIsRegex = \stripos($groupName, '/') === 0; if ($groupIsRegex) { @@ -189,8 +193,8 @@ final class EventManager implements \Countable } } - foreach ($groups as $groupName => $groupValues) { - foreach ($this->groups[$groupName] as $idName => $value) { + foreach ($groups as $groupName => $_) { + foreach ($this->groups[$groupName] as $idName => $_2) { $idNameIsRegex = \stripos($idName, '/') === 0; if ($idIsRegex) { diff --git a/Localization/ISO3166Trait.php b/Localization/ISO3166Trait.php index d47f889f8..0b2451a1c 100644 --- a/Localization/ISO3166Trait.php +++ b/Localization/ISO3166Trait.php @@ -35,6 +35,7 @@ trait ISO3166Trait */ public static function getBy2Code(string $code) : mixed { + /** @var string $code3 */ $code3 = ISO3166TwoEnum::getName($code); return self::getByName($code3); diff --git a/Math/Matrix/Vector.php b/Math/Matrix/Vector.php index afae98a93..662b1f614 100755 --- a/Math/Matrix/Vector.php +++ b/Math/Matrix/Vector.php @@ -99,7 +99,7 @@ final class Vector extends Matrix */ public function cosine(self $v) : float { - $dotProduct = 0; + $dotProduct = 0.0; for ($i = 0; $i < $this->m; ++$i) { $dotProduct += $this->matrix[$i][0] * $v[$i]; } @@ -110,7 +110,7 @@ final class Vector extends Matrix } $magnitude1 = \sqrt($sumOfSquares); - $sumOfSquares = 0; + $sumOfSquares = 0.0; foreach ($v->matrix as $value) { $sumOfSquares += $value[0] * $value[0]; } diff --git a/Math/Topology/MetricsND.php b/Math/Topology/MetricsND.php index 587cd8304..4e5548d77 100755 --- a/Math/Topology/MetricsND.php +++ b/Math/Topology/MetricsND.php @@ -107,12 +107,12 @@ final class MetricsND */ public static function cosine(array $a, array $b) : float { - if (\count($a) !== \count($b)) { + if (($length = \count($a)) !== \count($b)) { throw new InvalidDimensionException(\count($a) . 'x' . \count($b)); } $dotProduct = 0; - for ($i = 0; $i < \count($a); ++$i) { + for ($i = 0; $i < $length; ++$i) { $dotProduct += $a[$i] * $b[$i]; } @@ -128,7 +128,7 @@ final class MetricsND } $magnitude2 = \sqrt($sumOfSquares); - if ($magnitude1 === 0 || $magnitude2 === 0) { + if ($magnitude1 == 0 || $magnitude2 == 0) { return \PHP_FLOAT_MAX; } diff --git a/Message/ResponseAbstract.php b/Message/ResponseAbstract.php index 96863b00a..28537b59a 100755 --- a/Message/ResponseAbstract.php +++ b/Message/ResponseAbstract.php @@ -45,15 +45,232 @@ abstract class ResponseAbstract implements \JsonSerializable, MessageInterface /** * Get response by ID. * - * @param mixed $id Response ID + * @param mixed $key Response ID * * @return mixed * * @since 1.0.0 */ - public function get(mixed $id) : mixed + public function get(mixed $key, string $type = null) : mixed { - return $this->data[$id] ?? null; + if ($key === null) { + return $this->data; + } + + $key = \is_string($key) ? \mb_strtolower($key) : $key; + if (!isset($this->data[$key])) { + return null; + } + + switch ($type) { + case null: + return $this->data[$key]; + case 'int': + return (int) $this->data[$key]; + case 'string': + return (string) $this->data[$key]; + case 'float': + return (float) $this->data[$key]; + case 'bool': + return (bool) $this->data[$key]; + case 'DateTime': + return new \DateTime((string) $this->data[$key]); + default: + return $this->data[$key]; + } + } + + /** + * Get data. + * + * @param string $key Data key + * + * @return null|string + * + * @since 1.0.0 + */ + public function getDataString(string $key) : ?string + { + $key = \mb_strtolower($key); + + if (($this->data[$key] ?? '') === '') { + return null; + } + + return (string) $this->data[$key]; + } + + /** + * Get data. + * + * @param string $key Data key + * + * @return null|int + * + * @since 1.0.0 + */ + public function getDataInt(string $key) : ?int + { + $key = \mb_strtolower($key); + + if (($this->data[$key] ?? '') === '') { + return null; + } + + return (int) $this->data[$key]; + } + + /** + * Get data. + * + * @param string $key Data key + * + * @return null|float + * + * @since 1.0.0 + */ + public function getDataFloat(string $key) : ?float + { + $key = \mb_strtolower($key); + + if (($this->data[$key] ?? '') === '') { + return null; + } + + return (float) $this->data[$key]; + } + + /** + * Get data. + * + * @param string $key Data key + * + * @return null|bool + * + * @since 1.0.0 + */ + public function getDataBool(string $key) : ?bool + { + $key = \mb_strtolower($key); + + if (($this->data[$key] ?? '') === '') { + return null; + } + + return (bool) $this->data[$key]; + } + + /** + * Get data. + * + * @param string $key Data key + * + * @return null|\DateTime + * + * @since 1.0.0 + */ + public function getDataDateTime(string $key) : ?\DateTime + { + $key = \mb_strtolower($key); + + return empty($this->data[$key] ?? null) + ? null + : new \DateTime((string) $this->data[$key]); + } + + /** + * Get data. + * + * @param string $key Data key + * + * @return array + * + * @since 1.0.0 + */ + public function getDataJson(string $key) : array + { + $key = \mb_strtolower($key); + + if (($this->data[$key] ?? '') === '') { + return []; + } + + $json = \json_decode($this->data[$key], true); /** @phpstan-ignore-line */ + + return \is_array($json) ? $json : []; + } + + /** + * Get data. + * + * @param string $key Data key + * @param string $delim Data delimiter + * + * @return array + * + * @since 1.0.0 + */ + public function getDataList(string $key, string $delim = ',') : array + { + $key = \mb_strtolower($key); + + if (($this->data[$key] ?? '') === '') { + return []; + } + + /* @phpstan-ignore-next-line */ + $list = \explode($delim, $this->data[$key]); + + if ($list === false) { + return []; // @codeCoverageIgnore + } + + foreach ($list as $i => $e) { + $list[$i] = \trim($e); + } + + return $list; + } + + /** + * Get data based on wildcard. + * + * @param string $regex Regex data key + * + * @return array + * + * @since 1.0.0 + */ + public function getLike(string $regex) : array + { + $data = []; + foreach ($this->data as $key => $value) { + if (\preg_match('/' . $regex . '/', (string) $key) === 1) { + $data[$key] = $value; + } + } + + return $data; + } + + /** + * Check if has data. + * + * The following empty values are considered as not set (null, '', 0) + * + * @param string $key Data key + * + * @return bool + * + * @since 1.0.0 + */ + public function hasData(string $key) : bool + { + $key = \mb_strtolower($key); + + return isset($this->data[$key]) + && $this->data[$key] !== '' + && $this->data[$key] !== null; } /** diff --git a/Module/ModuleAbstract.php b/Module/ModuleAbstract.php index dd24377d1..74f99cdcf 100755 --- a/Module/ModuleAbstract.php +++ b/Module/ModuleAbstract.php @@ -697,6 +697,8 @@ abstract class ModuleAbstract * * @return void * + * @todo find a way to offload this to the cli in a different process (same for other similar functions) + * * @since 1.0.0 */ protected function createModel(int $account, mixed $obj, string | \Closure $mapper, string $trigger, string $ip) : void @@ -712,17 +714,18 @@ abstract class ModuleAbstract $mapper(); } - $this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', - [ - $account, - null, $obj, - StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger, - static::NAME, - (string) $id, - null, - $ip, - ] - ); + $data = [ + $account, + null, $obj, + StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger, + static::NAME, + (string) $id, + null, + $ip, + ]; + + $this->app->moduleManager->get('Auditor', 'Api')->eventLogCreate(...$data); + $this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data); } /** @@ -756,17 +759,18 @@ abstract class ModuleAbstract $mapper(); } - $this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', - [ - $account, - null, $obj, - StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger, - static::NAME, - (string) $id, - null, - $ip, - ] - ); + $data = [ + $account, + null, $obj, + StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger, + static::NAME, + (string) $id, + null, + $ip, + ]; + + $this->app->moduleManager->get('Auditor', 'Api')->eventLogCreate(...$data); + $this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data); } } @@ -801,17 +805,18 @@ abstract class ModuleAbstract $mapper(); } - $this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', - [ - $account, - $old, $new, - StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger, - static::NAME, - (string) $id, - null, - $ip, - ] - ); + $data = [ + $account, + $old, $new, + StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger, + static::NAME, + (string) $id, + null, + $ip, + ]; + + $this->app->moduleManager->get('Auditor', 'Api')->eventLogUpdate(...$data); + $this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data); } /** @@ -844,17 +849,18 @@ abstract class ModuleAbstract $mapper(); } - $this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', - [ - $account, - $obj, null, - StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger, - static::NAME, - (string) $id, - null, - $ip, - ] - ); + $data = [ + $account, + $obj, null, + StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger, + static::NAME, + (string) $id, + null, + $ip, + ]; + + $this->app->moduleManager->get('Auditor', 'Api')->eventLogDelete(...$data); + $this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data); } /** @@ -890,17 +896,19 @@ abstract class ModuleAbstract $this->app->eventManager->triggerSimilar('PRE:Module:' . $trigger, '', $rel1); $mapper::writer()->createRelationTable($field, \is_array($rel2) ? $rel2 : [$rel2], $rel1); - $this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', - [ - $account, - '', [$rel1 => $rel2], - StringUtils::intHash($mapper), $trigger, - static::NAME, - null, - null, - $ip, - ] - ); + + $data = [ + $account, + '', [$rel1 => $rel2], + StringUtils::intHash($mapper), $trigger, + static::NAME, + null, + null, + $ip, + ]; + + $this->app->moduleManager->get('Auditor', 'Api')->eventLogRelationCreate(...$data); + $this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data); } /** @@ -928,16 +936,18 @@ abstract class ModuleAbstract $this->app->eventManager->triggerSimilar('PRE:Module:' . $trigger, '', $rel1); $mapper::remover()->deleteRelationTable($field, \is_array($rel2) ? $rel2 : [$rel2], $rel1); - $this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', - [ - $account, - [$rel1 => $rel2], '', - StringUtils::intHash($mapper), $trigger, - static::NAME, - null, - null, - $ip, - ] - ); + + $data = [ + $account, + [$rel1 => $rel2], '', + StringUtils::intHash($mapper), $trigger, + static::NAME, + null, + null, + $ip, + ]; + + $this->app->moduleManager->get('Auditor', 'Api')->eventLogRelationDelete(...$data); + $this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data); } } diff --git a/System/File/FileUtils.php b/System/File/FileUtils.php index e2993b861..24c3c3266 100755 --- a/System/File/FileUtils.php +++ b/System/File/FileUtils.php @@ -293,8 +293,8 @@ final class FileUtils public static function makeSafeFileName(string $name) : string { $name = \preg_replace("/[^A-Za-z0-9\-_.]/", '_', $name); - $name = \preg_replace("/_+/", '_', $name); - $name = \trim($name, '_'); + $name = \preg_replace("/_+/", '_', $name ?? ''); + $name = \trim($name ?? '', '_'); $name = \strtolower($name); return $name; diff --git a/Utils/ArrayUtils.php b/Utils/ArrayUtils.php index fcf808ead..e704f4b2a 100755 --- a/Utils/ArrayUtils.php +++ b/Utils/ArrayUtils.php @@ -319,7 +319,9 @@ final class ArrayUtils return null; } - return \trim($args[(int) $key + 1], '" '); + $value = $args[(int) $key + 1]; + + return \is_string($value) ? \trim($value, '" ') : $value; } /** diff --git a/Utils/Formatter/HtmlFormatter.php b/Utils/Formatter/HtmlFormatter.php index f37eabdf1..3cb6bbf79 100644 --- a/Utils/Formatter/HtmlFormatter.php +++ b/Utils/Formatter/HtmlFormatter.php @@ -42,6 +42,8 @@ class HtmlFormatter $dom->preserveWhiteSpace = false; $dom->formatOutput = true; - return $dom->saveXML($dom->documentElement); + $formatted = $dom->saveXML($dom->documentElement); + + return $formatted === false ? '' : $formatted; } } diff --git a/Utils/ImageUtils.php b/Utils/ImageUtils.php index 1376f0190..72d596ad2 100755 --- a/Utils/ImageUtils.php +++ b/Utils/ImageUtils.php @@ -312,13 +312,17 @@ final class ImageUtils $color1Avg = self::getAverageColor($src1, $i, $j, $imageDim2[0], $imageDim2[1], $diffArea); $color2Avg = self::getAverageColor($src2, $i, $j, $newDim[0], $newDim[1], $diffArea); - $color1 = \imagecolorat($src1, $i, $j); + //$color1 = \imagecolorat($src1, $i, $j); $color2 = \imagecolorat($src2, $i, $j); if (\abs($color1Avg - $color2Avg) / $color1Avg > 0.05 && $color1Avg > 0 && $color2Avg > 0) { ++$difference; if ($diff === 0) { + if ($color2 === false) { + continue; + } + /** @var \GdImage $dst */ \imagesetpixel($dst, $i, $j, $color2); } elseif ($diff === 1) {