Nesting MYSQLi functions - php

This question refers to nesting mysqli functions. I'm not sure the term "nesting" is the correct one here so i'll explain.
Look at this code for example:
$query = 'SELECT id FROM users WHERE id="' . $_POST['uid'] . '"';
$result = $mysqli->query($query);
$user_id = mysqli_fetch_row($result);
The code above can be turned into a shorthand version as follows:
$user_id = mysqli_fetch_row($mysqli->query('SELECT id FROM users WHERE id="' . $_POST['uid'] . '"'));
I know this works because I've tried it. I see that PHP is taking care of the code from "inside-out", is it basically a recursive method to write this code or am I completely off with the terms?
My question is this, does this work for all MYSQL commands or PHP functions? are there exceptions for this functionality? what are the drawbacks to using such form? (besides it being less readable by a programmer)
EDIT: I know the query is not a prepared statement.

In order to call a function or class method, PHP has to evaluate all of its supplied parameters.
In this case, given the statement:
$user_id = mysqli_fetch_row($mysqli->query("SELECT id FROM users WHERE id = $_POST[uid]"));
in order to call mysqli_fetch_row PHP will first evaluate its argument, that is $mysqli->query("SELECT id FROM users WHERE id = $_POST[uid]")
in order to call $mysqli->query PHP will first evaluate its argument, that is "SELECT id FROM users WHERE id = $_POST[uid]"
now PHP will pass the query string to $mysqli->query and return the result set (or error maybe)
that return value will be passed to mysqli_fetch_row
I would say that this is not PHP specific, but a quite general behaviour in parameter evaluation.
However it has one major drawback: you forego any kind of error checking which, especially when dealing with databases, is very important.

Related

shorthand PDO query

Currently to perform a query with PDO, I use the following lines of code:
$sql = "SELECT * FROM myTable WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':id', $id);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
And after some research, I found a shorter way of executing the same command:
$stmt_test = $conn->prepare("SELECT * FROM status WHERE status_id = ?");
$stmt_test->execute([$id])->fetchAll(PDO::FETCH_ASSOC);
$result = $stmt_test->fetchAll(PDO::FETCH_ASSOC);
From there I thought I could possibly make it even shorter with the following code:
$stmt_test = $conn->prepare("SELECT * FROM status WHERE status_id = ?");
$result = $stmt_test->execute([$id])->fetchAll(PDO::FETCH_ASSOC);
But I get the following error:
Fatal error: Call to a member function fetchAll() on a non-object in
/home/.../index.php on line 20
QUESTION: Why am I getting this error? From my understanding, $stmt_test->execute([$id]) should be executing first, then the result of that would execute the ->fetchAll(PDO::FETCH_ASSOC) and from there return the array to $result, but since the error is happening, something must be flawed in my logic. What am I doing wrong? Also, does anyone know a better shorthand method to perform the previous query?
So you've got an answer for the question "Why I am getting this error", but didn't get one for the "shorthand PDO query".
For this we will need a bit of a thing called "programming".
One interesting thing about programming is that we aren't limited to the existing tools, like with other professions. With programming we can always create a tool of our own, and then start using it instead of a whole set of old tools.
And Object Oriented Programming is especially good at it, as we can take an existing object and just add some functionality, leaving the rest as is.
For example, imagine we want a shorthand way to run a prepared query in PDO. All we need is to extend the PDO object with a new shorthand method. The hardest part is to give the new method a name.
The rest is simple: you need only few lines of code
class MyPDO extends PDO
{
public function run($sql, $bind = NULL)
{
$stmt = $this->prepare($sql);
$stmt->execute($bind);
return $stmt;
}
}
This is all the code you need. You may store it in the same file where you store your database credentials. Note that this addition won't affect your existing code in any way - it remains exactly the same and you may continue using all the existing PDO functionality as usual.
Now you have to change only 2 letters in PDO constructor, calling it as
$conn = new MyPDO(...the rest is exactly the same...);
And immediately you may start using your shiny new tool:
$sql = "SELECT * FROM myTable WHERE id = :id";
$result = $conn->run($sql, ['id' => $id])->fetchAll(PDO::FETCH_ASSOC);
Or, giving it a bit of optimization,
$result = $conn->run("SELECT * FROM myTable WHERE id = ?", [$id])->fetchAll();
as you can always set default fetch mode once for all, and for just a single variable there is no use for the named placeholder. Which makes this code a real shorthand compared to the accepted answer,
$stmt_test = $conn->prepare("SELECT * FROM status WHERE status_id = ?");
$stmt_test->execute([$id]);
$result = $stmt_test->fetchAll(PDO::FETCH_ASSOC);
and even to the best answer you've got so far,
$result = $conn->prepare("SELECT * FROM status WHERE status_id = ?");
$result->execute([$id]);
not to mention that the latter is not always usable, as it fits for getting an array only. While with a real shorthand any result format is possible:
$result = $conn->run($sql, [$id])->fetchAll(); // array
$result = $conn->run($sql, [$id])->fetch(); // single row
$result = $conn->run($sql, [$id])->fetchColumn(); // single value
$result = $conn->run($sql, [$id])->fetchAll(PDO::FETCH_*); // dozens of different formats
$stmt_test->execute([$id]) returns a boolean value. That mean that
$result = $stmt_test->execute([$id])->fetchAll(PDO::FETCH_ASSOC);
isn't valid. Instead you should do
$stmt_test->execute([$id]);
$result = $stmt_test->fetchAll(PDO::FETCH_ASSOC);
The error you're getting comes form the way PDO was designed. PDOStatement::execute() doesn't return the statement, but a boolean indicating success. The shortcut you want therefore isn't possible.
See function definition in http://php.net/manual/en/pdostatement.execute.php
Additionally let me add that forEach() often (not always) is a code smell and takes relatively much memory as it has to store all rows as PHP values.
I believe PDO's execute() method returns either true or false. As the error already tells you: fetchAll() expects an object. Using three lines of code would be the shortest way.
Another option is to use an ORM like propel, it works really smooth and will save you alot of time.

