Skip to content

Commit 535b539

Browse files
melhorias e adição de novas funcionalidades
1 parent f08188c commit 535b539

8 files changed

Lines changed: 337 additions & 27 deletions

File tree

README.md

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,21 @@ A complete library, with PSR standard and guarantee of all methods unit tested b
99
- Validate Data in General
1010
- Validate Upload Files
1111

12+
## Table of Contents
13+
14+
- [Installation](#installation)
15+
- [Data Validation](#data-validation-example)
16+
- [File Upload Validation](#validating-files-upload)
17+
- [Validation Types](#validation-types-validators)
18+
- [Custom Messages](#defining-custom-message)
19+
- [Formatting](#formatting-examples)
20+
- [Comparisons](#comparisons-examples)
21+
- [Validations Methods](#validations-in-the-form-of-methods)
22+
- [Generation Utilities](#generation-utilities)
23+
- [Arrays Manipulation](#manipulate-arrays)
24+
- [Utilities](#utilities)
25+
- [CI/CD Coverage](#check-the-minimum-coverage-of-cicd-unit-tests-using-phpunit)
26+
1227
## Installation
1328

1429
Install using Composer:
@@ -20,7 +35,7 @@ composer require brunoconte3/dev-utils
2035
Or add to your `composer.json`:
2136

2237
```json
23-
"brunoconte3/dev-utils": "2.12.0"
38+
"brunoconte3/dev-utils": "2.13.0"
2439
```
2540

2641
## Data Validation Example
@@ -460,14 +475,55 @@ ValidateString::minWords('Bruno Conte', 2) //Return boolean
460475
ValidateString::maxWords('Bruno Conte', 2) //Return boolean
461476
```
462477

478+
## Generation Utilities
479+
480+
### UUID v7 - Generate and Validate
481+
482+
```php
483+
<?php
484+
485+
require 'vendor/autoload.php';
486+
487+
use DevUtils\Uuid;
488+
489+
// Generate UUID v7 (timestamp-based, sortable, unique)
490+
$uuid = Uuid::generate(); // ==> 01890f87-4f0b-7f6b-8b1d-9f4f9d7c3b5a
491+
492+
// Validate any UUID version (v1 to v8)
493+
Uuid::isValid('550e8400-e29b-41d4-a716-446655440000'); // ==> true
494+
495+
// Validate specific version
496+
Uuid::isValid('01890f87-4f0b-7f6b-8b1d-9f4f9d7c3b5a', 7); // ==> true
497+
498+
```
499+
500+
### Password Generation
501+
502+
```php
503+
<?php
504+
505+
use DevUtils\Utility;
506+
507+
/*
508+
Generate secure passwords
509+
int $size ==> Number of characters (Required)
510+
bool $uppercase ==> Include uppercase letters (default: true)
511+
bool $lowercase ==> Include lowercase letters (default: true)
512+
bool $numbers ==> Include numbers (default: true)
513+
bool $symbols ==> Include symbols (default: true)
514+
*/
515+
Utility::generatePassword(10); // ==> aB3$xY9!zK
516+
Utility::generatePassword(16, true, true, true, false); // Without symbols
517+
```
518+
463519
## Manipulate Arrays
464520

465521
```php
466522
<?php
467523

468524
require 'vendor/autoload.php';
469525

470-
use DevUtils\Array;
526+
use DevUtils\Arrays;
471527

472528
$array = ['primeiro' => 15, 'segundo' => 25];
473529
var_dump(Arrays::searchKey($array, 'primeiro')); // Search for key in array, and Return position ==> returns 0
@@ -533,16 +589,6 @@ use DevUtils\Utility;
533589

534590
Utility::captureClientIp(); // Return user IP, capture per layer available, eg 201.200.25.40
535591

536-
/*
537-
Return an automatically generated password, there are 5 parameters, only the first one is mandatory
538-
int $size ==> Number of characters in the password (Required)
539-
bool $uppercase ==> If there will be capital letters
540-
bool $lowercase ==> If there will be lowercase letters
541-
bool $numbers ==> if there will be numbers
542-
bool $symbols ==> if there will be symbols
543-
*/
544-
Utility::generatePassword(10);
545-
546592
/*
547593
* @return string -> Full URL string
548594
* @param string $host -> system domain

src/Arrays.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
class Arrays
88
{
9+
private const XML_ATTR_KEY = '@attr';
10+
911
public static function searchKey(array $array, string $key): ?int
1012
{
1113
$position = array_search($key, array_keys($array), true);
@@ -92,12 +94,12 @@ public static function findIndexByValue(array $array, string | int | bool $searc
9294
public static function convertArrayToXml(array $array, \SimpleXMLElement &$xml): void
9395
{
9496
foreach ($array as $key => $value) {
95-
if (is_numeric($key) && is_array($value) && isset($value['@attr'])) {
96-
$key = $value['@attr'];
97+
if (is_numeric($key) && is_array($value) && isset($value[self::XML_ATTR_KEY])) {
98+
$key = $value[self::XML_ATTR_KEY];
9799
}
98100

99101
if (is_array($value)) {
100-
unset($value['@attr']);
102+
unset($value[self::XML_ATTR_KEY]);
101103
$subnode = $xml->addChild((string) $key);
102104
self::convertArrayToXml($value, $subnode);
103105
continue;

src/Uuid.php

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DevUtils;
6+
7+
class Uuid
8+
{
9+
private static function formatUuid(string $hex): string
10+
{
11+
return sprintf(
12+
'%s-%s-%s-%s-%s',
13+
substr($hex, 0, 8),
14+
substr($hex, 8, 4),
15+
substr($hex, 12, 4),
16+
substr($hex, 16, 4),
17+
substr($hex, 20, 12)
18+
);
19+
}
20+
21+
private static function setVersionAndVariant(string $hex, int $version): string
22+
{
23+
$timeHi = hexdec(substr($hex, 12, 4));
24+
$timeHi = ($timeHi & 0x0fff) | ($version << 12);
25+
26+
$clockSeq = hexdec(substr($hex, 16, 4));
27+
$clockSeq = ($clockSeq & 0x3fff) | 0x8000;
28+
29+
return substr($hex, 0, 12)
30+
. str_pad(dechex($timeHi), 4, '0', STR_PAD_LEFT)
31+
. str_pad(dechex($clockSeq), 4, '0', STR_PAD_LEFT)
32+
. substr($hex, 20);
33+
}
34+
35+
private static function validateFormat(string $uuid): bool
36+
{
37+
return preg_match(
38+
'/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i',
39+
$uuid
40+
) === 1;
41+
}
42+
43+
private static function extractVersion(string $uuid): ?int
44+
{
45+
if (!self::validateFormat($uuid)) {
46+
return null;
47+
}
48+
49+
$versionHex = substr($uuid, 14, 1);
50+
$version = (int) hexdec($versionHex);
51+
52+
return ($version >= 1 && $version <= 8) ? $version : null;
53+
}
54+
55+
public static function generate(): string
56+
{
57+
$timestamp = (int) (microtime(true) * 1000);
58+
$timestampHex = str_pad(dechex($timestamp), 12, '0', STR_PAD_LEFT);
59+
60+
$randomBytes = random_bytes(10);
61+
$randomHex = bin2hex($randomBytes);
62+
63+
$hex = $timestampHex . $randomHex;
64+
$hex = self::setVersionAndVariant($hex, 7);
65+
66+
return self::formatUuid($hex);
67+
}
68+
69+
public static function isValid(string $uuid, ?int $version = null): bool
70+
{
71+
$detectedVersion = self::extractVersion($uuid);
72+
73+
if ($detectedVersion === null) {
74+
return false;
75+
}
76+
77+
if ($version === null) {
78+
return in_array($detectedVersion, [1, 2, 3, 4, 5, 6, 7, 8], true);
79+
}
80+
81+
return $detectedVersion === $version;
82+
}
83+
}

src/ValidateUuid.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DevUtils;
6+
7+
class ValidateUuid
8+
{
9+
private const UUID_V4_V7_REGEX = '/^[0-9a-f]{8}-[0-9a-f]{4}-[47][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i';
10+
11+
private static function matchesUuidV4OrV7(string $uuid): bool
12+
{
13+
return preg_match(self::UUID_V4_V7_REGEX, $uuid) === 1;
14+
}
15+
16+
public static function isValid(string $uuid): bool
17+
{
18+
if (empty($uuid)) {
19+
return false;
20+
}
21+
22+
return self::matchesUuidV4OrV7($uuid);
23+
}
24+
}

tests/UnitArrayTest.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
class UnitArrayTest extends TestCase
1313
{
14+
private const VEGETABLE_RUCULA = 'Rúcula';
15+
1416
private array $fruitArray;
1517
private array $simpleArray;
1618

@@ -34,7 +36,7 @@ private function assertXmlFrutas(SimpleXMLElement $xml): void
3436

3537
private function assertXmlVerduras(SimpleXMLElement $xml): void
3638
{
37-
self::assertSame('Rúcula', (string) $xml->verduras->verdura_1);
39+
self::assertSame(self::VEGETABLE_RUCULA, (string) $xml->verduras->verdura_1);
3840
self::assertSame('Acelga', (string) $xml->verduras->verdura_2);
3941
self::assertSame('Alface', (string) $xml->verduras->verdura_3);
4042
self::assertCount(3, $xml->verduras->children());
@@ -49,7 +51,7 @@ protected function setUp(): void
4951
'fruta_3' => 'fruta',
5052
'fruta_4' => 'Uva',
5153
],
52-
'verduras' => ['verdura_1' => 'Rúcula', 'verdura_2' => 'Acelga', 'verdura_3' => 'Alface'],
54+
'verduras' => ['verdura_1' => self::VEGETABLE_RUCULA, 'verdura_2' => 'Acelga', 'verdura_3' => 'Alface'],
5355
'legume' => 'Tomate',
5456
];
5557

@@ -82,7 +84,7 @@ public function testFindValueByKey(): void
8284

8385
public function testFindIndexByValue(): void
8486
{
85-
self::assertIsArray(Arrays::findIndexByValue($this->fruitArray, 'Rúcula'));
87+
self::assertIsArray(Arrays::findIndexByValue($this->fruitArray, self::VEGETABLE_RUCULA));
8688
}
8789

8890
public function testConvertArrayToXml(): void
@@ -107,13 +109,13 @@ public function testConvertArrayToXml(): void
107109
public function testConvertJsonIndexToArray(): void
108110
{
109111
$array = $this->fruitArray;
110-
$array['verduras'] = '{"verdura_1": "Rúcula", "verdura_2": "Acelga", "verdura_3": "Alface"}';
112+
$array['verduras'] = '{"verdura_1": "' . self::VEGETABLE_RUCULA . '", "verdura_2": "Acelga", "verdura_3": "Alface"}';
111113

112114
Arrays::convertJsonIndexToArray($array);
113115

114116
self::assertIsArray($array);
115117
self::assertIsArray($array['verduras']);
116-
self::assertSame('Rúcula', $array['verduras']['verdura_1']);
118+
self::assertSame(self::VEGETABLE_RUCULA, $array['verduras']['verdura_1']);
117119
}
118120

119121
public function testCheckExistsIndexArrayRecursive(): void

0 commit comments

Comments
 (0)