I am in the process of learning PDO and am trying to implement it in my current project. When I used mysqli, I could get detailed info about any error using mysqli_error($connection). I googled at what the comparable for PDO would be and found this post, and decided to implement it in my code. However, I am unable to get any error messages even when I know there is an obvious error in the sql statement.
Relevant code:
class Database {
public $connection;
function __construct() {
$this->open_database_connection();
}
public function open_database_connection() {
try {
$this->connection = new PDO('mysql:host=' . DB_HOST . ';dbname=' . DB_NAME, DB_USER, DB_PASSWORD);
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->connection->setAttribute( PDO::ATTR_EMULATE_PREPARES, false);
} catch(PDOException $e) {
echo $e->getMessage();
die('Could not connect');
}
} // end of open_database_connection method
public function query($sql, $params = []) {
try {
$query = $this->connection->prepare($sql);
} catch (Exception $e) {
var_dump('mysql error: ' . $e->getMessage());
}
foreach($params as $key => $value) {
if ($key === ':limit') {
$query->bindValue($key, $value, PDO::PARAM_INT);
} else {
$query -> bindValue($key, $value);
}
}
try {
$query->execute();
} catch(Exception $e) {
echo 'Exception -> ';
var_dump($e->getMessage());
}
/*
DID NOT WORK:
if (!$query->execute()) {
print_r($query->errorinfo());
}*/
$result = $query->fetchAll(PDO::FETCH_ASSOC);
$this->confirm_query($result);
return $result;
} // end of query method
function confirm_query($query) {
if (!$query) {
die('mysql error: ');
}
}
When I run the code, I do get the "mysql error", but I do not get any details about it. What am I doing wrong?
Update: As requested, I am providing additional details below.
What I am trying to do is get the user's login detail to be verified. To that end, once the user inputs his credentials , this code runs:
if (isset($_POST['submit'])) {
$username = trim($_POST['username']);
$password = trim($_POST['password']);
//check the database for the user
$user_found = User::verify_user($username, $password);
Relevant code from the User class:
public static function verify_user($username, $password) {
global $db;
$username = $db->escape_string($username);
$password = $db->escape_string($password);
$values = [ ":username" => $username,
":password" => $password,
":limit" => 1
];
$result_array = self::find_this_query("SELECT * FROM users WHERE username=:username AND password=:password LIMIT :limit", true, $values);
return !empty($result_array)? array_shift($result_array) : false;
}
public static function find_this_query($sql, $prepared = false, $params = []) {
global $db;
$the_object_array = array();
$result = $db->query($sql, $params);
$arr_length = count($result);
for ($i = 0; $i < $arr_length; $i++) {
$the_object_array[] = self::instantiation($result[$i]);
}
return $the_object_array;
}
public static function instantiation($the_record) {
$the_object =new self; //we need new self because $the_record corresponds to one user!
foreach($the_record as $the_attribute => $value) {
if ($the_object->has_the_attribute($the_attribute)) {
$the_object->$the_attribute = $value;
}
}
return $the_object;
}
public function has_the_attribute($attribute) {
$object_properties = get_object_vars($this);
return array_key_exists($attribute, $object_properties);
}
You have to use PDO::errorInfo():
(...)
public function query($sql, $params = []) {
try {
$query = $this->connection->prepare($sql);
if( !$query )
{
$error = $this->connection->errorInfo();
die( "mysql error: {$error[2]}" );
}
} catch (Exception $e) {
var_dump('mysql error: ' . $e->getMessage());
}
(...)
}
PDO::errorInfo returns an array:
Element 0: SQLSTATE error code (a five characters alphanumeric identifier defined in the ANSI SQL standard);
Element 1: Driver-specific error code;
Element 2: Driver-specific error message.
Related
This has nothing to do with Frameworks because it is an external project, I am currently developing to learn, some things about database management or how databases behave...
I need help with some php and PDO... Previously I dev this script:
<?php
class DataBaseManager
{
public function GetData($query, $user, $pass)
{
try {
$db_result = [];
$conn = new PDO("mysql:host=localhost;dbname=test", $user, $pass);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->exec("set names utf8");
reset($query);
$db_name = key($query);
$conn->exec('USE ' . $db_name);
$db_result['r'] = $conn->query($query[$db_name], PDO::FETCH_ASSOC);
$count = $db_result['r']->rowCount();
$db_result['c'] = $count;
if (0 == $count) {
$db_result['r'] = null;
} elseif (1 == $count) {
$db_result['r'] = $db_result['r']->fetch();
}
return $db_result;
} catch (PDOException $e) {
echo $e->getMessage();
return false;
}
}
public function DeleteData($query, $user, $pass)
{
try {
$conn = new PDO("mysql:host=localhost;dbname=test", $user, $pass);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->beginTransaction();
$conn->exec("set names utf8");
foreach ($query as $db_name => $query_arr) {
$conn->exec('USE ' . $db_name);
foreach ($query_arr as $key => $query_string) {
$conn->exec($query_string);
++$ct;
}
}
$conn->commit();
$conn = null;
return '<b>' . $ct . ' Records Deleted Successfully.</b>';
} catch (PDOException $e) {
$conn->rollback();
echo $e->getMessage();
return false;
}
}
public function SetData($query, $user, $pass)
{
try {
$db_result = [];
$conn = new PDO("mysql:host=localhost;dbname=test", $user, $pass);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->beginTransaction();
$conn->exec("set names utf8");
$count = ['u' => 0, 'i' => 0];
foreach ($query as $db_name => $query_arr) {
$conn->exec('USE ' . $db_name);
foreach ($query_arr as $key => $query_string) {
$cq = $conn->exec($query_string);
if (strpos($query_string, 'UPDATE') !== false) {
$count['u'] += $cq;
}
if (strpos($query_string, 'INSERT') !== false) {
$count['i'] += $cq;
}
}
}
$conn->commit();
$db_result['r'] = true;
$db_result['t'] = 'Updates: ' . $count['u'] . ', Inserts: ' . $count['i'];
return $db_result;
} catch (PDOException $e) {
$conn->rollback();
echo $e->getMessage();
return false;
}
}
}
I would like to be able to insert data by volumes in multiple tables in a single commit...
The idea of doing it that way is because if something fails I want it to be automatically rolled back in all table instances...
So I have a data structure in an array with the following content in my new class:
$dbquery =[
'test'=>[
'0' =>[
0 => 'INSERT INTO table_name_1(column1,column2) VALUES (?,?)', //mean it is the query
1 =>[value11,value12], // mean it is a row
2 =>[value21,value22], // mean it is a row
],
'1' =>[
0 => 'INSERT INTO table_name_2(column1,column2,column3,column4) VALUES (?,?,?,?)', //mean it is the query
1 =>[value11,value12,value13,value14], // mean it is a row
2 =>[value21,value22,value23,value24], // mean it is a row
],
],
];
but i have my first try with bindValue, this is my new class mentioned:
<?php
class DataBase
{
private static ?DataBase $instance = null;
public static function getInstance(): DataBase
{
if (!self::$instance instanceof self) {
self::$instance = new self();
}
return self::$instance;
}
private array $config;
public function __construct()
{
$this->config = ['DB_HOST'=>'test','DB_NAME'=>'test','DB_USER'=>'test','DB_PASSWORD'=>''];
$this->setConnection(new PDO("mysql:host=" . $this->config['DB_HOST'] . ";dbname=" . $this->config['DB_NAME'], $this->config['DB_USER'], $this->config['DB_PASSWORD']));
}
private PDO $connection;
/**
* #return PDO
*/
private function getConnection(): PDO
{
return $this->connection;
}
/**
* #param PDO $connection
*/
private function setConnection(PDO $connection): void
{
$this->connection = $connection;
}
public function changeConnectionServer(string $host, string $db_name, string $user, string $password): void
{
$this->setConnection(new PDO("mysql:host=" . $host . ";dbname=" . $db_name, $user, $password));
}
private array $query;
public function setDataBaseTarget(string $db_name)
{
if (empty($this->query)) {
$this->query = [];
}
$this->query[$db_name] = [];
}
public function buildQuery(string $query)
{
if (empty($this->query)) {
$this->query = [];
$this->query[$this->config['DB_NAME']] = [];
}
$target = array_key_last($this->query);
$this->query[$target][] = [$query];
}
public function addQueryData($data)
{
$target = array_key_last($this->query);
$key = array_key_last($this->query[$target]);
$this->query[$target][$key][] = $data;
}
private function getQuery(): array
{
return $this->query;
}
/**
* #throws Exception
*/
public function setData(): array
{
try {
$time = -microtime(true);
$con = $this->getConnection();
$con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$con->beginTransaction();
$con->exec("set names utf8;");
foreach ($this->getQuery() as $db_name => $query_arr) {
$con->exec('USE `' . $db_name . '`;');
$ct = 0;
// on this section have proble with code and logic .... i dont know what i need to dev to insert the data
foreach ($query_arr as $query_structure) {
foreach ($query_structure as $key => $raw) {
if ($key === 0) {
$ct++;
$stmt[$ct] = $con->prepare($raw);
} else {
if (is_array($raw)) {
$c = 0;
foreach ($raw as $value) {
$c++;
$stmt[$ct]->bindValue($c, $value, $this->getParamType($value));
}
}
}
}
$stmt[$ct]->execute();
}
//end section
}
//$con->commit();
return true;
} catch (PDOException $e) {
$con->rollback();
echo $e->getMessage();
return false;
}
}
private function getParamType($value)
{
if (is_int($value)) {
return PDO::PARAM_INT;
} elseif (is_bool($value)) {
return PDO::PARAM_BOOL;
} elseif (is_null($value)) {
return PDO::PARAM_NULL;
} elseif (is_string($value)) {
return PDO::PARAM_STR;
} else {
return false;
}
}
}
$db_handler = DataBase::getInstance();
$db_handler->buildQuery("INSERT INTO `client_list`(`email`,`mobile`) VALUES ('?','?');");
$db_handler->addQueryData(['mail1#test.com', '35634634636546']);
$db_handler->addQueryData(['mail2#test.com', '35634634636546']);
$db_handler->addQueryData(['mail3#test.com', '35634634636546']);
$db_handler->setData();
I can't figure out, develop the part that allows me to package everything in a single transaction... what I have is a stm[] ...
Can someone help me with this development?
I can't make heads or tails of all the things your class is doing, but here's a generalized version according to the bits that seem obvious:
public function runMultipleQueries() {
$dbh = $this->getConnection();
// ... setup stuff
$dbh->beginTransaction();
try {
foreach($this->queries as $query) {
$stmt->prepare($query->queryString);
$param_id = 1;
foreach($query->params as $param) {
$stmt->bindValue($param_id++, $param);
}
$stmt->execute();
}
} catch( \Exception $e ) {
$dbh->rollback();
throw $e;
// IMO if you cannot fully/meaningfully recover, just re-throw and let it kill execution or be caught elsewhere where it can be
// otherwise you're likely having to maintain a stack of if(foo() == false) { ... } wrappers
}
$dbh->commit();
}
Additionally, singleton DB classes have the drawbacks of both being limiting if you ever need a second DB handle, as well as boiling down to being global state, and subject to the same "spooky action at a distance" problems.
Consider using dependency inversion and feeding class dependencies in via constructor arguments, method dependencies via method arguments, etc. Eg:
interface MyWrapperInterface {
function setQueries(array $queries);
function runQueries();
}
class MyDbWrapper implements MyWrapperInterface {
protected $dbh;
public function __construct(\PDO $dbh) {
$this->dbh = $dbh;
}
public function setQueries(array $queries) { /* ... */ }
public function runQueries() { /* ... */ }
}
class MyOtherThing {
protected $db;
public function __construct( MyWrapperInterface $db ) {
$this->db = $db;
}
// ...
}
$wrapper1 = new MyDbWrapper(new PDO($connstr1, $options));
$wrapper2 = new MyDbWrapper(new PDO($connstr2, $options));
$thing1 = new MyOtherThing($wrapper1);
$thing2 = new MyOtherThing($wrapper2);
$thing1_2 = new MyOtherThing($wrapper1);
// etc
i have a class which has custom query execution. Then it shown some error if after i execute that.
SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.
I have search out my problem answer but, almost of them recommend me to put $stmt->closeCursor() in my code, but i have done with it and still get error. The error shown is same with error above. Below is my DBClassification class. Please help me. Thanks :)
<?php
class DBClassification
{
public $db = null;
public $host = "localhost";
public $user = "root";
private $pass = "";
public $path = __DIR__ . "\\";
public $prefixFilename = "klasifikasi_";
public $dbexception = [];
public $stmt;
public function setHost($host){
$this->host = $host;
}
public function setUser($user){
$this->user = $user;
}
public function setPass($pass){
$this->pass = $pass;
}
public function setPath($path)
{
if (!is_dir($path)) die ("Directory \$path is not correct!\n$path");
$lastchar = substr($path, -1);
if ($lastchar != "/" && $lastchar != "\\") $path = $path . "/";
if (strpos($path, '/') !== false) $path = str_replace("/","\\",$path);
$this->path = $path . $this->host . "\\"; // setting path to the generated output file
}
public function setPrefixFilename($prefixFilename){
$this->prefixFilename = $prefixFilename;
}
public function setDBException($dbexception=[]){
$this->dbexception = $dbexception;
}
public function init($host,$user,$pass,$path,$prefixFilename,$dbexception=[])
{
if (!$dbexception) $dbexception = ["information_schema","mysql","performance_schema","phpmyadmin","sys"];
$this->setHost($host);
$this->setUser($user);
$this->setPass($pass);
$this->setPath($path);
$this->setPrefixFilename($prefixFilename);
$this->setDBException($dbexception);
$this->openConnection();
}
// Establishing Connection to mysql database on specified host
public function openConnection(){
try {
$db = new PDO("mysql:host=".$this->host, $this->user, $this->pass);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->db = $db;
return true;
} catch (PDOException $e) {
die("Error!: " . $e->getMessage());
}
return false;
}
public function run(){
try {
$databases = $this->stmtExec("SHOW DATABASES",true);
foreach($databases as $database): // execute each database
$dbname = $database['Database']; // database name
if(!in_array($dbname,$this->dbexception)): // prevent clasifying dbname which contain in dbexception
echo "USE $dbname\n";
$this->stmtExec("USE $dbname");
$tables = $this->stmtExec("SHOW TABLES",true);
endif; // if(!in_array($dbname,$dbexception)):
endforeach; // foreach($databases as $database):
} catch (Exception $e) {
echo "Something wrong, failed to clasify each database in host " . $this->host . "\n";
die("Error!: ".$e->getMessage());
}
}
public function stmtExec($sql,$fetch=false)
{
try {
$this->stmt = $this->db->prepare($sql);
if ($fetch) {
if ($this->stmt->execute()) $return = $this->stmt->fetchAll(PDO::FETCH_ASSOC);
} else {
$return = $this->stmt->execute();
}
$this->stmt->closeCursor();
} catch (PDOException $e) {
$errormsg = "db Error: ". $this->stmt->queryString . PHP_EOL . $e->getMessage();
$queryFilename = $this->path . "error.txt";
file_put_contents($queryFilename, $errormsg);
print_r($errormsg);die();
}
return $return;
}
}
[ANSWERED]
I have found the solution from that, i have to delete false status in pdo attribute "PDO::ATTR_EMULATE_PREPARES". I think it become error because it will check query in prepare method. And query "use $dbname" is one which has no output and will give error if prepare check is on. Thats all my opinion.
This question already has answers here:
Reference - What does this error mean in PHP?
(38 answers)
Closed 2 years ago.
I keep getting the following error:
Fatal error: Call to a member function execute() on null in /home/[sitename]/public_html/fc/includes/class_db_handle.php on line 130
This is from the u-Auctions script and I honestly am extremely noob to PDO
please help in "DUMMIE TERMS".
if (!defined('InuAuctions')) exit('Access denied');
class db_handle
{
// database
private $pdo;
private $DBPrefix;
private $CHARSET;
private $lastquery;
private $fetchquery;
private $error;
public $PDOerror;
public function connect($DbHost, $DbUser, $DbPassword, $DbDatabase, $DBPrefix, $CHARSET)
{
$this->DBPrefix = $DBPrefix;
$this->CHARSET = $CHARSET;
try {
// MySQL with PDO_MYSQL
$this->pdo = new PDO("mysql:host=$DbHost;dbname=$DbDatabase;charset =$CHARSET", $DbUser, $DbPassword);
// set error reporting up
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// actually use prepared statements
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
catch(PDOException $e) {
$this->trigger_error($e->getMessage());
}
}
// to run a direct query
public function direct_query($query)
{
try {
$this->lastquery = $this->pdo->query($query);
}
catch(PDOException $e) {
$this->trigger_error($e->getMessage());
}
}
// put together the quert ready for running
/*
$query must be given like SELECT * FROM table WHERE this = :that AND where = :here
then $params would holds the values for :that and :here, $table would hold the vlue for :table
$params = array(
array(':that', 'that value', PDO::PARAM_STR),
array(':here', 'here value', PDO::PARAM_INT),
);
last value can be left blank more info http://php.net/manual/en/pdostatement.bindparam.php
*/
public function query($query, $params = array())
{
try {
//$query = $this->build_query($query, $table);
$params = $this->build_params($params);
$params = $this->clean_params($query, $params);
$this->lastquery = $this->pdo->prepare($query);
//$this->lastquery->bindParam(':table', $this->DBPrefix . $table, PDO::PARAM_STR); // must always be set
foreach ($params as $val)
{
$this->lastquery->bindParam($val[0], $val[1], #$val[2], #$val[3], #$val[4]);
}
$this->lasta->execute();
//$this->lastquery->debugDumpParams();
}
catch(PDOException $e) {
//$this->lastquery->debugDumpParams();
$this->trigger_error($e->getMessage());
}
//$this->lastquery->rowCount(); // rows affected
}
// put together the quert ready for running
public function fetch($method = 'FETCH_ASSOC')
{
try {
// set fetchquery
if ($this->fetchquery == NULL)
{
$this->fetchquery = $this->lastquery;
}
if ($method == 'FETCH_ASSOC') $result = $this->fetchquery->fetch(PDO::FETCH_ASSOC);
if ($method == 'FETCH_BOTH') $result = $this->fetchquery->fetch(PDO::FETCH_BOTH);
if ($method == 'FETCH_NUM') $result = $this->fetchquery->fetch(PDO::FETCH_NUM);
// clear fetch query
if ($result == false)
{
$this->fetchquery = NULL;
}
return $result;
}
catch(PDOException $e) {
$this->trigger_error($e->getMessage());
}
}
// put together the quert ready for running + get all results
public function fetchall($method = 'FETCH_ASSOC')
{
try {
// set fetchquery
if ($this->fetchquery == NULL)
{
$this->fetchquery = $this->lastquery;
}
if ($method == 'FETCH_ASSOC') $result = $this->fetchquery->fetchAll(PDO::FETCH_ASSOC);
if ($method == 'FETCH_BOTH') $result = $this->fetchquery->fetchAll(PDO::FETCH_BOTH);
if ($method == 'FETCH_NUM') $result = $this->fetchquery->fetchAll(PDO::FETCH_NUM);
// clear fetch query
if ($result == false)
{
$this->fetchquery = NULL;
}
return $result;
}
catch(PDOException $e) {
$this->trigger_error($e->getMessage());
}
}
public function result($column = NULL)
{
$data = $this->lastquery->fetch(PDO::FETCH_BOTH);
if (empty($column) || $column == NULL)
{
return $data;
}
else
{
return $data[$column];
}
}
public function numrows()
{
try {
return $this->lastquery->rowCount();
}
catch(PDOException $e) {
$this->trigger_error($e->getMessage());
}
}
public function lastInsertId()
{
try {
return $this->pdo->lastInsertId();
}
catch(PDOException $e) {
$this->trigger_error($e->getMessage());
}
}
private function clean_params($query, $params)
{
// find the vars set in the query
preg_match_all("(:[a-zA-Z_]+)", $query, $set_params);
//print_r("params" . $query);
//print_r($params);
//print_r("set_params");
//print_r($set_params);
$new_params = array();
foreach ($set_params[0] as $val)
{
$key = $this->find_key($params, $val);
$new_params[] = $params[$key];
}
//print_r("new_params");
//print_r($new_params);
return $new_params;
}
private function find_key($params, $val)
{
foreach ($params as $k => $v)
{
if ($v[0] == $val)
return $k;
}
}
private function build_params($params)
{
$PDO_constants = array(
'int' => PDO::PARAM_INT,
'str' => PDO::PARAM_STR,
'bool' => PDO::PARAM_BOOL,
'float' => PDO::PARAM_STR
);
// set PDO values to params
for ($i = 0; $i < count($params); $i++)
{
// force float
if ($params[$i][2] == 'float')
{
$params[$i][1] = floatval($params[$i][1]);
}
$params[$i][2] = $PDO_constants[$params[$i][2]];
}
return $params;
}
private function trigger_error($error)
{
// DO SOMETHING
//$this->error = $error;
$this->PDOerror = $error;
}
// close everything down
public function __destruct()
{
// close database connection
$this->pdo = null;
}
}
You call $this->lasta->execute(); but you have no field lasta
Try this
$this->lastquery->execute();
I would try extending the db_handle class and modifying/creating some methods like so:
<?php
// Make sure the db_handle is included and loaded before hand so it can be extended
class QueryEngine extends db_handle
{
private $bind;
public function connect($host, $username, $password, $database)
{
// One note, I removed:
// $this->DBPrefix = $DBPrefix;
// $this->CHARSET = $CHARSET;
// You can add those back in if you want
try {
// Create connection
$opts = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC);
$this->pdo = new PDO('mysql:host='.$host.';dbname='.$database, $username, $password,$opts);
}
catch(PDOException $e) {
die($e->getMessage());
}
}
public function query($query, $params = false)
{
if(!empty($params))
$this->bindVals($params);
try {
if(!empty($this->bind)) {
$this->lastquery = $this->pdo->prepare($query);
$this->lastquery->execute($this->bind);
}
else
$this->lastquery = $this->pdo->query($query);
}
catch(PDOException $e) {
die($e->getMessage());
}
return $this;
}
public function fetch()
{
while($row = $this->lastquery->fetch())
$result[] = $row;
return (!empty($result))? $result : 0;
}
private function bindVals($params = false)
{
$this->bind = false;
if(empty($params) || !is_array($params))
return $this;
$i = 0;
foreach($params as $values) {
$this->bind[':'.$i] = $values;
$i++;
}
return $this;
}
}
To use our new class:
$dbEngine = new QueryEngine();
$dbEngine->connect($host,$username,$password,$database);
print_r($dbEngine->query("select * from users where ID = :0",array("1"))->fetch());
This would give you something like (in my db obviously, the table and columns will be different for you):
Array
(
[0] => Array
(
[ID] => 1
[unique_id] => 20150203190700523616
[username] => tester
[password] => $2a$12$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
[first_name] => Ras
[last_name] => Clatt
[email] => ras#clatt.com
[usergroup] => 3
[user_status] => on
[reset_password] => $2y$10$xxxxxxxxxxxxxxxxxxx
[timestamp] => 2015-09-25 08:35:09
)
)
This class library you are using is similar to mine so what I have added is parts of the class I use. I tested this extended class out and it works with my database, so hopefully it works with yours!
I've tried disabling emulated prepares in PDO but I cannot get it to work. Everything else works. The query is successful. The reason I believe it's not working is because it does not escape quotes and such so I get syntax errors.
I've tried doing it two different ways.
$this->dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
and
$insert = $database->$con->prepare($insert, array(PDO::ATTR_EMULATE_PREPARES => false));
I've also noticed that getAttribute does not work.
By doing this...
$emul = $database->$con->getAttribute(PDO::ATTR_EMULATE_PREPARES);
var_dump($emul);
...I get this error
SQLSTATE[IM001]: Driver does not support this function: driver does not support that attribute
And here's my database class where the action happens. (I might have left some unneccessary/stupid code in there while I was testing.)
<?php
class Database
{
public $dbh;
public $dbh1;
public $dbh2;
private static $instance;
public $numResults;
private $result = array(); // Results that are returned from the query
public function __construct()
{
try
{
$this->dbh = new PDO(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8', DB_USER, DB_PASS);
$this->dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->dbh1 = new PDO(DB_TYPE1.':host='.DB_HOST1.';dbname='.DB_NAME1.';charset=utf8', DB_USER1, DB_PASS1);
$this->dbh1->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->dbh1->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->dbh2 = new PDO(DB_TYPE2.':host='.DB_HOST2.';dbname='.DB_NAME2.';charset=utf8', DB_USER2, DB_PASS2);
$this->dbh2->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->dbh2->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e)
{
die("Database Error: ". $e->getMessage() . "<br />");
}
}
public static function getInstance()
{
if (!isset(self::$instance))
{
$object = __CLASS__;
self::$instance = new $object;
}
return self::$instance;
}
private function tableExists($table, $con)
{
switch($con)
{
case 'dbh':
$db_name = DB_NAME;
break;
case 'dbh1':
$db_name = DB_NAME1;
break;
case 'dbh2':
$db_name = DB_NAME2;
break;
}
$database = Database::getInstance();
if(is_array($table))
{
for($i = 0; $i < count($table); $i++)
{
$tablesInDb = $database->$con->prepare('SHOW TABLES FROM '.$db_name.' LIKE "'.$table[$i].'"');
$tablesInDb->execute();
$rowCount = $tablesInDb->rowCount();
if($tablesInDb)
{
if($rowCount <> 1)
{
die('Error: Table does not exist'.$table[$i]);
}
}
}
}else
{
$tablesInDb = $database->$con->prepare('SHOW TABLES FROM '.$db_name.' LIKE "'.$table.'"');
$tablesInDb->execute();
$rowCount = $tablesInDb->rowCount();
if($tablesInDb)
{
if($rowCount <> 1)
{
die('Error: Table does not exist'.$table);
}
}
}
return true;
}
public function insert($con, $table, $values, $cols = null)
{
if($this->tableExists($table, $con))
{
$insert = 'INSERT INTO '.$table;
if($cols != null)
{
$cols = implode(',', $cols);
$insert.= '('.$cols.')';
}
for($i = 0; $i < count($values); $i++)
{
if(is_string($values[$i]))
$values[$i] = "'".$values[$i]."'";
}
$values = implode(',', $values);
$insert .= ' VALUES ('.$values.')';
$database = Database::getInstance();
$insert = $database->$con->prepare($insert, array(PDO::ATTR_EMULATE_PREPARES => false));
$insert->execute();
if($insert)
{
return true;
}else
{
return false;
}
}
}
public function getResult()
{
return $this->result;
}
}
?>
As manual states, getAttribute() don't support ATTR_EMULATE_PREPARES
There shouldn't be no escaping with native prepares at all.
To check if you are in emulation mode or not you can use LIMIT clause with lazy binding. It will raise an error if emulation is on.
Your main problem is whatever "syntax error" you mentioned and you have to solve it first.
As Álvaro G. Vicario noted in comments, you are not using prepared statements. It is apparently the root of the problem. PDO doesn't "escape" your data by itself. It can do it only if you are using placeholders to represent your data in the query. You can read more here
I am getting this php error and I can't seem to fix it.
Fatal error: Call to a member function prepare() on a non-object in C:\xampp\htdocs\mlrst\database.php on line 26
here is the line that is calling function prepare.
$this->statement->prepare($strQuery);
and here is it being declared.
protected $statement;
any ideas?
Edit: Here is my full code (don't mind the testing dummies)
<?php
$d = new database(); // test
class database {
protected $db_connect;
protected $statement;
function database() {
$db_connect = new MySQLi("localhost", "root" ,"", "test") or die("Could not connect to the server.");
$statement = $db_connect->stmt_init();
$this->preparedQuery("INSERT INTO feedback (name, feedback) VALUES ('?', '?')");
$this->close();
echo "Done!";
}
protected function cleanString($strLine) {
$strCleansedLine = preg_replace("/[^a-zA-Z0-9\s]/", "", $strLine);
return $strCleansedLine;
}
public function preparedQuery($strQuery, $parameters = NULL) {
try {
$this->statement->prepare($strQuery);
$statement->bind_param("ss", $name, $feedback);
for ($i = 0; $i < count($parameters); $i++) {
}
$name = $this->cleanString("this is my name");
$feedback = $this->cleanString("this is some feedback");
$query = $statement->execute();
} catch(Exception $e) {
echo $e->getMessage();
}
}
protected function close() {
try {
if ($this->statement != NULL)
$this->statement->close();
if ($this->db_connect != NULL)
$this->db_connect->close();
} catch (Exception $e) {
$e->getMessage();
}
}
}
?>
You assigned the local variable $statement. You need to set the instance's property using $this->statement.
In other words, change this:
$statement = $db_connect->stmt_init();
To this:
$this->statement = $db_connect->stmt_init();
And this:
$statement->bind_param("ss", $name, $feedback);
To this:
$this->statement->bind_param("ss", $name, $feedback);
...and this:
$query = $statement->execute();
To this:
$query = $this->statement->execute();