PDO does not throw exception - php

I know this question has been there many times, but no answer works for me.
My PDO just doesn't throw any error... or something catch the error before me.
I'm quite new to php, and I hate to not understand simple things.
Here's my initialization code
$pdo = new PDO("mysql:host=" . $db['host'] . ";dbname=" . $db['dbname'], $db['user'], $db['pass']);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
and an example where I'm, for example, inserting a duplicate row with an unicity constraint (but same problem for unknown row, or any pdo exception...)
$columnString = "....";
$valueString = "....";
$sql = "INSERT INTO " . $table . " (" . $columnString . ") VALUES (" . $valueString . ")";
try {
$stmt = $this->pdo->prepare($sql);
foreach($request_data as $key => $value){
$stmt->bindValue(':' . $key,$request_data[$key]);
}
$stmt->execute();
} catch (PDOException $e) {
return null;
}
Of course, this code works well when no database problem occurs.
I'm using Slim 3 framework, and php7. Same problem with php5.
Does it have something to do with the framework? Is there other configurations ? Why the hell exceptions are not caugh?

First, I do not see any use clause in your code snippet when you create PDO class instance or when you catch exception PDOException. If you miss them, it may give you error as PHP can not find where they are. You need to make sure you add
use PDO;
use PDOException;
in code that refer those classes.
Second, you suppress any exception related to PDO operation by using this code.
try {
//your code
} (PDOException $e) {
return null;
}
To be able to identify the cause of any database-related error, you need to handle exception properly. You need to replace return null; to do more meaningful action to handle the error.

Related

PHP PDO - There is no active transaction

