[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Joomla! Content Management System 5 * 6 * @copyright (C) 2005 Open Source Matters, Inc. <https://www.joomla.org> 7 * @license GNU General Public License version 2 or later; see LICENSE.txt 8 */ 9 10 namespace Joomla\CMS; 11 12 use Joomla\CMS\Application\CMSApplicationInterface; 13 use Joomla\CMS\Cache\Cache; 14 use Joomla\CMS\Cache\CacheControllerFactoryInterface; 15 use Joomla\CMS\Client\ClientHelper; 16 use Joomla\CMS\Date\Date; 17 use Joomla\CMS\Document\Document; 18 use Joomla\CMS\Document\FactoryInterface; 19 use Joomla\CMS\Filesystem\Stream; 20 use Joomla\CMS\Language\Language; 21 use Joomla\CMS\Language\LanguageFactoryInterface; 22 use Joomla\CMS\Log\Log; 23 use Joomla\CMS\Mail\Mail; 24 use Joomla\CMS\Mail\MailHelper; 25 use Joomla\CMS\Session\Session; 26 use Joomla\CMS\User\User; 27 use Joomla\Database\DatabaseDriver; 28 use Joomla\Database\DatabaseInterface; 29 use Joomla\DI\Container; 30 use Joomla\Registry\Registry; 31 use PHPMailer\PHPMailer\Exception as phpmailerException; 32 33 // phpcs:disable PSR1.Files.SideEffects 34 \defined('JPATH_PLATFORM') or die; 35 // phpcs:enable PSR1.Files.SideEffects 36 37 /** 38 * Joomla Platform Factory class. 39 * 40 * @since 1.7.0 41 */ 42 abstract class Factory 43 { 44 /** 45 * Global application object 46 * 47 * @var CMSApplicationInterface 48 * @since 1.7.0 49 */ 50 public static $application = null; 51 52 /** 53 * Global cache object 54 * 55 * @var Cache 56 * @since 1.7.0 57 */ 58 public static $cache = null; 59 60 /** 61 * Global configuration object 62 * 63 * @var \JConfig 64 * @since 1.7.0 65 * @deprecated 5.0 Use the configuration object within the application 66 */ 67 public static $config = null; 68 69 /** 70 * Global container object 71 * 72 * @var Container 73 * @since 4.0.0 74 */ 75 public static $container = null; 76 77 /** 78 * Container for Date instances 79 * 80 * @var array 81 * @since 1.7.3 82 */ 83 public static $dates = array(); 84 85 /** 86 * Global session object 87 * 88 * @var Session 89 * @since 1.7.0 90 * @deprecated 5.0 Use the session service in the DI container 91 */ 92 public static $session = null; 93 94 /** 95 * Global language object 96 * 97 * @var Language 98 * @since 1.7.0 99 * @deprecated 5.0 Use the language service in the DI container 100 */ 101 public static $language = null; 102 103 /** 104 * Global document object 105 * 106 * @var Document 107 * @since 1.7.0 108 * @deprecated 5.0 Use the document service in the DI container 109 */ 110 public static $document = null; 111 112 /** 113 * Global database object 114 * 115 * @var DatabaseDriver 116 * @since 1.7.0 117 * @deprecated 5.0 Use the database service in the DI container 118 */ 119 public static $database = null; 120 121 /** 122 * Global mailer object 123 * 124 * @var Mail 125 * @since 1.7.0 126 */ 127 public static $mailer = null; 128 129 /** 130 * Get the global application object. When the global application doesn't exist, an exception is thrown. 131 * 132 * @return CMSApplicationInterface object 133 * 134 * @since 1.7.0 135 * @throws \Exception 136 */ 137 public static function getApplication() 138 { 139 if (!self::$application) { 140 throw new \Exception('Failed to start application', 500); 141 } 142 143 return self::$application; 144 } 145 146 /** 147 * Get a configuration object 148 * 149 * Returns the global {@link \JConfig} object, only creating it if it doesn't already exist. 150 * 151 * @param string $file The path to the configuration file 152 * @param string $type The type of the configuration file 153 * @param string $namespace The namespace of the configuration file 154 * 155 * @return Registry 156 * 157 * @see Registry 158 * @since 1.7.0 159 * @deprecated 5.0 Use the configuration object within the application. 160 */ 161 public static function getConfig($file = null, $type = 'PHP', $namespace = '') 162 { 163 @trigger_error( 164 sprintf( 165 '%s() is deprecated. The configuration object should be read from the application.', 166 __METHOD__ 167 ), 168 E_USER_DEPRECATED 169 ); 170 171 /** 172 * If there is an application object, fetch the configuration from there. 173 * Check it's not null because LanguagesModel can make it null and if it's null 174 * we would want to re-init it from configuration.php. 175 */ 176 if (self::$application && self::$application->getConfig() !== null) { 177 return self::$application->getConfig(); 178 } 179 180 if (!self::$config) { 181 if ($file === null) { 182 $file = JPATH_CONFIGURATION . '/configuration.php'; 183 } 184 185 self::$config = self::createConfig($file, $type, $namespace); 186 } 187 188 return self::$config; 189 } 190 191 /** 192 * Get a container object 193 * 194 * Returns the global service container object, only creating it if it doesn't already exist. 195 * 196 * This method is only suggested for use in code whose responsibility is to create new services 197 * and needs to be able to resolve the dependencies, and should therefore only be used when the 198 * container is not accessible by other means. Valid uses of this method include: 199 * 200 * - A static `getInstance()` method calling a factory service from the container, 201 * see `Joomla\CMS\Toolbar\Toolbar::getInstance()` as an example 202 * - An application front controller loading and executing the Joomla application class, 203 * see the `cli/joomla.php` file as an example 204 * - Retrieving optional constructor dependencies when not injected into a class during a transitional 205 * period to retain backward compatibility, in this case a deprecation notice should also be emitted to 206 * notify developers of changes needed in their code 207 * 208 * This method is not suggested for use as a one-for-one replacement of static calls, such as 209 * replacing calls to `Factory::getDbo()` with calls to `Factory::getContainer()->get('db')`, code 210 * should be refactored to support dependency injection instead of making this change. 211 * 212 * @return Container 213 * 214 * @since 4.0.0 215 */ 216 public static function getContainer(): Container 217 { 218 if (!self::$container) { 219 self::$container = self::createContainer(); 220 } 221 222 return self::$container; 223 } 224 225 /** 226 * Get a session object. 227 * 228 * Returns the global {@link Session} object, only creating it if it doesn't already exist. 229 * 230 * @param array $options An array containing session options 231 * 232 * @return Session object 233 * 234 * @see Session 235 * @since 1.7.0 236 * @deprecated 5.0 Load the session service from the dependency injection container or via $app->getSession() 237 */ 238 public static function getSession(array $options = array()) 239 { 240 @trigger_error( 241 sprintf( 242 '%1$s() is deprecated. Load the session from the dependency injection container or via %2$s::getApplication()->getSession().', 243 __METHOD__, 244 __CLASS__ 245 ), 246 E_USER_DEPRECATED 247 ); 248 249 return self::getApplication()->getSession(); 250 } 251 252 /** 253 * Get a language object. 254 * 255 * Returns the global {@link Language} object, only creating it if it doesn't already exist. 256 * 257 * @return Language object 258 * 259 * @see Language 260 * @since 1.7.0 261 * @deprecated 5.0 Load the language service from the dependency injection container or via $app->getLanguage() 262 */ 263 public static function getLanguage() 264 { 265 @trigger_error( 266 sprintf( 267 '%1$s() is deprecated. Load the language from the dependency injection container or via %2$s::getApplication()->getLanguage().', 268 __METHOD__, 269 __CLASS__ 270 ), 271 E_USER_DEPRECATED 272 ); 273 274 if (!self::$language) { 275 self::$language = self::createLanguage(); 276 } 277 278 return self::$language; 279 } 280 281 /** 282 * Get a document object. 283 * 284 * Returns the global {@link \Joomla\CMS\Document\Document} object, only creating it if it doesn't already exist. 285 * 286 * @return Document object 287 * 288 * @see Document 289 * @since 1.7.0 290 * @deprecated 5.0 Load the document service from the dependency injection container or via $app->getDocument() 291 */ 292 public static function getDocument() 293 { 294 @trigger_error( 295 sprintf( 296 '%1$s() is deprecated. Load the document from the dependency injection container or via %2$s::getApplication()->getDocument().', 297 __METHOD__, 298 __CLASS__ 299 ), 300 E_USER_DEPRECATED 301 ); 302 303 if (!self::$document) { 304 self::$document = self::createDocument(); 305 } 306 307 return self::$document; 308 } 309 310 /** 311 * Get a user object. 312 * 313 * Returns the global {@link User} object, only creating it if it doesn't already exist. 314 * 315 * @param integer $id The user to load - Can be an integer or string - If string, it is converted to ID automatically. 316 * 317 * @return User object 318 * 319 * @see User 320 * @since 1.7.0 321 * @deprecated 5.0 Load the user service from the dependency injection container or via $app->getIdentity() 322 */ 323 public static function getUser($id = null) 324 { 325 @trigger_error( 326 sprintf( 327 '%1$s() is deprecated. Load the user from the dependency injection container or via %2$s::getApplication()->getIdentity().', 328 __METHOD__, 329 __CLASS__ 330 ), 331 E_USER_DEPRECATED 332 ); 333 334 $instance = self::getApplication()->getSession()->get('user'); 335 336 if (\is_null($id)) { 337 if (!($instance instanceof User)) { 338 $instance = User::getInstance(); 339 } 340 } elseif (!($instance instanceof User) || \is_string($id) || $instance->id !== $id) { 341 // Check if we have a string as the id or if the numeric id is the current instance 342 $instance = User::getInstance($id); 343 } 344 345 return $instance; 346 } 347 348 /** 349 * Get a cache object 350 * 351 * Returns the global {@link CacheController} object 352 * 353 * @param string $group The cache group name 354 * @param string $handler The handler to use 355 * @param string $storage The storage method 356 * 357 * @return \Joomla\CMS\Cache\CacheController object 358 * 359 * @see Cache 360 * @since 1.7.0 361 * @deprecated 5.0 Use the cache controller factory instead 362 */ 363 public static function getCache($group = '', $handler = 'callback', $storage = null) 364 { 365 @trigger_error( 366 sprintf( 367 '%s() is deprecated. The cache controller should be fetched from the factory.', 368 __METHOD__ 369 ), 370 E_USER_DEPRECATED 371 ); 372 373 $hash = md5($group . $handler . $storage); 374 375 if (isset(self::$cache[$hash])) { 376 return self::$cache[$hash]; 377 } 378 379 $handler = ($handler === 'function') ? 'callback' : $handler; 380 381 $options = array('defaultgroup' => $group); 382 383 if (isset($storage)) { 384 $options['storage'] = $storage; 385 } 386 387 $cache = self::getContainer()->get(CacheControllerFactoryInterface::class)->createCacheController($handler, $options); 388 389 self::$cache[$hash] = $cache; 390 391 return self::$cache[$hash]; 392 } 393 394 /** 395 * Get a database object. 396 * 397 * Returns the global {@link DatabaseDriver} object, only creating it if it doesn't already exist. 398 * 399 * @return DatabaseDriver 400 * 401 * @see DatabaseDriver 402 * @since 1.7.0 403 * @deprecated 5.0 Load the database service from the dependency injection container 404 */ 405 public static function getDbo() 406 { 407 @trigger_error( 408 sprintf( 409 '%1$s() is deprecated. Load the database from the dependency injection container.', 410 __METHOD__ 411 ), 412 E_USER_DEPRECATED 413 ); 414 415 if (!self::$database) { 416 if (self::getContainer()->has('DatabaseDriver')) { 417 self::$database = self::getContainer()->get('DatabaseDriver'); 418 } else { 419 self::$database = self::createDbo(); 420 } 421 } 422 423 return self::$database; 424 } 425 426 /** 427 * Get a mailer object. 428 * 429 * Returns the global {@link Mail} object, only creating it if it doesn't already exist. 430 * 431 * @return Mail object 432 * 433 * @see Mail 434 * @since 1.7.0 435 */ 436 public static function getMailer() 437 { 438 if (!self::$mailer) { 439 self::$mailer = self::createMailer(); 440 } 441 442 $copy = clone self::$mailer; 443 444 return $copy; 445 } 446 447 /** 448 * Return the {@link Date} object 449 * 450 * @param mixed $time The initial time for the Date object 451 * @param mixed $tzOffset The timezone offset. 452 * 453 * @return Date object 454 * 455 * @see Date 456 * @since 1.7.0 457 */ 458 public static function getDate($time = 'now', $tzOffset = null) 459 { 460 static $classname; 461 static $mainLocale; 462 463 $language = self::getLanguage(); 464 $locale = $language->getTag(); 465 466 if (!isset($classname) || $locale != $mainLocale) { 467 // Store the locale for future reference 468 $mainLocale = $locale; 469 470 if ($mainLocale !== false) { 471 $classname = str_replace('-', '_', $mainLocale) . 'Date'; 472 473 if (!class_exists($classname)) { 474 // The class does not exist, default to Date 475 $classname = 'Joomla\\CMS\\Date\\Date'; 476 } 477 } else { 478 // No tag, so default to Date 479 $classname = 'Joomla\\CMS\\Date\\Date'; 480 } 481 } 482 483 $key = $time . '-' . ($tzOffset instanceof \DateTimeZone ? $tzOffset->getName() : (string) $tzOffset); 484 485 if (!isset(self::$dates[$classname][$key])) { 486 self::$dates[$classname][$key] = new $classname($time, $tzOffset); 487 } 488 489 $date = clone self::$dates[$classname][$key]; 490 491 return $date; 492 } 493 494 /** 495 * Create a configuration object 496 * 497 * @param string $file The path to the configuration file. 498 * @param string $type The type of the configuration file. 499 * @param string $namespace The namespace of the configuration file. 500 * 501 * @return Registry 502 * 503 * @see Registry 504 * @since 1.7.0 505 * @deprecated 5.0 Use the configuration object within the application. 506 */ 507 protected static function createConfig($file, $type = 'PHP', $namespace = '') 508 { 509 @trigger_error( 510 sprintf( 511 '%s() is deprecated. The configuration object should be read from the application.', 512 __METHOD__ 513 ), 514 E_USER_DEPRECATED 515 ); 516 517 if (is_file($file)) { 518 include_once $file; 519 } 520 521 // Create the registry with a default namespace of config 522 $registry = new Registry(); 523 524 // Sanitize the namespace. 525 $namespace = ucfirst((string) preg_replace('/[^A-Z_]/i', '', $namespace)); 526 527 // Build the config name. 528 $name = 'JConfig' . $namespace; 529 530 // Handle the PHP configuration type. 531 if ($type === 'PHP' && class_exists($name)) { 532 // Create the JConfig object 533 $config = new $name(); 534 535 // Load the configuration values into the registry 536 $registry->loadObject($config); 537 } 538 539 return $registry; 540 } 541 542 /** 543 * Create a container object 544 * 545 * @return Container 546 * 547 * @since 4.0.0 548 */ 549 protected static function createContainer(): Container 550 { 551 $container = (new Container()) 552 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Application()) 553 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Authentication()) 554 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\CacheController()) 555 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Config()) 556 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Console()) 557 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Database()) 558 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Dispatcher()) 559 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Document()) 560 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Form()) 561 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Logger()) 562 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Language()) 563 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Menu()) 564 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Pathway()) 565 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\HTMLRegistry()) 566 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Session()) 567 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Toolbar()) 568 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\WebAssetRegistry()) 569 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\Router()) 570 ->registerServiceProvider(new \Joomla\CMS\Service\Provider\User()); 571 572 return $container; 573 } 574 575 /** 576 * Create a database object 577 * 578 * @return DatabaseDriver 579 * 580 * @see DatabaseDriver 581 * @since 1.7.0 582 * @deprecated 5.0 Use the database service in the DI container 583 */ 584 protected static function createDbo() 585 { 586 @trigger_error( 587 sprintf( 588 '%1$s() is deprecated, register a service provider to create a %2$s instance instead.', 589 __METHOD__, 590 DatabaseInterface::class 591 ), 592 E_USER_DEPRECATED 593 ); 594 595 $conf = self::getConfig(); 596 597 $host = $conf->get('host'); 598 $user = $conf->get('user'); 599 $password = $conf->get('password'); 600 $database = $conf->get('db'); 601 $prefix = $conf->get('dbprefix'); 602 $driver = $conf->get('dbtype'); 603 604 $options = array('driver' => $driver, 'host' => $host, 'user' => $user, 'password' => $password, 'database' => $database, 'prefix' => $prefix); 605 606 if ((int) $conf->get('dbencryption') !== 0) { 607 $options['ssl'] = [ 608 'enable' => true, 609 'verify_server_cert' => (bool) $conf->get('dbsslverifyservercert'), 610 ]; 611 612 foreach (['cipher', 'ca', 'key', 'cert'] as $value) { 613 $confVal = trim($conf->get('dbssl' . $value, '')); 614 615 if ($confVal !== '') { 616 $options['ssl'][$value] = $confVal; 617 } 618 } 619 } 620 621 try { 622 $db = DatabaseDriver::getInstance($options); 623 } catch (\RuntimeException $e) { 624 if (!headers_sent()) { 625 header('HTTP/1.1 500 Internal Server Error'); 626 } 627 628 jexit('Database Error: ' . $e->getMessage()); 629 } 630 631 return $db; 632 } 633 634 /** 635 * Create a mailer object 636 * 637 * @return Mail object 638 * 639 * @see Mail 640 * @since 1.7.0 641 */ 642 protected static function createMailer() 643 { 644 $conf = self::getConfig(); 645 646 $smtpauth = ($conf->get('smtpauth') == 0) ? null : 1; 647 $smtpuser = $conf->get('smtpuser'); 648 $smtppass = $conf->get('smtppass'); 649 $smtphost = $conf->get('smtphost'); 650 $smtpsecure = $conf->get('smtpsecure'); 651 $smtpport = $conf->get('smtpport'); 652 $mailfrom = $conf->get('mailfrom'); 653 $fromname = $conf->get('fromname'); 654 $mailer = $conf->get('mailer'); 655 656 // Create a Mail object 657 $mail = Mail::getInstance(); 658 659 // Clean the email address 660 $mailfrom = MailHelper::cleanLine($mailfrom); 661 662 // Set default sender without Reply-to if the mailfrom is a valid address 663 if (MailHelper::isEmailAddress($mailfrom)) { 664 // Wrap in try/catch to catch phpmailerExceptions if it is throwing them 665 try { 666 // Check for a false return value if exception throwing is disabled 667 if ($mail->setFrom($mailfrom, MailHelper::cleanLine($fromname), false) === false) { 668 Log::add(__METHOD__ . '() could not set the sender data.', Log::WARNING, 'mail'); 669 } 670 } catch (phpmailerException $e) { 671 Log::add(__METHOD__ . '() could not set the sender data.', Log::WARNING, 'mail'); 672 } 673 } 674 675 // Default mailer is to use PHP's mail function 676 switch ($mailer) { 677 case 'smtp': 678 $mail->useSmtp($smtpauth, $smtphost, $smtpuser, $smtppass, $smtpsecure, $smtpport); 679 break; 680 681 case 'sendmail': 682 $mail->isSendmail(); 683 break; 684 685 default: 686 $mail->isMail(); 687 break; 688 } 689 690 return $mail; 691 } 692 693 /** 694 * Create a language object 695 * 696 * @return Language object 697 * 698 * @see Language 699 * @since 1.7.0 700 * @deprecated 5.0 Load the language service from the dependency injection container or via $app->getLanguage() 701 */ 702 protected static function createLanguage() 703 { 704 @trigger_error( 705 sprintf( 706 '%1$s() is deprecated. Load the language from the dependency injection container or via %2$s::getApplication()->getLanguage().', 707 __METHOD__, 708 __CLASS__ 709 ), 710 E_USER_DEPRECATED 711 ); 712 713 $conf = self::getConfig(); 714 $locale = $conf->get('language'); 715 $debug = $conf->get('debug_lang'); 716 $lang = self::getContainer()->get(LanguageFactoryInterface::class)->createLanguage($locale, $debug); 717 718 return $lang; 719 } 720 721 /** 722 * Create a document object 723 * 724 * @return Document object 725 * 726 * @see Document 727 * @since 1.7.0 728 * @deprecated 5.0 Load the document service from the dependency injection container or via $app->getDocument() 729 */ 730 protected static function createDocument() 731 { 732 @trigger_error( 733 sprintf( 734 '%1$s() is deprecated. Load the document from the dependency injection container or via %2$s::getApplication()->getDocument().', 735 __METHOD__, 736 __CLASS__ 737 ), 738 E_USER_DEPRECATED 739 ); 740 741 $lang = self::getLanguage(); 742 743 $input = self::getApplication()->input; 744 $type = $input->get('format', 'html', 'cmd'); 745 746 $version = new Version(); 747 748 $attributes = array( 749 'charset' => 'utf-8', 750 'lineend' => 'unix', 751 'tab' => "\t", 752 'language' => $lang->getTag(), 753 'direction' => $lang->isRtl() ? 'rtl' : 'ltr', 754 'mediaversion' => $version->getMediaVersion(), 755 ); 756 757 return self::getContainer()->get(FactoryInterface::class)->createDocument($type, $attributes); 758 } 759 760 /** 761 * Creates a new stream object with appropriate prefix 762 * 763 * @param boolean $usePrefix Prefix the connections for writing 764 * @param boolean $useNetwork Use network if available for writing; use false to disable (e.g. FTP, SCP) 765 * @param string $userAgentSuffix String to append to user agent 766 * @param boolean $maskUserAgent User agent masking (prefix Mozilla) 767 * 768 * @return Stream 769 * 770 * @see Stream 771 * @since 1.7.0 772 */ 773 public static function getStream($usePrefix = true, $useNetwork = true, $userAgentSuffix = 'Joomla', $maskUserAgent = false) 774 { 775 // Setup the context; Joomla! UA and overwrite 776 $context = array(); 777 $version = new Version(); 778 779 // Set the UA for HTTP and overwrite for FTP 780 $context['http']['user_agent'] = $version->getUserAgent($userAgentSuffix, $maskUserAgent); 781 $context['ftp']['overwrite'] = true; 782 783 if ($usePrefix) { 784 $FTPOptions = ClientHelper::getCredentials('ftp'); 785 $SCPOptions = ClientHelper::getCredentials('scp'); 786 787 if ($FTPOptions['enabled'] == 1 && $useNetwork) { 788 $prefix = 'ftp://' . $FTPOptions['user'] . ':' . $FTPOptions['pass'] . '@' . $FTPOptions['host']; 789 $prefix .= $FTPOptions['port'] ? ':' . $FTPOptions['port'] : ''; 790 $prefix .= $FTPOptions['root']; 791 } elseif ($SCPOptions['enabled'] == 1 && $useNetwork) { 792 $prefix = 'ssh2.sftp://' . $SCPOptions['user'] . ':' . $SCPOptions['pass'] . '@' . $SCPOptions['host']; 793 $prefix .= $SCPOptions['port'] ? ':' . $SCPOptions['port'] : ''; 794 $prefix .= $SCPOptions['root']; 795 } else { 796 $prefix = JPATH_ROOT . '/'; 797 } 798 799 $retval = new Stream($prefix, JPATH_ROOT, $context); 800 } else { 801 $retval = new Stream('', '', $context); 802 } 803 804 return $retval; 805 } 806 }
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 |