The code that I will post works but I want to know if it's okay and safe. I will use it to connect my Android APP with my MySQL database.
Here I create the PDO connection. I don't know if I should create it in the construct or using a method. Right now I'm using the connect() method and get() to return the same object. Should I close the connection? Why?
db_config.php
private $db;
function __construct(){
}
function __destruct(){
}
public function connect(){
$host = "XXXXXXXX";
$dbname = "XXXXXXXX";
$username = "XXXXXXX";
$password = "XXXXXXXX";
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8');
try{
$this -> db = new PDO("mysql:host={$host};dbname={$dbname};charset=utf8", $username, $password, $options);
} catch (PDOException $ex) {
die("Failed to connect to the database: " . $ex->getMessage());
}
$this-> db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this -> db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
return $this->db;
}
public function get(){
return $this -> db;
}
trainer_functions.php
In this code I have the functions that I will use to interact with the database. I initialize the connection in the construct and then I use the get() method to return the same connection everytime I need it. Is this okay?
private $db;
function __construct(){
require_once 'db_config.php';
$this->db = new DB_Connect();
$this->db->connect();
}
public function storeUser($json){
$obj = json_decode($json);
$email = $obj -> {"email"};
$pass = $obj -> {"password"
$query = "INSERT INTO USUARIOS (email, pass) VALUES (:email , :pass)";
$query_params = array(
':email' => $email,
':pass' => $pass
);
try {
$stmt = $this -> db -> **get()** -> prepare($query);
$result = $stmt -> execute($query_params);
//json response
}
catch (PDOException $ex) {
//json response
}
The last part of my test code are the calls to the functions using tags. I create a trainer_functions object, then I collect the parameters via POST and call the function with the object. Here I have two questions:
- I send a JSON. Should I send the tag inside or outside the JSON?
- I think here should close the connection because the request has already been completed. It is true?
I would make a good web service because it is the last project of my course and later it will be a personal project with some iOS integration.
Thank you very much.
I've no idea on other files you included (they are too hard to read) but to answer the question from the title: PDO is already a class. You don't need no more.
So, db_config.php
<?php
$host = "XXXXXXXX";
$dbname = "XXXXXXXX";
$username = "XXXXXXX";
$password = "XXXXXXXX";
$charset = 'utf8';
$options = array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES $charset',
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
);
$dsn = "mysql:host=$host;dbname=$dbname;charset=$charset"
$db = new PDO($dsn, $username, $password, $options);
is all you need.
Related
I have searched the forum, but I have not found anything directly related to my issue. I am fairly new to PDOs and class OOP creation. I am trying to create a database connection class where I can instantiate the connection as needed. I having issues instantiating my connection.
File Organization:
parent directory (folder)
|
private (folder)
|
config.php
classes (folder)
|
class1.class.php
DatabaseConnection.class.php
db_cred.inc.php
public (folder)
|
search.php
Process:
I have created a database credential php file "db_cred.inc.php"
I have a database connection class called "DatabaseConnect" in "DatabaseConnect.class.php" file
I load those files as follows
require_once 'db_cred.inc.php'; in the "DatabaseConnect.class.php" file
spl_autoload_register for all of my class files
Expected actions:
When my "search.php" page request data from mysql via a pdo, a new database connection will instantiate a new connection via the "openConnection()" method.
The class "DatabaseConnection" will load the credentials from "db_cred.inc.php" as a sting and connect to the database
The class will then use the credentials to connect to the mysql database, and execute the requested pdo query returning the results and storing them into a variable "$row".
Issue:
When I execute the pdo, the following error is returned:
Uncaught TypeError: PDO::__construct() expects parameter 1 to be string, array given in private/classes/DatabaseConnect.class.php:21 Stack trace: #0 private\classes\DatabaseConnect.class.php(21): PDO->__construct(Array) #1 \public\search.php(53): DatabaseConnect->openConnection() #2 {main} thrown in \private\classes\DatabaseConnect.class.php on line 21
spl_autoload_register() in the config.php file
function my_autoload($class) {
if(preg_match('/\A\w+\Z/', $class)) {
require ('classes/' . $class . '.class.php');
}
}
spl_autoload_register('my_autoload');
Credential setup in "db_cred.inc.php"
<?php
// define an array for db connection.
define("DB", [
"DB_HOST" => "mysql:host=localhost",
"DB_USER" => "user",
"DB_PASS" => "pass",
"DB_DATABASE" => "mytestdb",
"DB_CHAR" => "utf8",
]);
?>
My class for database connection:
<?php
require_once 'db_cred.inc.php';
// creating db connection class
class DatabaseConnect {
private $server = 'DB_HOST';
private $database = 'DB_DATABASE';
private $pass = 'DB_PASS';
private $user = 'DB_USER';
private $opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
protected $con;
public function openConnection() {
**ERROR TAKES PLACE HERE**
try {
$this->con = new PDO([$this->server, $this->database, $this->user, $this->pass]);
return $this->con;
} catch(PDOExeption $e){
echo "ERROR: " . $e->getMessage(), (int)$e->getCode();
}
}
public function closeConnection() {
$this->con = null;
}
}
?>
PDO for search.php
<?php
$dbconn = new DatabaseConnect();
$pdo = $dbconn->openConnection();
$sql = "SELECT * FROM report";
foreach ($pdo->query($sql) as $row) {
echo " PI: ".$row['pi'] . "<br>";
}
?>
I am not sure what is causing the error. I am sure it is due to my inexperience with classes and oop. It appears that the config.php file is working fine. The class is identified by the request because the error happens inside the PDO __construct method. Please help.
UPDATE - MY WORKING SOLUTION
I hope this might help someone moving forward with a similar question. I am not finished with the development of this process, but this kicked in a huge door.
My revised class
<?php
// Associating db_cred.inc.php with class
require_once('db_cred.inc.php');
// Creating db connection class
class DatabaseConnect {
/*
!! Assigning defined constants per define('DB_CONSTANT', 'value') loaded from "db_cred.inc.php" file to variables
!! "db_cred.inc.php" should not be loaded into the "config.php" file
!! BECAUSE THE VALUES OF THE VARIABLES ($variable) ARE CONSTANTS (DB_CONSTANT), DO NOT USE SINGLE OR DOUBLE QUOTES. THE PDO __CONSTRUCT FUNCTION WILL IGNORE THE VALUE OF THE VARIABLE
*/
private $host = DB_HOST;
private $database = DB_DATABASE;
private $pass = DB_PASS;
private $user = DB_USER;
private $char = DB_CHAR;
// Setting attributes and storing in variable $opt
private $opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
// $con variable will store PDO connection and is set to NULL
private $con;
// Create Connection to database
public function openConnection() {
// Setting $con to null
$this->con = NULL;
// If $con is not NULL make it NULL
if ($this->con === NULL){
try {
// Establish DSN
$dsn = "mysql:host={$this->host};dbname={$this->database};charset={$this->char}";
// Complete the PDO connection
$this->con = new PDO($dsn, $this->user, $this->pass,$this->opt);
// Return the connection and store it in $con
return $this->con;
// Catch any exceptions and store in $e
} catch(PDOExeption $e){
// Echo error and Exception message
echo "ERROR: " . $e->getMessage(), (int)$e->getCode();
}
// If the try/catch block fails, echo that no connection was established
} else {
echo "ERROR: No connection can be established";
}
}
// Close connection and set it to NULL
public function closeConnection() {
if($this->con !== NULL){
$this->con = NULL;
}
}
// create CRUD subclass (Create, Read, Update, Delete)
}
?>
I changed "db_cred.inc.php" eliminating the array. I may revisit the idea.
<?php
// defining DB Credential CONSTANTS to be stored in variables and instantiated by connect class
define("DB_HOST", "localhost");
define("DB_USER", "user");
define("DB_PASS", "pass");
define("DB_DATABASE", "mytestdb");
define("DB_CHAR", "utf8");
// define an array for db connection.
/*define("DB", [
"DB_HOST" => "localhost",
"DB_USER" => "user",
"DB_PASS" => "pass",
"DB_DATABASE" => "mytestdb",
"DB_CHAR" => "utf8",
]);*/
?>
The error explains itself: You're passing an array where you should be using a string instead.
You need to change this line:
$this->con = new PDO([$this->server, $this->database, $this->user, $this->pass]);
To this, (specifies the DSN first):
$dsn = "mysql:dbname={$this->database};host:{$this->host}";
$this->con = new PDO($dsn, $this->user, $this->password);
With the help of the answer on a post on similar topic Answer by "teresko" I have managed to understand the factory design method to establish connection to my database. But I am unable to implement the logic in my code as I am receiving this error:
Fatal error: Class 'conn' not found in C:\somewhere\db2.php on line 42
Here is my db file:
$provider = function() {
$db_user="root"; // db user
$db_password="";// db password (mention your db password here)
$db_database="cl";// database name
$db_host="localhost"; // db server
$instance = new PDO("mysql:host=$db_host;dbname=$db_database", $db_user, $db_password);
$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$instance->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
return $instance;
};
$factory = new StructureFactory( $provider );
$conn = $factory->create('conn');
class StructureFactory {
// protected $provider = null;
protected $connection = null;
public function __construct( callable $provider ) {
$this->provider = $provider;
}
public function create($name) {
if ( $this->connection == null ) {
$this->connection = call_user_func( $this->provider );
}
return new $name($this->connection );
}
}
Since I am a new user, I am unable to request this question as a comment on the original answer. Can you guys help me work out where I'm going wrong please? As the original question says, "I would really like to know how to properly connect to a MySQL database using PHP and PDO and make it easy access-able.I'm eager to learn..."
Given you are a new user, just make it simple PDO instance.
$db_user="root"; // db user
$db_password="";// db password (mention your db password here)
$db_database="cl";// database name
$db_host="localhost"; // db server
$db_charset="utf8";
$conn = new PDO("mysql:host=$db_host;dbname=$db_database;charset=$db_charset", $db_user, $db_password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
I get this error when I try to test my codes.
Call to a member function prepare() on a non-object in ........
Below is my codes :
ConnectionStrings.php
<?php
$config = require dirname(__FILE__).'../../Configs/Local.php';
$host = '127.0.0.1';
$db = 'CWW_SecurityDB';
$user = $config['db']['user'];
$pass = $config['db']['password'];
$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);
?>
Authentication.php (Related part)
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require dirname(__FILE__).'../../../ConnectionStrings.php';
$app -> group('/authentication', function(){
$this -> Get('/login',
function($request, $response, $args)
{
$Username = $request->getQueryParams()['Username'];
$Password = $request->getQueryParams()['Password'];
$sql = 'CALL SEC.usp_GetSecurityUsers(:Username)';
$stmt = $pdo -> prepare($sql);
$stmt -> bindParam(':Username', $Username, PDO::PARAM_STR);
$stmt -> execute();
.
.
. (just a try out on the codes)
The problem should lie in the line $stmt = $pdo -> prepare($sql);. However, I really could not figure it out after hours. I have read some other posts with similar issue suggesting that the $pdo is out of scope.. but how exactly is my $pdo out of scope in this case? Can someone please enlighten me. Thank you in advance guys :)
In PHP, you don't have global variables automatically available in the function scope (more on variable scope). Inside the function, $pdo needs to either be defined or somehow made available. Few ways come to my mind:
Using global $pdo; in the function start - very old-school and won't be generally preferred way by php professionals.
Replacing $pdo with $GLOBALS['pdo'] - pretty much the same thing, kind of PHP3 style :)
Pass $pdo to the closure's scope:
$app->group('/authentication', function() use ($pdo) {
$this->Get('/login', function($request, $response, $args) use ($pdo) {
Fetch $pdo through dependency container (Slim3 uses Pimple for that):
// Store $pdo in DI container.
$container = $app->getContainer();
$container['database'] = $pdo;
...
// Then inside route controller:
$pdo = $this->get('database');
I am hearing great things about Slim Framework- and it seems easy. Except none of the tutorials address where to put the MySQL info.
I see things like $dbCon = getConnection();
But where do I define the username/pw/db/host etc?
First thing first lets open src/settings.php file and configure database connection details to the settings array as shown below.
<?php
return [
'settings' => [
'displayErrorDetails' => true, // set to false in production
// Renderer settings
....
....
// Monolog settings
....
....
// Database connection settings
"db" => [
"host" => "localhost",
"dbname" => "slim3",
"user" => "root",
"pass" => "xxxxx"
],
],
];
There are many database libraries available for PHP, but this example uses PDO. Now open your src/dependencies.php file and configure database library as shown below. you can use your own libraries by adapting the example.
// DIC configuration
$container = $app->getContainer();
...
...
...
// PDO database library
$container['db'] = function ($c) {
$settings = $c->get('settings')['db'];
$pdo = new PDO("mysql:host=" . $settings['host'] . ";dbname=" . $settings['dbname'],
$settings['user'], $settings['pass']);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
return $pdo;
};
via: https://arjunphp.com/configure-load-database-slim-framework-3/
Its best to keep these credentials in a local configuration file. I add a configs folder outside the web root and add a local.php configuration file to that.
....
/configs
local.php
/public
/vendor
....
You can configure anything you like, but here's the DB:
<?php
// configs/local.php
return array(
'db' => ['user' => 'root', 'password' => 'root']
);
Then include the file in your app and create the connection:
// public/index.php
$config = include(__DIR__ . '/../configs/local.php');
$db = new PDO("mysql:host=localhost;dbname=dbname", $config['db']['user'], $config['db']['password'] );
$app->get('/', function () use ($app, $db) {
// do something with your db connection
});
You can define a function in your file (e.g. index.php)
function getConnection() {
$dbhost="yourdbhost";
$dbuser="yourdbuser";
$dbpass="yourdbpass";
$dbname="yourdb";
$dbh = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $dbh;
}
I had great success with this MVC pattern where you store the credentials in a config.php file which gets loaded on every instance of a model: https://github.com/revuls/SlimMVC
You can configure PDO in an external class:
class Connection
{
protected $db;
public function Connection()
{
$conn = NULL;
try{
$conn = new PDO("mysql:host=YOUR_HOST;dbname=DB_NAME;charset=utf8;collation=utf8_unicode_ci", "USER_DB", "PASS_DB");
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
$this->db = $conn;
}
public function getConnection()
{
return $this->db;
}
}
Then in Slim (Php object oriented):
<?php
class Proxy
{
require_once 'Connection.php';
// init Slim
private $conn = NULL;
// Api Rest code...
# getConnection
public function getConnection(){
if(is_null($this->conn)){
$this->conn = new Connection();
}
return $this->conn->getConnection();
}
Or Php no OO:
<?php
require_once 'Connection.php';
// init Slim
$conn = NULL;
// Api Rest code...
# getConnection
function getConnection(){
global $conn;
if(is_null($conn)){
$conn = new Connection();
}
return $conn->getConnection();
}
Hey guys I have a connection class I found for pdo. I am calling the connection method on the page that the file is included on. The problem is that within functions the $conn variable is not defined even though I stated the method was public, and I was wondering if anyone had an elegant solution other then using global in every function. Any suggestions are greatly appreciated.
CONNECTION
class PDOConnectionFactory{
// receives the connection
public $con = null;
// swich database?
public $dbType = "mysql";
// connection parameters
// when it will not be necessary leaves blank only with the double quotations marks ""
public $host = "localhost";
public $user = "user";
public $senha = "password";
public $db = "database";
// arrow the persistence of the connection
public $persistent = false;
// new PDOConnectionFactory( true ) <--- persistent connection
// new PDOConnectionFactory() <--- no persistent connection
public function PDOConnectionFactory( $persistent=false ){
// it verifies the persistence of the connection
if( $persistent != false){ $this->persistent = true; }
}
public function getConnection(){
try{
// it carries through the connection
$this->con = new PDO($this->dbType.":host=".$this->host.";dbname=".$this->db, $this->user, $this->senha,
array( PDO::ATTR_PERSISTENT => $this->persistent ) );
// carried through successfully, it returns connected
return $this->con;
// in case that an error occurs, it returns the error;
}catch ( PDOException $ex ){ echo "We are currently experiencing technical difficulties. We have a bunch of monkies working really hard to fix the problem. Check back soon: ".$ex->getMessage(); }
}
// close connection
public function Close(){
if( $this->con != null )
$this->con = null;
}
}
PAGE USED ON
include("includes/connection.php");
$db = new PDOConnectionFactory();
$conn = $db->getConnection();
function test(){
try{
$sql = 'SELECT * FROM topic';
$stmt = $conn->prepare($sql);
$result=$stmt->execute();
}
catch(PDOException $e){ echo $e->getMessage(); }
}
test();
You can declarate database class where you carrying conn pdo class, then you don't must duplicates instaces of this. And all database operations you can doing by this class. I mean my answer is what you searching.
But i see, you using only PDO hadle class in Product Factory pattern. You can use normal full database support class under PDO (includes queryies execution from one function) and without this design pattern when you don't want to use many database connectors engines.