PHP - PDO 'config' file equivalent - php

This may be a question that has been answered before - if so please just leave a comment below and I'll remove this one.
I have been learning classes in PHP and at the same time making the jump to PDO.
One concept I cant seem to find is how to acomplish the equivalent to this with classes:
config.php
<?php
$host = 'localhost';
$user = 'user';
$pass = 'pass';
$con = mysql_connect($host, $user, $pass) or die("MySQL Error");
mysql_select_db("account_db", $con);
?>
another.php
<?php
require_once('config.php');
$selectStatement = "SELET foo FROM bar";
$selectQuery = mysql_query($selectStatement, $con);
?>
I haven't quite figured out how I would create a config file/class for a PDO connection and then use it in another class, i.e. Users as below:
<?php
class Users
{
private $_userId;
function setUserId($username)
{
// Use a predefined database handle to connect to a database to get the users ID - I assume using a preconfigured $dbh handle via an include or extend?
$sth = $dbh->prepare("SELECT id FROM users WHERE username = :username");
$sth->bindParam(':username', $username);
...
}
}
?>
Thanks all :)

In my projects, I prefer using a class with a static member which holds the PDO object.
<?php
class DB
{
private static $instance = null;
public static function get()
{
if(self::$instance == null)
{
try
{
self::$instance = new PDO('mysql:host=localhost;dbname=name', 'user', 'abc123');
}
catch(PDOException $e)
{
// Handle this properly
throw $e;
}
}
return self::$instance;
}
}
The I can access it like so:
<?php
require 'DB.php';
class Users
{
private $_userId;
function setUserId($username)
{
// Using DB::get() to get the PDO object
$sth = DB::get()->prepare("SELECT id FROM users WHERE username = :username");
$sth->bindParam(':username', $username);
...
}
}

Related

Passing a db connection in function

