I am still learning mostly from books I buy, but today I leart that my book is old even though I bought it this year concerning programming in PHP. Now I know that mysql_* commands in PHP are deprecated and should be replaced with more secure and stable prepared statements and PDO. So I put myself to rewrite all my web according to it and maybe I will need some advices from you how to do it properly and working from you all more experienced guys :)
So I will start my rewrite with only main part (connect to db and choosing DB) in here (the rest I can do on my own with google and manuals). I will write here my old script and ask you if I am doing everything right and not missing anything and I hope this could be some good manual/answer for other people as well. So lets start.
So in config I have something like this:
$db = new dbConn('127.0.0.1', 'root', 'pass', 'people', 'animals');
Which should be like this:
$db = new PDO('mysql:host=127.0.0.1;dbname=people;charset=UTF-8', 'root', 'pass');
Right? But when I need to choose database later should i do it without dbname=people;? But how to choose database later?
Here is my one and only script to rewrite which is basic in most web projects and I hope it will bring not only me some understanding how new PDO system really works:
class dbConn
{
public function __construct($server, $user, $pass, $db_people, $db_animals)
{
if (!empty($server) && !empty($user) && !empty($pass) && !empty($db_people) && !empty($db_animals))
{
$this->server = $server;
$this->user = $user;
$this->pass = $pass;
$this->db_people = $db_people;
$this->db_animals = $db_animals;
$this->connect();
}
else
{
die("Set up connection to db");
}
}
public function connect()
{
$this->conn = mysql_connect($this->server, $this->user, $this->pass) or die ('cannot connect to MySQL');
}
public function selectDb($database)
{
switch($database)
{
case 'people':
mysql_select_db($this->db_people, $this->conn) or die ('cannot connect to database '.$this->db_people.'.');
mysql_query("SET NAMES 'utf8'");
break;
case 'animals':
mysql_select_db($this->db_animals, $this->conn) or die ('cannot connect to database '.$this->db_animals.'.');
mysql_query("SET NAMES 'utf8'");
}
}
public function __destruct()
{
if (!empty($this->conn))
{
mysql_close($this->conn);
}
}
}
So from what I know from Google and Wiki - functions like public function __construct and public function __destruct() should not be needed anymore, right? The same with functions like public function connect() SO only whats left is public function selectDb($database) but i have no idea how to do this correctly without damading all connection to database. Because in rest of my code (not mentioned here) I can easily choose database by this code: $this->db->selectDb("people"); But with prepared statements I do not know if this is even possible in easy way. I hope some advices around this from you will help me and other users understand this new code better. Other parts in code you may have are eplained in this PDO Tutorial for MySQL Developers. Thank you.
Actually, a simple, sweet and short: Yes, not necessary any longer.
Let's review the code not that we have lost something:
__construct - The constructor merely contained all the configuration. PDO has a much easier concept here, a connection string containing the most information:
mysql:host=127.0.0.1;dbname=people;charset=UTF-8
Also PDO provides the constructor for use ready-made, so double not necessary.
connect - The connection function is not necessary any longer as well. This is done by instantiating PDO already. You can look for exceptions, the PHP manual has an example on it's constructor page.
selectDb - This complicated function is not needed any longer as well. Wow, the third function we can just drop because of the PDO connection string. Much power with so less characters. Cheers!
__destruct - The destructor. Let's be fair: MySQL did not need this as well. However with PDO we get it for free - without writing a single line of code.
Looks good! You managed to migrate from that obscure database class to PDO by removing outdated code! Congratulations:
$db = new PDO('mysql:host=127.0.0.1;dbname=people;charset=UTF-8', 'root', 'pass');
If you now think, what about if I want to have database class on my own? Well you can do that, because you can extend from PDO (yes that works!):
class DB extends PDO
{
... my super-new-shiny-code
}
Why you might want to do that? No idea, but maybe it's more fluent for your code. If you're looking for a better code-example, I have one at PHP/MySQL Table with Hyperlinks.
I think the easiest way to switch the database inside your application will be:
$pdo_instance->query("USE people");
and
$pdo_instance->query("USE animals");
or the maybe better (and cleaner) way might be
$db_people = new PDO('mysql:host=127.0.0.1;dbname=people;charset=UTF-8', 'root', 'pass');
and
$db_animals = new PDO('mysql:host=127.0.0.1;dbname=animals;charset=UTF-8', 'root', 'pass');
If you mark a database in your class active, you can access the data with $db_people->query() or $db_animals->query().
Related
I have a quick question to you guys, i have created the CFG file which stores my database connection detail in two dimensional array. I then connect it to my PHP class file and make it launch the arrays stated in CFG file. As you can see below in my code:
cfg.php
<?php
$cfg['db']['host'] = 'localhost';
$cfg['db']['user'] = 'root'; //your user name
$cfg['db']['pass'] = ''; //your password
$cfg['db']['db'] = 'db3'; //your database
?>
and my class file :
<?php
require_once(dirname(__FILE__) . 'cfg.php');
class Database {
private $dbConn; //stores the database connection
public function __construct($dbConn)
{
global $cfg;
mysql_connect(DB_HOST,DB_USER,DB_PASSWORD) or die('Could not connect to MySQL server.');
mysql_select_db(DB_DATABASE)or die('Unable to select database: ');
}
}
What i want to ask you is: is this right way of doing this? also what do I need to add in my index to see that it is connected. and the output of the database content. Thank you in advance for taking time and reading my problem. Cheerio.
Edit :
<?php
require_once(dirname(__FILE__) . 'cfg.php');
class Database {
private $dbConn; //stores the database connection
public function __construct($dbConn)
{
global $cfg;
mysqli_connect($cfg['db']['host'], $cfg['db']['user'], $cfg['db']['pass'])
or die('Could not connect to MySQL server.');
mysqli_select_db($dbConn, $cfg['db']['db'])
or die('Unable to select database: ');
}
}
Does this looks better now? If yes. How do i connect it with the index.php file where my forms will be stored. say to output the message of (connected to database). Thank you.
EDIT: changed to mysqli and now when selecting the database it states that i am missing the database name. Not sure where to put that and how to alter it. Thank you.
EDIT: I am on my way to create functions for 'Select' 'Insert' and 'Delete' . If any of you can point me do a great source of information which will help me in my research it will be most appreciated.
You are using constants instead of the actual values from your config in your mysql_connect() function, so that wouldn't work. You would need to do it this way:
mysql_connect($cfg['db']['host'], $cfg['db']['user'], $cfg['db']['pass'])
Aside from that and OO paradigms, it would probably be better if you used PHP's mysqli (as stated here) or PDO, as PHP's mysql_ is pretty outdated.
No you are not doing it correctly. By using this line
require_once(dirname(__FILE__) . 'cfg.php');
in your class file you have introduced a somewhat tight coupling to the config file and you have made it hard to swap it out for other credentials. I.e. you will have to change the file with the Database class in it to change the credentials. So start by dropping that include there.
Another thing you do is using the global keyword which is as far from OOP as you could possibly get. Inject the information the class needs instead.
Also you are using the ancient, deprecated and soon to be removed mysql_* API. You are also calling the execution of your script of something fails (or die()) which makes it impossible to integrate your code in a project and also makes it impossible to correctly handle errors (i.e. custom error page).
When upgrading to a better database API (e.g. PDO) you even don't have the need anymore to use a database class at all.
The above would simply look something like the following:
bootstrap.php
try {
$dbConnection = new \PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
$dbConnection->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
} catch (\PDOException $e) {
// nicely handle error here
}
Alternatively you could implement lazy loading for the database connection depending on your requirements.
As you can see now there is no need for an external config file (you can just change the credentials here in the bootstrap file) and there is no need for a database class.
Pre-emptive apology: This post contains basic questions.However, I have searched and I have not found an answer, if there is one...sorry.
I am following some youtube tutorials for making a basic ajax web chat, and in the tutorial the person is using MySQLi to connect to the DB. I want to create the same ajax chat application except I want to use PDO instead of MySQLi.
The person uses these two files:
config.php
<?php
define('DB_HOST', 'localhost');
define('DB_USER', 'bucky_chat');
define('DB_PASSWORD', '123456');
define('DB_NAME', 'bucky_chat');
?>`
chat.class.php
<?php
require_once('config.php');
require_once('error_handler.php');
class Chat {
private $mysqli;
//constructor opens DB connection
function __construct(){
$this->mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
}
//destructor closes db connection
function __destruct(){
$this->mysqli->close();
}
}
?>
I'm trying to replicate the above snippets with PDO. The problem is that I'm not sure how to adapt the PDO examples I have looked at to do this.
First of all I'm confused as to why he defined these things in a separate file.. are there any benefits in doing this?
In another PDO tutorial I am looking at I see it can be done the followings way:
<?php
$config['db'] = array(
'host' => 'localhost',
'username' => '',
'password' => '',
'dbname' => ''
);
$db = new PDO('mysql:host=' . $config['db']['host'] . ';dbname=' . $config['db']['db_name'], $config['db']['username'], $config['db']['password']);
//some code
$db = null; //closes connection
?>
`
I think this is what I need to use (in a try catch block), but why does he put these things in an array? it seems to over complicate things... why not just variables? But does this code replicate the mysqli example? Howcome I don't see __construct() being used with PDO?
Some minor questions...
When creating a website with a user, is there a standard place to store DB connection?
Any book recommendations?
Sorry for all these questions, All help is strongly appreciated!
To answer your questions:
First of all I'm confused as to why he defined these things in a separate file
The authentication details are defined in a second file because if you create another query script, now both scripts can include the authentication details. If the authentication details change, you only need to update one file. If you are just writing a simple application, than just keep everything in one file.
but why does he put these things in an array
I think this is just done in-case the authentication details are needed someone else in the script (much like the defined globals from your first sample). Its often best practice to define parameters into variables (even if you use the variable once). This way, if you typo a variable, you will get an error; versus copy and pasting the same string over and over again.
Howcome I don't see __construct() being used with PDO
When ever you create a new object in PHP, you do not need to call __construct, it is called automatically with the "new" statement.
$PDOConnection = new PDO($dsn, $username, $password);
When creating a website with a user, is there a standard place to store DB connection
Definitely make sure the authentication details are stored in an inaccessible file to the public. The connection object has no harm to be accessed by the public (unless of course you need to authenticate the client (website user) before establishing a database connection). Is is best practice to always begin your (secure) PHP files with:
<?php
BUT... never end the file with "?>". If an extra character is inserted after the "?>" on accident, your web server could display your whole script to the world (of course your Apache, etc... would have to be configured wrong). Like I said... best practices.
Any book recommendations?
Googleing "php arcitechture best practices" may help.
You are confusing WAY TOO MUCH things that can be explained in one answer. you don't even know what to ask.
Please, don't take the art of programming as a some sort of cheap trick one can learn in 2 hours. To write a AJAX-based chat one need to learn for at least several months. To learn by understanding, not by copy-pasting. To learn step by step, going from variables to arrays, from arrays to functions, from functions to classes and so on - not by throwing all the code they find in one bowl and then asking on SO how to deal with all that. One cannot get to another step without having understand a previous one. And of course all these youtube tutorials are definitive pieces of useless rubbish.
some of your confusions are:
__construct() method actually has nothing to do with PDO. Nor with mysql. this is a Chat class method. And method which is all wrong. Chat class shouldn't create its own connection but use already created one.
This thing on variables vs. array vs. constants doesn't really matter. To have connection options in a separate file is a good thing but nonetheless you need to have a connection code in the separate file as well, to avoid writing connection code in the every file.
You should not use this code in a try catch block (unless you have an idea what to do in case of error, which I doubt you have).
Before starting for a chat, you have to learn smaller, simpler applications, like telephone book or the like, to learn basic database operations, from which you'll be later able to build ANY application, like any house can be built of bricks.
PDO basics you can get right here, in the tag wiki. But OOP basics is not that easy.
First the reason you define config in different file is so that you can just include that file instead of writing the database configuration anytime you want database access. It is preferred best practice.
you can do:
try
{
$PDOConnection = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.'', DB_USER, DB_PASS);
$PDOConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//Do you stuffs
$PDOConnection = null;
}
catch(PDOException $e)
{
//Do something with error
}
Why not just do:
<?php
$hostname = 'host';
$dbname = 'dbname';
$username = 'uname';
$password = 'pw';
try {
$db = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $ex) {
echo "An Error occurred!";
}
?>
In a separate PHP file I call mine dbPDO.php and then have:
require_once("dbPDO.php");
In your PHP pages. And then run queries by doing:
EDIT: to condense my answer.
$username = $_POST['username'];
$stmt = $db->prepare("SELECT field1, field2, field3, etc FROM mytable WHERE username = :username");
$stmt->bindParam(':username', $username);
$stmt->execute();
while ($r = $stmt->fetch()) {
$field1 = $r['field1'];
$etc = $r['etc'];
}
Make sure you bindParam and use the ':' in the query. Don't just put WHERE username = $username or WHERE username = $_POST['username'] That would led you prone to SQL Injection. Also, I didn't show it here, but you should have some sort of exemption handling for each query. I place the whole query in a Try/Catch, but I hear there are other ways to deal with it. I personally think its personal preference.
First of all you don't need an array nor variables, you can directly input the configuration..like:
try { //try connection
//common db
$db = new PDO('mysql:host=localhost;dbname=some_db_name', 'some_usernane', 'some_pass');
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (Exception $e) { //connection failed
die("Oh no! It seems we took too long to respond, we are sorry for that..");
}
Secondly _constructor() means that whenever the class Chat is called everything in the _constructor() is executed .
Here is a good tutorial for PDO http://wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers
I'm kinda going crazy about this problem. I can't do it myself so I need the community to help me get this thing solved. I've been spending hours on this because I didn't know where to look. I now know a possible fix but it's just messy (read on). I just need someone who knows more about this than I do.
This is my situation:
I want to use 2 or more mysql connections.
I use OOP
I have a class called dbase, it has two functions, setConnection and getConnection and two class variables called $connection and $dbaseName.
In my main project file I include dbase and create two objects:
dbase
maindbase
then I do:
$this->dbase->setConnection($server, $uname, $pword);
$this->maindbase->setConnection($server, $uname, $pword);
the setConnection function looks like this:
function setConnection ($server, $serv_Username, $serv_Password) {
$this->connection = mysql_connect($server, $serv_Username, $serv_Password, true);
// echo $this->connection . "<BR>";
}
I echo it to see the resourcenumber and added true to mysql_connect (and I know it's deprecated since 5.5, I'm not here for that).
Now, as I understand OOP, the class variables are set per object. So $connection from dbase will never be the same as maindbase (unless, of course, I use the same credentials, but even then it will create a new link because of the $new_link option I enabled). They both have different resource ID's.
My problem:
In class dbase I also have a function which runs a query like this:
$connection = $this->getConnection();
$dbase_name = $this->getDbaseName();
mysql_select_db($dbase_name, $connection);
$q = "SELECT * FROM {$table_name} WHERE {$column} LIKE '{$value}'";
$result = mysql_query($q);
Now, when I use it like this, it will ALWAYS use the FIRST $connection that has been set in class dbase and it doesn't matter which object this is, either object dbase or maindbase.
I get this error:
Table 'testdbase1.skye_domains' doesn't exist
object dbase is connected to testdbase1
object maindbase is connected to testdbase2
the above error I get when trying to select results using the maindbase object.
When I remove the $connection string from mysql_select_db it works perfectly because it will try to open a new connection as if using mysql_connect.
Why is this? This is impossible right? How can objectmaindbase have the same $connection as object dbase? They are in NO WAY connected to eachother... Is PHP somehow using a global mysql_connect variable or buffer which I'm not aware about?
I would like to keep using connectionstrings as this is just handy now and then. Leaving the $connection string out seems messy.
Does anybody have any suggestions I can try to make PHP (or my head) sane again?
Try to put echo $this->connection EVERYWHERE you use it. Also, create an "id" member and fill it with a unique value upon constructing a dbase-object and echo it along the value of $this->connection. This way you can track where what happens to your connection.
And check if there's maybe some place outside of the class that assigns $foo->connection. If you're not using "private" on the members, you're bound to have such problems when you e.g. forget to remove a hack or an experiment from unrelated parts of your code.
On the existing system its use old MySQL functions.. I would like to replace it all to PDO but it would take a long time and a lot of testing.
Is it possible to mix PDO and MySQL Functions on the existing system? For example new pages/php files will use PDO... All the old files will still use old MySQL for time being and will be replaced slowly as system will continue to update..
Yes, it is perfectly fine to use both at the same time. Keep in mind, though, that you would need a seperate connection for either type and beware of the implications that arise from such an approach.
I am new to SO but I have faced this problem too. Many people find it troublesome to switch from mysql_* to PDO.
In my case I was using a separate connection.php that stored functions to connect to database and returned the handle
function connect()
{
$cn = mysql_connect("localhost","username","pass" );
$select = mysql_select_db("dbname", $cn);
return($cn);
}
//For PDO
function pdoconnect()
{
$db="";
try
{
$db=new PDO("mysql:host=localhost;dbname=dbname", "username", "pass");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $er)
{
print("errr".$er."<br />");
return(1);
}
return($db);
}
while for old functions I used $cn=connect();.
I switched to $cn=pdoconnect(); for new ones.
This worked because I was already using connect.php in old files as well.
I am used to mysql database access using the procedural mysql method. I am a beginner - intermediate programmer.
I am trying to learn the PDO api, however all resources which discuss using PDO show the connection string, username and password.
e.g.
<?php
try {
$db_conn = new PDO('mysql:host=localhost;dbname=databaseName','username', 'password');
}
catch (PDOException $e) {
echo 'Could not connect to database';
}
$sql = 'SELECT * FROM Products';
$stmt = $db_conn->prepare($sql);
...
...
...
?>
What I want, and think would be better programming is to put my PDO connection into a new file. then where I want to run an SQL query, I require_once('PDO.php') or similar.
The problem I have with this is as follows:
How do I close the connection? Simply $db_conn = null; ??
Should I close the connection after each query is run, then re-open the connection?
Should I close the connection or is it automatically destroyed when the user closes the browser?
I am working from a book called PHP Master: Writing Cutting Edge Code. http://www.sitepoint.com/books/phppro1/ and this has completely omitted any reference to closing the connection / destroying the object after it has been used.
Furthermore, I have looked at online tutorials, and they all connect to the database using PDO inline as opposed to having a separate database connector. This I am not happy with for many reasons:
I have to type username & password to connect every time.
If I get a developer to take a look at code / write some code, they will all have access to the database.
If I change the DB username & Password, then each file which connects to the database will need to be updated.
Could anybody recommend a better resource? Could anybody advise on what is the best practice way to do this?
Many thanks
Your question about how to store the database name, username and password have nothing to do with the capabilities of PDO. This is an implementation choice. The way you use to work with procedural functions can also be applied to PDO, the difference is that with PDO you work with objects instead.
So for simplicity, store the PDO creation of an object, either in a function or class, in which you can create the PDO instance anytime, e.g.
function createPDO($cfg) {
try {
return new PDO("mysql:host=".$cfg['host'].",port:".($cfg['port']).";dbname=".($cfg['name']).";",$cfg['username'], $cfg['password']);
} catch(PDOException $e) {
// handle exceptions accordingly
}
}
You can centralise these in whatever PHP file you like to include, just like you were used with the procedural functions.
You have two choices, either put all the relevant database information inside the createPDO, or use something like a config ($cfg) variable to store all this information.
$config = array();
$config['db'] = array(
'host' => 'localhost',
'name' => 'databse',
'username' => 'userx',
'password' => 'passy'
/* .. etc */
)
Using the createPDO function would be as followed
$db_conn = createPDO($config['db']);
For connections closing, each connection made to the database automatically disconnects after PHP exits its execution. You can however, close the connection if you wish, by setting the variable of the PDO object you assigned it to, in this example (and in yours) $db_conn to null
$db_conn = null; // connection closed.
The PDO has a manual http://php.net/manual/en/book.pdo.php here, which is a good start getting to know PDO a bit better.
You do not close the connection after a query, you simply leave it open for the next query. When PHP exists and your page is shown, the connection will be closed automatic.
It is a good idea to put the db stuff in a separate file and include that.
Even better, put all your db stuff in a class in use that.
Have a look at the pdo php page. Although not the best examples, they should get you started.