I have some working php/mysql which I am now migrating to stored procedures.
As soon as any stored procedure is called, subsequent CALLs and SELECTs fail with "Commands out of sync; you can't run this command now".
Existing stored procedures which are not SELECTs work fine.
function db_all ($query)
{
log_sql_read ($query);
$result = mysql_query ($query, db_connection ());
if (!$result)
{
log_sql_error ($query);
return Array ();
}
$rows = Array ();
while ($row = mysql_fetch_assoc ($result))
array_push ($rows, $row);
mysql_free_result ($result);
return $rows;
}
db_all ("SELECT 1 as `test`");
db_all ("SELECT 2 as `test`");
db_all ("CALL `$db`.`select_info`($id);"); // RETURNS CORRECT DATA
db_all ("CALL `$db`.`select_info`($id);"); // ERROR HERE
db_all ("SELECT 5 as `test`"); // ERROR HERE
This error is explained elsewhere as a result of not calling mysql_free_result, but I do call this. So what's wrong?
I'm seeing some solutions which refer to mysqli. I need a non-mysqli solution for now.
The problem is when executed, a stored procedure will give you two resultsets back. One with the actual resultset and another with the status of the executing. And you need to consume both before making another call that returns result set.
In mysqli_* you can utilize mysqli_multi_query, mysqli_store_result, mysqli_next_result to achieve that. You can see how to do that in mysqlihere.
In your case with mysql_* you can just close the connection after you done fetching results.
function db_all ($query)
{
$link = db_connection(); //Open connection
log_sql_read ($query);
$result = mysql_query ($query, $link);
if (!$result)
{
log_sql_error ($query);
return Array ();
}
$rows = Array ();
while ($row = mysql_fetch_assoc ($result))
array_push ($rows, $row);
mysql_free_result ($result);
mysql_close($link); //Close the connection
return $rows;
}
Related
Alright, so I believe that there is a better way that I can fetch an array from the database, here's the code right now that I have.
$id = 1;
$userquery = mysql_query("SELECT * FROM login WHERE id='$id'");
while($row = mysql_fetch_array($userquery, MYSQL_ASSOC)) {
$username = $row['username'];
$password = $row['password'];
$email = $row['email'];
}
So If I am not wrong, you want a better way to get all the returned rows from mysql in a single statement, instead of using the while loop.
If thats the case, then I must say mysql_ drivers do not provide any such functionality, which means that you have to manually loop through them using foreach or while.
BUT, since mysql_ is already depricated, you are in luck! you can actually switch to a much better and newer mysqli_ or the PDO drivers, both of which DO actually have functions to get all the returned rows.
For mysqli_: mysqli_result::fetch_all
For PDO : PDOStatement::fetchAll
Eg.
mysqli_fetch_all($result,MYSQLI_ASSOC);
// The second argument defines what type of array should be produced
// by the function. `MYSQLI_ASSOC`,`MYSQLI_NUM`,`MYSQLI_BOTH`.
Like the comments already told you: PHP's mysql driver is deprecated. And you should use prepared statements and parameters.
for example in PDO your code would look something like this:
//connection string:
$pdo= new PDO('mysql:host=localhost;dbname=my_db', 'my_user', 'my_password');
//don't emulate prepares, we want "real" ones:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
//use exception-mode if you want to use exception-handling:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$id = 1;
//it's always better to strictly use backticks for db-names (db, tables, fields):
$sql = "SELECT * FROM `login` WHERE `id` = :id";
try
{
//create your prepared statement:
$stmt = $pdo->prepare($sql);
//bind a parameter and explicitly use a parameter of the type integer (in this case):
$stmt->bindParam(":id", $id, PDO::PARAM_INT);
//execute the query
$stmt->execute();
}
catch(PDOException $e)
{
exit("PDO Exception caught: " . $e->getMessage());
}
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
$username = $row['username'];
$password = $row['password'];
$email = $row['email'];
}
here you go: your PHP-MySQL routine is save against SQL-injections now and no longer uses deprecated PHP-functions! it's kinda state of the art ;)
I have a function which is printed below. THis is meant to dynamicly draw user data from the database using PDO (that situation is clear and all works well). But, instead of returning the result (i e. an email for you("email)), it returns the number 1.
Here's my setup:
public function you($row) {
if(isset($_COOKIE["SK"])) {
$pw = $this->baseXencode($_SESSION["password"]);
$usr = $this->baseXencode($_SESSION["username"]);
$q = "SELECT $row FROM SN_users WHERE username=':USR' AND password=':PW'";
$this->netCore->q($q);
$this->netCore->bind(":PW", $pw);
$this->netCore->bind(":USR", $usr);
$result = $this->netCore->single();
$result = $result[$row];
return $result;
} else {
$q = "SELECT $row FROM SN_users WHERE username='Anonymous' AND password='Anonymous'";
$this->netCore->q($q);
$result = $this->netCore->single();
$result = $result[$row];
return $result;
}
}
}
$this->netCore->q() = PDO query
$this->netCore->single() PDO fetch(PDO::FETCH_ASSOC)
As for ->bind, self-explanatory.
Please help, will be very much appreciated.^^
When using parametrized queries, you don't put the parameters in quotes. That prevents the parameters from being substituted, since it's treated as a literal string. So it should be:
$q = "SELECT $row FROM SN_users WHERE username=:USR AND password=:PW";
I'm surprised it's returning 1. I'd expect your code to cause an error, because single() should be returning false, and false[$row] is not valid.
You should also check that a row was returned; if the username and password are not valid, you won't get an result. So it should be:
$result = $this->netCore->single();
if ($result) {
return $result[$row];
} else {
return false;
}
And the caller of you() needs to check the value as well.
I'm trying to optimize a platform I created, and removing code that maybe aren't necessary. and since I started read about PHP classes and decided to rewrite the entire function page.
I'm having two functions for my login page.
valid_credientials($email,$password){} and
function fetch_user_id($email){ }
the fetch_user_id returns the id from logged in user, so my session would change from session email to session uid.
Now Am i trying to combine this two function, but i get only error messages so i was thinking, that maybe i need this two function ?
This is what i have for now.
public function valid_credientials($email,$password){
if(!empty($email) && !empty($password)){
$query = $this->db->prepare("SELECT id FROM user WHERE email=? AND password=?" );
$query-> bindParam(1, $email);
$query-> bindParam(2, $password);
$query-> execute();
if($query->rowCount() == 1){
$row = $query->fetch(PDO::FETCH_ASSOC);
return $row[id];
echo "user verified Access granted";
}
}else{
echo 'Wrong Username of password';}
}
}
function fetch_user_id($email){
global $db;
$query = $db->query("SELECT id FROM user WHERE email='{$_SESSION['email']}'");
$row = $query->fetch(PDO::FETCH_ASSOC);
return $row[id];
}
As you see am i trying to use the $row = query inside the valid_credential function.
but it only returns error - undefined constant id - assumed 'id' in.
thanks!
Hey Guys I'm running this little function here
function getBeaches() {
$request=Slim::getInstance()->request();
$args=filter_var_array(func_get_args(),FILTER_SANITIZE_STRING);
$sql="SELECT * FROM beaches WHERE state=:state AND city=:city";
// var_export($args); die();
// array ( 0 => 'wa', 1 => 'seattle', )
try {
$db = getConnection();
$stmt = $db->prepare($sql);
$stmt->bindValue('state', $args[0], PDO::PARAM_STR); //should bind wa
$stmt->bindValue('city', $args[1], PDO::PARAM_STR); //should bind seattle
$stmt->execute();
$stmt = $db->query($sql);
$beaches = $stmt->fetchObject();
$db = null;
echo '{"map": ' . stripslashes(json_encode($beaches)) . '}';
} catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
/* {"error":{"text":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 ':state AND city=:city' at line 1}}
*/
}
And am getting the error I commented at the bottom, trying to run this like so
mysql$ SELECT * FROM beaches WHERE state='wa' AND city='seattle';
May be this rings some bells?
You need the semicolons before your param names: (Not 100% true, see edit)
$stmt->bindValue(':state', $args[0], PDO::PARAM_STR); //should bind wa
$stmt->bindValue(':city', $args[1], PDO::PARAM_STR); //should bind seattle
From the PHP docs on PDOStatement::bindValue():
Parameter identifier. For a prepared statement using named placeholders, this will be a parameter name of the form :name. For a prepared statement using question mark placeholders, this will be the 1-indexed position of the parameter.
EDIT
As #jeroen has pointed out the problem (the same one in your pastebin) that you overwrite the $stmt variable before you get the data from it. In you code the problem is around the 17th line:
$stmt->execute(); // $stmt now has query results (from the query with parameters bounded)
$stmt = $db->query($sql); // You redo the query. Now $stmt has no query results and no parameters are bound
$beaches = $stmt->fetchObject(); // Statement assumes you want to execute query and does so but not parameters are bound
You can remedy this by changing the above lines to:
$stmt->execute();
$beaches = $stmt->fetchObject();
Not sure if it helps, but I always used bindParam over bindValue. If you chose to do so, modify your binders as such:
$stmt->bindParam(':state', $args[0], PDO::PARAM_STR);
$stmt->bindParam(':city', $args[1], PDO::PARAM_STR);
Other than that, everything you're doing looks fine to me.
How can I return a value of 'no data found' if my query returns no results???
This is my code:
function getTerms($letter) {
$this->db->select('term, definition');
$this->db->from('glossary');
$this->db->where(array('letter' => $letter));
$query = $this->db->get();
foreach ($query->result() as $row) {
$data[] = array(
'term' => $row->term,
'definition' => $row->definition
);
}
return $data;
}
It currently returns the $data variable even if the query returns no results which is giving me php errors. How can I check that there are results before returning the $data array.
Simply check that the query returns at least one row:
if ($query->num_rows() > 0) {
// query returned results
} else {
// query returned no results
}
Read more in the docs
It currently returns the $data variable even if the query returns no results which is giving me php errors.
It's a good habit to initialize the array that you intend to build:
$data = array();
// Loop through possible results, adding to $data
If there are no results you'll get an empty array returned, then check that in your controller.
This way, at least the variable is defined and you won't get notices.
What about to give initial empty array value for $data
Just put
$data = array();
before foreach
<?php
return is_array($data) ? $data : array();
}