I Can Never Execute SQL-Safe Queries? - php

I am using the ODBC extension in PHP to connect to an SQL 2000 server. Here is what I am up against:
I can execute queries with odbc_exec() OR
I can execute queries with odbc_execute()
In my opinion, the differences between these two query executing methods are nearly as different as night and day:
odbc_exec() will execute a non SQL-safe query and return the results from the query
odbc_execute() is used in conjunction with odbc_prepare() to execute an SQL safe query on the database. However, odbc_execute() can only ever return a boolean, and therefore cannot be used to return the results from a SELECT statement, or to check how many rows were updated from an UPDATE or DELETE statement
Is this really the way this all works, or is there some way to escape values for use in odbc_exec() or to get the results back from odbc_execute()?
The PHP documentation doesn't seem to over any solutions for the above dilemma.
Thank you for your time.

The resource for the query you're running is returned by the odbc_prepare function, not odbc_execute.
These two blocks of code do the same thing:
$query=odbc_exec("SELECT * FROM table WHERE userinput=".$hopefully_escaped_user_input);
while($row=odbc_fetch_array($query) {
//do stuff with $row
}
$query=odbc_prepare("SELECT * FROM table WHERE userinput=?");
odbc_execute($query,Array($user_input);
while($row=odbc_fetch_array($query) {
//do stuff with $row
}

Prepared statements are used in conjuction with a resource that "points to" the prepared statement.
Imagine prepared statements as if they were a function/ procedure you defined in SQL and then you use the resource to "call" that function.
Example from here:
<?php
$res = odbc_prepare($db_conn, $query_string);
if(!$res) die("could not prepare statement ".$query_string);
if(odbc_execute($res, $parameters)) {
$row = odbc_fetch_array($res);
} else {
// handle error
}
?>

Related

pg_prepare problems with Create role?

Hi There i want to create a new postgresql role with a prepared statement:
My Code:
$stmt = pg_prepare($conn,"test","CREATE ROLE $1 WITH LOGIN PASSWORD $2 NOCREATEDB NOCREATEROLE");
$result = pg_execute($conn,"test",array($username,$password));
if (!$result){
die("error in SQL query:".pg_last_error());
}
But i get this error on execution:
PHP Warning: pg_prepare(): Query failed: FEHLER: Syntaxfehler bei »$1«
If i try a simple select:
$stmt = pg_prepare($conn,"test","Select * from pg_user where usename=$1");
everything works as expected.
Anyone have a hint?
Thanks
You can not use a prepared statement for this purpose. The parameters of a prepared statement can only refer to data values (like in an INSERT or UPDATE statement, or in the WHERE example you give). The values for the role name and password in the CREATE ROLE statement need to be supplied as string literals.
Use of a prepared statement in CREATE ROLE is also not useful at all. A prepared statement is used to plan execution of a complex statement once and then execute it many times with different parameters. A CREATE ROLE statement is not complex and neither will you ever have enough statements to run in a single session to make a prepared statement useful, if it were possible to begin with.
I think you need pg_escape_identifier() to avoid SQL injection on dynamic items like this.

PDO::query() run into "Cannot execute queries while other unbuffered queries are active."

Maybee some other have the same problem than me.
I run over the error:
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.
on PDO. As in many threads mentioned the error can at be at least one of the following problems:
The query cursor was not closed with closeCursor() as mentioned here; Causes of MySQL error 2014 Cannot execute queries while other unbuffered queries are active
There are more than two querys with one statement like mentioned here: PDO Cannot execute queries while other unbuffered queries are active
A bug in mysql-driver as mentioned here: What is causing PDO error Cannot execute queries while other unbuffered queries are active?
In my case all above did not help and it took some time till i solved the problem. this was my code (pseudo-code):
$stmt->startTransaction();
$stmt = db::getInstance()->prepare("CALL phones(:phone)");
$stmt->prepare('SELECT * FROM database');
$stmt->execute();
$aData = $stmt->fetchAll();
$stmt->closeCursor();
$stmt->query("USE sometable;");
After I changed it to:
$stmt->startTransaction();
$stmt = db::getInstance()->prepare("CALL phones(:phone)");
$stmt->prepare('SELECT * FROM database');
$stmt->execute();
$aData = $stmt->fetchAll();
$stmt->closeCursor();
$stmt->exec("USE sometable;");
It worked for my. What is the difference between query and exec?
PDO::exec() - "Execute an SQL statement and return the number of affected rows"
PDO::query() - "Executes an SQL statement, returning a result set as a PDOStatement object"
Why in this case PDO::query() does not work? The cursor IS closed, when called.
While it could conceivably be true that you've encountered the mysql driver bug here, we can't be sure of that because you've not given us that information (what version of PHP are you using? Does it use mysqlnd => check with php -i | grep mysqlnd? What does the rest of your code look like?).
There are many other possible explanations for your problem. I suspect the issue is actually your failing to close all the cursors, and/or fetch all the results, because $stmt is being reused heavily:
Quoted directly from the PDO::query manual page:
If you do not fetch all of the data in a result set before issuing your next call to PDO::query(), your call may fail. Call PDOStatement::closeCursor() to release the database resources associated with the PDOStatement object before issuing your next call to PDO::query().
You call closeCursor on $stmt, that's true, but you've not closed all cursors that have been created by you:
//<-- what is $stmt here?
$stmt->startTransaction();
//no matter, you've reassigned it a PDOStatement instance
$stmt = db::getInstance()->prepare("CALL phones(:phone)");
//Huh? You're preparing yet another query on an instance of PDOStatement?
$stmt->prepare('SELECT * FROM database');
//you're executing this one, though
$stmt->execute();
//and fetching all data
$aData = $stmt->fetchAll();
//and closing this last statement
$stmt->closeCursor();
But what about the first statement you assigned to $stmt (the stored procedure call)? That cursor isn't closed anywhere
Now for the major difference between PDO::query and PDO::exec. Again, quoting the manual:
PDO::exec() does not return results from a SELECT statement.
Whereas:
PDO::query() executes an SQL statement in a single function call, returning the result set (if any) returned by the statement as a PDOStatement object.
I came across this problem too. It is likely to be a bug. If we take the following code, then you will see how it fails with the message 'General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll().'
$pdo = new \PDO("mysql:host=localhost", "root", "");
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query("USE test");
If you change $pdo->query("USE test"); to $pdo->exec("USE test"); it will work. If you change $pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false); to $pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true); it will also work. I haven't been able to find a proper solution yet though.
I solve the issue with steps:
After from performed:
$stmt = db::getInstance()->prepare("CALL phones(:phone)");
I close the:
$stmt->startTransaction();
And after that, I open again the transaction to use the query below:
$stmt->prepare('SELECT * FROM database');
My solve it is: One statement to call the procedure "CALL phones(:phone)" and another to execute the query wtih "SELECT * FROM database".
That is it.
Be careful, This can also happen if you are trying to fetch a non SELECT query (Eg - UPDATE/INSERT/ALTER/CREATE)

mysql not updating in a while statement

I am trying to extract two fields from tables accesscode and student the update the table borrowers with the data that i have extracted from the previous tables.
$q=$db->query("SELECT regnum, accesscode FROM student,student_accesscode WHERE student.id=student_accesscode.studentid");
while($qd=$q->fetch(PDO::FETCH_ASSOC))
{
$access=$qd['accesscode'];
$regnum=$qd['regnum'];
$q2=$db->exec("UPDATE borrowers SET cardnumber='$access' WHERE cardnumber='$regnum'");
if($q2)
{
echo $access.' '. $regnum.'<br/>';
}
else
{
echo'erro....<br/>';
}
}
?>
Appending $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); before $db->query() probably gives you an Exception...
Prior to the $db->setAttribute, you will get this:
PDO::prepare(): 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.
So, instead of fetch(), use fetchAll() with foreach loop, it will make you less insane.
Ref. from php.net
For a statement that you need to issue multiple times, prepare a PDOStatement
object with PDO::prepare() and issue the statement with PDOStatement::execute().
From the PHP exec page at http://www.php.net/manual/en/pdo.exec.php
I don't know if this is the problem, I always use prepare and execute. It could just be for performance reasons. Something to try anyway.

