Function to connect to database using PDO [duplicate] - php

This question already has answers here:
Can't connect to MySQL with PDO
(2 answers)
Closed 26 days ago.
I have to create getConnection function inside of Database class. The function should connect to a database using PDO object and returning it.
I have something like this:
class Database {
public function getConnection() {
$result = new PDO('mysql:host=localhost;dbname=demo', 'root', '');
return $result;
}
}
Is it correct? How can i know if i'm connected to database?

PDO will throw an exception if the connection attempt fails, so you can normalize that like this:
class Database {
private $_conn = null;
public function getConnection() {
if (!is_null($this->_conn)) {
return $this->_conn
}
$this->_conn = false;
try {
$this->_conn = new PDO('mysql:host=localhost;dbname=demo', 'root', '');
} catch(PDOException $e) { }
return $this->_conn;
}
}
$db = new Database();
$conn = $db->getConnection();
if (!$conn) {
die("Error connecting to the database");
}
$conn->whatever();

How can i know if i'm connected to database?
PDO will throw an exception in case of connection error.
Is it correct?
Nope, it's not a good idea, because the method is called getConnection while in reality it creates a connection. And a public property asks to call it in the application code, resulting multiple connections from the same script.
Besides, you should always set PDO in exception mode. And you should set charset in DSN as well.
Depends on the proposed use of this function the code could be
protected function connect()
{
$pdo = new PDO('mysql:host=localhost;dbname=demo;charset=utf8', 'root', '');
$pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
return $pdo;
}
if it's intended to be used only once in the constructor.
While for the getConnection() function you are bound to use a static variable ho hold the single instance of PDO.
Recently I took time to compile all the common mistakes for the database wrappers in the article Your first DB wrapper's childhood diseases. You may find this reading extremely useful.

Related

mysqli connection done in __construct and cause too many connections

I have mysqli connection that is created in the __construct part of my database class:
public function __construct() {
$link = new mysqli($this->host, $this->user, $this->password, $this->db);
}
because of that, every time that I want to create an object of a database (for query) It's create new connection, and that cause "Too many connections" in my script.
The way I am calling to the database (from another class) is like this:
$db = new Database;
$db->query("SELECT language_iso_code FROM languages WHERE language_iso_code = ");
Is there another way to call the query function? Or maybe a way to pass the connection of mysqli to another classes?
You might consider to use a static variable for your class and only connect to the database if the connections not up:
class Example {
private static link = null;
public function __construct() {
if(self::$link === null) {
self::link = new mysqli($this->host, $this->user, $this->password, $this->db);
}
}
}

How to access variables in OOP

I am trying to find a way to get the variable called $connect to run but don't know how.
Filename: /engine/init.php
class Engine {
function MySQL() {
$connect = new PDO("mysql:host=$db_host;dbname=$db_name;charset=$db_char", $db_user, $db_pass);
}
}
Filename: /inc/database.php
require 'engine/init.php;
$engine = new Engine;
$conn = $engine->MySQL;
// Activate $connect variable
If it's not clear, please request for more info.
Thanks,
CrAzYz_
You will have to update the class to access members outside.
You have several options to do it.
1: store the connection in a public property
class Engine {
public $connection;
public function MySQL() {
$this->connection = new PDO("mysql:host=$db_host;dbname=$db_name;charset=$db_char",$db_user, $db_pass);
}
}
This way you can retrieve it by
$engine = new Engine();
$engine->MySQL();
$conn = $engine->connection;
2: Make the function return the connection
class Engine {
public function MySQL() {
return new PDO("mysql:host=$db_host;dbname=$db_name;charset=$db_char",$db_user, $db_pass);
}
}
This way your example will work (if you use Mysql as a function):
$engine = new Engine();
$conn = $engine->MySQL();
3: A more complicated but generally better aproach:
class Engine {
protected $connection;
public function __construct($db_host, $db_name, $db_user, $db_pass $db_char = "utf-8") {
$this->connection = new PDO("mysql:host=$db_host;dbname=$db_name;charset=$db_char",$db_user, $db_pass);
}
public function MySQL() {
if ( !$this->connection instanceof PDO ) {
throw new Exception("Connection is not set up");
}
return $this->connection;
}
}
This would work almost as you wanted, except you cant access the connection directly (its protected), but only through the MySql function. This way if you forgot to init the connection an exception is thrown.
$engine = new Engine("localhost", "db_name", "user", "pass");
$conn = $engine->MySQL(); // you don't even need to save the connection to a local variable, because the function only references the connection and won't start a new one
Footnote:
If you had to as this kind of question you should probably look up and learn more about OOP. For php this is a start: http://php.net/manual/en/language.oop5.php
About to run off so this is a little quickly done.
class Engine
{
public $db;
public function connect($host, $database, $charset, $user, $pass)
{
$this->db = new PDO("mysql:host=$host;dbname=$database;charset=$charset", $user, $pass);
}
}
First of we have your Engine class that you want to create, we've created a property named db on the class that we can access with ->db. We also have a method called connect which we pass our database variables into so that PDO can connect to our database.
Now we pass in our database credentials to our connect method, in a production environment I really would advise against hard coding these and instead use something like environment variables.
$engine = new Engine();
$engine->connect('127.0.0.1', 'example_database', 'UTF-8', 'root', 'root');
We can then use our newly initiated PDO connection like so:
$statement = $engine->db->query('SELECT * FROM some_table');
$result = $statement->execute();
That should at least give you a starting point, there are other ways to go about this but I didn't want to stray too far from your original code.
Also if anyone spots anything wrong, let me know and i'll update it when I'm back in, need to run off in a sec.

