Mysqli to PDO - If else statement to try catch - php

I'm trying to convert some mysqli code to PDO.
Before I had this:
$updateTaskQuery = "UPDATE `task` SET `user_id` = {$query['user_id']}, `status_id` = {$query['status_id']} WHERE `id` = {$query['task_id']}";
$updateTask = mysqli_query($mysqli, $updateTaskQuery);
//### Check for error
if($mysqliError = mysqli_error($mysqli)) {
echo json_encode(array('error' => 'Update Task MySQLi Error: '.$mysqliError));
exit;
} else {
echo json_encode(array('success' => true));
exit;
}
So far, I have convertet it to this:
$sql = $db->prepare ( "UPDATE `task` SET `user_id` = {$query['user_id']}, `status_id` = {$query['status_id']} WHERE `id` = {$query['task_id']}" );
$sql->execute ();
$updateTask = $sql->fetchAll ( PDO::FETCH_ASSOC );
try {
$updateTask;
} catch ( PDOException $ex ) {
//handle
}
My question here is, how can I include my else statement in the new code?
UPDATE: Wrong, but working code
try {
// Update task
$query = $db->prepare ( "UPDATE `task` SET `user_id` = {$query['user_id']}, `status_id` = {$query['status_id']} WHERE `id` = {$query['task_id']}" );
$query->execute();
echo json_encode ( array (
'success' => true
) );
} catch ( PDOException $e ) {
// catch a pdo error
echo json_encode ( array (
'error' => 'Update Task PDO Error: ' . $e->getMessage (),
'error_trace' => $e->getTraceAsString ()
) );
}

you have a lot wrong here, I will see If i can help - I haven't "tested" this but it should be really close.
//your using json so set the correct content headers
header('Content-Type: application/json');
//try only works on code you "try" anything outside isn't included in the try block
try{
//connect
$PDO = new PDO(
'mysql:host=' . $_dbHost . ';' . 'dbname=' . $_dbName,
$_dbUser,
$_dbPass
);
//set exception error mode
$PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//set fetch assoc array as default
$PDO->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
//query with named placeholders ( even pdo can get sql injection when you dont use placeholders )
$sql = 'UPDATE `task` SET `user_id` = :user_id, `status_id` = :status_id WHERE `id` = :id';
//prepare query
$stmt = $PDO->prepare( $sql );
//execute with data
$stmt->execute(array(
':user_id' => $query['user_id'],
':status_id' => $query['status_id'],
':id' => $query['id'],
));
echo json_encode(array(
'success' => true,
'results' => $stmt->fetchAll()
)
);
}catch( PDOException $e ){
//catch a pdo error
echo json_encode(array(
'error' => 'Update Task PDO Error: '.$e->getMessage(),
'error_trace' => $e->getTraceAsString()
)
);
}catch( Exception $e ){
//the beauty of exceptions ~ catch some other non-pdo exception
echo json_encode(array(
'error' => 'Runtime Error: '.$e->getMessage(),
'error_trace' => $e->getTraceAsString()
)
);
}
///more code can go here
To answer your question, you don't need the else statement any longer. Everything in the try block with run until it throws an exception, then it will land in the appropriate catch block and run that code. In that block you can get the error messages by referencing the variable you set for the exception class instance to use, in this case I set $e. This is a common convention to use $e just as it is to use $i for iteration on a loop. Generally I wont use short variables like this except in cases where the variable is not a integral part of your code. In this case $e is not something I expect to use outside of the catch.
I also included the proper content header. This will help javascript libraries such as jQuery parse the JSON properly when they return the data.
I love these kinds of questions, so I hope my explanation has helped you to understand PDO and Exceptions a bit more. Your on the right track using them.
One last note is you can run more code after the try catch blocks.
To explain my comment ( about wrong code that works ), when you don't sanitize input in your SQL you get nasty things like this. Assume we have this query:
$sql = "UPDATE
`task`
SET
`user_id` = {$query['user_id']},
`status_id` = {$query['status_id']}
WHERE
`id` = {$query['task_id']}
";
The problem here is if someone enters a chunk of sql into one of your inputs such as
$query['task_id'] = '0; DROP table task;';
What this does is complete your query and drop your table!
$sql = "UPDATE
`task`
SET
`user_id` = 1,
`status_id` = 2
WHERE
`id` = 0;
DROP table task;
";
While I am by no means and expert at SQL injection, as I never have done it, that's the gist of it. There are a lot of things they can do worse then dropping tables, such as creating database users. Accessing files on the system, such as password files for system users or other confidential information. Not to mention a whole plethora of second stage attacks such as adding malicious javascript. Which would be printed on the screen and allow them to do XSS ( cross site scripting ) type attacks on site visitors etc...
Trust me even if you think you don't have anything worth "stealing" on your site. It's better to learn the right way then the hard way on something like this. Sorry if I'm a bit harsh on this but it is a very important concept to learn if you plan to do any "serious" coding.
Just because something doesn't work strait off, such as a code "sample" that I provided ( I did explicitly say I didn't test it ). Doesn't mean there is a fundamental problem with it ( it was a simple copy paste error ). The "wrong" code that works is fundamentally flawed.

