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.
Related
I am having a problem where a prepared MySQL stored procedure call runs fine in a transaction, and I see the expected results from the stored procedure, but the changes do not appear to be saving to the actual database.
The PHP side of things looks like this:
$options = array();
$db = new PDO("mysql:host=localhost;dbname=mydb", "myuser", "mypass", $options);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
// ..... .... ... .. .
$response["error"] = true;
if ($db->beginTransaction() == true)
{
try
{
$stmt = $db->prepare("call Layout_Row_Add(:pageid, :position);");
// $jason->page_id
$stmt->bindValue(':pageid', (int)$jason->page_id, PDO::PARAM_INT);
// $jason->position
$stmt->bindValue(':position', (int)$jason->position, PDO::PARAM_INT);
$stmt->execute();
$response["dbg1"] = $jason->page_id;
$response["dbg2"] = $jason->position;
$response["intrans1"] = $db->inTransaction();
$row = $stmt->fetch();
$db->commit();
$response["intrans2"] = $db->inTransaction();
$response["new_row_id"] = $row["NewRowId"];
$response["error"] = false;
}
catch (PDOException $e)
{
$db->rollBack();
$response["errortext"] = "PDO exception: " . $e->getMessage();
}
catch (Exception $exc)
{
$db->rollBack();
$response["errortext"] = "Exception: " . $e->getMessage();
}
}
else
{
$response["errortext"] = "Couldn't start transaction";
}
The $response variable gets encoded into JSON and sent back to the browser, which gets this:
error false
dbg1 1
dbg2 3
intrans1 true
intrans2 false
new_row_id 21
Everything looks exactly like it should, new_row_id is at its expected value meaning the autoincrement field ticked up, and the debug fields and transaction info is as expected.
However, doing a select * in MySQL Workbench doesn't return any of these rows that were supposedly added by the procedure. Running the procedure itself in MySQL Workbench works fine, as in, the commit actually sticks. Here's the procedure itself:
CREATE DEFINER=`myuser`#`myhost` PROCEDURE `Layout_Row_Add`(PageId int, Position int)
BEGIN
declare NewRowId int unsigned default 0;
update pages_layout_rows set ordinal = ordinal + 1 where page_id = PageId and ordinal >= Position;
insert into pages_layout_rows (page_id, ordinal) values (PageId, Position);
set NewRowId = last_insert_id();
select NewRowId;
END
The table is set to InnoDB, so transaction support should be available. I don't really know what to try next.
Found it - it looks like if you don't consume all the resultsets, the transaction appears to get rolled back in the end anyway. A stored procedure call adds an empty resultset as the last resultset, so that's what's happening.
// ...
$row = $stmt->fetch();
// let's consume all resultsets
while($stmt->nextRowset() && $stmt->columnCount());
$sol->db->commit();
// ...
I am trying to write a function that is supposed to receive any MySQL statement and apply it,
The basic idea is not to repeat needed code to write to Database, well what is needed to connect to Database is creating new PDO object, starting a transaction and preparing a statement, binding values to it, executing it,
so every time I want to access the Database I don't have to repeat these steps,
Here is a function that does that :
==============================================================================================
protected function applyQuery($statement, $bindparameters , &$values , $selectStatement, &$result){
try{
$dbh = DataBase::setConnection();// new PDO("MySQL= .....");
$dbh->beginTransaction();
$stmt = $dbh->prepare($statement);
if($bindparameters == true){
foreach($values as $key => $value){
$stmt->bindValue($key, $value);
}
}
$stmt->execute();
$dbh->commit();
if($selectStatement == TRUE){
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}catch (PDOException $e){
$dbh->rollBack();
throw DataBase::$Errors[0];
}
}
============================================================================================
$statement = the desired statement (e.g 'SELECT * from users WHERE username = :username')
$bindparameters = do we need to bind values (in this examples yes) so its value TRUE
&$values = array by reference in this case equals = (':username' => 'User');
$selectStatement = tells if using SELECT in statement ,in this case TRUE
$result = array by reference in this case the final fetch result will be stored in it
so in this example we get the following call to the function :
applyQuery('SELECT * from users WHERE username = :username', TRUE ,
array(':username' => 'User') , TRUE , result )
My question is : will this code work ? is the logical sequence of what it does and should do make sense ? whats the difference between $stmt->execute and $dbh->commit ? is omitting any line will cause failure to achieve the desired result
Please understand that I did lookup what is PDO and read a lot but unable to answer these questions!
I am trying to write a function that is supposed to receive any MySQL statement and apply it,
The basic idea is not to repeat needed code to write to Database, well what is needed to connect to Database is creating new PDO object, starting a transaction and preparing a statement, binding values to it, executing it,
so every time I want to access the Database I don't have to repeat these steps,
Here is a function that does that :
==============================================================================================
protected function applyQuery($statement, $bindparameters , &$values , $selectStatement, &$result){
try{
$dbh = DataBase::setConnection();// new PDO("MySQL= .....");
$dbh->beginTransaction();
$stmt = $dbh->prepare($statement);
if($bindparameters == true){
foreach($values as $key => $value){
$stmt->bindValue($key, $value);
}
}
$stmt->execute();
$dbh->commit();
if($selectStatement == TRUE){
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}catch (PDOException $e){
$dbh->rollBack();
throw DataBase::$Errors[0];
}
}
============================================================================================
$statement = the desired statement (e.g 'SELECT * from users WHERE username = :username')///
$bindparameters = do we need to bind values (in this examples yes) so its value TRUE///
&$values = array by reference in this case equals = (':username' => 'User');///
$selectStatement = tells if using SELECT in statement ,in this case TRUE///
$result = array by reference in this case the final fetch result will be stored in it///
so in this example we get the following call to the function :
applyQuery('SELECT * from users WHERE username = :username', TRUE ,array(':username' => 'User') , TRUE , result )
My question is : will this code work ?
is the logical sequence of what it does and should do make sense ?
whats the difference between $stmt->execute and $dbh->commit ?
is omitting any line will cause failure to achieve the desired result
Please understand that I did lookup what is PDO and read a lot but unable to answer these questions!
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.
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.