PDO and executing code

Just a quick question around executing PDO statements.
Below is my query
$setDate = "INSERT INTO wl_datecheck (inputdate) VALUES (UNIX_TIMESTAMP(STR_TO_DATE($reportDate, '%Y%m%d')))";
Now, what I am doing is setting the query & connection as the variable $data as follows:
$data = $conn->query($setDate);
What I need to know, is does that ^^ alone execute or do I need to include
$data->execute();
The reason for asking is that I seem to be getting duplicate content from the INSERT statement & I'm not sure why
You are indeed doing it twice, you either use Query or Execute.
From the Docs:
PDO::query() executes an SQL statement in a single function call,
returning the result set (if any) returned by the statement as a
PDOStatement object.
For a query that you need to issue multiple times, you will realize
better performance if you prepare a PDOStatement object using
PDO::prepare() and issue the statement with multiple calls to
PDOStatement::execute().
http://us2.php.net/pdo.query
You can also simply check the result of the Insert statement by using rowCount()
$data = $conn->query($setDate);
if($data->rowCount() >= 1){
//echo "Inserted";
}else{
//echo "An error occurred while inserting";
//$arr = $data->errorInfo();
//print_r($arr);
}
And no need to call execute()

Getting the results of a variable length prepared statement in MySQLi

I writing an accounting website which has quite a few MySQL statements in it. To prevent SQL injection I use prepared statements for any data which is put in by the user.
In order to prevent having to write the steps of preparing and binding statements I have the following function:
function executeSql($mysqli,$query_string,$params=null,$paramtypes=null){
$nr_params=strlen($paramtypes);
$query_type = substr($query_string,0,3);
$stmt = $mysqli->prepare($query_string);
$queryParams[] = $paramtypes;
$counter=1;
if($nr_params>1){
while($counter<=$nr_params){
$queryParams[$counter]=&$params[$counter-1];
$counter++;
}
} else {
$queryParams[1]=&$params;
}
// Actual binding of the statement. Taking into account a variable numbers of '?' in the query string.
call_user_func_array(array($stmt,'bind_param'),$queryParams);
// Execution of the statement
$stmt->execute();
// Part where i'd like to have a substitute for:
$result = $stmt->get_result();
return $result;
}
In the last part I'd like to return the result because then using the result I can treat each row. The problem is that the mysqlnd driver is not installed on the production server so the function $stmt->get_result() cannot be used. I tried to bind the result into variables but then again, every query returns a different number of columns.
Anyone has an idea how to tackle this?
So in summary (in response to the comments):
How can I retrieve a results object of an executed MySQLi statement while I cannot use $stmt->get_result();
Kind regards,
EJG
PS I know the code is not flawless, e.g. if strings are used as variables to bind to the statement but that is easily fixed.
UPDATE:
I came across the function $stmt->result_metadata(); Although supposedly the function name suggests only the meta data the php documentation states that:
"If a statement passed to mysqli_prepare() is one that produces a result set, mysqli_stmt_result_metadata() returns the result object"...

Categories