I have a database function and I am trying to figure out if passing the db info can be done in the same format as a new function
I was using a global db connect function but was told that is a bad practice so I wrote one of my functions as follows
function mysystem(mysqli $db){
//mystuff here
}
and it connects to the database with no issue.
my 2nd function is a little different I created a function to check if anything duplicate exists
function check_duplicate_entries($table, $column_name, $value){
$db = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME);
$stmt = $db->prepare("SELECT * FROM $table WHERE $column_name = ?");
$stmt->bind_param('s', $value);
$stmt->execute();
$result = $stmt->get_result();
$stmt->close();
if (mysqli_num_rows($result) == 1) {
return true;
} else {
return false;
}
}
is there a way that I can pass my db info like the rest of my functions instead of calling a new db connection.
like this
function check_duplicate_entries(mysqli $db, $table, $column_name, $value){
Yes. It's common practice to use singleton pattern to handle this. This is code example for PDO, you can refactor it to mysqli
class MysqlConnector
{
private static $connection;
private function __construct()
{
}
public static function getConnection(): PDO
{
$username = "root";
$password = "";
$database = "blog";
$servername = "localhost";
if (!empty(self::$connection)) {
return self::$connection;
}
self::$connection = new PDO("mysql:host=$servername;dbname=$database", $username, $password);
self::$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return self::$connection;
}
}
// now you can get your connection anywhere
// just make sure this class is available in your current namespace
$connection = MysqlConnector::getConnection();
$connection->query('SELECT COUNT(*) FROM articles');

Using PHP DBC Class in other files [duplicate]

I think I've a problem in understanding how OOP works. I already changed the code that it works, but it isn't the propper way I think. Following scenario (No, I'm not creating a userlogin by myself, its really just for local dev. to understand OOP better):
I've a database.php file:
class Database {
/* Properties */
private $conn;
private $dsn = 'mysql:dbname=test;host=127.0.0.1';
private $user = 'root';
private $password = '';
/* Creates database connection */
public function __construct() {
try {
$this->conn = new PDO($this->dsn, $this->user, $this->password);
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "";
die();
}
return $this->conn;
}
}
So in this class I'm creating a database connection and I return the connection (object?)
Then I have a second class, the famous User class (actually I'm not using autoload, but I know about it):
include "database.php";
class User {
/* Properties */
private $conn;
/* Get database access */
public function __construct() {
$this->conn = new Database();
}
/* Login a user */
public function login() {
$stmt = $this->conn->prepare("SELECT username, usermail FROM user");
if($stmt->execute()) {
while($rows = $stmt->fetch()) {
$fetch[] = $rows;
}
return $fetch;
}
else {
return false;
}
}
}
So thatare my two classes. Nothing big, as you see. Now, don't get confued about the function name login - Actually I just try to select some usernames and usermails from database and displaying them. I try to achieve this by:
$user = new User();
$list = $user->login();
foreach($list as $test) {
echo $test["username"];
}
And here comes the problem. When I execute this code, I get the following error message:
Uncaught Error: Call to undefined method Database::prepare()
And I'm not sure that I really understand what causes this error.
The code works well when I change the following things:
Change $conn in database.php to public instead of private (I think thats bad...? But when its private, I can only execute querys inside of the Database class, I'm right? So should I put all these querys in the Database class? I think that's bad, because in a big project it will get become really big..)
And the second change I've to do is:
Change $this->conn->prepare to $this->conn->conn->prepare in the user.php file. And here I've really no Idea why.
I mean, in the constructor of the user.php I've a $this->conn = new Database() and since new Database will return me the connection object from DB class, I really don't know why there have to be a second conn->
Do not create classes such as your Database class as it's rather useless. It would make sense to create a database wrapper if it adds some extra functionality to PDO. But given its current code, better to use vanilla PDO instead.
Create a single $db instance from either vanilla PDO or your database class.
Pass it as a constructor parameter into every class that needs a database connection
database.php:
<?php
$host = '127.0.0.1';
$db = 'test';
$user = 'root';
$pass = '';
$charset = 'utf8';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new \PDO($dsn, $user, $pass, $opt);
user.php
<?php
class User {
/* Properties */
private $conn;
/* Get database access */
public function __construct(\PDO $pdo) {
$this->conn = $pdo;
}
/* List all users */
public function getUsers() {
return $this->conn->query("SELECT username, usermail FROM user")->fetchAll();
}
}
app.php
include 'database.php';
$user = new User($pdo);
$list = $user->getUsers();
foreach($list as $test) {
echo $test["username"],"\n";
}
output:
username_foo
username_bar
username_baz
Check out my (The only proper) PDO tutorial for more PDO details.

New to PHP Classes, need your input on login_user class [duplicate]

This question already has answers here:
How to initialize static variables
(10 answers)
Closed 6 years ago.
I am teaching myself PHP and am playing around with different projects to learn as much as possible. Right now I am working on a login script and everything works as expected. I originally wrote the script with just functions and no classes but then decided to incorporate classes to help myself learn them. I need some input on the following class. I don't feel switching to a class has accomplished anything because I simply inserted the function into the class. I know there is a better way to do this but am having trouble figuring it out.
Also, in each function I call the database connection class to establish a connection, is there a way to extend the database connection and use a variable for the connection so I don't have to call the class for each and every function?
I tried
<?php
include('dbClass.php');
class login_user extends Database {
public $db = Database::getInstance();
public $conn = $db->getConnection();
and I get the following error
Fatal error: Constant expression contains invalid operations in /Applications/MAMP/htdocs/login_project/includes/classes/login_userClass.php on line 5
dbClass.php
<?php
class Database {
private $_connection;
private static $_instance; //The single instance
private $_host = SERVER;
private $_username = USER;
private $_password = PASS;
private $_database = DB;
/*
Get an instance of the Database
#return Instance
*/
public static function getInstance() {
if(!self::$_instance) { // If no instance then make one
self::$_instance = new self();
}
return self::$_instance;
}
// Constructor
private function __construct() {
$this->_connection = new mysqli($this->_host, $this->_username,
$this->_password, $this->_database);
// Error handling
if(mysqli_connect_error()) {
trigger_error("Failed to conencto to MySQL: " . mysql_connect_error(),
E_USER_ERROR);
}
}
// Magic method clone is empty to prevent duplication of connection
private function __clone() { }
// Get mysqli connection
public function getConnection() {
return $this->_connection;
}
}
login_userClass.php
<?php
class login_user {
//see if the user exists
function does_user_exist($username){
$db = Database::getInstance();
$conn = $db->getConnection();
$stmt = $conn->prepare("SELECT user_name FROM users WHERE user_name = ?");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->store_result();
return $stmt->num_rows;
}
//get the user hash and if create session variables and log users in.
function get_user_hash($username, $password){
$db = Database::getInstance();
$conn = $db->getConnection();
$stmt = $conn->prepare("SELECT id, user_name, user_password, user_email, user_registered FROM users WHERE user_name = ? LIMIT 1");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->bind_result($id, $user, $pass, $email, $user_registered);
while($stmt->fetch()){
if(password_verify($password, $pass)){
$_SESSION['user_id'] = $id;
$_SESSION['user'] = $user;
$_SESSION['email'] = $email;
$_SESSION['registered_on'] = $user_registered;
$_SESSION['loggedin'] = true;
header("Location: http://".$_SERVER['HTTP_HOST']."/user.php");
exit;
} else {
return false;
}
}
}
}
you need to place initialization to some static method and call it after class definition
How to initialize static variables

Reusing a mysql connection in oop php [duplicate]

This question already has answers here:
Use global variables in a class
(4 answers)
Closed 7 years ago.
Solution taken from comment so I can't accept an answer for this to be closed. But I did post the actual solution that works for me below
I'm new to OOP and I just can't figure out, even after reading through quite few examples, how use the same mysql connection without using $GLOBALS.
If someone can explain it like I'm a two year old that would be super helpful.
This is my connection file.
$hostname = 'hostname';
$username = 'db';
$password = 'password';
try {
$dbh = new PDO("mysql:host=$hostname;dbname=db", $username, $password);
}
catch(PDOException $e)
{
echo $e->getMessage();
}
but then to use this in a class or a function I do this:
class basic {
function simple($id) {
$query = $GLOBALS['dbh']->query("SELECT * FROM table WHERE id = $id");
$row = $query->fetch(PDO::FETCH_OBJ);
$thing = $row->partoftable;
echo $thing;
}
}
$first = new basic();
$first->simple(12);
This of course will return what I'm looking for the $thing with the id of 12. But how do I do this without the GLOBALS['dbh'] to connect to the db?
Also feel free to rip anything else apart but just keep in mind this was the easiest example of what I'm talking about.
Thanks in advance.
This is the solution that works for me based on the comment below.
class basic {
function __construct($dbh)
{
$this->dbh = $dbh;
}
function simple($id) {
$query = $this->dbh->query("SELECT * FROM table WHERE id = $id");
$row = $query->fetch(PDO::FETCH_OBJ);
$thing = $row->partoftable;
echo $thing;
}
}
$first = new basic($dbh);
$first->simple(12);
Thanks. hope this helps someone else.
class basic {
var $CONNECTION;
function __construct($dbh) {
$this->CONNECTION = $dbh;
}
function simple($id) {
$conn = $this->CONNECTION;
$query = $conn->prepare("SELECT * FROM table WHERE id = $id");
$query->execute();
$row = $query->fetch(PDO::FETCH_OBJ);
$thing = $row->partoftable;
echo $thing;
}
}
//class ends you can use thae class like this
$hostname = 'hostname';
$username = 'db';
$password = 'password';
try {
$dbh = new PDO("mysql:host=$hostname;dbname=db", $username, $password);
}
catch(PDOException $e)
{
echo $e->getMessage();
}
$first = new basic($dbh);
$first->simple(12);
You can create a class for database connection :
class MysqlDB
{
private $conn;
public function __construct($hostName, $userName, $passWord, $databaseName)
{
$this->conn = new PDO("mysql:host=$hostName;dbname=$databaseName", $userName, $passWord);
}
public function query($id)
{
//This is just a sample query
$this->conn->query("SELECT * FROM table WHERE id = $id");
return $query->fetch(PDO::FETCH_OBJ);
}
}
And then you can use in another class like:
class basic {
private $dbConn;
function __construct(){
$dbConn = new MysqlDB('hostName', 'username', 'password', 'database')
}
function simple($id) {
$row = $dbConn->query($id);
$thing = $row->partoftable;
echo $thing;
}
}
You can also create a database connection in common class and extend it with you class
I like this solution:
class db_connection
{
public static $sql_object = NULL;
public function __construct()
{
if ($sql_object === NULL)
{
// Initialize self::$sql_object
}
}
}
Then you can use it with:
$db = new db_connection();
// Do something with $db->sql_object
Since $sql_object is static, it will be initialized only once, no matter how many times you use new db_connection().
<?php
define('DB_SERVER','localhost');
define('DB_USER','root');
define('DB_PASS' ,'');
define('DB_NAME', 'db');
class DB_con {
function __construct()
{
$conn = mysql_connect(DB_SERVER,DB_USER,DB_PASS) or die('localhost connection problem'.mysql_error());
mysql_select_db(DB_NAME, $conn);
}
public function insert($fname,$lname,)
{
$res = mysql_query("INSERT users(first_name,last_name,) VALUES('$fname','$lname')");
return $res;
}
public function select($id)
{
$res=mysql_query("SELECT * FROM users WHERE id = $id");
return $res;
}
} ?>

Using a function or file for a database connection

I am having a really hard time understanding why I cannot do either of two things:
Wrap a PDO database connection in a function
Store a PDO database connection in a separate file and require it on load
So I have a file: db_connect.php
try {
$db = new PDO('mysql:host=xxx;dbname=xxx;charset=utf8', 'xxx', 'xxx');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
echo $e->getMessage();
}
I know this does connect to my db. Trouble is when I
require_once('db_connect.php');
//or
include('db_connect.php');
Into my functions.php it doesn't seem to load the connection. If I move the contents from db_connect.php into my function which has some SQL command:
function doStuff(){
//Copy and paste db_connect.php
$var= $db->prepare('SELECT .........
}
It works. What is the issue here? I thought it was because $db is not established outside of "try/catch" but globally declaring it
$db;
didn't help. I also moved the contents of db_connect.php into it's own function db_connect() within functions.php
function doStuff(){
db_connect();
$var= $db->prepare('SELECT ...
}
And no luck! I TRULY can't understand how that wouldn't work..
You was right, $db is a local variable. You have two choice :
Return $db variable from db_connect() and use it
Store $db into superglobal $GLOBALS["db"]
With an MVC work flow:
in my model, I have a db_connect file with:
try{
$this->db = new PDO($hostname,$username,$password);
}
catch (Exception $e) {
echo 'ERROR: unable to connect to remote DB. Try again or contact Web Master - dbcp'; exit;
}
also in my model file
<?php
class FunStuff
{
private $db
public function __construct()
{
include 'config_DB.php';
}
private function isValidAdminLogin($userName, $password)
{
// boolean return
$password = sha1($password);
$query = 'SELECT adminID FROM admin WHERE adminName = :username AND password = :password';
$statement = $this->db->prepare($query);
$statement->bindValue(':username', $userName);
$statement->bindValue(':password', $password);
$statement->execute();
if($statement->rowCount() == 1){return true;}
else {return false;}
}
}

Categories