host = $host; $this->port = $port; } /** * Extracts the correctly formatted host and port values from the user-provided * database server host. * * @param string $dbHost The user provided host to extract values from * @return HostPortExtractor|null Extracted Host and Port, null if nothing can be extracted */ public static function extract(string $dbHost): ?HostPortExtractor { try { if (self::isIPv6($dbHost)) { return self::extractIPv6($dbHost); } elseif (self::isUnixSocket($dbHost)) { return self::extractUnixSocket($dbHost); } elseif (self::isIPWithPort($dbHost)) { return self::extractIPAndPort($dbHost); } else { return null; } } catch (InvalidArgumentException $e) { return null; } } /** * Determines if the provided host is correctly formatted IPv6 * * @param string $dbHost The user provided database server host * @return boolean Whether the provided host is correct IPv6 */ private static function isIPv6(string $dbHost): bool { // filter_var requires potential IPv6 addresses to not be encased preg_match_all('/^\[(.*?)\]/', $dbHost, $matches); $listOfTextInsideSquareBrackets = $matches[1]; /* * Only return true if there is some text inside square brackets, * and that text is considered valid IPv6 as per filter_var() */ if ( count($listOfTextInsideSquareBrackets) > 0 && filter_var( $listOfTextInsideSquareBrackets[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) !== false ) { return true; } return false; } /** * Extracts the Host and Port from a user provided database server host, * assuming the provided host is a IPv6 address, with or without a port * * @param string $dbHost The user provided database server host * @throws InvalidArgumentException if the provided dbHost is not a valid IPv6 * @return HostPortExtractor The extracted Host & Port */ private static function extractIPv6(string $dbHost): HostPortExtractor { if (!self::isIPv6($dbHost)) { throw new InvalidArgumentException('$dbHost must be a valid IPv6 address'); } // find and extract the text inside square brackets: [] preg_match_all('/\[(.*?)\]/', $dbHost, $matches); $listOfTextInsideSquareBrackets = $matches[1]; $port = ''; // extract text after closing bracket to search for port $components = explode(']', $dbHost); if (count($components) > 1 && strlen($components[1]) > 0) { // check if the text is a valid port e.g. ':3000' preg_match('/^:(\d+)$/', $components[1], $portMatches); if (count($portMatches) > 0) { $port = $portMatches[1]; } else { throw new InvalidArgumentException('$dbHost port is invalid'); } } // db connector requires IPv6 to be encased in square brackets $host = '[' . $listOfTextInsideSquareBrackets[0] . ']'; return new HostPortExtractor($host, $port); } /** * Determines if the provided host is a Unix Socket * * @param string $dbHost The user provided database server host * @return boolean Whether the provided host is a unix socket */ private static function isUnixSocket(string $dbHost): bool { return (strpos($dbHost, '/') !== false); } /** * Extracts the host & port from the user provided database server host, * assuming the provided host is a unix socket * * @param string $dbHost The user provided database server host * @throws InvalidArgumentException if the provided dbHost is not a valid Unix Socket * @return HostPortExtractor The extracted Host & Port */ private static function extractUnixSocket(string $dbHost): HostPortExtractor { if (!self::isUnixSocket($dbHost)) { throw new InvalidArgumentException('$dbHost must be a valid Unix Socket'); } /* * The DB connector requires unix sockets to be provided as ports in * order to connect successfully. */ $portIndex = strpos($dbHost, '/'); $port = substr($dbHost, $portIndex); return new HostPortExtractor('', $port); } /** * Determines if the provided host is a standard web address or IP with a port * * @param string $dbHost The user provided database server host * @return boolean Whether the provided host is a standard address or IP with port */ private static function isIPWithPort(string $dbHost): bool { $numColons = substr_count($dbHost, ':'); return ($numColons === 1); } /** * Extracts the host & port from the user provided database server host, * assuming the provided host is a standard address or IP with a port * * @param string $dbHost The user provided database server host * @throws InvalidArgumentException if the provided dbHost is not a valid address with a port * @return HostPortExtractor The extracted host & port */ private static function extractIPAndPort(string $dbHost): HostPortExtractor { if (!self::isIPWithPort($dbHost)) { throw new InvalidArgumentException('$dbHost must be a valid address'); } [$host, $port] = explode(':', $dbHost); return new HostPortExtractor($host, $port); } }