I have a database which has a semicolon in the name e.g. a;a. I can't rename the database. In SQL I would use the backticks to escape the name, but how can I do it in PDO DSN?
$db = 'a;a';
$dsn = "mysql:host=localhost;dbname=$db;charset=utf8mb4";
$options = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_EMULATE_PREPARES => false,
];
try {
$pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int) $e->getCode());
}
Since ; is used as a separator in the DSN, PDO thinks my database is called a and I get this error:
Fatal error: Uncaught PDOException: SQLSTATE[HY000] [1049] Unknown database 'a'
I solved it by using double semicolon.
$db = 'a;;a'; // <-- means the database is called `a;a`
$dsn = "mysql:host=localhost;dbname=$db;charset=utf8mb4";
Related
I have multiple classes and most of them need to connect to database,
How can I set PDO options/host/dbname etc only once and then use it in every class while having the following in mind:
I don't want to wrap PDO
I need to close the PDO connection after each query ($db=null), so I simply cannot just use $db = new PDO(...) and then pass $db to my classes
I want to skip having this in every class that needs to connect to the database:
<?php
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
$pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
If you want complete control over opening and closing connections then I suggest we only centralise the $dsn, $user, $pass and $options variables. I'm assuming there are also variables like $host, $db and $charset which you did not reveal to us but lets add them.
Lets call this file global_db.php:
<?php
$host = "127.0.0.1";
$db = "mydb";
$charset = "UTF-8";
$user = "root";
$pass = "";
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
That looks like we have all the goods there, keep in mind I am not testing this so we might get a syntax error or two.
Now in our classes or other php files where we want to open a connection.
Lets call this page fooClass.php
<?php
require_once 'global_db.php';
class FooClass {
public function __construct() {
try {
$pdo = new PDO(
$GLOBALS['dsn'],
$GLOBALS['user'],
$GLOBALS['pass'],
$GLOBALS['options']);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
}
}
That should do the trick or at least give you a general idea on where to go from here on your own route. There are many other ways to accomplish similar but no need to overcomplicate things.
nJoy!
I have searched the forum, but I have not found anything directly related to my issue. I am fairly new to PDOs and class OOP creation. I am trying to create a database connection class where I can instantiate the connection as needed. I having issues instantiating my connection.
File Organization:
parent directory (folder)
|
private (folder)
|
config.php
classes (folder)
|
class1.class.php
DatabaseConnection.class.php
db_cred.inc.php
public (folder)
|
search.php
Process:
I have created a database credential php file "db_cred.inc.php"
I have a database connection class called "DatabaseConnect" in "DatabaseConnect.class.php" file
I load those files as follows
require_once 'db_cred.inc.php'; in the "DatabaseConnect.class.php" file
spl_autoload_register for all of my class files
Expected actions:
When my "search.php" page request data from mysql via a pdo, a new database connection will instantiate a new connection via the "openConnection()" method.
The class "DatabaseConnection" will load the credentials from "db_cred.inc.php" as a sting and connect to the database
The class will then use the credentials to connect to the mysql database, and execute the requested pdo query returning the results and storing them into a variable "$row".
Issue:
When I execute the pdo, the following error is returned:
Uncaught TypeError: PDO::__construct() expects parameter 1 to be string, array given in private/classes/DatabaseConnect.class.php:21 Stack trace: #0 private\classes\DatabaseConnect.class.php(21): PDO->__construct(Array) #1 \public\search.php(53): DatabaseConnect->openConnection() #2 {main} thrown in \private\classes\DatabaseConnect.class.php on line 21
spl_autoload_register() in the config.php file
function my_autoload($class) {
if(preg_match('/\A\w+\Z/', $class)) {
require ('classes/' . $class . '.class.php');
}
}
spl_autoload_register('my_autoload');
Credential setup in "db_cred.inc.php"
<?php
// define an array for db connection.
define("DB", [
"DB_HOST" => "mysql:host=localhost",
"DB_USER" => "user",
"DB_PASS" => "pass",
"DB_DATABASE" => "mytestdb",
"DB_CHAR" => "utf8",
]);
?>
My class for database connection:
<?php
require_once 'db_cred.inc.php';
// creating db connection class
class DatabaseConnect {
private $server = 'DB_HOST';
private $database = 'DB_DATABASE';
private $pass = 'DB_PASS';
private $user = 'DB_USER';
private $opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
protected $con;
public function openConnection() {
**ERROR TAKES PLACE HERE**
try {
$this->con = new PDO([$this->server, $this->database, $this->user, $this->pass]);
return $this->con;
} catch(PDOExeption $e){
echo "ERROR: " . $e->getMessage(), (int)$e->getCode();
}
}
public function closeConnection() {
$this->con = null;
}
}
?>
PDO for search.php
<?php
$dbconn = new DatabaseConnect();
$pdo = $dbconn->openConnection();
$sql = "SELECT * FROM report";
foreach ($pdo->query($sql) as $row) {
echo " PI: ".$row['pi'] . "<br>";
}
?>
I am not sure what is causing the error. I am sure it is due to my inexperience with classes and oop. It appears that the config.php file is working fine. The class is identified by the request because the error happens inside the PDO __construct method. Please help.
UPDATE - MY WORKING SOLUTION
I hope this might help someone moving forward with a similar question. I am not finished with the development of this process, but this kicked in a huge door.
My revised class
<?php
// Associating db_cred.inc.php with class
require_once('db_cred.inc.php');
// Creating db connection class
class DatabaseConnect {
/*
!! Assigning defined constants per define('DB_CONSTANT', 'value') loaded from "db_cred.inc.php" file to variables
!! "db_cred.inc.php" should not be loaded into the "config.php" file
!! BECAUSE THE VALUES OF THE VARIABLES ($variable) ARE CONSTANTS (DB_CONSTANT), DO NOT USE SINGLE OR DOUBLE QUOTES. THE PDO __CONSTRUCT FUNCTION WILL IGNORE THE VALUE OF THE VARIABLE
*/
private $host = DB_HOST;
private $database = DB_DATABASE;
private $pass = DB_PASS;
private $user = DB_USER;
private $char = DB_CHAR;
// Setting attributes and storing in variable $opt
private $opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
// $con variable will store PDO connection and is set to NULL
private $con;
// Create Connection to database
public function openConnection() {
// Setting $con to null
$this->con = NULL;
// If $con is not NULL make it NULL
if ($this->con === NULL){
try {
// Establish DSN
$dsn = "mysql:host={$this->host};dbname={$this->database};charset={$this->char}";
// Complete the PDO connection
$this->con = new PDO($dsn, $this->user, $this->pass,$this->opt);
// Return the connection and store it in $con
return $this->con;
// Catch any exceptions and store in $e
} catch(PDOExeption $e){
// Echo error and Exception message
echo "ERROR: " . $e->getMessage(), (int)$e->getCode();
}
// If the try/catch block fails, echo that no connection was established
} else {
echo "ERROR: No connection can be established";
}
}
// Close connection and set it to NULL
public function closeConnection() {
if($this->con !== NULL){
$this->con = NULL;
}
}
// create CRUD subclass (Create, Read, Update, Delete)
}
?>
I changed "db_cred.inc.php" eliminating the array. I may revisit the idea.
<?php
// defining DB Credential CONSTANTS to be stored in variables and instantiated by connect class
define("DB_HOST", "localhost");
define("DB_USER", "user");
define("DB_PASS", "pass");
define("DB_DATABASE", "mytestdb");
define("DB_CHAR", "utf8");
// define an array for db connection.
/*define("DB", [
"DB_HOST" => "localhost",
"DB_USER" => "user",
"DB_PASS" => "pass",
"DB_DATABASE" => "mytestdb",
"DB_CHAR" => "utf8",
]);*/
?>
The error explains itself: You're passing an array where you should be using a string instead.
You need to change this line:
$this->con = new PDO([$this->server, $this->database, $this->user, $this->pass]);
To this, (specifies the DSN first):
$dsn = "mysql:dbname={$this->database};host:{$this->host}";
$this->con = new PDO($dsn, $this->user, $this->password);
I have a fatal error showing when I am trying to get MySQL to use a PDO instance in Godaddy shared hosting.
Code I tried to connect my database:
code 1
try{
$connect = new PDO('mysql:host=localhost;dbname=dbname;charset=utf8', 'user', 'password',
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
$connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}catch(PDOException $e){
die('Error connecting to database');
}
When I used this code, it is printing 'Error connecting to database'
code 2
$dsn = 'mysql:host=localhost;dbname=dbname';
$user = 'user';
$password = 'password';
try {
$dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
When I used this code it is printing an error:
'Connection failed: SQLSTATE[HY000] [1044] Access denied for user 'user'#'localhost' to database 'dbname"
Godaddy support is saying it is a string error that I have to review from my end and they are asking paid service to resolve it from their end. I found this both code running in my local server (xaamp).
First, make sure everything is correct in your config array, then add '\' this before PDO instance:
// Define Config Options
$config = [
'username' => 'YourUsername',
'password' => 'YourPassword',
'database' => 'YourDatabase'
];
// Make a function to easily access it
function connect($config)
{
try{
$conn = new \PDO('mysql:host=localhost;dbname=' .$config['database'], $config['username'], $config['password']);
$conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
return $conn;
}
catch(Exception $e){
return false;
}
}
In shared hosting you normally find that the mysql server is not localhost, you normally find that your provider will place the mysql server on a separate machine.
Login in to you control panel with godaddy and look at the settings, you'll probably have to create a database first.
I use this code for check connection to the database(MYSQL).If the database name not available then also it show connect successfully.
if(isset($_REQUEST['submit']))
{
echo $name = $_REQUEST['name'];
echo $pwd = $_REQUEST['password'];
$servername = "localhost";
$username = "root";
$password = "";
try
{
$conn = new PDO("mysql:host = $servername;dbname = pdo",$username,$password);
//echo "Connected successfully";
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "connect successfully";
}
catch(PDOException $e)
{
echo "Connection failed: " . $e->getMessage();
}
}
TL;DR
Because your code is using try-catch blocks you can be sure that as long as no exceptions are thrown the connection was successfully established. Otherwise check the error code stored inside the exception to resolve the type of error.
More detailed
Your code makes use of exceptions, so if an error occurred while a connection was attempted established an exception would be thrown. As far as I know the PDO object throws exceptions by default while it is constructed and falls back to silent mode when to instance is created. So you are assured you will be warned if anything bad happens during construction.
Update 1
How to check the database name is available or not in to the database using PDO?
As said you can utilize exceptions. But instead of echoing the exception message you can inspect the returned error code using the PDOException method getCode(). Using php version 5.6.8 I will get the code 1049. You can then check using the following:
try {
$pdo = new PDO($dsn, $username, $passowrd, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false
]);
}catch(PDOException $exception) {
if($exception->getCode() == 1049) {
echo 'Database does not exist!';
}
// Continue error handling...
}
Update 2: Alternative
Using the same PHP version as above you can avoid selecting a database in the DSN. With this you can fetch a list of accessible databases for the used MYSQL user. Using this list you can check the existence of one or more databases at the same time and avoid the overhead of an exception halting execution of your script.
/*
* I assume you are on localhost.
*/
$pdo = new PDO('mysql:host=127.0.0.1', $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false
]);
$databases = $pdo->query('SHOW DATABASES'); // Does not require a prepared statement since it takes no input.
/*
* The following can be done more elegant/efficient.
*/
$exists = false; // Equals TRUE if the database exists.
$check = 'test'; // Enter the database to check for.
foreach($databases->fetchAll(PDO::FETCH_ASSOC) as list($database)) {
if($database == $check) {
$exists = true;
break;
}
}
Bonus
You are setting the error mode after the PDO instance has been constructed. This can also be done with the fourth parameter of PDO's constructer. I think this leads to more readable code.
I would also recommend setting the configuration PDO::ATTR_EMULATE_PREPARES to false. This ensure prepared statements are always used. The documentation can be found here.
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false
]);
Happy coding!
I'm using a slight variation on the PHP PDO Wrapper Class found here: http://www.imavex.com/php-pdo-wrapper-class/
This is the new constructor I'm using:
public function __construct($dsn, $user='', $passwd='') {
$options = array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
try {
parent::__construct($dsn, $user, $passwd, $options);
} catch (PDOException $e) {
$this->error = $e->getMessage();
}
}
error is a private variable of this class, defined at the begin of the class, above the constructor.strong text
And when I use it like this
$database = new Database(
'mysql:host=' . $config['mysql_host'] . ';port=' . $config['mysql_port'] . ';dbname=' . $config['mysql_database'],
$config['mysql_username'],
$config['mysql_password']
);
It shows me this error: Creating default object from empty value, pointing to the database class file, at the line $this->error = $e->getMessage();.
The reason an exception is thrown is because I haven't set the mysql username and password yet, so don't worry about that. I'm trying to figure out why it gives this error and how to fix it.
It seems that since the db class extends PDO, when the PDO constructor throws an exception $this becomes NULL.
class db extends PDO {
public function __construct($dsn, $user="", $passwd="") {
$options = array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
try {
parent::__construct($dsn, $user, $passwd, $options);
} catch (PDOException $e) {
echo "Got PDOException\n";
var_dump($this);
}
}
}
new db('mysql:host=localhost;port=3306;dbname=something', 'invaliduser', 'invalidpass');
If you run that code you will get this output:
Got PDOException
NULL
To solve that you could remove the offending line and check if the db object is null or remove the try-catch and do the exception handling when you instantiate a new db.
Alternatively, you could rewrite the class to store the PDO object in a variable instead of extending PDO.