I have a query I would like to use that I would like to be reused for other select queries.
Is it possible to have a select query like this:
SELECT * FROM ? WHERE id = ?;
And then bind the values like this:
$stmt->bindValue(1, $table, PDO::PARAM_STR);
$stmt->bindValue(2, $id, PDO::PARAM_INT);
The problem is when I do this I get this $database->errorInfo() from a PDOException
HY000 1 near "?" syntax error.
I have tried taking out the table placeholder and it does work. Is it possible to do it my way or do I need to have separate functions?
Short answer: NO.
Long answer:
Refer to the PDO::prepare manual. There is a statement: This must be a valid SQL statement for the target database server. This means that your DB backend have to support prepared statement syntax that you use.
As far as I know, neither mysql, nor any other DB does not allow binding variables to occur in FROM clause. The reason for that lays deep in the concept of prepared statement. Prepared statement is being prepared inside the DB when you are calling prepare. This means that DB planner builds a plan for the query, so it can be executed multiple times with different parameters without building it again and again. To build a plan, planner needs to know affected tables, functions called, opportunities to use different fetch and join strategies (index scans/nested loops/etc.) and so on.
So, you cant 'bind' table name into prepared statement at the moment you want it to run, because DB needs table names at the moment when you prepare the statement. That's why you receive that message: DB requires all table names to be present in the preparing query.
Related
I am trying to understand when I should use prepared statements in php/mysqli. Should every php/mysqli query use prepared statements or just queries and instances where user input is involved ... such as an html form that asks a user to enter data to search within a database?
I am migrating my old php5/mysql code to php7/mysqli. I have many php files that query a mysql db. I would like clarification if I need to use prepared statements for every php file that connects to a mysql db ... for example php files that are referenced via "php require" and include simple sql select statements to render images and links to a html page?
<?php
//establish connection
$con = new mysqli('localhost','uid','pw','db');
//check connection
if ($con->connect_error) {
die("Connection failed: " . $con->connect_error);
}
//search variable that stores user input
$search = "%{$_POST['search']}%";
//prepare, bind and fetch
$stmt = $con->prepare("SELECT image, caption FROM `tblimages`
WHERE catid = 3 AND caption LIKE ? order by caption ASC");
$stmt->bind_param("s", $search);
$stmt->execute();
$stmt->bind_result($image,$caption);
while ($stmt->fetch()) {
echo "{$image} <br> {$caption} <br>";
}
$stmt->close();
//close database connection
mysqli_close($con);
?>
The code above works and is the first I've ever used prepared statements. It takes user input from a form (blank box to enter a search term - POST) and searches a db ... then renders results to an html page. This seems like a logical use of prepared statements. However ... I have other php files where users select data from a drop down box in a form to render a result (the user does not enter data into a search box like above). Do I use prepared statements for that instance as well? Plus do I use prepared statements for php files that are referenced via "php require" and include simple sql select statements to render images and links to a html page? I've yet to find clarification of the specific instances to use prepared statements to prevent sql injections. Any clarification or references welcome.
Short answer: Always use prepared statements.
Long answer:
Prepared statements separate your data from SQL commands. They are provided by PDO or by MySQLi. Their biggest advantage is that it is impossible to have SQL injection if your data is treated as data. Another advantage is that you can execute the same query over and over again with different set of data, which might be better for your performance and often keeps your code cleaner.
However, there are times when you would like to have some kind of dynamic query based on user's selection or actions. As you probably know table and column names are not data, but part of SQL query, therefore you can't keep them separated. The alternative to prepared statements then is to have a white list of possible values and only allow user input validated against the white list.
You might ask what are query, real_query, multi_query and PDO::exec good for?
As the PHP Manual shows they are good at times when you only need to execute constant query without any variables or when you have a query which can't be prepared. e.g.
$mysqli->query('SELECT Name FROM City LIMIT 10');
$pdo->exec('DELETE FROM fruit');
$mysqli->multi_query('DELETE FROM fruit; DELETE FROM pets;');
What if you know the type and values of your data? Should you also prepare/bind?
Yes! Get into a habit of binding all data going with SQL query. There is no reason to make exceptions. It is much more difficult to trace those exceptions in your code and always be sure you do not overwrite the "safe" value with some unknown input.
If you are still not sure how to use prepared statements or you think that they are too complicated (they are not) you can take a look at an amazing PHP tutorial at https://phpdelusions.net
This is how MySQLi prepared statements work in PHP:
Prepare an SQL query with empty values as placeholders (with a question mark for each value).
Bind variables to the placeholders by stating each variable, along with its type.
Execute query.
The four variable types allowed:
i - Integer
d - Double
s - String
b - Blob
A prepared statement, as its name implies, is a way of preparing the MySQL call, without storing the variables. You tell it that variables will go there eventually — just not yet. The best way to demonstrate it is by example.
$stmt = $mysqli->prepare("SELECT * FROM myTable WHERE name = ? AND age = ?");
$stmt->bind_param("si", $_POST['name'], $_POST['age']);
$stmt->execute();
//fetching result would go here, but will be covered later
$stmt->close();
If you've never seen prepared statements before, this may look a little weird.
Basically what's happening is that you are creating a template for what the SQL statement will be.
In this case, we are selecting everything from myTable, where name and age equal ?. The question mark is just a placeholder for where the values will go.
The bind_param() method is where you attach variables to the dummy values in the prepared template.
Notice how there are two letters in quotes before the variables.
This tells the database the variable types.
The s specifies that name will be a string value, while the i forces age to be an integer.
This is precisely why I didn't add quotation marks around the question mark for name, like I normally would for a string in an SQL call.
You probably thought I just forgot to, but the reality is that there is simply no need to (In fact, it actually won't work if you do put quotes around the ?, since it will be treated as a string literal, rather than a dummy placeholder.).
You are already telling it that it will be a string literal when you call bind_param(), so even if a malicious user tries to insert SQL into your user inputs, it will still be treated as a string.
$stmt->execute() then actually runs the code; the last line simply closes the prepared statement. We will cover fetching results in the Select section.
Looking at thegeneral MySQL log, when I use mysqli with parameterized queries with PHP I see statements like this:
Prepare SELECT * FROM my_table WHERE id = ?
Execute SELECT * FROM my_table WHERE id = 9
Prepare INSERT INTO my_table SET name = ?
Execute INSERT INTO my_table SET name = 'Alex'
This makes me feel warm and fuzzy, because I distinctly see that first, my query was sent, and them, my parameters, in two separate statements.
But when using an ORM (Doctrine in this case), I see the following:
Query SELECT t0.id AS id_1, t0.name AS name_2 FROM my_table t0 WHERE t0.id = '9'
Query START TRANSACTION
Query INSERT INTO my_table (name) VALUES ('Alex')
Query COMMIT
This has me feel alerted, as I do not see the same sequence of statement being send followed by parameters. It's statement + parameters in one go.
Questions about this that I have are:
Is Doctrine actually using parameterized statements, and why doesn't it do what MySQL does - log two packets, like mysqli does natively?
Is Doctrine safe from injection attacks in whatever it is doing now?
How is Doctrine safe from attacks, when it lumps statement and parameters into the same single query, per query? Does it really do something else here?
Doctrine uses PDO internally in most cases.
http://php.net/manual/en/pdo.prepare.php says in part:
PDO will emulate prepared statements/bound parameters for drivers that do not natively support them, and can also rewrite named or question mark style parameter markers to something more appropriate, if the driver supports one style but not the other.
When emulation of prepared statements is enabled, the prepare() that your app runs is basically a no-op. PDO saves your SQL string, but it does not send the SQL query to the database server at that time.
Then when you call execute(), it copies your parameter values into the appropriate places in the query, using proper string-escaping. Then it finally sends the final string to the database server. No prepare is done at the database server, it just executes the query as-is.
This is also how PDO supports both positional (?) and named (:param) parameters for all brands of RDBMS, even though most brands support one or the other style, but not both.
If you disble emulation of prepared statements, you should see both the Prepare and the Execute lines appear in the query log. I believe this can be done in Doctrine this way:
$pdo = $entityManager->getConnection()->getWrappedConnection();
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
While I don't know the Doctrine library specifically, I can speak to MySQL logs and what's going on as far as the DB is concerned:
The first example (prepare/execute) uses prepared statements, while the latter (query) does not. Prepared statements have a number of advantages, primarily performance- and security-related (avoiding SQL injection, as you mentioned), and I would personally avoid an ORM that did not use prepared statements, as they are generally considered a best practice for executing queries from within an application.
That's not to say that Doctrine isn't doing some sanitation internally to protect from SQL injection, and I certainly hope it is; at the same time, it would be more effective to use prepared statements, and I don't know why they wouldn't.
I'm working on an application at the moment that uses PDO with a MySQL database.
I'm seeing some queries, which are just very simple SELECT statements, e.g.
SELECT * FROM table ORDER BY name ASC
The code does not use prepare, for example:
$sql = "SELECT * FROM " . $this->table . " ORDER BY name ASC";
$stmt = $this->db->query($sql);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $results;
Is it ok to do this, i.e. without using prepare, if there's no placeholders in the query?
The reason I've asked this is because according to the documentation it says
The SQL statement can contain zero or more named (:name) or question mark (?) parameter markers
which makes me wonder why you'd use this in the case of having no (zero) parameter markers?
Yes, because the use of prepared statements have 2 main causes:
Enhance running the same query with different parameters.
Prevent sql injection by separating sql code from the parameters.
Since you have no parameters that could be handled by a prepared statement (table names cannot be a parameter), you do not gain anything by pushing the query through as a prepared statement.
You still need to make sure that whatever is returned by $this->table will not cause any issues with the generated sql code.
Of course you can omit prepare if there is no dynamic data in your query.
But prepared statements have more advantages than only securing your queries.
According to http://php.net/manual/en/pdo.prepared-statements.php a second advantage is, that statements can be prepared once and executed multiple times.
The query only needs to be parsed (or prepared) once, but can be executed multiple times with the same or different parameters. When the query is prepared, the database will analyze, compile and optimize its plan for executing the query. For complex queries this process can take up enough time that it will noticeably slow down an application if there is a need to repeat the same query many times with different parameters. By using a prepared statement the application avoids repeating the analyze/compile/optimize cycle. This means that prepared statements use fewer resources and thus run faster.
Nevertheless, if you run your query only once and there is no dynamic data inside your query, omitting prepare is also fine.
In reality, you have to run such a query extremely seldom. A few tables with configuration-like options may be.
In all other cases at least LIMIT clause is obligatory.
So the question is rather a theoretical one.
I'm updating some old PHP code and ran across an issue I don’t completely understand. In the old days of mysql_* functions you could include a variable in your SQL query like:
$query = "SELECT * FROM table $limit";
Where $limit = "LIMIT 0,50";. Thus the complete query was
$query = "SELECT * FROM table LIMIT 0,50";
And everything worked fine. However, with PDO prepared statements and named parameters, this type of simple substitution doesn't seem possible unless you break up the limit statement. For example:
$stmt = $conn->prepare('SELECT * FROM table :myLimit');
$stmt->execute(array(':myLimit'=>' LIMIT 0,50'));
Results in the error:
ERROR: 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 '?' at line
1
But if I change that query to the following so that the LIMIT is broken down further:
$stmt = $conn->prepare('SELECT * FROM table LIMIT :start,:end ');
$stmt->execute(array(':start'=>0,':end'=>50));
It works great.
So why doesn't using :myLimit as the named parameter and
array(':myLimit'=>' LIMIT 0,50') as the value work?
What are the
rules for using named parameters, and how do they differ from the
simple variable substitution in the SQL string that the old mysql_*
functions could use?
The PDO pages on php.net are a little ambiguous when it comes to what can and can’t be used as named parameters and I was looking for something a little more in-depth than what I found:
You must include a unique parameter marker for each value you wish to pass in to the statement
You cannot use a named parameter marker of the same name twice in a prepared statement.
You cannot bind multiple values to a single named parameter in, for example, the IN() clause of an SQL statement.
I'm currently using PHP 5.1.6
why doesn't using :myLimit as the named parameter and array(':myLimit'=>' LIMIT 0,50') as the value work?
Because prepared statements are for data only
What are the rules for using named parameters, and how do they differ from the simple variable substitution in the SQL string that the old mysql_* functions could use?
The rules are simple: you can use parameters (of either type) for the data only
I'm currently using PHP 5.1.6
Man. You know, you are a bit late with upgrade. Around ten years or so.
You cannot use a named parameter marker of the same name twice in a prepared statement.
That's true. In order to use this feature you'll have to turn the emulation mode on, which would make it inconvenient for other queries.
You cannot bind multiple values to a single named parameter in, for example, the IN() clause of an SQL statement.
That's true. Again because [native] prepared statement is for data literals only
When you bind a value, you can only include a value not any part of the query other than a value to be checked against.
Bound values are used to protect against query manipulation so if you could change the query or add extra mysql commands into the bound parameter then this would negate the whole point of binding a value
For example you can bind a name or number to check if something equals that value, you cannot bind a condition
After code like this:
$stmt = $mysqli->prepare("SELECT District FROM City WHERE Name=?")) {
$stmt->bind_param("s", $city);
$stmt->execute();
$stmt->bind_result($district);
$stmt->fetch();
printf("%s is in district %s\n", $city, $district);
How Do I See The Actual SQL Statement That Was Executed?
(It Should Look Something Like "SELECT District FROM City WHERE Name='Simi Valley';")
I already realize that in this simplistic case it would be very easy to simply reconstruct the query... but how can I access it in a general way that will work for very complicated prepared statements, and cases where I don't necessarily already understand the intended structure of the query, etc. Isn't there some function or method that can be called on the statement object that will return the actual text of the SQL query, after binding?
When you are using prepared statements, there is no "SQL query" :
First, you have a statement, that contains placeholders
This statement is sent to the DB server, and prepared there
which means that the SQL statement is analysed, parsed, and that some data-structure representing it is prepared in memory
And, then, you have bound variables
which are sent to the server
and the prepared statement is executed -- working on those data
But there is actualy no re-construction of an actual real SQL query -- neither on the PHP side, nor on the database side.
So, there is no way to get the prepared statement's SQL -- as there is no such SQL.
If you need to see some informations, for debugging purposes, as your said, you'll generally have two kind of options :
Either create the SQL query that would correspond to the prepared statement + binding by hand.
Or ouput the code of the statement, with the placeholders ; and the list of data
This means you will not have a real SQL query that can be executed
But it'll generally be enough, to help with debugging
PDO simulates binding if you set it like that; in this topic you can read about the debugDumpParams statement, which is also in the PHP documentation. There is no way, however, to check if the value substitution happened properly when you leave it to the real sql engine; one workaround could be a SELECT with the field placeholders in it so that in the result you get the actual string values:
SELECT :field1 as field1, :field2 as field2
If you bind and fetch this one, it will contain the values:
Array
(
[field1] => Lorem ipsum
[field2] => dolor sit amet
)
With this, you can build your own debug function which stitches the original query string together using sql's CONCAT - but you won't learn a lot from this since SQL is quite reliable when it comes to parameter binding :)