I'm sorry for the lack of information on this question I just need some advice on some code. I think only a programmer can answer this because my code is unique and I couldn't find any answers that help me.
Index.php
<?php
include ( 'Blue/BlueDatabase.php' );
include ( 'Blue/BlueUsers.php' );
use Blue\BlueDatabase;
use Blue\BlueLoader;
$database = new BlueDatabase();
$database->Connect('localhost', 'root', '', 'database');
?>
And now I have my "BlueLoader" class and I have this code in the class aswell
$database = new BlueDatabase();
$database->Connect('localhost', 'root', '', 'database');
What I want to know is. Is it worth adding that code to every class? It makes it look untidy and I think there will be a more stabler way of doing it. Do i need to do the connect function once ive done it before? does it need to be done for every class? I'm just new to php and unsure about some things. Is this script stable? / Secure
Any advice or answers will be helpful
Just incase you need my connect function (All my mysql commands are in an array like
//Example:
$commands['mysql_query'] = mysql_query;
final public function connect($sHost, $sUser, $sPass, $sName, $sPort = false, $sType = 'mysql_connect')
{
if(!$this->connected)
{
if ($sPort)
{
$sHost = $sHost . ':' . $sPort;
}
$this->connection = $this->_aCmd[$sType]($sHost, $sUser, $sPass);
if($this->connection)
{
$mydatabase = $this->_aCmd['mysql_select_db']($sName, $this->connection);
if($mydatabase)
{
$this->connected = true;
}
else
{
die('could not connect to database');
}
}
else
{
die('could not connect to host');
}
}
}
Advice:
Stop using the deprecated ext/mysql extension. Don't bother trying to wrap it in an OO framework.
Use PDO, because it already has a good OO usage, and has several other features that ext/mysql doesn't have. Mysqli is a runner-up, but I find PDO is easier to use.
Don't open a new connection in each class that uses a database. Create one connection and pass the connection object to each such class, probably as a constructor argument.
An alternative is to use a Registry class to store "global" objects like database connections.
Globals are great! They are perfect for indicating that you're taking a sub-optimal approach and you need to step back and re-evaluate.
Here are a few different ways you can address the issue.
$dbh = new DatabaseObject($connection_info);
$foo = new Object1($dbh);
$bar = new Object2();
$bar->GiveDbh($dbh);
$baz = new RegistryObject();
$baz->register('dbh', $dbh);
$bom = new Object3($baz);
I'd also include a Singleton method, but SO yells at me every time I do. :/
Also, you should probably re-jigger your database class to stop using mysql_* functions. Yadda yadda PDO MySQLi, you know the drill.
Related
I'm in the process of upgrading from mysql to mysqli.
All my mysql code was procedural, and I'd now like to convert to OOP, as most mysqli examples online are in OOP.
The problem I'm having is that, with mysql, once I had set up a connection, I never had to inject that connection into any functions as arguments for mysql to be accessible in the function.
Here is my old connection code:
$location = "localhost";
$user = "rogerRamjet";
$pass = "bestPassInTheWorld";
$dbName = "myDBName";
$link = mysql_connect($location, $user, $pass);
if (!$link) {
die("Could not connect to the database.");
}
mysql_select_db("$dbName") or die ("no database");
And an example function that has access to the mysql connection, without $link needing to be injected into the function:
function getUser($data)
{
$data=mysql_real_escape_string($data);
$error = array('status'=>false,'userID'=>-1);
$query = "SELECT `user_id`, `user_email` FROM `myTable` WHERE `data`='$data'";
if ($result = mysql_query($query))
{
$row = mysql_fetch_array($result, MYSQL_ASSOC);
if ($row['user_id']!="")
{
return array( 'status'=>true, 'userID'=>$row['user_id'], 'email'=>$row['user_email'] );
}
else return $error;
}
else return $error;
}
And here's my new mysqli connection:
$mysqli=new MySQLi($location, $user, $pass, $dbName);
So, to upgrade the first line in the above function, I'd need:
$data = $mysqli->real_escape_string($data);
But that throws the error:
Undefined variable: mysqli
Does this mean that for any function needing access to $mysqli, I need to inject $mysqli as an argument into it, or is there a way for it to be accessible the way mysql is without injection?
I know I need to move to prepared statements, but this is just so I can get my head around mysqli basics.
Making the variable global is bad practice. The singleton pattern solves the issue of needing to share one instance of an object throughout an application lifecycle. Consider using a Singleton.
The crude solution would be global $mysqli; as first line of your function. But as hsan wrote, read about PHP variable scope
I am thinking, is it safe and OK to use db connection in function to return it anywhere in the project? If I want to reuse this project to build another one, I can change db connection only in this function and I don't need to go all over the script searching and changing connection parameter.
function connect_db(){
$db = new PDO('mysql:host=localhost;dbname=;charset=utf8', '', '');
return $db;
}
Now I can call it anywhere functions.php file is required once, by returning
$db = connect_db();
and then whatever statement follows.
Is it ok and safe?
And how to close connection like this at the end of the page?
$db = NULL;
apparently won't work.
Yes, it is safe and ok to have a single place that creates a connection to your database. I would change your function just a bit though:
<?php
function connect_db(){
try{
return new PDO('mysql:host=localhost;dbname=mydb', 'username', 'password', array(PDO::MYSQL_ATTR_INIT_COMMAND =>'SET NAMES utf8'));
}catch (PDOException $e){
echo '<p>Error connecting to database! ' . $e->getMessage() . '</p>';
die();
}
}
?>
You can read more about the PDO constructor in the documentation.
And to close the PDO connection created this way you do indeed just:
<?php
$pdo = NULL;
?>
Please note that there is really a lot more to be said on this subject. Ideally you would have a class that handles the creation of your PDO object(s). You might want to take a look at this excellent answer from Gordon as a place to start.
I realize this is probably super simple but i just started taking peoples advice and im converting a small program from mysql to PDO as an attempt to learn and switch to PDO.
The script is a script that shows you how to build a shopping cart, so keep in mind its focused on a learning audience like myself. Anyway i converted the old script here:
function db_connect()
{
$connection = mysql_pconnect('localhost', 'database_1', 'password');
if(!$connection)
{
return false;
}
if(!mysql_select_db('database_1'))
{
return false;
}
return $connection;
}
to this which does connect fine:
function db_connect() {
//Hostname
$hostname = 'xxx.com';
//username
$username = 'xxx';
//password
$password = 'xxx';
try {
$connection = new PDO("mysql:host=$hostname;dbname=database_1", $username, $password);
}
catch(PDOException $e){
echo $e->getMessage();
}
}
Now in other parts of the script before accessing the database it does this:
$connection = db_connect();
Now i have 2 questions. First is to help me understand better what is going on.
I understand in the original mysql function we connect to the database, if the connection is unsuccessful or the database doesnt exist it returns false. If it does connect to the database then it returns true.
With that i mind i dont understand this:
$connection = db_connect();
Isnt that just assigning true or false to the $connection variable, if so then whats going on in this part of the code.
$price = 0.00;
$connection = db_connect();
if (is_array($cart))
{
foreach($cart as $id => $qty)
{
$query = "SELECT price
FROM products
WHERE products.id = '$id' ";
$result = mysql_query($query);
if($result)
{
$item_price = mysql_result($result, 0, 'price');
$price += $item_price * $qty;
}
}
}
Instead couldn't i just create an include file with the PDO connection and no function and include that at the top of each page i run scripts on. I just don't understand where the $connection = db_connect comes in.
So the 2nd question if my above suggestion is not the answer is how do i return a boolean value from the connection function to return true or false (If i even need to)
There is one essential difference between old mysql and PDO: both these libraries require a resource variable to connect with. If you take a look at mysql_query() function definition, you will notice the second parameter, represents such a resource.
$connection variable returned by your old function by no means contain boolean value but such a resource variable. Which can be used in every mysql_query call.
But while for mysql ext this resource parameter being optional, and used automatically when not set, with PDO you have to address this resource variable explicitly. Means you cannot just call any PDO function anywhere in the code, but only as a method of existing PDO object. Means you have to make this variable available wherever you need PDO.
Thus, you need not a boolean but PDO object.
Here is the right code for the function:
function db_connect()
{
$dsn = "mysql:host=localhost;dbname=test;charset=utf8";
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);
return new PDO($dsn,'root','', $opt);
}
now you can use it this way
$pdo = db_connect();
but note again - unlike with mysql_query(), you have to always use this $pdo variable for your queries.
Further reading is PDO tag wiki
As you guessed from the context, db_connect() is supposed to return the connection object. Your converted version doesn't return anything, which is a problem.
With the mysql module, you can run queries without using the connection object - this is not the case with PDO. You'll need to use the connection object to run any queries -
$result = $connection->query('SELECT * FROM foo');
First off, let me congratulate you for making the effort to learn PDO over mysql_*. You're ahead of the curve!
Now, a few things to understand:
PDO is OO, meaning the connection to the database is represented by a PDO Object.
Your db_connect() function should return the object that gets created.
Passing in the parameters required by PDO will give you more flexibility!
So what we have is:
function db_connect($dsn, $username, $password)
{
$conn = new PDO($dsn, $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //This makes sure that PDO will throw PDOException objects on errors, which makes it much easier enter code hereto debug.
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); //This disables emulated prepared statements by PHP, and switches to *true* prepared statements in MySQL.
return $conn; //Returns the connection object so that it may be used from the outside.
}
Now, you may have noticed we aren't checking for PDOExceptions inside of the function! That's because you can't handle the error from inside of the function correctly (becuase you don't know what you would want to do? Would you terminate the page? Redirect to an error message?). So you can only know it when you call the function.
So usage:
try {
$connection = db_connect("mysql:host=$hostname;dbname=database", "user", "pass");
}
catch (PDOException $e) {
echo "Database error! " . $e->getMessage();
}
Further Reading!
The PDO Manual entry - is super easy and super useful. I recommend you read all of it.
I have, what I think/hope, is a very simple PHP question. I have made a class to create database connections and issue common queries. I am trying to open two different database connections by creating two objects from the same database class. My code is as follows:
//connect to DB
$dbh = new DB('localhost', 'db1', 'user', 'pass');
//check connection
if(!$dbh->getStatus()) {
echo($dbh->getErrorMsg());
die;
}//if
//connect to DB 2
$dbh2 = new DB('localhost', 'db2', 'user', 'pass');
//check connection
if(!$dbh2->getStatus()) {
echo($dbh2->getErrorMsg());
die;
}//if
However, when I call a method for $dbh to query the database, it attempts to query with the credentials for $dbh2.
My DB constructor is below:
class DB {
function __construct($host, $db, $user, $pass) {
$dbh = mysql_connect($host, $user, $pass);
mysql_select_db($db, $dbh);
if(!$dbh) {
$this->status = false;
$this->error_msg = 'Error connecting to database: '.mysql_error();
return(false);
}//if
$this->dbh = $dbh;
$this->resetStatusAndErrors();
return($dbh);
}//_construct
Simple solution: Use PDO instead. It does exactly what you want, probably has better syntax and implementation and abstracts the interface for DB access.
You're not showing the full class, but the most probable reason is that you are not passing the current connection to the mysql_query() command.
Save $dbh as a property of your class, and add the connection parameter to each mysql_ function that accepts it:
mysql_query("SELECT * from.......", $this->dbh);
That said, if you are building this from scratch at the moment, take a look whether you don't want to use PDO instead. It is better, safer and more flexible than the old style mySQL library.
If you are using the mysql extension (using either mysqli or PDO_MySQL would give both superior performance, more features, etc., so check that for new code), you'll have to store the database handle, and use that on every mysql_* call:
class db {
....
function query($query){
return mysql_query($query, $this->dbh);//notice the second parameter.
}
}
I've been playing around with PDO for the last few days, I'm working on a small CMS system to teach myself OOP skills, but even though it's only a small CMS, I want it to be able to handle whatever the web can throw at it.
This is what I've come up with so far, I'm going to add connection pooling to the constructor to enable large amounts of concurrent connects on demand. I'm very new to this OOP stuff so I'm wanting a little advise and critism, no doubt I've done something terribly wrong here.
I took the top answer to Global or Singleton for database connection? as the base design, although I've added a private constructor as I want to use $this->dbConnectionInstance throughout the class for numerous helper functions to use.
Thanks very much for your time, I really will appreciate any advise you can give me,
-Drew
// Usage Example: $dbconn = dbManager::getConnection();
// $dbconn->query("SELECT * FROM accounts WHERE id=:id", "':id' => $id");
<?php
class dbManager {
private static $dbManagerInstance;
private $dbConnectionInstance;
private $stime;
private $etime;
public $timespent;
public $numqueries;
public $queries = array();
public static function getManager(){
if (!self::$dbManagerInstance){
self::$dbManagerInstance = new dbManager();
}
return self::$dbManagerInstance;
}
// Server details stored in definition file
private function __construct($db_server=DB_SERVER, $db_user=DB_USER, $db_pass=DB_PASS, $db_params=array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")) {
if(!$this->dbConnectionInstance)
{
try{
$this->dbConnectionInstance = new PDO($db_server, $db_user, $db_pass, $db_params);
$this->dbConnectionInstance->setAttribute(PDO::ATTR_PERSISTENT, PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
$this->dbConnectionInstance = null;
die($e->getMessage());
}
}
return $this->dbConnectionInstance;
}
private function __destruct(){
$this->dbConnectionInstance = null;
}
private function query($sql, $params = array()) {
$this->queries[] = $sql;
$this->numqueries++;
$this->sTime = microtime();
$stmt = $this->dbConnectionInstance->prepare($sql);
$stmt->execute($params);
$this->eTime = microtime();
$this->timespent += round($this->eTime - $this->sTime, 4);
return $stmt;
}
}
?>
Thank you both for your suggestions, I've now added the rollback and commit into my exception handling, I'm just researching the use of buffered queries, I'm not entirely sure what ths will give me?
Looks good, I would add rollback functionality, along with the buffered query/errorInfo suggestions (If you're using a RDBMS that supports transactions):
try {
$this->dbConnectionInstance->beginTransaction();
$stmt = $this->dbConnectionInstance->prepare($sql);
$stmt->execute($params);
$this->dbConnectionInstance->commit();
}catch(PDOException $e){
$this->dbConnectionInstance->rollback();
}
commit() , beginTransaction()
EDIT: added links below for more info on buffered queries:
mysql performance blog
pdo mysql buffered query support
stack overflow: pdo buffered query problem
The code you have dosent look too bad. however if i could make a couple small changes (mainly error handling).
both the prepare and execute statements will return false on error. and you can access the error from $this->dbConnectionInstance->errorInfo() in your example above.
also if you plan on using any large queries I suggest using a buffered query: PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
looks like a good start. Good luck on your CMS.