Related

"Execute Array" problem from Database PHP

As I'm a beginner, I have a problem with executing an array from the database.
My code:
$operation_id = (int)$_GET["operation"];
$operation_query = $db_link->prepare('SELECT * FROM `shop_users_accounting` WHERE `id` = ? AND `active` = 0 AND `user_id` = ?;');
$operation_query->execute( array($operation_id, $user_id) );
$operation = $operation_query->fetch();
if($operation == false)
{
$answer = array();
$answer["result"] = false;
$answer["code"] = 2;
exit(json_encode($answer));
}
For now, I can echo $operation_id and $user_id without any problem
but in shop_users_accounting table I have more columns, like pay_orders and amount
I have tried do like this $operation_query->execute( array($operation_id, $user_id, $pay_orders) ); but then IF function get executed and I get false
I have tried $operation_query = $db_link->prepare('SELECT * FROM `shop_users_accounting` WHERE `id` = ? AND `active` = 0 AND `user_id` = ? AND `pay_orders` = ?;'); and the result is the same, IF function get executed and I get false
The question is, what I'm doing wrong, and how I can get pay_orders and amount from DB without getting False
First I'd define the connection adding the request to return the error from mysql:
$pdo = new PDO('mysql:host=127.0.0.1;dbname=mydbname', $db_user, $db_pass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
You see the last array()? It tells mysql to return the errors.
Then I'd put everything in a try catch block so that I can handle the errors:
try{
$operation_query = $db_link->prepare('SELECT * FROM `shop_users_accounting` WHERE `id` = ? AND `active` = 0 AND `user_id` = ?;');
$operation_query->execute( array($operation_id, $user_id) );
$operation = $operation_query->fetch();
}
catch (PDOException $e) {
echo $e->getMessage();
}
So the try block will be always executed. The catch one will be executed only if there is an error and will just echo the error message. What you will do is to put inside the catch block your logic if the query fails, after the catch block your logic if your query is successfull.
The error you are getting is obscure with your code but is probably due to a value that you pass incorrectly to the query (value of the array element). There is no strict error on the syntax you use to pass the array to the query (what you call execute the array).
I'd also suggest to use named parameters in the query and bindParams() to have a more readible code with many parameters. See here for more details on how to build prepared statements.

MySQL Complete CREATE OR REPLACE VIEW before moving on to SELECT Statement [duplicate]

I do know that PDO does not support multiple queries getting executed in one statement. I've been Googleing and found few posts talking about PDO_MYSQL and PDO_MYSQLND.
PDO_MySQL is a more dangerous
application than any other traditional
MySQL applications. Traditional MySQL
allows only a single SQL query. In
PDO_MySQL there is no such limitation,
but you risk to be injected with
multiple queries.
From: Protection against SQL Injection using PDO and Zend Framework (June 2010; by Julian)
It seems like PDO_MYSQL and PDO_MYSQLND do provide support for multiple queries, but I am not able to find more information about them. Were these projects discontinued? Is there any way now to run multiple queries using PDO.
As I know, PDO_MYSQLND replaced PDO_MYSQL in PHP 5.3. Confusing part is that name is still PDO_MYSQL. So now ND is default driver for MySQL+PDO.
Overall, to execute multiple queries at once you need:
PHP 5.3+
mysqlnd
Emulated prepared statements. Make sure PDO::ATTR_EMULATE_PREPARES is set to 1 (default). Alternatively you can avoid using prepared statements and use $pdo->exec directly.
Using exec
$db = new PDO("mysql:host=localhost;dbname=test", 'root', '');
// works regardless of statements emulation
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
$sql = "
DELETE FROM car;
INSERT INTO car(name, type) VALUES ('car1', 'coupe');
INSERT INTO car(name, type) VALUES ('car2', 'coupe');
";
$db->exec($sql);
Using statements
$db = new PDO("mysql:host=localhost;dbname=test", 'root', '');
// works not with the following set to 0. You can comment this line as 1 is default
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
$sql = "
DELETE FROM car;
INSERT INTO car(name, type) VALUES ('car1', 'coupe');
INSERT INTO car(name, type) VALUES ('car2', 'coupe');
";
$stmt = $db->prepare($sql);
$stmt->execute();
A note:
When using emulated prepared statements, make sure you have set proper encoding (that reflects actual data encoding) in DSN (available since 5.3.6). Otherwise there can be a slight possibility for SQL injection if some odd encoding is used.
After half a day of fiddling with this, found out that PDO had a bug where...
--
//This would run as expected:
$pdo->exec("valid-stmt1; valid-stmt2;");
--
//This would error out, as expected:
$pdo->exec("non-sense; valid-stmt1;");
--
//Here is the bug:
$pdo->exec("valid-stmt1; non-sense; valid-stmt3;");
It would execute the "valid-stmt1;", stop on "non-sense;" and never throw an error. Will not run the "valid-stmt3;", return true and lie that everything ran good.
I would expect it to error out on the "non-sense;" but it doesn't.
Here is where I found this info:
Invalid PDO query does not return an error
Here is the bug:
https://bugs.php.net/bug.php?id=61613
So, I tried doing this with mysqli and haven't really found any solid answer on how it works so I thought I's just leave it here for those who want to use it..
try{
// db connection
$mysqli = new mysqli("host", "user" , "password", "database");
if($mysqli->connect_errno){
throw new Exception("Connection Failed: [".$mysqli->connect_errno. "] : ".$mysqli->connect_error );
exit();
}
// read file.
// This file has multiple sql statements.
$file_sql = file_get_contents("filename.sql");
if($file_sql == "null" || empty($file_sql) || strlen($file_sql) <= 0){
throw new Exception("File is empty. I wont run it..");
}
//run the sql file contents through the mysqli's multi_query function.
// here is where it gets complicated...
// if the first query has errors, here is where you get it.
$sqlFileResult = $mysqli->multi_query($file_sql);
// this returns false only if there are errros on first sql statement, it doesn't care about the rest of the sql statements.
$sqlCount = 1;
if( $sqlFileResult == false ){
throw new Exception("File: '".$fullpath."' , Query#[".$sqlCount."], [".$mysqli->errno."]: '".$mysqli->error."' }");
}
// so handle the errors on the subsequent statements like this.
// while I have more results. This will start from the second sql statement. The first statement errors are thrown above on the $mysqli->multi_query("SQL"); line
while($mysqli->more_results()){
$sqlCount++;
// load the next result set into mysqli's active buffer. if this fails the $mysqli->error, $mysqli->errno will have appropriate error info.
if($mysqli->next_result() == false){
throw new Exception("File: '".$fullpath."' , Query#[".$sqlCount."], Error No: [".$mysqli->errno."]: '".$mysqli->error."' }");
}
}
}
catch(Exception $e){
echo $e->getMessage(). " <pre>".$e->getTraceAsString()."</pre>";
}
A quick-and-dirty approach:
function exec_sql_from_file($path, PDO $pdo) {
if (! preg_match_all("/('(\\\\.|.)*?'|[^;])+/s", file_get_contents($path), $m))
return;
foreach ($m[0] as $sql) {
if (strlen(trim($sql)))
$pdo->exec($sql);
}
}
Splits at reasonable SQL statement end points. There is no error checking, no injection protection. Understand your use before using it. Personally, I use it for seeding raw migration files for integration testing.
Like thousands of people, I'm looking for this question:
Can run multiple queries simultaneously, and if there was one error, none would run
I went to this page everywhere
But although the friends here gave good answers, these answers were not good for my problem
So I wrote a function that works well and has almost no problem with sql Injection.
It might be helpful for those who are looking for similar questions so I put them here to use
function arrayOfQuerys($arrayQuery)
{
$mx = true;
$conn->beginTransaction();
try {
foreach ($arrayQuery AS $item) {
$stmt = $conn->prepare($item["query"]);
$stmt->execute($item["params"]);
$result = $stmt->rowCount();
if($result == 0)
$mx = false;
}
if($mx == true)
$conn->commit();
else
$conn->rollBack();
} catch (Exception $e) {
$conn->rollBack();
echo "Failed: " . $e->getMessage();
}
return $mx;
}
for use(example):
$arrayQuery = Array(
Array(
"query" => "UPDATE test SET title = ? WHERE test.id = ?",
"params" => Array("aa1", 1)
),
Array(
"query" => "UPDATE test SET title = ? WHERE test.id = ?",
"params" => Array("bb1", 2)
)
);
arrayOfQuerys($arrayQuery);
and my connection:
try {
$options = array(
//For updates where newvalue = oldvalue PDOStatement::rowCount() returns zero. You can use this:
PDO::MYSQL_ATTR_FOUND_ROWS => true
);
$conn = new PDO("mysql:host=$servername;dbname=$database", $username, $password, $options);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo "Error connecting to SQL Server: " . $e->getMessage();
}
Note:
This solution helps you to run multiple statement together,
If an incorrect a statement occurs, it does not execute any other statement
PDO does support this (as of 2020). Just do a query() call on a PDO object as usual, separating queries by ; and then nextRowset() to step to the next SELECT result, if you have multiple. Resultsets will be in the same order as the queries. Obviously think about the security implications - so don't accept user supplied queries, use parameters, etc. I use it with queries generated by code for example.
$statement = $connection->query($query);
do {
$data[] = $statement->fetchAll(PDO::FETCH_ASSOC);
} while ($statement->nextRowset());
Try this function : multiple queries and multiple values insertion.
function employmentStatus($Status) {
$pdo = PDO2::getInstance();
$sql_parts = array();
for($i=0; $i<count($Status); $i++){
$sql_parts[] = "(:userID, :val$i)";
}
$requete = $pdo->dbh->prepare("DELETE FROM employment_status WHERE userid = :userID; INSERT INTO employment_status (userid, status) VALUES ".implode(",", $sql_parts));
$requete->bindParam(":userID", $_SESSION['userID'],PDO::PARAM_INT);
for($i=0; $i<count($Status); $i++){
$requete->bindParam(":val$i", $Status[$i],PDO::PARAM_STR);
}
if ($requete->execute()) {
return true;
}
return $requete->errorInfo();
}
Tried following code
$db = new PDO("mysql:host={$dbhost};dbname={$dbname};charset=utf8", $dbuser, $dbpass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
Then
try {
$db->query('SET NAMES gbk');
$stmt = $db->prepare('SELECT * FROM 2_1_paidused WHERE NumberRenamed = ? LIMIT 1');
$stmt->execute(array("\xbf\x27 OR 1=1 /*"));
}
catch (PDOException $e){
echo "DataBase Errorz: " .$e->getMessage() .'<br>';
}
catch (Exception $e) {
echo "General Errorz: ".$e->getMessage() .'<br>';
}
And got
DataBase Errorz: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '/*' LIMIT 1' at line 1
If added $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); after $db = ...
Then got blank page
If instead SELECT tried DELETE, then in both cases got error like
DataBase Errorz: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '* FROM 2_1_paidused WHERE NumberRenamed = '¿\' OR 1=1 /*' LIMIT 1' at line 1
So my conclusion that no injection possible...

How can I use MySQL statement 'show index' with PDO?

I am trying to use PDO and prepared statements to get the primary key of a table. From other questions I saw that this is possible when executing something like this:
show index from TABLENAME where Key_name = 'PRIMARY'
The problem is that I can not use this from inside a prepared statement by using PDO under PHP. The code I use is the following:
$pdo = new PDO('mysql:host=localhost;charset=utf8;dbname=eclass', "user", "pass");
$stm = $pdo->prepare("show index from `TABLENAME` where `Key_name` = 'PRIMARY'");
$res = $stm->execute();
Now, the problem is that although the statement is created correctly, the execution fails. I am sure that this is not a permission's problem, since I run this as root with no result. When I directly run this SQL code from mysql prompt, it shows result indeed.
EDIT: It seems that after the weekend, the statement magically works. I don't know why this happened. Thank you for your help.
are you sure it fails? what is the result of this code?
$pdo = new PDO(
"mysql:dbname=" . SQL_DB . ";host=" . SQL_HOST, SQL_USER, SQL_PWD,
array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
)
);
try {
$stm = $pdo->prepare("show index from `TABLENAME` where `Key_name` = 'PRIMARY'");
$res = $stm->execute();
print_r($stm->fetch(PDO::FETCH_ASSOC));
} catch (Exception $e) {
print_r($e);
}