Strange Error in mysql_query() function in PHP (And clause in Query)

When I add AND operator in mysql_query() function, it stops working and anything after that stops working!
For Example:
When i wrote this:
$query1 = mysql_query("SELECT * FROM chat1 where friendname = '$_POST[fname]' ");
$row= mysql_fetch_array($query1) or die(mysql_error());
echo "$row[message]";
The above query runs successfully !
But when i do this :
$query1 = mysql_query("SELECT * FROM chat1 where friendname = '$_POST[fname]' AND username = '$_POST[uname]' ");
$row= mysql_fetch_array($query1) or die(mysql_error());
echo "$row[message]";
I get Null output!
I think the "AND" operator is not working!!!
please help me with this!!
Have a look at my complete code and Database Snapshot!
Click here
If it is returning NULL then probably the record doesn't exists. Try to output this query on the screen and post the raw query here.
Maybe your search needs a LIKE instead of a =
Likely, the row(s) you are looking for do not exist.
The AND is a boolean operator that requires that both expressions have to evaluate to true. In the context of your query, that means for a row to be returned, both of the conditions have to be true on that single row.
I suspect that you may want an OR those two conditions. Did you want to return only rows that meet both criteria, or did you want any rows that have fname with a certain value, along with any rows that have uname of a specific value? If the first query is returning rows, then replacing AND with OR should return you some rows.
For debugging this type of problem, generate the SQL text into a variable, and then echo or var_dump the SQL text, before you send it to the database.
e.g.
$sql = "SELECT * FROM chat1 where friendname = '"
. mysql_real_escape_string($_POST['fname'])
."' ";
echo "SQL=" . $sql ; # for debugging
Take the text of SQL statement that's emitted to another client, to test the SQL statement, to figure out if the SQL statement is actually returning the resultset you expect it to return.
(In your code, reference the $sql in the function that prepares/executes the SQL statement.)
Follow this pattern for all dynamically generated SQL text: generate the SQL text into a variable. For debugging, echo or var_dump or otherwise emit or log the contents of the variable. Take the SQL text to another client and test it.
Dumping code that isn't working on to StackOverflow is not the most efficient way to debug your program. Narrow down where the problem is.
How to debug small programs http://ericlippert.com/2014/03/05/how-to-debug-small-programs/
NOTES
You probably want to verify that $_POST['fname']) contains a value.
It's valid (SQL-wise) for a SELECT statement to return zero rows, if there are no rows that satisfy the predicates.
Potentially unsafe values must be properly escaped if you include them in the text of a SQL statement. (A better pattern is to use prepared statements with bind placeholders, available in the (supported) mysqli and PDO interfaces.
Also, use single quotes around fname.... e.g.
$_POST['fname']
^ ^

Assign MySQL database value to PHP variable

I have a MySQL Database Table containing products and prices.
Though an html form I got the product name in a certain php file.
For the operation in this file I want to do I also need the corresponding price.
To me, the following looks clear enough to do it:
$price = mysql_query("SELECT price FROM products WHERE product = '$product'");
However, its echo returns:
Resource id #5
instead a value like like:
59.95
There seem to be other options like
mysqli_fetch_assoc
mysqli_fetch_array
But I can't get them to output anything meaningful and I don't know which one to use.
Thanks in advance.
You will need to fetch data from your database
$price = mysql_query("SELECT price FROM products WHERE product = '$product'");
$result = mysql_fetch_array($price);
Now you can print it with
echo $result['price'];
As side note I would advise you to switch to either PDO or mysqli since mysql_* api are deprecated and soon will be no longer mantained
If you read the manual at PHP.net (link), it will show you exactly what to do.
In short, you perform the query using mysql_query (as you did), which returns a Result-Resource. To actually get the results, you need to perform either mysql_fetch_array, mysql_fetch_assoc or mysql_fetch_object on the result resource. Like so:
$res = mysql_query("SELECT something FROM somewhere"); // perform the query on the server
$result = mysql_fetch_array($res); // retrieve the result from the server and put it into the variable $result
echo $result['something']; // will print out the result you retrieved
Please be aware though that you should not use the mysql extension anymore; it has been officially deprecated. Instead you should use either PDO or MySQLi.
So a better way to perform the same process, but using for example the MySQLi extension would be:
$db = new mysqli($host, $username, $password, $database_name); // connect to the DB
$query = $db->prepare("SELECT price FROM items WHERE itemId=?"); // prepate a query
$query->bind_param('i', $productId); // binding parameters via a safer way than via direct insertion into the query. 'i' tells mysql that it should expect an integer.
$query->execute(); // actually perform the query
$result = $query->get_result(); // retrieve the result so it can be used inside PHP
$r = $result->fetch_array(MYSQLI_ASSOC); // bind the data from the first result row to $r
echo $r['price']; // will return the price
The reason this is better is because it uses Prepared Statements. This is a safer way because it makes SQL injection attacks impossible. Imagine someone being a malicious user and providing $itemId = "0; DROP TABLE items;". Using your original approach, this would cause your entire table to be deleted! Using the prepared queries in MySQLi, it will return an error stating that $itemId is not an integer and as such will not destroy your script.

MySQL Injection by LIKE operator [duplicate]

This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 9 years ago.
I've below code in one of my php files to fetch data from DB:
$products = $this->db->get_rows('SELECT * from products WHERE shop_id='.$_SESSION['shop_id'].'AND tags,title,text LIKE \'%'.$_POST['search'].'%\'');
Is it problematic? I mean LIKE operator can be injected?
Edited
please provide examples of injecting in this way
Any operator can be injected without binding.
$_POST['search'] = "1%'; DROP TABLE myTable LIKE '%";
Would make
.... AND tags,title,text LIKE '%1%'; DROP TABLE myTable LIKE '%%'
Read on how to bind parameters.
Of course this can be injected, you need to sanitize your input. Right now you are taking raw post data and inserting it into your SQL statement.
You should run your POST data through some sort of data sanitization, something like mysql_real_escape_string or the like
Or at least prepared statements. let server side code do the work for you.
Never, ever, use database queries like that, don't construct a string with variables and use it for database activities.
Construct a string that will later on be prepared and executed, by inserting the variables into the string, making them not act like "commands" but as "values".
You can do it like this:
$query = "SELECT * from products WHERE shop_id = :shopId;"; // An example, you can finish the rest on your own.
Now, you can prepare the statement (I recommend using PDO for this).
$statement = $db->prepare($query); // Prepare the query.
Now you can execute variables into the prepared query:
$statement->execute(array(
':shopId' => $_SESSION['shop_id']
));
If you're inserting or updating, then you would have wanted to do:
$success = $statement->execute(array(
':shopId' => $_SESSION['shop_id']
));
which stores a boolean in $success, or you can fetch the values from a result if you're SELECTing:
$statement->execute(array(
':shopId' => $_SESSION['shop_id']
));
$result = $statement->fetch(PDO::FETCH_ASSOC);
if($result )
{
// You can access $result['userId'] or other columns;
}
Note that you should actually make that be a function, and pass $shopId into the function, but not the session itself, and check if the session actually exists.
I recommend googling on how to use PDO, or take a look on one of my examples: How to write update query using some {$variable} with example
This is really bad. Pulling vars into an SQL statement without cleaning or checking them is a good way to get pwnd. There are several things that people can inject into code. Another injection method to watch out for, 1=1 always returns true.
$products = $this->db->get_rows('SELECT * from products WHERE shop_id='.$_SESSION['shop_id'].'AND tags,title,text LIKE \'%'.$_POST['search'].'%\'');
//This example expects no result from the table initially so we would blind attack the DB to pull the admin record.
$_POST['search'] = "-1\'; union all select * from users limit 1;";
Someone call pull up the top account in the database (like the admin).
$user_id = $this->db->get_rows('SELECT * from users WHERE email="'.$_POST['email'].'" and password="'.$_POST['password'].'"');
//This always returns true so now I'm the admin again
$_POST['password'] = "x\' or 1=1 limit 1";
You also want to be careful what you print on screen.
$user_id = $this->db->get_rows('SELECT * from users WHERE email="'.$_POST['email'].'" and password="'.$_POST['password'].'"');
A message that you echo that says "No user name exists for $_POST['email']" could be replaced with something else.
$_POST['email']=";
$fp = fopen('index.php', 'w');
fwrite($fp, \"header('Location: http://badwebsite.com;');\";
fclose($fp);";
index.php could now people to a different website entirely where an infected page exists or an infected page on the site.
If you're checking IDs do something like:
if(preg_match('!^[0-9]$!',$_POST['id'])){
$id = $_POST['id'];
} else {
//flush
}
or count for the number of possible records... if you're only expecting one and you get all of the records in the DB then it's an injection attempt.
if(is_numeric($_POST['id'])){
$id = $_POST['id'];
$count = mysql_result(mysql_query("select count(*) from users where id='$id''),0);
}

concatenate mysql select query with php variable?

I am trying to concatenate a MySQL SELECT query with PHP variable but got an error.
My PHP statement which gives an error is:
$result=mysql_query("SELECT user_id,username,add FROM users WHERE username =".$user."AND password=".$add);
and error as:
( ! ) Notice: Undefined variable: info in C:\wamp\www\pollBook\poll\login.php on line 18
Call Stack
I don't understand where I missed the code.
When I write query without WHERE clause it works fine.
The reason why your code isn't working
You are attempting to use a variable, $info, that has not been defined. When you attempt to use an undefined variable, you're effectively concatenating nothing into a string, however because PHP is loosely typed, it declares the variable the second you reference it. That is why you're seeing a notice and not a fatal error. You should go through your code, and ensure that $info gets a value assigned to it, and that it is not overwritten at some point by another function. However, more importantly, read below.
Stop what you are doing
This is vulnerable to a type of attack called an SQL Injection. I'm not going to tell you how to concatenate SQL strings. It's terrible practice.
You should NOT be using mysql functions in PHP. They are deprecated. Instead use the PHP PDO Object, with prepared statements. Here's a rather good tutorial.
Example
After you've read this tutorial, you'll be able to make a PDO Object, so I'll leave that bit for you.
The next stage is to add your query, using the prepare method:
$PDO->prepare("SELECT * FROM tbl WHERE `id` = :id");
// Loads up the SQL statement. Notice the :id bit.
$actualID = "this is an ID";
$PDO->bindParam(':id', $actualID);
// Bind the value to the parameter in the SQL String.
$PDO->execute();
// This will run the SQL Query for you.
You are missing space before "AND " and you should use single quotes as suggested in other answers.
$result=mysql_query("SELECT user_id,username,add FROM users WHERE *username =".$user."AND* password=".$add);
Updated:
echo $sql = "SELECT user_id,username,add FROM users WHERE username ='".$user."' AND password='".$add."'";
$result=mysql_query($sql);
although there is no $info variable used in the query but you need to correct the query:
$result=mysql_query("SELECT user_id,username,add FROM users WHERE username ='" . $user . "' AND password='" . $add . "'");
First from the error its looks like one of your variables is not defined. .. check it. Second surround your parameters with ' for safer syntax.
This is because the variables you are using might not have defined above
So first initialize your variables or if its coming from somewhere else(POST or GET) then check with isset method
So complete code would be
$user = 123; // or $user = isset($user)?$user:123;
$add = 123456; // or $add = isset($add)?$add:123456;
And then run your query
$result=mysql_query("SELECT user_id,username,add FROM users WHERE username =".$user."AND password=".$add);

Categories