Everything works with my site and database.
I've submitted a snippet of code where I think the PHP to prevent duplicate submissions needs to be inserted.
{
$pdo = new PDO('mysql:host=localhost;dbname=', '', '');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->exec('SET NAMES "utf8"');
}
catch (PDOException $e)
{
$error = 'Unable to connect to the database server.';
include 'error.html.php';
exit();
}
if (isset($_POST['profanetext']))
{
try
{
$sql = 'INSERT INTO profane SET
profanetext = :profanetext,
profanedate = CURDATE()';
$s = $pdo->prepare($sql);
$s->bindValue(':profanetext', $_POST['profanetext']);
$s->execute();
}
catch (PDOException $e)
{
$error = 'Error adding submitted profanity: ' . $e->getMessage();
include 'error.html.php';
exit();
}
header('Location: .');
exit();
}
You do a select where query to see if the value exist first.
Also you can make the actual profane text database column UNIQUE. This will prevent insertion of duplicate value and will produce an db error if trying to do so.
Well, I figured out a way to make it work. After changing the profanetext column from TEXT type to VARCHAR(255) -- which allowed me to make the column UNIQUE -- I added this to my php to make the db error message display as an alert:
catch (PDOException $e)
{
$error = 'Error adding submitted profanity: ' . $e->getMessage();
echo '<script language="javascript">';
echo 'alert("That profanity has already been submitted")';
echo '</script>';
exit();
}
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();
}
I am running a test to serialize an array using PHP, in order to update my database I use the PDO extension. I have tried changing the code a bit, but there is no error to be catched by the try block. I have other functions where I successfully updated other tables, the only diferense here is the PDO::PARAM_LOB line. Any help is greatly appreciated.
<?php
require("database.php");
try {
$test = array('15525');
array_push($test, '12345');
var_dump($test);
$stest = serialize($test);
var_dump($stest) ;
$dapartmentToUpdate = 3;
$result = $db->prepare("
UPDATE departments_employees
SET employee_id = ?
WHERE department_id = ?
");
$result ->bindParam(1,$stest,PDO::PARAM_LOB);
$result ->bindParam(2,$departmentToUpdate,PDO::PARAM_INT);
$result -> execute();
} catch (Exception $e) {
echo "Could not write to database for some odd reason";
exit;
}
?>
I must add that by taking the query directly to SQL makes it run just fine, so I must be missing something. The statement on SQL looks like
UPDATE departments_employees
SET employee_id = 'a:2:{i:0;s:5:"15525";i:1;s:5:"12345";}'
WHERE department_id = 3
config.php are just some environment constants, user, password and some other private stuff, database.php looks like this:
<?php
require_once ('config.php');
try {
$db = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME .";port=" . DB_PORT,DB_USER,DB_PASS);
$db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
$db->exec("SET NAMES 'utf8'");
} catch (Exception $e) {
echo "Could not connect to the database.";
exit;
}
Ok so I can't catch the exeption:
require_once 'config/config.php';
try {
$dbh = new PDO('mysql:host='.DB_HOST.';dbname='.DB_DATABASE, DB_USER, DB_PASS,array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
));
} catch (PDOException $e) {
print "Unable to connect!: " . $e->getMessage() . BR;
die();
}
try {
$stmt = $dbh->prepare("SELECT id,email FROM no_table ORDER BY id DESC LIMIT 5");
$stmt->execute();
$stmt->bindColumn(1, $id, PDO::PARAM_INT);
$stmt->bindColumn('email', $email, PDO::PARAM_STR);
while ($row = $stmt->fetch(PDO::FETCH_BOUND)) {
echo $id . "\t" . $email . BR;
}
} catch (PDOException $e) {
echo "Failed: " . $e->getMessage();
}
Ok I connect I have an error in the syntax (there isn't any no_table) it throws the exception but i can't catch it. In browser I see this:
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42S02]:
Base table or view not found: 1146 Table 'no_table' doesn't exist' in 'somepath'
PDOStatement->execute() #1 {main} thrown in some.php on line 15
The exception is thrown and i can't catch it, but if I put another try catch between $stmt->execute(); it catches it.
My php version 5.3.14
Have you been using namespaced classes in this project maybe?
If so, please try to use
\PDOException
instead of
PDOException
in your "catch" statement.
I just got similar problem and this move helped.
I'm new to PDO and I wanna do it right from the beginning - I'm going to replace my old mysql_ functions on a site.
Have I got it right?:
Should I put the connection code in a try/catch and save it to a file, and include it on top of the page. Then put the queries in try/catch as well.
Or:
Should I put the connection code in a file and include it in the in the top of the try/catch statement above the query?
ver1:
include('pdo.php'); // try/catch in file
try {
$stmt = $conn->prepare('SELECT * FROM myTable WHERE id = :id');
$stmt->execute(array('id' => $id));
while($row = $stmt->fetch()) {
print_r($row);
}
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
ver2:
try {
include('pdo.php'); // no try/catch in file
$stmt = $conn->prepare('SELECT * FROM myTable WHERE id = :id');
$stmt->execute(array('id' => $id));
while($row = $stmt->fetch()) {
print_r($row);
}
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
Or should I put the try/catch in both places?
You should do both and even more :
Set an error handler that displays a message to the user and stops the PHP (see set_error_handler)
When you initiate the connexion, add a try/catch and throw an error if you catch an exception. Your website won't run without database connection i guess.
Do a try/catch around your queries to recover gracefully from error (when you can)