PDOException only in certain use cases - php

I'm using an Articles class to pull data off my DB about ..articles. I can use instances to insert data, modify it but I can't seem to use it from a different set of pages.
Folder structure looks like this
/cms/conf.php (with proven to work define("DB_DSN" [..] etc)
/cms/classes/Article.php
/about.php
in about.php I want to pull out data off my DB using a static function in my Article class:
public static function getById($id) {
$conn = new PDO(DB_DSN, DB_USERNAME, DB_PASSWORD);
$sql = "SELECT * FROM articles WHERE id = :id";
$st = $conn->prepare($sql);
$st->bindValue(":id", $id, PDO::PARAM_INT);
$st->execute();
$row = $st->fetch();
$conn = null;
if ($row) return new Article($row);
}
I call it like this:
echo Article::getById(17)->content;
To get a Fatal error: Uncaught exception 'PDOException' with message 'invalid data source name' [...] PDO->__construct('DB_DSN', 'DB_USERNAME', 'DB_PASSWORD') #1
However I can use the same method and the same method call syntax in my toy file /cms/dataentry.php without problems (from either command line or web browser).
I'm making wrong environment assumptions I suppose? apps.php does have include 'cms/classes/Article.php';
PHP version 5.3.2

DB_DSN looks like it isn't defined when you try to create a new PDO instance.
PHP automatically quotes undefined constants, which is why you're getting this in your error:
PDO->__construct('DB_DSN', 'DB_USERNAME', 'DB_PASSWORD')
You'll probably want to require_once the file that defines these constants wherever you need them

Related

$stmt returned from function is different than inside the function

Here is the function where I create a DB connection:
function get_db_connection()
{
$host = "127.0.0.1:3306";
$username = "root";
$password = "";
$db = "crm";
return mysqli_connect($host, $username, $password, $db);
}
Here is a function where I use my query:
function query_user_by_username($username)
{
$conn = get_db_connection();
$stmt = $conn->prepare("SELECT * FROM `users` WHERE `username`=?");
$stmt->bind_param("s", $username);
$stmt->execute();
//var_dump($stmt->get_result()->fetch_assoc());
return $stmt;
}
When I execute var_dump inside the function I get NULL which is perfectly fine response for current scenario.
However, when I call this function from another place, I get an error when executing that same var_dump.
Example code:
require_once(__DIR__ . '/../../db/dbh.inc.php');
$db_response = query_user_by_username("zxc");
var_dump($db_response->get_result()->fetch_assoc());
When this is executed, I get the following error:
Fatal error: Uncaught Error: Call to a member function fetch_assoc() on boolean in /opt/lampp/htdocs/src/signinscreen/repo/signin.inc.php:17 Stack trace: #0 {main} thrown in /opt/lampp/htdocs/src/signinscreen/repo/signin.inc.php on line 17
For some reason, $stmt->get_result() inside the function is an actual object but when returned from the function, it is bool.
Why?
When you call get_db_connection() it creates a new instance of the mysqli class and opens a connection to the MySQL server. This object lives as long as you have a PHP variable pointing to it. In your case the connection is alive only within the scope of your query_user_by_username() function.
Prepared statements in mysqli are by default producing unbuffered results. The results are not fetched from MySQL server automatically and you need to call get_result(), store_result() or fetch them row by row. To fetch the result set from the server the connection must be open.
When you leave the query_user_by_username() function, PHP will close the connection and discard any remaining results. When you try to fetch the result set using get_result() outside the function, there are no results to be fetched because the connection is closed.
To fix this problem you should pass the mysqli connection as an argument to the function.
function query_user_by_username(mysqli $conn, $username)
{
$stmt = $conn->prepare("SELECT * FROM `users` WHERE `username`=?");
$stmt->bind_param("s", $username);
$stmt->execute();
return $stmt;
}
Then you should ensure that the connection lives for as long as your code needs it. Effectively it means you should create only one instance of mysqli class and pass it as an argument to functions that require it.
require_once(__DIR__ . '/../../db/dbh.inc.php');
$conn = get_db_connection();
$db_response = query_user_by_username($conn, "zxc");
var_dump($db_response->get_result()->fetch_assoc());
As you can see, mysqli is a low-level API that makes handling database operations difficult. For this reason it is better to use PDO. If you wish to continue using mysqli then you can consider writing a wrapper class or write your function in such a way that they never expose the underlying mysqli functions to your business layer. For example:
function query_user_by_username(mysqli $conn, $username): ?array
{
$stmt = $conn->prepare("SELECT * FROM `users` WHERE `username`=?");
$stmt->bind_param("s", $username);
$stmt->execute();
// only return the data, not the mysqli object
return $stmt->get_result()->fetch_assoc()
}

PDO query like always

In my class 'uzytkownikclass.php' i have a variable which is called '$handler'. That variable store connection with my MySQL database. Before, i created few methods that query database for data. Those functions are working fine. But i created a new method called 'hasRole' which check user role (Administator, moderator etc). But i have a error, PDO is new for me and i can not fix this alone.
Here is my code:
public function hasRole()
{
$email=$_SESSION['email_session'];
$stmt = $this->handler->prepare("SELECT COUNT(*) FROM users INNER JOIN rolausera ON users.id = idusera INNER JOIN rola ON idroli = rola.id WHERE email = :email AND rola.id = :rola");
$stmt->bindValue(':email',$email, PDO::PARAM_STR);
$stmt->bindValue(':rola',$rola, PDO::PARAM_STR);
$stmt->execute();
$result = $stmt->fetchAll();
if($result[0]>0)
{
return TRUE;
}
else
{
return FALSE;
}
}
Here is an error:
Fatal error: Call to a member function prepare() on null in D:\Programy\XAMPP\htdocs\logic\uzytkownikclass.php on line 120
As i said before, i have working methods:
$stmt = $this->handler->prepare("SELECT id, login, email, haslo FROM users WHERE email=:email1 ");
$stmt->execute(array(':email1'=>$email1));
$userRow=$stmt->fetch(PDO::FETCH_ASSOC);
and here is my connection method:
public $handler;
public function connection()
{
$this->handler = new PDO('mysql:host=localhost;dbname=blog', 'root', '',array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
if($this->handler==false)
{
echo 'Blad';
}
}
I tried to delete relation in query and use simple 'SELECT * FROM user' and i had same error.
Greetings.
The question is: did you call the connection() method before calling the hasRole(), or perhaps you closed the connection somewhere in your code? Anyway, I would check in all methods, that try to query the database, if the connection is established and call the connection() method if not. Php's is_null() function helps determining if a variable has been set. I would also check if $handle is false.
i think it's a problem with PHP 5.6 [Beta].
Check your active PHP version, if you have PHP 5.6 [Beta], change to 5.4.
I haved the same problem, a class for connection with PDO working fine, and without changes into the code, this error: Fatal error: Call to a member function prepare() on null in...
For experience, when i have these errors, i see into my PHP version. On my case the hosting changes the PHP version without advise :(
See: PHP bugs

Zend Raw SQL Query

I'm looking to execute a raw SQL query in a Zend Controller.
I looked here http://framework.zend.com/manual/1.11/en/zend.db.statement.html and it says to do
$sql = 'SELECT * FROM bugs WHERE reported_by = ? AND bug_status = ?';
$stmt = new Zend_Db_Statement_Mysqli($db, $sql);
$stmt->execute(array('goofy', 'FIXED'));
but whenever I do that it gives me an error cause of the $db.... What's $db supposed to hold cause it doesn't say anywhere in the documentation...
Also whenever I'm done I would like to return an array with whatever the result was, what would I be able to do something like $resultArray = $stmt->execute(array('goofy', 'FIXED')); ???
Thanks,
It should be an object of type Zend_Db_Adapter.
Elsewhere in the documentation examples, the variable $db is commonly used as an instance of a Zend_Db_Adapter. I guess one is expected to read the full documentation, and notice conventions like that.
Re your comment:
You can load your application.ini file into a Zend_Config_Ini object, and then use that Zend_Config object as the argument to Zend_Db_Factory. See example here: http://framework.zend.com/manual/1.11/en/zend.db.adapter.html#zend.db.adapter.connecting.factory-config
Try this code:
Put code in bootstrap.php
protected function _initRegistry() {
$this->bootstrap('db');
$dbc = $this->getResource('db');
$dbc->setFetchMode(Zend_Db::FETCH_OBJ);
Zend_Registry::set('db', $dbc);
global $db;
$db = Zend_Registry::get('db');
}

PDO - having trouble inserting data using a class

I'm having a little trouble making something work with a PDO. I will explain as I provide the code.I'm not expecting an answer, but I'm hoping that somebody could provide an explication on what I'm doing wrong and how a correct solution would work like.
I'm working on a CMS and trying to implement a MVC pattern, hence the use of PDOs.
Here is the section of my index.php file where we have the PDO declaration:
<?php
include_once 'models/USER_mapper.php';
$USER_mapper = new USER_mapper( 'localhost', 'root', 'root', 'online_magazine' );
$user = new User();
$user->setIDUser("JohnnyBoy");
$USER_mapper->registerUser($user);
?>
In the USER_mapper I have the connect function which is called on creation of a new USER_mapper and I also have the registerUser() function which takes a User object as a parameter and it should insert into the DB the info from the User object that was used.
Below is the registerUser() function:
public function registerUser($userOBJ) {
try {
$q = $this->DBH->prepare ( "INSERT INTO online_magazine.USER_TABLE (id_user, permission) VALUES (:id_user, :permission)" );
$q->execute ( ( array ) $userOBJ );
$this->DBH->commit ();
echo "it works";
} catch ( Exception $e ) {
echo "it doesn't work";
echo $e->getMessage ();
}
}
The table into which I am inserting has two columns: ID_USER and PERMISSION. Permission's has a default value, which is why I only provide the ID_USER with the setter function and leave the permission blank.
What I'm trying to achieve is to insert data into a table using a User object that has the right values and passing the User object to USER_mapper which will recuperate the info and put it in the respective table.
I hope I have been clear enough to highlight my problem. Let me know if I should add more detail and where.
EDIT1: I forgot to mention that when I use the method above I get a php error that looks like this:
[22-Nov-2013 03:18:08 Europe/Berlin] PHP Fatal error: Uncaught exception 'PDOException' with message 'There is no active transaction' in directory
EDIT2: I found out how to do it using bindParam() as follows:
$id_user = $userObject->getIDUser ();
$this->DBH->beginTransaction ();
$stmt = $this->DBH->prepare ( "INSERT INTO online_magazine.USER_TABLE (id_user) VALUES (:id_user)" );
$stmt->bindParam ( ':id_user', $id_user, PDO::PARAM_STR );
$stmt->execute ();
$this->DBH->commit ();
Thank you all!!

PDO object not in scope of a function

OK, I see some similar questions to mine, but their examples all use PHP classes...mine does not. Maybe that's the problem? I shouldn't need classes because my site is exceedingly simple at this point in time.
Anyway, I'm trying to use PDO to connect to a MySQL db. I connect to the db fine in a file called config.php, and include this file in index.php with require_once().
I can successfully query the db from another file called process.php, but the problem is within a function within that file; it seems my DBO object is out of scope within that function.
Here are the relevant code snippets:
index.php
require_once('./lib/config.php');
config.php
// tested and connects fine
$pdo = new PDO('mysql:host=' . $hostname . ';dbname=' . $dbname, $username, $password, array(
PDO::ATTR_PERSISTENT => true
));
process.php
<?php
...
// can call $pdo fine in this file outside of functions
...
function authenticate($u, $p) {
// can't call $pdo in here, error says $pdo is non-object
$que = $pdo->query('select user_id, user_pass from users where user_name = \'' . $u . '\' limit 1');
...
}
?>
By the way, I'm using PDO because I was having similar trouble with mysqli, and am trying to get away from mysql, which is apparently depreciated and discouraged.
EDIT: I should have clarified first based on the number of responses I got on this matter: I did try to pass $pdo in as a param to the function, with no luck or change in the error message.
SOLUTION: OK, apparently the problem was that I needed to add require_once('config.php') in my process.php file as well. Not sure why (wouldn't it already be included when index.php was run first?). Then I was able to successfully pass $pdo in as a param to my function, and voila.
That's pretty basic PHP stuff. Variables inside functions are local variables unless you use the global keyword to load them. I suppose you want this:
function authenticate(PDO $pdo, $u, $p) {
$que = $pdo->query('select user_id, user_pass from users where user_name = \'' . $u . '\' limit 1');
//...
}
Edit: If PHP claims that $pdo is not an object, it's not an object, so it doesn't really matter how it's passed to the function. Inspect the variable right before you call authenticate():
var_dump($pdo);
Without the relevant code there's no way to say why. (Assuming it's true that new PDO succeeds.)
You need to pass the PDO object as a parameter to the authenticate() function:
function authenticate(PDO $pdo, $u, $p) {
// ..as in the question..
}
Oh and you should be using a place holder for that username in the query, not string concatenation which is prone to SQL injection attacks.
because $pdo has been declared outside of the function authenticate it isn't available inside it. You need to either pass $pdo in
function authenticate($u, $p, $pdo) {
$que = $pdo->query('...');
}
or declare it as global inside the function to be able to access it
function authenticate($u, $p) {
global $pdo;
$que = $pdo->query('...');
}

Categories