PDO Connection and abstract class

I am using abstract class with PDO. I want to know if it is necessary to null the $conn variable every time, or if it does so itself when the scripts ends?
Can you also tell me, with this type of structure, what would be the best way to nullify $conn?
abstract class DB_Connection
{
protected static $tbl_admin = "prof_admin";
//protected static $tbl_admin = "prof_admin";
protected static function obj_db()
{
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "salmanshahid";
$conn = null;
try
{
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $conn;
}
catch(PDOException $e)
{
echo $sql . "<br>" . $e->getMessage();
}
}
protected static function select($query)
{
try
{
$conn = self::obj_db();
$stmt = $conn->prepare($query);
$stmt->execute();
// set the resulting array to associative
$stmt->setFetchMode(PDO::FETCH_ASSOC);
return $stmt->fetchAll();
}
catch(PDOException $e)
{
throw new Exception("Error In SELECT STATMENT: " . $e->getMessage());
}
}
protected static function insert($query)
{
try
{
$conn = self::obj_db();
$stmt = $conn->prepare($query);
$stmt->execute();
}
catch(PDOException $e)
{
throw new Exception("Error In INSERT STATMENT: " . $e->getMessage());
}
}
}
or if it does so itself when the scripts ends?
Yes, sure, PHP automatically close and clean up all the resources that has been opened during script execution, so, don't worry to close it manually.
Anyway, to nullify conn, just nullify it: $this->conn = NULL;
But all that stuff is utterly negligible compared to the other problems of your class, which is insecure, inefficient and unusable.
First of all, I have no idea why would you want to make this class abstract. Abstract classes are prototype classes, used to be source of other classes. But a database wrapper is rather a ready to use final class. I see no point in making it abstract.
Error reporting is also superfluous and inconsistent. Adding "Error In SELECT STATMENT" to the error message is quite useless. While connection error handling is plainly wrong. Instead, let PDO to throw an exception and just let it go. It will be handled the same way as any other error in your site.
Next problem is security. For some reason neither select() not insert() function supports prepared statements, which renders them quite useless: you can use PDO::query() instead, with exactly the same outcome. But what you really have to is to use prepare/execute properly, by using placeholders in the query while sending actual variables to execute();
Another problem is duplicated code: both functions are pretty much the same.
And at the same time both function are quite unreliable: select() function is limited to only one type of result set, while insert() doesn't return anything at all. Instead, you can use just single function to run all your queries, and make it return the statement, which will be extremely useful. It will let you to get the returned data in dozens different formats supported by PDO, and even let you to get the number of affected rows from DML queries.
Let me suggest you another approach, a simple PDO wrapper that can let you to use PDO most simple and secure way:
<?php
define('DB_HOST', 'localhost');
define('DB_NAME', 'test');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_CHAR', 'utf8');
class DB
{
protected static $instance = null;
public function __construct() {}
public function __clone() {}
public static function instance()
{
if (self::$instance === null)
{
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => TRUE,
);
$dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset='.DB_CHAR;
self::$instance = new PDO($dsn, DB_USER, DB_PASS, $opt);
}
return self::$instance;
}
public static function __callStatic($method, $args)
{
return call_user_func_array(array(self::instance(), $method), $args);
}
public static function run($sql, $args = [])
{
$stmt = self::instance()->prepare($sql);
$stmt->execute($args);
return $stmt;
}
}
It's extremely powerful, secure, and easy to use.
You can use any PDO function by simply adding it's call after DB:: prefix:
$stmt = DB::query("SELECT * FROM table WHERE foo='bar'");
So, in the first place, it's a PDO wrapper, which is able to run any PDO method by means of using magic __call() method. The only function I added is run().
Instead of your own insecure and unreliable select() and insert() methods let me suggest you to use one universal run() method, which is nothing more than a shorthand to these three lines:
$stmt = DB::prepare($query);
$stmt->execute($params);
$data = $stmt->fetch();
So, instead you can write it as a neat one-liner:
$data = DB::run($query, $params)->fetch();
Note that it can run a query of any kind and return the result in any format that PDO supports.
I wrote an article about this simple wrapper, where you can find some usage examples. All the example code can be run as is, just copy and paste it in your script and set up credentials: http://phpdelusions.net/pdo/pdo_wrapper#samples

mysql_real_escape_string with singleton database in php?

I get the following error on my php pages that use database functions:
Warning: mysql_real_escape_string()
[function.mysql-real-escape-string]: Access denied for user
'apache'#'localhost'
I know I have to have a working connection to my database, but here is the 'problem'. The class that connects to my database looks like this:
class Database
{
private static $instance = null;
private static $conn;
private function __construct()
{
try {
self::$conn = new mysqli('localhost', 'root', 'user', 'database');
} catch (Exception $ex) {
$errorpager = new CustomPageGenerator();
$errorpager->generateErrorPage("Connection to database failed. Please try again later.");
}
}
public static function getInstance()
{
try {
if (self::$instance == null) {
self::$instance = new Database();
}
return self::$instance;
} catch (Exception $ex) {
$errorpager = new CustomPageGenerator();
$errorpager->generateErrorPage("Connection to database failed. Please try again later.");
return false;
}
}
public function query($sql)
{
try {
return self::$conn->query($sql);
} catch (Exception $ex) {
$errorpager = new CustomPageGenerator();
$errorpager->generateErrorPage("Connection to database failed. Please try again later.");
return false;
}
}
}
As you can see, I use the Singleton pattern for this. But even though I put a
Database::getInstance();
at the very beginning of my code to open up the connection I keep getting this error. How do I correctly open up the connection so that I can use the mysql_real_escape_string() function?
Thanks.
And here is le fix
Added this function to the Database class:
public static function getConnection()
{
self::getInstance();
return self::$conn;
}
Replaced every single mysql_real_escape_string( with mysqli_real_escape_string(Database::getConnection(),
I think the problem is that you are using mysql_real_escape_string().
That is from a different library than mysqli, maybe that's why there is no connection?
From the mysql_real_escape_string page in the PHP manual:
string mysql_real_escape_string ( string $unescaped_string [, resource
$link_identifier = NULL ] )
This is the definition for the second parameter, $link_identifier.
The MySQL connection. If the link identifier is not specified, the
last link opened by mysql_connect() is assumed. If no such link is
found, it will try to create one as if mysql_connect() was called with
no arguments. If no connection is found or established, an E_WARNING
level error is generated.
A possible, but kind of ugly solution, is to just add a wrapper to the real_escape_string method on your mysqli instance in your db singleton.
public function escapeString($value){
return $this->conn->real_escape_string($value);
}
Another alternative may be to use the procedural version for mysqli library (although, I haven't actually tried to see if you can mix both, but I think you can): mysqli_real_escape_string

Best way to make a PDO mysql static connection class?

I'm quite new to PDO and also OOP with PHP in general so please be nice :) Basically I'm trying to make a connection object based on PDO so that I can have one connection that I call throughout my site.
I need some prepared statements that simply look up different results based on an ID I pass through using the same db object that I'm trying to create below.
How do I make and access the db class I set below and then use functions within it to extract the relevant info I need? Any examples would be great so I can get an idea of the best practices etc.
Many thanks in advance.
class db {
private static $connection;
private function __construct(){}
private function __clone(){}
private static function connect($db_server="localhost", $db_user="user", $db_pass="password") {
if(!$this->connection){
try{
$this->connection = new PDO($db_server, $db_user, $db_pass);
} catch (PDOException $e) {
$this->connection = null;
die($e->getMessage());
}
}
return $this->connection;
}
}
$dbh = new db::connect();
$stmt = $dbh->prepare("SELECT * FROM questions where id = ?");
if($stmt->execute(array($_REQUEST['testid']))) {
while ($row = $stmt->fetch()) {
print_r($row);
}
}
You could begin by not ever using Singleton pattern again. It (and static classes in general) is bad for all the same reasons why global variables in procedural programming are bad.
That said ... Instead of trying to enforce the uniqueness of the connection object, you should be just making sure that you using the same connection all over the place.
Here's an example of what i mean by that:
class Foo
{
protected $connection = null;
public function __construct( PDO $connection )
{
$this->connection = $connection;
}
}
class Bar
{
// all the same as in Foo
}
$connection = new PDO('sqlite::memory');
$foo = new Foo( $connection );
$bar = new Bar( $connection );
At this point both $foo and $bar objects will have access to the same PDO instance. If you have an object that needs access to database, then you just provide it with a connection in the constructor.
There are two videos you might want to watch (slides will contain Java code, but you should have no troble understanding it):
Global State and Singletons
Don't Look For Things!
Persistent connections are built in:
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(
PDO::ATTR_PERSISTENT => true
));
See Example #4 Persistent connections

Categories