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();
}
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);
I'm learning some PHP while trying to build my own framework as apractice excersice, currently I have a config.php file where I store the database info to connect to plus some PDO settings, both stored into two different arrays.
I also have a Conectar.php file to stablish connection, in this the conexion(coection) method has to receive database and connection data from my arrays...
My ISSUE is I don't know if I a passing this info correctly and I also don't know how to pass my PDO settings array into the conection. Any help would be appreciated!
config.php
<?php
$config = array(
"driver" =>"mysql",
"host" =>"localhost",
"user" =>"root",
"pass" =>"root",
"dbname" =>"projecto1",
"charset" =>"utf8"
);
PDOoptions = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_CASE => PDO::CASE_NATURAL,
PDO::ATTR_ORACLE_NULLS => PDO::NULL_EMPTY_STRING
);
?>
Conectar.php
<?php
class Conectar{
private $driver;
private $host, $user, $pass, $database, $charset;
public function __construct() {
require_once 'config/database.php';
$this->driver=$config["driver"];
$this->host=$config["host"];
$this->user=$config["user"];
$this->pass=$config["pass"];
$this->database=$config["database"];
$this->charset=$config["charset"];
}
public function conexion(){
if($this->driver=="mysql" || $this->driver==null)
{
try
{
$con= new PDO("mysql:host=$config['host'];dbname=$config['dbname']",$config['user'],$config['pass'],charset=$config['charset']);
}
catch(PDOException $e)
{
echo "Error:".$e->getMessage();
}
}
return $con;
}
}
?>
You are trying to access to the $config variable which is not accessible in your conexion() function. Instead, you have to use the member's variable of your class, defined in your constructor :
$con = new PDO("{$this->driver}:host={$this->host};dbname={$this->database};charset={$this->charset}",
$this->user, $this->pass, $this->PDOoptions);
Also, in your configuration file, you're missing $ in your PDOoptions variable. And store in your class :
private $PDOoptions ;
And in constructor :
$this->PDOoptions = $PDOoptions ;
So, the final code :
class Conectar{
private $driver;
private $host, $user, $pass, $database, $charset;
private $PDOoptions ; // << NEW
public function __construct() {
require_once 'config/database.php';
$this->driver=$config["driver"];
$this->host=$config["host"];
$this->user=$config["user"];
$this->pass=$config["pass"];
$this->database=$config["database"];
$this->charset=$config["charset"];
$this->PDOoptions=$PDOoptions; // << NEW
}
public function conexion(){
$con = null ;
if($this->driver=="mysql" || $this->driver==null)
{
try
{
// NEW // The 2 next lines are changed :
$con = new PDO("mysql:host={$this->host};dbname={$this->database};charset={$this->charset}",
$this->user, $this->pass, $this->PDOoptions);
}
catch(PDOException $e)
{
echo "Error:".$e->getMessage();
}
}
return $con;
}
}
Finally, the $con variable is undefined if the driver is not MySQL. So create a variable to null to avoid a notice.
$con= new PDO("mysql:host={$config['host']};dbname={$config['dbname']}",$config['user'],$config['pass'],charset=$config['charset']);
You need curly braces in the quoted string.
In my app.php I set up a container where I configure the database connection:
$container['db'] = function ($c) {
$db = $c['settings']['db'];
$pdo = new PDO("sqlsrv:Server=" . $db['host'] . ";Database=" . $db['dbname'], $db['user'], $db['pass'], array(PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT));
return $pdo;
};
and specify route and controller related information:
$container['CourseController'] = function($container)
{
return new \App\Controllers\CourseController($container);
};
require __DIR__ . '/../app/routes.php';
In my routes.php, I have a single route:
<?php
$app->get('/courses', 'CourseController:getAll');
and below are my Controller.php and CourseController.php classes:
<?php
namespace App\Controllers;
class Controller
{
protected $container;
public function __construct($container)
{
$this->container = $container;
}
}
<?php
namespace App\Controllers;
class CourseController extends Controller
{
public function getAll($request, $response)
{
try
{
$statement = $this->container->db->prepare("SELECT * FROM Course");
$statement->execute();
$results = $statement->fetchAll(PDO::FETCH_ASSOC);
$response->getBody()->write(json_encode($results));
return $response;
}
catch(PDOException $e)
{
print $e->getMessage();
}
}
}
I am getting 500 error and unable to track down the problem. Here is what I know so far:
I don't have any problems connecting to my database; if I put my
routing code inside app.php i am able to retrieve the results of my
query.
I am passing the container to my controller. By using var_dump($this->container) on my controller I observe that container is fine.
var_dump($this->container->db) is empty though. So, I am assuming that the pdo object wasn't passed or the connection was lost.
I have tried this suggestion to no avail: "The sqlsrv extension will fail to connect when using error mode PDO::ERRMODE_EXCEPTION (default). To connect, you will need to explicitly pass array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING) (or PDO::ERRMODE_SILENT) into the constructor, or override the getDefaultOptions() method when using sqlsrv." from https://github.com/FaaPz/Slim-PDO
Is there a way for me to pass my pdo connection properly to my controllers by using a container and not get a 500? I am open to other solutions as well if this is not possible.
You are getting 500 because in your CourseController.php file, PHP tries to find PDO class under App\Controllers namespace.
You have to use a leading backslash to indicate that PDO is a global class:
$results = $statement->fetchAll(\PDO::FETCH_ASSOC);
A 500 error means that a PHP error has occurred.
Firstly change your PDO instantiation to enable errors:
$pdo = new PDO(
"sqlsrv:Server=" . $db['host'] . ";Database=" . $db['dbname'],
$db['user'],
$db['pass'],
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
);
To view the errors directly, update your Slim settings to enable error display:
$config = [
'settings' => [
'displayErrorDetails' => true,
],
];
$app = new Slim\App();
You should now see the error displayed. Alternatively look in the PHP error log and you should see it there.
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);
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.