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
Related
I work now on a project for learning i'm a beginner, i use singelton pattern to make sure, that there is just one PDO connection to the Data Base.
I made var_dump() for all possible connections to the Mysql and I founded that there were 10 objects of pdo.
how can i found, from where come all this objects?
Are 10 objects of PDO normal?
I wanted to use just one for all the project.
my singelton
<?php
namespace App\Database;
use PDO;
use PDOException;
class DataBase
{
private static $instance;
private PDO $pdo;
private function __construct()
{
try {
$db= parse_ini_file("..//..//..//config.ini");
#$db= parse_ini_file("..//..//config.ini");
$type = $db['type'];
$host = $db['host'];
$name = $db['name'];
$user = $db['user'];
$password = $db['password'];
$this->pdo = new PDO($type . ':host=' . $host . ';dbname=' . $name, $user, $password);
}
catch (PDOException $e) {
echo "there is an error";
die();
}
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
return $this->pdo;
}
private function __clone() {}
public static function getInstance()
{
if (!static::$instance) {
static::$instance = new DataBase();
}
return static::$instance;
}
public function getPdo(): PDO
{
return $this->pdo;
}
}
?>
then I made a connection of the pdo like this in another place, where I need to use pdo init.
function makePdo(){
$db= DataBase::getInstance();
$pdo= $db->getPdo();
var_dump($pdo);
return $pdo;
}
Thank you
10 connections are not normal, you should have only one to one DB. Use singleton pattern for database connection:
https://gist.github.com/jonashansen229/4534794
https://phpenthusiast.com/blog/the-singleton-design-pattern-in-php
In this case, you will have one connection and always will get it instead of creating duplicates.
No it should be only one object, the best way to implment it, is to create a separate config file to store your DBMS credentials as associative array, like mysql db_name, host .. etc.
Then create a config class to get those values by creating a static get method.
and finally use this get method inside your db constructor to get the credentials.
I'm pretty sure If you do that you'll get only one instance of PDO object.
I am currently trying to get a PDO SELECT statement to work with a variable passed in through the parameter of the function it is contained within. I am using this function to return values to the class constructor.
Here is the function for which i am encountering a "Fatal error: Call to a member function prepare() on a non-object"
public function select($field) {
global $pdo;
$query = $pdo->prepare("SELECT `".$field."` FROM `iwp_incident` WHERE `incident_id=`". $this->oid ."`");
$query->execute();
$result = $query->fetch();
return $result[0];
Your main problem is that the assumed PDO instance is not what you think it is (my guess is null).
To alleviate this problem, you should remove the reliance on globals and instead use dependency injection. For example
namespace Some\Namespace;
use \PDO;
class YourClass {
/**
* #var PDO
*/
private $pdo;
private $oid;
public function __construct(PDO $pdo, $oid) {
$this->pdo = $pdo;
$this->oid = $oid;
$someField = $this->select('some_field');
}
public function select($field) {
$stmt = $this->pdo->prepare(sprintf(
'SELECT `%s` FROM `iwp_incident` WHERE `incident_id = ? LIMIT 1',
$field));
$stmt->bindParam(1, $this->oid);
$stmt->execute();
return $stmt->fetchColumn();
}
}
To use this, you simply pass in your PDO instance when creating the class, eg
$pdo = new PDO('mysql:...', 'username', 'password', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
$obj = new \Some\Namespace\YourClass($pdo, 123);
The error message is quite helpful. $pdo is a non-object, as stated. presumably your initial connection failed. It might be good practice to check that $pdo is valid, though the initial connection (wherever that is in your code) should throw an exception if the connection fails. (Did you catch that exception and swallow it without reporting anything...?)
As an aside, may I suggest that instead of string concatenation you do something like this which handles quoting and escaping to help prevent mistakes that allow injection attacks:
$query = $pdo->prepare("SELECT `".$field."` FROM `iwp_incident` WHERE `incident_id`= :oid");
$params = array(":oid"=>$this->oid);
$success = $query->execute($params);
if($success) {
$results = $query->fetchAll(PDO::FETCH_ASSOC);
// process results
}
Sorry for the stupid question am a newbie to oop in php...i have a proble wiriting a mysqli class thet returns a connection handler that enable me the connection handler in other classes/methods. i run a small procedural blog n wanted to convert to oop.
heres a my working code example. please refactor for me where necessary. Thank in advance.
$db_link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
class myDB extends mysqli
{
public function getConfig($id, $db_link) // thanks cbuckley
{
$db_link = $this->db_link;
$res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
}
i have defined the constants already and the connection is successful but the select is not working. on the index page this goes
include('inc/dbc.php');
$db = new MyDB();
echo $db->getConfig(1, $db_link);
any help is appreciated
Your question is not very specific, and I have the feeling you're not really aware what your concrete problems are. You've already accept an answer that gives you some code but puts you in the wrong direction as it does not solve your underlying problem and wastes code.
The first thing you should know if you want to make use and benefit of the object oriented interface of PHP's mysqli extension is, that the Mysqli class represents the database connection (the "link" as it was named for a procedural approach) already:
require('inc/dbc.php');
$dbConnection = new Mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
That's already it. Sure you might want to use some error handling here:
if ($dbConnection->connect_error)
{
throw new Exception(
sprintf('(#%d) %s', $dbConnection->connect_errorno,
$dbConnection->connect_error)
);
}
Throwing exception instead of let's say die('message') is done, because you can easily create an exception handler so that you can display a more useful response to the user from within a central place instead of handling each exceptional error-case where it appears (actually at the place where die would be).
You can also log and mail the backtrace so you can fix things more easily. Naturally you do not need to use exceptions, however the rule of thumb is to use die only in scripts you throw away in let's say a week and it does not work well with object oriented design.
As you will need this code anyway in all places where you will need your database connection, you can create your own connection object to bring those parts together as they belong together:
class DatabaseException extends Exception
{
}
class DatabaseConnection extends Mysqli
{
public function __construct($host, $user, $password, $database = "", $port = NULL, $socket = NULL) {
parent::__construct($host, $user, $password, $database, $port, $socket);
$this->throwConnectionExceptionOnConnectionError();
}
private function throwConnectionExceptionOnConnectionError() {
if (!$this->connect_error) return;
$message = sprintf('(%s) %s', $this->connect_errno, $this->connect_error);
throw new DatabaseException($message);
}
}
The usage is actually pretty straight forward and very much the same, only the name of the class varies and it's definition needs to be loaded:
require('inc/dbc.php');
require('inc/database.php');
$dbConnection = new DatabaseConnection(DB_HOST, DB_USER, DB_PASS, DB_NAME);
As written, the connection object already represents your database connection. So every part in your application that needs it, has to ask for it. Let's review your example function:
function getOption($id, $db_link)
{
// $db_link = $this->db_link;
$res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
I renamed the function and I commented the first line, even this might be what you want. Actually, if that function would be part of the DatabaseConnection object, it could work like this:
class DatabaseConnection extends Mysqli
{
...
public function getOption($id) {
$statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
$statement->bind_param('i', $id);
$statement->execute();
$statement->bind_result($option);
$statement->fetch();
$statement->close();
return $option;
}
As this example demonstrates, the database connection is already there. However, this is not advisable. Imagine you not only have options but this and that and such and what not more. You would create one function after the other all in one class. Well for a little application that might even so work right, but imagine more and more. You would get one very large class that is responsible for many things. So it would be bad to do this, even if you can use $this already to prepare the statement.
Also take note that you should prepare statements. This has been answered here numerous times, if you're not used to it, read about it, it's worth the lines. There are better ways to not repeat code (DRY: Don't repeat yourself) while stepping into object oriented (you should even already do this with procedural).
So as to have this all in one class would be a problem, you instead put it in a class of it's own:
class DatabaseModelBase
{
protected $connection;
public function __construct(Connection $connection) {
$this->connection = $connection;
}
protected function prepare($query) {
$connection = $this->connection;
$statement = $connection->prepare($query);
if (!$statement) {
throw new DatabaseException(
sprintf('(%s) %s', $connection->error, $connection->errno)
);
}
return $statement;
}
}
class Option extends DatabaseModelBase
{
public function find($id) {
$statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
$statement->bind_param('i', $id);
$statement->execute();
$statement->bind_result($option);
$statement->fetch();
$statement->close();
return $option;
}
}
This has some extended error handling again, because most often mistakes are made in the SQL query. And as you can see the individual function to fetch some specific data is placed in it's own class. You can use such classes to group the fetching and updating for specific datatypes.
Usage in full:
$dbConnection = new Connection(DB_HOST, DB_USER, DB_PASS, DB_NAME);
$option = new Option($dbConnection);
$optionValue = $option->find(1);
echo $optionValue; # value for option with ID1
The names of the Option object probably is not well, I tried to keep the example lightweight but also offer some separation. For other scenarious you might want to prefer some different kind how to access the db connection, because it is injected into Option via it's constructor, Option does not deal any longer with the details how the database connection is being created.
For example you can make the database connection object more smart only to connect to the database the first time prepare or query is actually used with it. So that requests to your website that do not need a database connection would not needlessly connect to the database.
You find more examples in other questions and you might want to learn about dependency injection. Also you always want to keep things apart from each other, so you have some objects that are only lightly connected to each other.
How to successfully rewrite old mysql-php code with deprecated mysql_* functions?
Dependency Injection simple implementation
I would suggest moving the connect to the database also inside the class:
class myDB extends mysqli
{
private $link;
public function Connect()
{
$this->link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
}
public function getConfig($id) // thanks cbuckley
{
$res = mysqli_query($this->link,"SELECT * from config where id='$id'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
}
And use it like this:
include('inc/dbc.php');
$db = new MyDB();
$db->Connect();
echo $db->getConfig(1);
I recommend you to Wrap the mysqli class in a new Class instead extending it:
For those Classes, where you need the Configuration, just include the Configuration with Dependency Injection. This brings you the Benefit, that the Code, where you need the Configuration, don't need to know about the Way, Configuration get its values.
If you later decide to parse Configuration from a iniFile, you only need to change the Configuration-Class or even better, write a new Class which implements ConfigurationInterface and inject the new ConfigurationClass.
class Configuration implements ConfigurationInterface{
private $mysqli;
public function construct(mysqli $mysqli) {
$this->mysqli = $mysqli;
}
public function get($key)
{
// You should escape this query to prevent SQL-injection
$res = $this->mysqli->query("SELECT * from config where id='$key'");
$row = $res>fetch_array();
return $row['option'];
}
}
interface ConfigurationInterface {
public get($key);
}
Use it like this:
$mysqli = new mysqli('localhost', 'root', 'pw', 'my_db');
$config = new Configuration($mysqli);
var_dump($config->get(0));
So I started this tutorial as an intro to the PHP PDO. Up until now I've only worked with basic mysql_* type queries.
I've noticed that, throughout the tutorial, the connect -> do action -> disconnect pattern is repeated, and only the do action part ever changes.
In a real-world setting, would it be a good idea to eliminate repetition by creating a function into which queries can be passed?
For example:
a function for handling queries:
<?php
function databaseDo($action) {
$db_hostname = 'localhost';
$db_username = 'root';
$db_password = 'root';
try {
// Establish DB connection
$dbh = new PDO("mysql:host=$hostname;dbname=mysql",
$db_username, $db_password);
echo 'Connected to database';
// Do something
$action($dbh); // <- here goes whatever action we wish to perform
// Close connection
$dbh = null;
}
catch(PDOException $e) {
echo $e->getMessage();
}
?>
Then, suppose I want to perform the action in the first example of the PDO tutorial, I would set it like this:
<?php
// Define action
$insert = function($dbh) {
$query = "INSERT INTO animals(animal_type, animal_name)
VALUES ('kiwi', 'troy')";
$exec = $dbh->exec($query);
echo $exec;
};
// Perform action
databaseDo($insert);
?>
Scope of $dbh
I am using $dbh as an argument. Is this the proper way of passing a variable to a function like this without making it global?
Yes it is a great idea
A suggestion would be making a database helper class that uses the singleton pattern.. Something like
abstract class DB
{
protected static $instance;
protected $db;
protected static $host = 'host';
protected static $user = 'user';
protected static $pass = 'pass';
protected static $database;
public static function getInstance()
{
if (!isset(self::$instance)) self::$instance = new static();
return self::$instance;
}
public static function doStatement($statement, array $parameters)
{
$handler = self::sql()->prepare($statement);
$handler->closeCursor();
$handler->execute($parameters);
return $handler;
}
protected function __construct()
{
$this->db = new PDO(sprintf('mysql:host=%s;dbname=%s', static::$host, static::$database), static::$user, static::$pass);
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
}
public static function db()
{
return static::getInstance()->db;
}
}
class Main extends DB
{
protected static $database = 'db';
}
to use it
$db = Main::getInstance();
$results = $db::doStatement('SELECT * FROM table WHERE id = :id', array(':id' => 5));
Now this is just very basic, and much more would need to be added (Exception handling, more/better helper methods, etc) but I have used something like this in many projects.
While avoidance of repetition (DRY) is a principle that should always factor into your coding decisions, it should be achieved without violating another important principle, which is the separation of concerns (SoC, see also SRP). Your example, databaseDo($action), is dual-purpose: it (1) instantiates a database connection and (2) it executes a query.
Now, you may say, 'Yes! That is just what I want! Kill two birds with one stone!', and your reason for saying so would be understandable. However, mixing responsibilities can become problematic because, when you have to make changes to the way in which one responsibility is handled, you will likely also have to make changes to the way the other responsibility is handled.
Imagine you were, at some point down the road, required to support two database connections instead of just one. Suppose one of the two databases supports transactions on tables for which the other does not. Your databaseDo() function will first have to negotiate to which database to connect, and then, in order to safely execute the 'do' action, some transaction support testing will be required. It would look something like this:
$context = 'production'; // but it could equally be 'development'
function databaseDo($action) {
$db_hostname = ($context == 'production') ? 'http://remotehost.com' : 'localhost';
$db_username = ($context == 'production') ? 'apache' : 'root';
$pass = ($context == 'production') ? 'productionpassword' : 'developmentpassword';
try {
$dbh = new PDO("mysql:host=$db_hostname;dbname=mysql", $db_username, $db_password);
echo 'Connected to database';
if($context == 'production') {
// ... some complicated logic to determine whether the production db
// will support your query, then execute it if so, exit if not ...
}
if($context == 'development') {
// ... some more complicated logic for testing and querying the
// development db ...
}
$dbh = null;
} catch(PDOException $e) {
echo $e->getMessage();
}
}
Additional requirements for handling one responsibility will add complexity to the handling of the second responsibility, and this function will become more and more difficult to maintain.
A better approach to DRY in this scenario would be to handle database connection management in one component, such as within a context-aware singleton class instance (a common approach), and the query handling in another component. Thus, your query function would not necessarily have to change on account of a change in database connection handling. The tutorial to which you referred has instructions for creating and using such a singleton instance.
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