[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * This file is part of the ramsey/uuid library 4 * 5 * For the full copyright and license information, please view the LICENSE 6 * file that was distributed with this source code. 7 * 8 * @copyright Copyright (c) Ben Ramsey <[email protected]> 9 * @license http://opensource.org/licenses/MIT MIT 10 * @link https://benramsey.com/projects/ramsey-uuid/ Documentation 11 * @link https://packagist.org/packages/ramsey/uuid Packagist 12 * @link https://github.com/ramsey/uuid GitHub 13 */ 14 15 namespace Ramsey\Uuid; 16 17 use DateTime; 18 use Exception; 19 use InvalidArgumentException; 20 use Ramsey\Uuid\Converter\NumberConverterInterface; 21 use Ramsey\Uuid\Codec\CodecInterface; 22 use Ramsey\Uuid\Exception\InvalidUuidStringException; 23 use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; 24 use Ramsey\Uuid\Exception\UnsupportedOperationException; 25 use ReturnTypeWillChange; 26 27 /** 28 * Represents a universally unique identifier (UUID), according to RFC 4122. 29 * 30 * This class provides immutable UUID objects (the Uuid class) and the static 31 * methods `uuid1()`, `uuid3()`, `uuid4()`, and `uuid5()` for generating version 32 * 1, 3, 4, and 5 UUIDs as specified in RFC 4122. 33 * 34 * If all you want is a unique ID, you should probably call `uuid1()` or `uuid4()`. 35 * Note that `uuid1()` may compromise privacy since it creates a UUID containing 36 * the computer’s network address. `uuid4()` creates a random UUID. 37 * 38 * @link http://tools.ietf.org/html/rfc4122 39 * @link http://en.wikipedia.org/wiki/Universally_unique_identifier 40 * @link http://docs.python.org/3/library/uuid.html 41 * @link http://docs.oracle.com/javase/6/docs/api/java/util/UUID.html 42 */ 43 class Uuid implements UuidInterface 44 { 45 /** 46 * When this namespace is specified, the name string is a fully-qualified domain name. 47 * @link http://tools.ietf.org/html/rfc4122#appendix-C 48 */ 49 const NAMESPACE_DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; 50 51 /** 52 * When this namespace is specified, the name string is a URL. 53 * @link http://tools.ietf.org/html/rfc4122#appendix-C 54 */ 55 const NAMESPACE_URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; 56 57 /** 58 * When this namespace is specified, the name string is an ISO OID. 59 * @link http://tools.ietf.org/html/rfc4122#appendix-C 60 */ 61 const NAMESPACE_OID = '6ba7b812-9dad-11d1-80b4-00c04fd430c8'; 62 63 /** 64 * When this namespace is specified, the name string is an X.500 DN in DER or a text output format. 65 * @link http://tools.ietf.org/html/rfc4122#appendix-C 66 */ 67 const NAMESPACE_X500 = '6ba7b814-9dad-11d1-80b4-00c04fd430c8'; 68 69 /** 70 * The nil UUID is special form of UUID that is specified to have all 128 bits set to zero. 71 * @link http://tools.ietf.org/html/rfc4122#section-4.1.7 72 */ 73 const NIL = '00000000-0000-0000-0000-000000000000'; 74 75 /** 76 * Reserved for NCS compatibility. 77 * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 78 */ 79 const RESERVED_NCS = 0; 80 81 /** 82 * Specifies the UUID layout given in RFC 4122. 83 * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 84 */ 85 const RFC_4122 = 2; 86 87 /** 88 * Reserved for Microsoft compatibility. 89 * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 90 */ 91 const RESERVED_MICROSOFT = 6; 92 93 /** 94 * Reserved for future definition. 95 * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 96 */ 97 const RESERVED_FUTURE = 7; 98 99 /** 100 * Regular expression pattern for matching a valid UUID of any variant. 101 */ 102 const VALID_PATTERN = '^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$'; 103 104 /** 105 * Version 1 (time-based) UUID object constant identifier 106 */ 107 const UUID_TYPE_TIME = 1; 108 109 /** 110 * Version 2 (identifier-based) UUID object constant identifier 111 */ 112 const UUID_TYPE_IDENTIFIER = 2; 113 114 /** 115 * Version 3 (name-based and hashed with MD5) UUID object constant identifier 116 */ 117 const UUID_TYPE_HASH_MD5 = 3; 118 119 /** 120 * Version 4 (random) UUID object constant identifier 121 */ 122 const UUID_TYPE_RANDOM = 4; 123 124 /** 125 * Version 5 (name-based and hashed with SHA1) UUID object constant identifier 126 */ 127 const UUID_TYPE_HASH_SHA1 = 5; 128 129 /** 130 * The factory to use when creating UUIDs. 131 * @var UuidFactoryInterface 132 */ 133 private static $factory = null; 134 135 /** 136 * The codec to use when encoding or decoding UUID strings. 137 * @var CodecInterface 138 */ 139 protected $codec; 140 141 /** 142 * The fields that make up this UUID. 143 * 144 * This is initialized to the nil value. 145 * 146 * @var array 147 * @see UuidInterface::getFieldsHex() 148 */ 149 protected $fields = [ 150 'time_low' => '00000000', 151 'time_mid' => '0000', 152 'time_hi_and_version' => '0000', 153 'clock_seq_hi_and_reserved' => '00', 154 'clock_seq_low' => '00', 155 'node' => '000000000000', 156 ]; 157 158 /** 159 * The number converter to use for converting hex values to/from integers. 160 * @var NumberConverterInterface 161 */ 162 protected $converter; 163 164 /** 165 * Creates a universally unique identifier (UUID) from an array of fields. 166 * 167 * Unless you're making advanced use of this library to generate identifiers 168 * that deviate from RFC 4122, you probably do not want to instantiate a 169 * UUID directly. Use the static methods, instead: 170 * 171 * ``` 172 * use Ramsey\Uuid\Uuid; 173 * 174 * $timeBasedUuid = Uuid::uuid1(); 175 * $namespaceMd5Uuid = Uuid::uuid3(Uuid::NAMESPACE_URL, 'http://php.net/'); 176 * $randomUuid = Uuid::uuid4(); 177 * $namespaceSha1Uuid = Uuid::uuid5(Uuid::NAMESPACE_URL, 'http://php.net/'); 178 * ``` 179 * 180 * @param array $fields An array of fields from which to construct a UUID; 181 * see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure. 182 * @param NumberConverterInterface $converter The number converter to use 183 * for converting hex values to/from integers. 184 * @param CodecInterface $codec The codec to use when encoding or decoding 185 * UUID strings. 186 */ 187 public function __construct( 188 array $fields, 189 NumberConverterInterface $converter, 190 CodecInterface $codec 191 ) { 192 $this->fields = $fields; 193 $this->codec = $codec; 194 $this->converter = $converter; 195 } 196 197 /** 198 * Converts this UUID object to a string when the object is used in any 199 * string context. 200 * 201 * @return string 202 * @link http://www.php.net/manual/en/language.oop5.magic.php#object.tostring 203 */ 204 public function __toString() 205 { 206 return $this->toString(); 207 } 208 209 /** 210 * Converts this UUID object to a string when the object is serialized 211 * with `json_encode()` 212 * 213 * @return string 214 * @link http://php.net/manual/en/class.jsonserializable.php 215 */ 216 public function jsonSerialize() 217 { 218 return $this->toString(); 219 } 220 221 /** 222 * Converts this UUID object to a string when the object is serialized 223 * with `serialize()` 224 * 225 * @return string 226 * @link http://php.net/manual/en/class.serializable.php 227 */ 228 #[ReturnTypeWillChange] 229 public function serialize() 230 { 231 return $this->toString(); 232 } 233 234 /** 235 * @return array{string: string} 236 */ 237 #[ReturnTypeWillChange] 238 public function __serialize() 239 { 240 return ['string' => $this->toString()]; 241 } 242 243 /** 244 * Re-constructs the object from its serialized form. 245 * 246 * @param string $serialized 247 * @link http://php.net/manual/en/class.serializable.php 248 * @throws InvalidUuidStringException 249 */ 250 #[ReturnTypeWillChange] 251 public function unserialize($serialized) 252 { 253 $uuid = self::fromString($serialized); 254 $this->codec = $uuid->codec; 255 $this->converter = $uuid->converter; 256 $this->fields = $uuid->fields; 257 } 258 259 /** 260 * @param array{string: string} $serialized 261 * @return void 262 * @throws InvalidUuidStringException 263 */ 264 #[ReturnTypeWillChange] 265 public function __unserialize(array $serialized) 266 { 267 // @codeCoverageIgnoreStart 268 if (!isset($serialized['string'])) { 269 throw new InvalidUuidStringException(); 270 } 271 // @codeCoverageIgnoreEnd 272 273 $this->unserialize($serialized['string']); 274 } 275 276 public function compareTo(UuidInterface $other) 277 { 278 if ($this->getMostSignificantBitsHex() < $other->getMostSignificantBitsHex()) { 279 return -1; 280 } 281 282 if ($this->getMostSignificantBitsHex() > $other->getMostSignificantBitsHex()) { 283 return 1; 284 } 285 286 if ($this->getLeastSignificantBitsHex() < $other->getLeastSignificantBitsHex()) { 287 return -1; 288 } 289 290 if ($this->getLeastSignificantBitsHex() > $other->getLeastSignificantBitsHex()) { 291 return 1; 292 } 293 294 return 0; 295 } 296 297 public function equals($other) 298 { 299 if (!$other instanceof UuidInterface) { 300 return false; 301 } 302 303 return $this->compareTo($other) == 0; 304 } 305 306 public function getBytes() 307 { 308 return $this->codec->encodeBinary($this); 309 } 310 311 /** 312 * Returns the high field of the clock sequence multiplexed with the variant 313 * (bits 65-72 of the UUID). 314 * 315 * @return int Unsigned 8-bit integer value of clock_seq_hi_and_reserved 316 */ 317 public function getClockSeqHiAndReserved() 318 { 319 return hexdec($this->getClockSeqHiAndReservedHex()); 320 } 321 322 public function getClockSeqHiAndReservedHex() 323 { 324 return $this->fields['clock_seq_hi_and_reserved']; 325 } 326 327 /** 328 * Returns the low field of the clock sequence (bits 73-80 of the UUID). 329 * 330 * @return int Unsigned 8-bit integer value of clock_seq_low 331 */ 332 public function getClockSeqLow() 333 { 334 return hexdec($this->getClockSeqLowHex()); 335 } 336 337 public function getClockSeqLowHex() 338 { 339 return $this->fields['clock_seq_low']; 340 } 341 342 /** 343 * Returns the clock sequence value associated with this UUID. 344 * 345 * For UUID version 1, the clock sequence is used to help avoid 346 * duplicates that could arise when the clock is set backwards in time 347 * or if the node ID changes. 348 * 349 * For UUID version 3 or 5, the clock sequence is a 14-bit value 350 * constructed from a name as described in RFC 4122, Section 4.3. 351 * 352 * For UUID version 4, clock sequence is a randomly or pseudo-randomly 353 * generated 14-bit value as described in RFC 4122, Section 4.4. 354 * 355 * @return int Unsigned 14-bit integer value of clock sequence 356 * @link http://tools.ietf.org/html/rfc4122#section-4.1.5 357 */ 358 public function getClockSequence() 359 { 360 return ($this->getClockSeqHiAndReserved() & 0x3f) << 8 | $this->getClockSeqLow(); 361 } 362 363 public function getClockSequenceHex() 364 { 365 return sprintf('%04x', $this->getClockSequence()); 366 } 367 368 public function getNumberConverter() 369 { 370 return $this->converter; 371 } 372 373 /** 374 * @inheritdoc 375 */ 376 public function getDateTime() 377 { 378 if ($this->getVersion() != 1) { 379 throw new UnsupportedOperationException('Not a time-based UUID'); 380 } 381 382 $unixTimeNanoseconds = $this->getTimestamp() - 0x01b21dd213814000; 383 $unixTime = ($unixTimeNanoseconds - $unixTimeNanoseconds % 1e7) / 1e7; 384 385 return new DateTime("@{$unixTime}"); 386 } 387 388 /** 389 * Returns an array of the fields of this UUID, with keys named according 390 * to the RFC 4122 names for the fields. 391 * 392 * * **time_low**: The low field of the timestamp, an unsigned 32-bit integer 393 * * **time_mid**: The middle field of the timestamp, an unsigned 16-bit integer 394 * * **time_hi_and_version**: The high field of the timestamp multiplexed with 395 * the version number, an unsigned 16-bit integer 396 * * **clock_seq_hi_and_reserved**: The high field of the clock sequence 397 * multiplexed with the variant, an unsigned 8-bit integer 398 * * **clock_seq_low**: The low field of the clock sequence, an unsigned 399 * 8-bit integer 400 * * **node**: The spatially unique node identifier, an unsigned 48-bit 401 * integer 402 * 403 * @return array The UUID fields represented as integer values 404 * @link http://tools.ietf.org/html/rfc4122#section-4.1.2 405 */ 406 public function getFields() 407 { 408 return [ 409 'time_low' => $this->getTimeLow(), 410 'time_mid' => $this->getTimeMid(), 411 'time_hi_and_version' => $this->getTimeHiAndVersion(), 412 'clock_seq_hi_and_reserved' => $this->getClockSeqHiAndReserved(), 413 'clock_seq_low' => $this->getClockSeqLow(), 414 'node' => $this->getNode(), 415 ]; 416 } 417 418 public function getFieldsHex() 419 { 420 return $this->fields; 421 } 422 423 public function getHex() 424 { 425 return str_replace('-', '', $this->toString()); 426 } 427 428 /** 429 * @inheritdoc 430 */ 431 public function getInteger() 432 { 433 return $this->converter->fromHex($this->getHex()); 434 } 435 436 /** 437 * Returns the least significant 64 bits of this UUID's 128 bit value. 438 * 439 * @return mixed Converted representation of the unsigned 64-bit integer value 440 * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present 441 */ 442 public function getLeastSignificantBits() 443 { 444 return $this->converter->fromHex($this->getLeastSignificantBitsHex()); 445 } 446 447 public function getLeastSignificantBitsHex() 448 { 449 return sprintf( 450 '%02s%02s%012s', 451 $this->fields['clock_seq_hi_and_reserved'], 452 $this->fields['clock_seq_low'], 453 $this->fields['node'] 454 ); 455 } 456 457 /** 458 * Returns the most significant 64 bits of this UUID's 128 bit value. 459 * 460 * @return mixed Converted representation of the unsigned 64-bit integer value 461 * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present 462 */ 463 public function getMostSignificantBits() 464 { 465 return $this->converter->fromHex($this->getMostSignificantBitsHex()); 466 } 467 468 public function getMostSignificantBitsHex() 469 { 470 return sprintf( 471 '%08s%04s%04s', 472 $this->fields['time_low'], 473 $this->fields['time_mid'], 474 $this->fields['time_hi_and_version'] 475 ); 476 } 477 478 /** 479 * Returns the node value associated with this UUID 480 * 481 * For UUID version 1, the node field consists of an IEEE 802 MAC 482 * address, usually the host address. For systems with multiple IEEE 483 * 802 addresses, any available one can be used. The lowest addressed 484 * octet (octet number 10) contains the global/local bit and the 485 * unicast/multicast bit, and is the first octet of the address 486 * transmitted on an 802.3 LAN. 487 * 488 * For systems with no IEEE address, a randomly or pseudo-randomly 489 * generated value may be used; see RFC 4122, Section 4.5. The 490 * multicast bit must be set in such addresses, in order that they 491 * will never conflict with addresses obtained from network cards. 492 * 493 * For UUID version 3 or 5, the node field is a 48-bit value constructed 494 * from a name as described in RFC 4122, Section 4.3. 495 * 496 * For UUID version 4, the node field is a randomly or pseudo-randomly 497 * generated 48-bit value as described in RFC 4122, Section 4.4. 498 * 499 * @return int Unsigned 48-bit integer value of node 500 * @link http://tools.ietf.org/html/rfc4122#section-4.1.6 501 */ 502 public function getNode() 503 { 504 return hexdec($this->getNodeHex()); 505 } 506 507 public function getNodeHex() 508 { 509 return $this->fields['node']; 510 } 511 512 /** 513 * Returns the high field of the timestamp multiplexed with the version 514 * number (bits 49-64 of the UUID). 515 * 516 * @return int Unsigned 16-bit integer value of time_hi_and_version 517 */ 518 public function getTimeHiAndVersion() 519 { 520 return hexdec($this->getTimeHiAndVersionHex()); 521 } 522 523 public function getTimeHiAndVersionHex() 524 { 525 return $this->fields['time_hi_and_version']; 526 } 527 528 /** 529 * Returns the low field of the timestamp (the first 32 bits of the UUID). 530 * 531 * @return int Unsigned 32-bit integer value of time_low 532 */ 533 public function getTimeLow() 534 { 535 return hexdec($this->getTimeLowHex()); 536 } 537 538 public function getTimeLowHex() 539 { 540 return $this->fields['time_low']; 541 } 542 543 /** 544 * Returns the middle field of the timestamp (bits 33-48 of the UUID). 545 * 546 * @return int Unsigned 16-bit integer value of time_mid 547 */ 548 public function getTimeMid() 549 { 550 return hexdec($this->getTimeMidHex()); 551 } 552 553 public function getTimeMidHex() 554 { 555 return $this->fields['time_mid']; 556 } 557 558 /** 559 * Returns the timestamp value associated with this UUID. 560 * 561 * The 60 bit timestamp value is constructed from the time_low, 562 * time_mid, and time_hi fields of this UUID. The resulting 563 * timestamp is measured in 100-nanosecond units since midnight, 564 * October 15, 1582 UTC. 565 * 566 * The timestamp value is only meaningful in a time-based UUID, which 567 * has version type 1. If this UUID is not a time-based UUID then 568 * this method throws UnsupportedOperationException. 569 * 570 * @return int Unsigned 60-bit integer value of the timestamp 571 * @throws UnsupportedOperationException If this UUID is not a version 1 UUID 572 * @link http://tools.ietf.org/html/rfc4122#section-4.1.4 573 */ 574 public function getTimestamp() 575 { 576 if ($this->getVersion() != 1) { 577 throw new UnsupportedOperationException('Not a time-based UUID'); 578 } 579 580 return hexdec($this->getTimestampHex()); 581 } 582 583 /** 584 * @inheritdoc 585 */ 586 public function getTimestampHex() 587 { 588 if ($this->getVersion() != 1) { 589 throw new UnsupportedOperationException('Not a time-based UUID'); 590 } 591 592 return sprintf( 593 '%03x%04s%08s', 594 ($this->getTimeHiAndVersion() & 0x0fff), 595 $this->fields['time_mid'], 596 $this->fields['time_low'] 597 ); 598 } 599 600 public function getUrn() 601 { 602 return 'urn:uuid:' . $this->toString(); 603 } 604 605 public function getVariant() 606 { 607 $clockSeq = $this->getClockSeqHiAndReserved(); 608 609 if (0 === ($clockSeq & 0x80)) { 610 return self::RESERVED_NCS; 611 } 612 613 if (0 === ($clockSeq & 0x40)) { 614 return self::RFC_4122; 615 } 616 617 if (0 === ($clockSeq & 0x20)) { 618 return self::RESERVED_MICROSOFT; 619 } 620 621 return self::RESERVED_FUTURE; 622 } 623 624 public function getVersion() 625 { 626 if ($this->getVariant() == self::RFC_4122) { 627 return (int) (($this->getTimeHiAndVersion() >> 12) & 0x0f); 628 } 629 630 return null; 631 } 632 633 public function toString() 634 { 635 return $this->codec->encode($this); 636 } 637 638 /** 639 * Returns the currently set factory used to create UUIDs. 640 * 641 * @return UuidFactoryInterface 642 */ 643 public static function getFactory() 644 { 645 if (!self::$factory) { 646 self::$factory = new UuidFactory(); 647 } 648 649 return self::$factory; 650 } 651 652 /** 653 * Sets the factory used to create UUIDs. 654 * 655 * @param UuidFactoryInterface $factory 656 */ 657 public static function setFactory(UuidFactoryInterface $factory) 658 { 659 self::$factory = $factory; 660 } 661 662 /** 663 * Creates a UUID from a byte string. 664 * 665 * @param string $bytes 666 * @return UuidInterface 667 * @throws InvalidUuidStringException 668 * @throws InvalidArgumentException 669 */ 670 public static function fromBytes($bytes) 671 { 672 return self::getFactory()->fromBytes($bytes); 673 } 674 675 /** 676 * Creates a UUID from the string standard representation. 677 * 678 * @param string $name A string that specifies a UUID 679 * @return UuidInterface 680 * @throws InvalidUuidStringException 681 */ 682 public static function fromString($name) 683 { 684 return self::getFactory()->fromString($name); 685 } 686 687 /** 688 * Creates a UUID from a 128-bit integer string. 689 * 690 * @param string $integer String representation of 128-bit integer 691 * @return UuidInterface 692 * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present 693 * @throws InvalidUuidStringException 694 */ 695 public static function fromInteger($integer) 696 { 697 return self::getFactory()->fromInteger($integer); 698 } 699 700 /** 701 * Check if a string is a valid UUID. 702 * 703 * @param string $uuid The string UUID to test 704 * @return boolean 705 */ 706 public static function isValid($uuid) 707 { 708 $uuid = str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}'], '', $uuid); 709 710 if ($uuid == self::NIL) { 711 return true; 712 } 713 714 if (!preg_match('/' . self::VALID_PATTERN . '/D', $uuid)) { 715 return false; 716 } 717 718 return true; 719 } 720 721 /** 722 * Generate a version 1 UUID from a host ID, sequence number, and the current time. 723 * 724 * @param int|string $node A 48-bit number representing the hardware address 725 * This number may be represented as an integer or a hexadecimal string. 726 * @param int $clockSeq A 14-bit number used to help avoid duplicates that 727 * could arise when the clock is set backwards in time or if the node ID 728 * changes. 729 * @return UuidInterface 730 * @throws UnsatisfiedDependencyException if called on a 32-bit system and 731 * `Moontoast\Math\BigNumber` is not present 732 * @throws InvalidArgumentException 733 * @throws Exception if it was not possible to gather sufficient entropy 734 */ 735 public static function uuid1($node = null, $clockSeq = null) 736 { 737 return self::getFactory()->uuid1($node, $clockSeq); 738 } 739 740 /** 741 * Generate a version 3 UUID based on the MD5 hash of a namespace identifier 742 * (which is a UUID) and a name (which is a string). 743 * 744 * @param string|UuidInterface $ns The UUID namespace in which to create the named UUID 745 * @param string $name The name to create a UUID for 746 * @return UuidInterface 747 * @throws InvalidUuidStringException 748 */ 749 public static function uuid3($ns, $name) 750 { 751 return self::getFactory()->uuid3($ns, $name); 752 } 753 754 /** 755 * Generate a version 4 (random) UUID. 756 * 757 * @return UuidInterface 758 * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present 759 * @throws InvalidArgumentException 760 * @throws Exception 761 */ 762 public static function uuid4() 763 { 764 return self::getFactory()->uuid4(); 765 } 766 767 /** 768 * Generate a version 5 UUID based on the SHA-1 hash of a namespace 769 * identifier (which is a UUID) and a name (which is a string). 770 * 771 * @param string|UuidInterface $ns The UUID namespace in which to create the named UUID 772 * @param string $name The name to create a UUID for 773 * @return UuidInterface 774 * @throws InvalidUuidStringException 775 */ 776 public static function uuid5($ns, $name) 777 { 778 return self::getFactory()->uuid5($ns, $name); 779 } 780 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |