/** * Constructor Method * @param int $type (required) - * @param string $name (required) - * @param string $user (required for secured) - * @param string $pass (required for secured) - * @param string $host (required for remote, optional because it defaults to localhost) - * @param integer $port (required for remote, optional because it defaults to server type's default port) - * @param strign $table (optional) - */ public function __construct($name, $user = null, $pass = null, $host = 'localhost', $port = null, $table = null) { $data = []; //instantiate data array /* * Input Handling for $name (database name) * * $name is required, must be a string, and must be a valid database name, * but we cannot check if it's a valid name until we connect. */ if (isset($name)) { //database name is set if (gettype($name) != 'string') { //database name is not a string throw new DatabaseException(__METHOD__ . '(): encountered database name argument of invalid type.', DatabaseException::EXCEPTION_INPUT_INVALID_TYPE, $this); } else { $data['name'] = $name; //add validated database name to data array } } else { //database name is not set throw new DatabaseException(__METHOD__ . '(): missing required database name argument.', DatabaseException::EXCEPTION_MISSING_REQUIRED_ARGUMENT, $this); } /* * Input Handling for $user (username) * * $user is only required for servers that require authentication. We cannot * test if authentication is required until after connecting. $user also must * be a string. */ if ($user !== null) { //username is set if (gettype($user) != 'string') { //username is not a string throw new DatabaseException(__METHOD__ . '(): encountered username argument of invalid type.', DatabaseException::EXCEPTION_INPUT_INVALID_TYPE, $this); } else { $data['user'] = $user; //add validated username to data array } } /* * Input Handling for $pass (password) * * $pass is only required for servers that require authentication. We cannot * test if authentication is required until after connecting. $pass also must * be a string. */ if ($pass !== null) { //password is set if (gettype($pass) != 'string') { //password is not a string throw new DatabaseException(__METHOD__ . '(): encountered password argument of invalid type.', DatabaseException::EXCEPTION_INPUT_INVALID_TYPE, $this); } else { $data['pass'] = $pass; //add validated password to data array } } /* * Input Handling for $host (server hostname) * * $host is only required for remote database servers (so not sqlite). However, * $host already has a default value of 'localhost', which means that it doesn't * have to be provided in an argument if using localhost. $host must be a string, * $host must be a valid IP address, hostname, or domain name, and if there is a * port after a : in the URL, that must be separated into $port. */ if ($host != 'localhost') { //hostname is set if (gettype($host) == 'string') { //hostname is a string if (!DatabaseUtils::isValidHost($host)) { //hostname has invalid syntax throw new DatabaseException(__METHOD__ . '(): encountered invalid given hostname (do not include URI scheme, port numbers, or paths!).', DatabaseException::EXCEPTION_INPUT_NOT_VALID, $this); } else { $data['host'] = $host; //add validated hostname to data array } } else { //hostname is not a string throw new DatabaseException(__METHOD__ . '(): encountered hostname argument of invalid type.', DatabaseException::EXCEPTION_INPUT_INVALID_TYPE, $this); } } else { $data['host'] = $host; //add default hostname to data array } /* * Input Handling for $port (server port number) * * $port is only required for remote database servers (so not sqlite). However, * $port will be given a default value based on the server type. $port must be an * integer greater than or equal to 0 and less than or equal to 65535. The actual * validity of the port cannot be validated until trying to connect to the server. */ if ($port !== null) { //port is set if (!is_int($port)) { //port is not an integer if (is_numeric($port)) { $port = (int) $port; if (0 > $port || $port > 65535) { throw new DatabaseException(__METHOD__ . '(): encountered port number argument outside of legal bounds.', DatabaseException::EXCEPTION_INPUT_NOT_VALID, $this); } else { $data['port'] = $port; //add validated password to data array } } else { throw new DatabaseException(__METHOD__ . '(): encountered port number argument of invalid type.', DatabaseException::EXCEPTION_INPUT_INVALID_TYPE, $this); } } } else { //port is not set $port = isset($this->dbms['config']['defaultPort']) ? $this->dbms['config']['defaultPort'] : null; //no port available $data['port'] = $port; //add validated port number to data array } /* * Input Handling for $table (default table) * * $table is optional. This only has to be set when a default table is required. * If it is not set, other methods will need to be given a table argument or they will * error. Table must be a string, and must be a valid name for a SQL table. We won't know * if the default table is valid until after the database connection is established, but * it will be tested then. */ if ($table !== null) { //table is set if (gettype($table) != 'string') { //table is not a string throw new DatabaseException(__METHOD__ . '(): encountered table argument of invalid type.', DatabaseException::EXCEPTION_INPUT_INVALID_TYPE, $this); } else { $data['table'] = $table; } } else { $data['table'] = $table; } //Set class properties/members $this->name = $data['name']; $this->user = $data['user']; $this->pass = $data['pass']; $this->host = $data['host']; $this->port = $data['port']; $this->table = $data['table']; //generate DSN $dsn = $this->dbms['dsn']['prefix'] . ':'; //add prefix $dsnargs = []; //instantiate dsn arguments array foreach ($this->dbms['dsn']['args'] as $arg) { //loop over each argument if ($arg['required']) { //check if argument is required if (!isset($data[$arg['value']]) || $data[$arg['value']] == null) { //check if required argument is missing throw new DatabaseException(__METHOD__ . '(): missing required argument "' . $arg['value'] . '" to build DSN.' . json_encode($data), DatabaseException::EXCEPTION_MISSING_REQUIRED_ARGUMENT, $this); continue; //skip iteration (in case exception is caught) } } //create DSN argument and insert it into argument array if (isset($arg['name']) && $arg['name'] != null) { //if argument has a name... $dsnargs[] = $arg['name'] . '=' . str_replace(';', '', $data[$arg['value']]); //format like "name=value"... } else { //if argument has no name... $dsnargs[] = str_replace(';', '', $data[$arg['value']]); //format like "value". } } $dsn .= implode(';', $dsnargs); //combine all arguments, separate with ';', add to DSN //create PDO object with DSN (this is the actual connection) try { $this->connector = new PDO($dsn, $user, $pass); $this->connector->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->connector->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); } catch (PDOException $e) { throw new DatabaseException(__METHOD__ . '(): caught exception when opening the database connection', DatabaseException::EXCEPTION_GENERIC_DATABASE_ERROR, $this, $e); } }