I am having problem with transactions in php script. I would like to make multiply queries and be able to recall them all, if at least one of them fails. Below you can find a simple example of the script I am using:
$tags_input = array(6,4,5);
$conn = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8',
DB_USER, DB_PASSW, array(
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
$conn->beginTransaction();
$sql = "INSERT INTO projects (id, pr_id, enabled) VALUES ( :val0, :val1, :val2)";
$stmt = $conn->prepare($sql);
if(count($tags_input)>0){
for($i = 0;$i<count($tags_input);$i++){
$stmt->bindValue(':val0', 57);
$stmt->bindValue(':val1', $tags_input[$i]);
$stmt->bindValue(':val2', 'Y');
$result = $stmt->execute();
}
}
$res1 = $conn->commit();
$conn->rollBack();
Now, this example generates an error:
Uncaught exception 'PDOException' with message 'There is no active
transaction'
If I erase the line $conn->rollBack();, the error disappears. Therefore I cannot understand, why pdo object can't see open transaction (begintransaction and commit do not generate any errors). I also tried putting rollBack() inside the transaction, but made no difference. I was still getting an error 'There is no active transaction'.
I am running PHP 5.6 and Mysql tables on InnoDB.
Wrap your transaction code inside a try-catch statement.
//try {
$tags_input = array(6,4,5);
$conn = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8',
DB_USER, DB_PASSW, array(
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
} catch (Exception $e) {
die("Unable to connect: " . $e->getMessage());
}
try {
$conn->beginTransaction();
$sql = "INSERT INTO projects (id, pr_id, enabled) VALUES ( :val0, :val1, :val2)";
$stmt = $conn->prepare($sql);
if(count($tags_input)>0){
for($i = 0;$i<count($tags_input);$i++){
$stmt->bindValue(':val0', 57);
$stmt->bindValue(':val1', $tags_input[$i]);
$stmt->bindValue(':val2', 'Y');
$result = $stmt->execute();
}
}
$res1 = $conn->commit();
} catch (Exception $e) {
$conn->rollBack();
echo "Failed: " . $e->getMessage();
}
EDIT
A really well-based and straight-forward explanation of the answer was provided by Richard as a comment.
The reason you got error is because you were trying to close a transaction when it was already closed. beginTransaction opens one, and EITHER rollBack OR commit closes it. You have to avoid doing BOTH actions, meaning commit/rollback, for a single beginTransaction statement, or you'll get an error. The above try/catch code ensures that only one closing statement is executed.
Peter and Richards answers are already correct, but there is one little mistake in the code from the transaction structure (and i can't add a comment).
The $connection->beginTransaction() must be outside of the try-catch block. When you're start the beginTransaction() in the try-block and your Database Operations throws an exception, the catch-block doesn't know something from an active transaction. So, you get the same error:
"There is no active transaction".
So the structure should be as well:
Get the Connection.
Start the Transaction with $connection->beginTransaction()
Open the try-catch block.
The try-block contains the $connection->commit() after DB Operations.
The catch-block contains the $connection->rollback() before a throw Exception.
So your code should look like this:
$tags_input = array(6,4,5);
$conn = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8',
DB_USER, DB_PASSW, array(
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
} catch (Exception $e) {
die("Unable to connect: " . $e->getMessage());
}
//Begin Transaction
$conn->beginTransaction();
try {
$sql = "INSERT INTO projects (id, pr_id, enabled) VALUES ( :val0, :val1, :val2)";
$stmt = $conn->prepare($sql);
if(count($tags_input)>0){
for($i = 0;$i<count($tags_input);$i++){
$stmt->bindValue(':val0', 57);
$stmt->bindValue(':val1', $tags_input[$i]);
$stmt->bindValue(':val2', 'Y');
$result = $stmt->execute();
}
}
$res1 = $conn->commit();
} catch (Exception $e) {
$conn->rollBack();
echo "Failed: " . $e->getMessage();
}

Connecting to MYSQL using php

I am trying to connect to MYSQL using php, but when I use the following command:
$link=mysql_connect("localhost","root","password");
and echo $link, it gives me Resource id #98. What does this mean? Am I not connected?
Okay, I guess it sounds like the connection is okay. Now, with the following code, I am not seeing any changes in the mysql database. Why could that be?
<?php
$conn=new mysqli("localhost","root","password","database");
$sql="INSERT INTO chat_active (user, time)
VALUES('John', '1234')";
?>
What makes you think you are not connected?
According to the docs, mysql_connect()
[r]eturns a MySQL link identifier on success or FALSE on failure.
Since it did not return FALSE, but rather a resource identifier, that means the connection was successful.
Also note that the mysql extension is deprecated since PHP 5.5.0 as MortimerCat pointed out. Instead you should look into the MySQLi or the PDO extension.
"Now, with the following code, I am not seeing any changes in the mysql database. Why could that be?"
As per your edit which you are now using mysqli_ to connect with, and that you're saying that you're not seeing any changes in your database, is because:
You're not passing the DB connection to your query and it is required when using mysqli_.
Rewrite, with a few more goodies:
<?php
$conn=new mysqli("localhost","root","password","database");
// Check if you've any errors when trying to access DB
if ($conn->connect_errno) {
printf("Connect failed: %s\n", $conn->connect_error);
exit();
}
$sql="INSERT INTO chat_active (user, time) VALUES ('John', '1234')";
$result = $conn->query($sql);
// Check if you've any errors when trying to enter data in DB
if (!$result)
{
throw new Exception($conn->error);
}
else{
echo "Success";
}
Read the manual http://php.net/manual/en/mysqli.query.php
Once you've grasped that, get to know mysqli with prepared statements, or PDO with prepared statements, they're much safer.
References:
http://php.net/manual/en/book.mysqli.php
http://php.net/manual/en/mysqli.query.php
http://php.net/manual/en/mysqli.error.php
http://php.net/manual/en/language.exceptions.php
Footnotes:
Your column names user, time suggests that you're trying to enter a string and what appears to be and to be intended as "time" and that the user column is set to varchar.
Make sure that you haven't setup your time column other than a datetime-related type, otherwise MySQL may complain about that.
MySQL stores dates as YYYY-mm-dd as an example.
Visit https://dev.mysql.com/doc/refman/5.0/en/datetime.html in regards to different date/time functions you can use.
MySQL references:
https://dev.mysql.com/doc/refman/5.0/en/char.html
https://dev.mysql.com/doc/refman/5.0/en/data-types.html
https://dev.mysql.com/doc/refman/5.0/en/datetime.html
You yould use mysqli or PDO.
Here's a connection example with PDO:
<?php
$dbuser = 'user';
$dbpasswd = 'passwd';
$dbname = 'dbname';
try {
$gbd = new PDO("mysql:host=localhost;dbname=$dbname;charset=utf8", $dbuser, $dbpasswd);
$gbd->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e) {
echo $e->getMessage();
}
PDO CRUD examples:
//INSERT
try {
$sentence = $gbd->prepare("INSERT INTO table (param1, param2) VALUES (:param1, :param2)");
$sentence->bindParam(':param1', $param1);
$sentence->bindParam(':param2', $param2);
$sentence->execute();
}
catch (PDOException $e) {
echo 'Query failed: ' . $e->getMessage();
}
//SELECT
try {
$sentence = $gbd->prepare("SELECT param1,param2 FROM table WHERE param1 = :param1 AND param2 = :param2)");
$sentence->bindParam(':param1', $param1);
$sentence->bindParam(':param2', $param2);
$sentence->execute();
while ($row = $sentence->fetch(PDO::FETCH_ASSOC)){ //Also available FETCH_NUM,FETCH_BOTH AND OTHERS
$result['param1'] = $row['param1'];
$result['param2'] = $row['param2'];
}
}
catch (PDOException $e) {
echo 'Query failed: ' . $e->getMessage();
}
//UPDATE
try {
$sentence = $gbd->prepare("UPDATE table SET param1 = :param1, param2 = :param2)");
$sentence->bindParam(':param1', $param1);
$sentence->bindParam(':param2', $param2);
$sentence->execute();
}
catch (PDOException $e) {
echo 'Query failed: ' . $e->getMessage();
}
//DELETE
try {
$sentence = $gbd->prepare("DELETE table WHERE param1 = :param1 AND param2 = :param2)");
$sentence->bindParam(':param1', $param1);
$sentence->bindParam(':param2', $param2);
$sentence->execute();
}
catch (PDOException $e) {
echo 'Query failed: ' . $e->getMessage();
}
And here's PDO manual
http://php.net/manual/en/book.pdo.php
u are not executing that query.u are only declaring that query.
for execution do--
$conn->query($qry);
it will,execute ur query.

Error Checking for PDO Prepared Statements [duplicate]

This question already has answers here:
Why does this PDO statement silently fail?
(2 answers)
Closed 5 years ago.
I'm trying to create proper error handling for queries on a MySQL database using PDO prepared statements. I want the program to exit the moment an error in the prepared statement process is detected. Taking advantage of the fact that each step in the PDO prepared statement process returns False on failure, I threw together this repugnant hack:
global $allFields;
global $db;
global $app;
//dynamically append all relevant fields to query using $allFields global
$selectQuery = 'SELECT ' . implode($allFields, ', ') .
' FROM People WHERE ' . $fieldName . ' = :value';
//prepared statement -- returns boolean false if failure running query; run success check
$success = $selectQueryResult = $db->prepare($selectQuery);
checkSuccess($success);
$success = $selectQueryResult->bindParam(':value', $fieldValue, PDO::PARAM_STR);
checkSuccess($success);
$success = $selectQueryResult->execute();
checkSuccess($success);
with checkSuccess() doing the following:
function checkSuccess($success) {
if ($success == false) {
//TODO: custom error page.
echo "Error connecting to database with this query.";
die();
}
}
Two things. First, this is horribly verbose and stupid. There must be a better way. Obviously I could store the booleans in an array or something to take out a line or 2 of code, but still.
Second, is it even necessary to check these values, or should I just check the result after I perform this line of code:
$result = $selectQueryResult->fetch(PDO::FETCH_ASSOC);
I already have code that does this:
if ($result) { //test if query generated results
// do successful shit
}
else {
echo "404";
$app->response()->status(404); //create 404 response header if no results
As much as I try to break the prepared statement process by inserting weird, mismatched, or lengthy queries, my program always makes it to the $result assignment without returning false on any of the functions where I run checkSuccess(). So maybe I don't need to be checking the above logic at all? Keep in mind that I check for a successful database connection earlier in the program.
I preffer setting the error mode to throwing exceptions like this:
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
right after I connect to the database. So every problem will throw an PDOException
So your code would be:
$selectQuery = '
SELECT
' . implode($allFields, ', ') . '
FROM
People
WHERE
' . $fieldName . ' = :value
';
try
{
$selectQueryResult = $db->prepare($selectQuery);
selectQueryResult->bindParam(':value', $fieldValue);
$selectQueryResult->execute();
}
catch(PDOException $e)
{
handle_sql_errors($selectQuery, $e->getMessage());
}
where the function would be:
function handle_sql_errors($query, $error_message)
{
echo '<pre>';
echo $query;
echo '</pre>';
echo $error_message;
die;
}
In fact I am using a general function that also has something like
$debug = debug_backtrace();
echo 'Found in ' . $debug[0]['file'] . ' on line ' . $debug[0]['line'];
to tell me where was the problem if I am running multiple queries
You have to catch PDOException:
try {
//your code/query
} catch (PDOException $e) {
//Do your error handling here
$message = $e->getMessage();
}
PDOException

How to Get Error Details From MySQL Stored Procedure

I am calling a mysql stored procedure using PDO in PHP
try {
$conn = new PDO("mysql:host=$host_db; dbname=$name_db", $user_db, $pass_db);
$stmt = $conn->prepare('CALL sp_user(?,?,#user_id,#product_id)');
$stmt->execute(array("user2", "product2"));
$stmt->setFetchMode(PDO::FETCH_COLUMN, 0);
$errors = $stmt->errorInfo();
if($errors){
echo $errors[2];
}else{
/*Do rest*/
}
}catch(PDOException $e) {
echo "Error : ".$e->getMessage();
}
that return below error because the name of the field in insert query was given wrong
Unknown column 'name1' in 'field list'
So i want to know if this is possible to get detailed error information something like:-
Unknown column 'Tablename.name1' in the 'field list';
that could tell me what column of which table is Unknown.
while creating the pdo connection, pass options like error mode and encoding:
The PDO system consists of 3 classes: PDO, PDOStatement & PDOException. The PDOException class is what you need for error handling.
Here is an example:
try
{
// use the appropriate values …
$pdo = new PDO($dsn, $login, $password);
// any occurring errors wil be thrown as PDOException
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$ps = $pdo->prepare("SELECT `name` FROM `fruits` WHERE `type` = ?");
$ps->bindValue(1, $_GET['type']);
$ps->execute();
$ps->setFetchMode(PDO::FETCH_COLUMN, 0);
$text = "";
foreach ($ps as $row)
{
$text .= $row . "<br>";
}
// a function or method would use a return instead
echo $text;
} catch (Exception $e) {
// apologise
echo '<p class="error">Oops, we have encountered a problem, but we will deal with it. Promised.</p>';
// notify admin
send_error_mail($e->getMessage());
}
// any code that follows here will be executed
I found this to be helpful for me. "error_log" prints to the php error log but you can replace with whatever way you'd like to display the error.
} catch (PDOException $ex){
error_log("MYSQL_ERROR"); //This reminds me what kind of error this actually is
error_log($ex->getTraceAsString()); // will show the php file line (and parameter
// values) so you can figure out which
// query/values caused it
error_log($ex->getMessage()); // will show the actual MYSQL query error
// e.g. constraint issue
}
p.s. I know this is a bit late but maybe it can help someone.

Reusing variables when working with PDO

I have to pull data from at least 3 databases, is there anything wrong with reusing my PDO objects?
$dbh = new PDO('mysql:host=' . $host . ';dbname=' . $db_name, $user, $password);
$sth = $dbh->prepare($query1);
// do something
$dbh = new PDO('mysql:host=' . $host2 . ';dbname=' . $db_name2, $user2, $password2);
$sth = $dbh->prepare($query2);
//do something else
Sorry for the edit but here's another consideration. With each of these I obviously should check whether or not the connection was successful and throw an exception if it wasn't:
if (!$dbh) {
$err=$dbh->errorInfo();
throw new Exception('Could not connect: ' . $err[2]);
}
I don't suppose there's a way to avoid this, unless I create all the connections at the same time and do if (!dbh1|!dbh2) { ... }. Just something else to consider.
When you assign $dbh to a new PDO() you are not technically reusing your pdo object. You are creating a new PDO instance and assigning it to a variable that you have previously used. There is nothing wrong with doing this as long as you understand what is occurring in your program.
EDIT:
I'm editing my answer to address the new question you've added to your previous question.
With each of these I obviously should check whether or not the connection was successful and throw an exception if it wasn't:
You can surround your connection attempt in a try catch which is a typical strategy for dealing with connection errors:
<?php
try {
$dbh = new PDO('mysql:host=localhost;dbname=databaseName', $userName, $password);
foreach($dbh->query('SELECT * from TableName') as $row) {
print_r($row);
}
$dbh = null;
} catch (PDOException $ex) {
print "Error!: " . $ex->getMessage() . "<br />";
die();
}
?>
You can do that, but ... don't. Use another variable name (they are cheap) it will make your code much easier to understand. Heck you can (should) even use variable names that will clue you in on what database your object is connecting to, ie:
// connection to data warehouse
$dbh_dataWH = new PDO('mysql:host=' . $host . ';dbname=' . $db_name, $user, $password);
// connection to crm
$dbh_crm = new PDO('mysql:host=' . $host2 . ';dbname=' . $db_name2, $user2, $password2);
This way you will be able to re-use your connection objects, and the code in my very humble opinion will be much clearer for you or anyone else that has to maintain it.

Categories