PHP variable doesn't load with MySQL update query

I have omitted unnecessary code. Whenever I try to run this, it processes without any errors. However, in the update query, whenever I use WHERE student_id='$student_id', it doesn't update. No errors, it just doesn't update. However, when I use the numeric equivalent of the variable, such as 1, it works just fine. What am I missing? Thank you!
$resolved_student_id = $_GET['student_id'];
try {
$request_sd = $db -> prepare("SELECT student_name,tutor,intervention FROM students WHERE student_id='$resolved_student_id'");
$request_sd -> execute();
} catch ( Exception $e ) {
echo "Could not query database.";
exit;
}
$studentdata = $request_sd -> fetch();
if ( empty( $_POST ) === false ) {
if ( empty( $_POST['student_name'] ) === true || empty( $_POST['student_tutor'] ) === true || empty( $_POST['student_intervention'] ) === true ) {
$updateStudentInformation = "You need to fill out all fields.";
} else {
$student_name = $_POST['student_name'];
$student_tutor = $_POST['student_tutor'];
$student_intervention = $_POST['student_intervention'];
try {
$updatedata = $db -> prepare("UPDATE students SET student_name='$student_name', tutor='$student_tutor', intervention='$student_intervention' WHERE student_id='$resolved_student_id'");
$updatedata -> execute();
} catch (Exception $e) {
echo "Could not update database.";
exit;
}
header("location: edit.php");
}
}
How come you are using both get and post methods here?
I guess this: $resolved_student_id = $_GET['student_id'];
Should be replaced by: $resolved_student_id = $_POST['student_id'];
and if you need both methods make sure to specify the GET data in the form URL.
eg:<form method="POST" action="abc.php?student_id=1">
And the reason its not updating where $student_id is you have not defined any such variable, not at least what i can see here in the code u posted.
You've written your query as a straight up query (where all the options are defined) but you're running prepare, where your query would look like this
UPDATE students SET student_name=?, tutor=?, intervention=? WHERE student_id=?
Then you would run bind_param to bind your data to the prepared statement and then execute()
So either convert your query to a prepared statement query and bind your parameters or change from prepare to query
Several things here...
Configure PDO to throw exceptions. I like using this constructor for optimal MySQL usage
$db = new PDO('mysql:host=localhost;dbname=db_name;charset=utf8', 'username', 'password', array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC));
Stop catching exceptions and discarding them. This is most important while developing. Once you're confident that your code runs properly, then you can implement a high-level exception handling scheme. Simply remove the try controls and catch blocks from your code
Use parameter binding with your queries instead of string interpolation. This will make your queries much more resilient to SQL injection attacks.
$request_sd = $db->prepare("SELECT student_name,tutor,intervention FROM students WHERE student_id = ?");
$request_sd->execute([$resolved_student_id]);
// use array($resolved_student_id) if using an older version of PHP
You would do the same with your update query.

