Slim Framework - PDO object created but seems not inside the scope - php

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');

Related

How to connect to database using PDO in multiple classes?

I have multiple classes and most of them need to connect to database,
How can I set PDO options/host/dbname etc only once and then use it in every class while having the following in mind:
I don't want to wrap PDO
I need to close the PDO connection after each query ($db=null), so I simply cannot just use $db = new PDO(...) and then pass $db to my classes
I want to skip having this in every class that needs to connect to the database:
<?php
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
$pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
If you want complete control over opening and closing connections then I suggest we only centralise the $dsn, $user, $pass and $options variables. I'm assuming there are also variables like $host, $db and $charset which you did not reveal to us but lets add them.
Lets call this file global_db.php:
<?php
$host = "127.0.0.1";
$db = "mydb";
$charset = "UTF-8";
$user = "root";
$pass = "";
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
That looks like we have all the goods there, keep in mind I am not testing this so we might get a syntax error or two.
Now in our classes or other php files where we want to open a connection.
Lets call this page fooClass.php
<?php
require_once 'global_db.php';
class FooClass {
public function __construct() {
try {
$pdo = new PDO(
$GLOBALS['dsn'],
$GLOBALS['user'],
$GLOBALS['pass'],
$GLOBALS['options']);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
}
}
That should do the trick or at least give you a general idea on where to go from here on your own route. There are many other ways to accomplish similar but no need to overcomplicate things.
nJoy!

Why can't I connect to database using PHP Slim framework?

I'm new to PHP Slim framework and I've written code to connect to database but it shows the following error in console (The database exists, still getting error):
Here's my code:
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require '../vendor/autoload.php';
function dbConnect(){
$host='127.0.0.1';
$user='root';
$pass='';
$dbname='testdbmysql';
$pdo= new PDO("mysql:host=$host; dbname= $dbname", $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
return $pdo;
}
$app = new \Slim\App;
$app->post('/hello/{id}', function (Request $request, Response $response, $args) {
echo "hello";
$names = $request->getParsedBody();
$db=dbConnect();
$names_arr=[];
$names_arr['name1']= filter_var($names['name1'], FILTER_SANITIZE_STRING);
$names_arr['name2']= filter_var($names['name2'], FILTER_SANITIZE_STRING);
$response->getBody()->write("Hello , ".$names_arr['name1']);
$query=mysqli_prepare($db, "INSERT into info(fname, lname) VALUES(?, ?)");
mysqli_stmt_bind_param($query, "ss", $names_arr['name1'], $names_arr['name2']);
$result=mysqli_stmt_execute($query);
$rows=mysqli_stmt_insert_id($query);
echo "Rows: ".$rows;
return $response;
});
$app->run();
?>
When I searched on Internet, I found solutions to same error caused by Laravel framework, but not about Slim. Is there something I can do?
You should remove the whitespace
$pdo= new PDO("mysql:host=$host; dbname=$dbname", $user, $pass);
The error output is displaying the whitespace, too. So that should be the mistake.
Also, do not Mix up PDO and mysqli. You are passing a PDO-Connection to mqsqli functions, thats why you get " Expected mysqli, got PDO."
I would stick with mysqli and set up a connection via mysqli_connect().

Defining MySQL connection in Slim Framework?

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();
}

PDO Connection MySQL Functions

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.

No database selected inside function, what the solution with PDO?

I'm attempting to perform a query inside a function but it return me "No database selected". I regularly have re-initialized the PDO object inside it
$db = "mysql:host=localhost;dbname=my_database";
$pdo = new PDO($db, 'dbname', 'dbpassword');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//some operations.. Works fine!
function sendMail($to)
{
$db = "mysql:host=localhost;dbname=my_database";
$pdo = new PDO($db, 'dbname', 'dbpassword');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$qryString="SELECT Codice FROM users WHERE Mail=:mail";
$qry = $pdo->prepare($qryString);
$params = array("mail" => $to);
$qry->execute($params); //won't work
}
Note that operations on the DB outside the function works fine.
The problem is that the code won't work neither passing the global $pdo object.
This is the actual code
$db = "mysql:host=localhost;dbname=my_database";
$pdo = new PDO($db, 'dbname', 'dbpassword');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
sendMail($mail, $pdo)
function sendMail($to, PDO $pdo)
{
$qryString="SELECT Codice FROM users WHERE Mail=:mail";
$qry = $pdo->prepare($qryString);
$params = array("mail" => $to);
$qry->execute($params);
}
Variable scope has absolutely nothing to do with database connection details.
If you have a connection where database selected, the same database will be selected if you are using this connection inside a function.
So, this is a clear case of too localized question, as the problem is obviously of typo-like - connecting to wrong database, misspelling variable name, database name and such.
Unfortunately, regular PHP user has very little knowledge on performing correct, reproduceable experiment to prove their assumption. Instead, they guess the reason by indirect consequences.
You just have to write the code you told us about and see that database is selected all right. And then turn to search for real reason. Full error reporting (E_ALL) often helps a lot.
Pass the PDO object to the function, because the scope of $pdo is outside the scope of sendMail().
function sendMail(PDO $pdo, $to) {
$queryString = "SELECT Codice FROM users WHERE Mail=:mail";
$statement = $pdo->prepare($queryString);
$params = array("mail" => $to);
$result = $statement->execute($params);
}
or
function sendMail($to) {
global $pdo;
$queryString = "SELECT Codice FROM users WHERE Mail=:mail";
$statement = $pdo->prepare($queryString);
$params = array("mail" => $to);
$result = $statement->execute($params);
}

Categories