pdo select statement returning no rows

I am making a simple select from mySQL using PHP. I am doing something wrong that I can't seem to track down.
Here's my statement:
$storyTitle = $_GET['title'];
$storyDate = urldecode($_GET['date']);
$SQL = "SELECT
*
FROM
tblContent
WHERE
REPLACE(contentTitle,' ' , '-') = :storyTitle
AND
date(publishDate) = date(:storyDate)";
$conn = new PDO("mysql:host=$dbhost;dbname=$dbname",$dbuser,$dbpass);
$q = $conn->prepare($SQL);
$q->execute(array(':storyTitle' => $storyTitle, ':storyDate' => $storyDate));
while($r = $q->fetch()){
echo $SQL;
};
This throws no errors and gives no rows.
If I replace the identifiers :storyTitle and :storyDate with a hard coded SQL statement, I get the correct results. I've stepped through and looked at the variables, and they seem right... I've already wasted so much time hunting, but I lack the expertise to pick out what I'm doing wrong.
Dump the contents of your variables. I'm suspicious of:
$storyDate = urldecode($_GET['date']);
$_GET parameters automatically are url-decoded.
you have to ask PDO to throw an error explicitly
try {
$conn = new PDO("mysql:host=$dbhost;dbname=$dbname",$dbuser,$dbpass);
$conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$q = $conn->prepare($SQL);
$q->execute(array(':storyTitle' => $storyTitle, ':storyDate' => $storyDate));
} catch (PDOException $e) {
echo $e->getMessage();
}

Categories