Can you run queries in PDO without preparing them? I am aware of the SQL-Injection issues that can arise with this but I am in a test environment.
I want to be able to write pure MySQL queries and just execute them, not have to prepare the query, bind the placeholders etc...
I would like to be able to execute a query like the following instantly.
INSERT INTO table (table_id, car, bike, date) VALUES (1, 'bmw', 'suzuki', 2004)
I seem to be getting errors running execute() directly on this query.
Thanks in advance.
The idea of prepared statements is not primarily that you can bind parameters, but that you can reuse the compiled statement multiple times, which should increase efficiency.
The prepare-execute workflow isn't too inconvenient for one-off use cases, but PDO offers other methods as well:
exec executes a statement and returns the number of affected rows. It is useful for initialization stuff, but not for SELECTs.
query is useful for static queries that don't involve untrusted input. It is similar to prepare-execute, but does not allow parameters, and does not allow the reuse of the compiled query.
Due to these limitations, they should generally only be used on static queries (i.e. the query is a plain string and not constructed from concatenations with variables).
You can safely escape user input with the quote method, so you could do something like
// untrusted data:
$car = 'bmw';
$bike = 'suzuki';
$year = 2004;
...
$dbh->exec('INSERT INTO table (table_id, car, bike, date) VALUES (1, '. $dbh->quote($car) .', '. $dbh->quote($bike) .', '. $dbh->quote($year) .')');
But this is so inconvenient that you'll end up using
$dbh->prepare('INSERT INTO table (table_id, car, bike, date) VALUES (1, :car, :bike, :year)')
->execute(array(':car' => $car, ':bike' => $bike, ':year' => $year));
instead.
Don't use a PDOStatement just use the PDO connection object directly.
$conn = new PDO("....");
$result = $conn->exec("INSERT INTO table (table_id, car, bike, date) VALUES (1, bmw, suzuki, 2004)");
or
$result = $conn->query("SELECT * FROM table");
http://www.php.net/manual/en/pdo.query.php
Related
How is best way add to database multiInsert row?
E.g I have array and i would like add all array to database. I can create loop foreach and add all arrays.
$array=['apple','orange'];
foreach($array as $v)
{
$stmt = $db->exec("Insert into test(fruit) VALUES ('$v')");
}
And it's work, but maybe i should use transaction? or it do other way?
Use a prepared statement.
$sql = "INSERT INTO test (fruit) VALUES ";
$sql .= implode(', ', array_fill(0, count($array), '(?)'));
$stmt = $db->prepare($sql);
$stmt->execute($array);
The SQL will look like:
INSERT INTO test (fuit) VALUES (?), (?), (?), ...
where there are as many (?) as the number of elements in $array.
Doing a single query with many VALUES is much more efficient that performing separate queries in a loop.
If you have an associative array with input values for a single row, you can use a prepared query like this:
$columns = implode(',', array_keys($array);
$placeholders = implode(', ', array_fill(0, count($array), '?'));
$sql = "INSERT INTO test($columns) VALUES ($placeholders)";
$stmt = $db->prepare($sql);
$stmt->execute(array_values($array));
The way you've done it is, in many ways, the worst option. So the good news is that any other way of doing it will probably be better. As it stands, the code may fail depending on what's in the data; consider:
$v="single ' quote";
$stmt = $db->exec("Insert into test(fruit) VALUES ('$v')");
But without knowing what your criteria are for "best", its rather hard to advise. Using a parametrised query with data binding, or as they are often described "prepared statements" is one solution to the problem described above. Escaping the values appropriately before interpolating the string is another (and is how most PHP implementations of data binding work behind the scenes) is another common solution.
Leaving aside the question of how you get the parameters into the SQL statement, then there is the question of performance. Each round trip to the database has a cost associated with it. And doing a single insert at a time also has a performance impact - for each query, the DBMS must parse the query, apply the appropriate concurrency controls, execute the query, apply the writes to the journal, then to the data tables and indexes then tidy up before it can return the thread of execution back to PHP to construct the next query.
Wrapping multiple queries in a transaction (you are using transactions already - but they are implicit and applied to each statement) can reduce some of the overhead I have described here, but can introduce other problems, the nature of which depends on which concurrency model your DBMS uses.
To get the data into the database as quickly as possible, and minimising index fragmentation, the "best" solution is to batch up multiple inserts:
$q="INSERT INTO test (fruit) VALUES ";
while (count($array)) {
$s=$q;
$j='';
for ($x=0; $x<count($array) && $x<CHUNKSIZE; $x++) {
$s.=$j." ('" . mysqli_real_escape_string($db,
array_shift($array)) . "')";
$j=',';
}
mysqli_query($db,$s);
}
This is similar to Barmar's method, but I think easier to understand when you are working with more complex record structures, and it won't break with very large input sets.
I am changing an existing data storage php code from mysql_* functions to PDO as well changing it from Procedural to OOB programming. I was updating the SQL statements when I noticed something, fairly far into the rewriting process.
I am setting up an array for multiple tables INSERT and UPDATE queries, as I was defining an array to work as the binding values I noticed that the order in which the bound values are called would be different from the UPDATE to the INSERT, here is a brief example:
$bound_values = array(
':column_aa' => 'aa',
':column_ab' => 'ab',
':column_ac' => 'ac'
)
);
Example sql for INSERT:
INSERT INTO `table_a`
(`id`, `column_aa`, `column_ab`, `column_ac`)
VALUES
('', :column_aa, :column_ab, :column_ac);
and the UPDATE:
UPDATE `table_a` SET
`column_ab` = :column_ab, `column_ac` = :column_ac, `column_aa` = :column_aa;
Example PHP PDO:
$pdo = new PDO('mysql:host=localhost;dbname=example', 'root', '');
// The second parameter of the PDO cursor is what I saw that raised the flag
$sth = $pdo->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute($boud_values);
So my question is, can I keep going forward using this method without an issue as to what order the SQL statements are in vs the $bound_values array, or am I right in being concerned and need to make some changes?
Please note that the existing code I am working with isn't anywhere near as simple as the SQL statements I have shown above.
Using named placeholders (:col_name), you can put them in any order as you please. However, using positional placeholders (?) - you need to put them in order.
It doesn't matter as long as you use named parameters ( :somename ). The binding simply tells your database engine "where I wrote the placeholder :abc, fill with this value. Where I wrote placeholder :xyz, put this other value".
Think about how the code would look like if you were binding each value separately instead of all at once in the execute
$sth->bindParam(':abc', 'value1', PDO::PARAM_STR);
$sth->bindParam(':xyz', 'value2', PDO::PARAM_STR);
$sth->execute();
Switching the bindParam() order would not have any impact.
Also, note that the order in which the column are set in INSERT and UPDATE sql queries doesn't matter, so if this really bugs you (or if you like things to be standardized a little) you can just order the column the same way in both queries.
UPDATE table SET col2 = 'xyz', col1 = 'abc'
// is the same as
UPDATE table SET col1 = 'abc', col2 = 'xyz'
I notice that these two ways of structuring a query with PHP PDO, both return the same data.
//prepare with $dbh->prepare
$w_ft = "36";
$sth = $dbh->prepare("SELECT * FROM main_products_common_dimensions WHERE w_ft = :w_ft");
$sth->bindParam(':w_ft', $theId, PDO::PARAM_INT);
$sth->execute();
$result = $sth->fetchAll(); //PHP array of data
//prepare with pg_prepare()
$result = pg_prepare($con, "my_query", 'SELECT * FROM main_products_common_dimensions WHERE w_ft = $1');
$result = pg_execute($con, "my_query", array("48")); //A query result resource on success or FALSE on failure.
while ($row = pg_fetch_assoc($result)){
echo $row['w_ft'] . "<BR>";
}
I read at http://php.net/manual/en/function.pg-execute.php that the second way returns "A query result resource on success or FALSE on failure." So I tried to iterate through it with pg_fetch_assoc(). It works, but is that not deprecated along with the rest of the pg_sql functions? Should I be using something in the PDO to look at the results of the query?
For this reason, I'm inclined to use the first method while using PDO. Is this the norm?
My question is how to submit multiple values to either method. Neither method works when I try to submit an array to the prepared statement
$w_ft = array("48", "36");
$result = pg_execute($con, "my_query", array("48", "36"));
I thought that I was able to submit multiple values to the query in this way. How can I do this?
Thank you
Looks like you're taking execute array wrong.
It takes values not for the consequent executions but for one execution only.
So, number of values should be equal to number of placeholders.
So it goes
$sql = 'SELECT * FROM table WHERE w_ft = $1 OR w_ft = $2 OR w_ft = $3'
for your array("48", "36", "12")
I am not a PG user though, so, I can confuse some syntax.
PDO is an agnostic database access API for PHP. This means, whatever your database is, you will be able to use the same objects and methods to query it and fetch results. PDO was the first step toward database abstraction layers in PHP.
The pg_* API is, afaik, not going to be deprecated and is dedicated to Postgres. It also contains functions that were not implemented in PDO (like binary escaping or event notifier functions amongst others).
The choice between PDO and dedicated library is often hidden by the choice of the Model Manager you use in your controllers code. Either it can be Object Relational Mapper over an abstraction layer like ORMs (Doctrine, Propel and many others) or it can be an Object Model Manager (OMM) dedicated to Postgresql like Pomm.
In both ways, you do not need to prepare statements, manage the columns types nor results cursors (btw, using PDO::fetch_all() will dump all results in memory), the database layer handles that for you. Your above query would be written like:
// Using Pomm
// SELECT * FROM main_products_common_dimensions WHERE w_ft = ?
// Returns a MainProductsCommonDimensions instance
$object = $connection
->getMapFor('\Database\Schema\MainProductsCommonDimensions')
->findWhere('w_ft = ?', array(48))
->current(); // fetch only the first result.
Note that both ORMs and OMMs do propose handy query builder:
$where = \Pomm\Query\Where::createWhere('w_ft = ?', array(48))
->orWhere('w_ft = ?', array(12))
->orWhere('w_ft = ?', array(66));
// which is pretty much the same as
$where = \Pomm\Query\Where::createIn('w_ft', array(48, 12, 66));
// SELECT * FROM main_products_common_dimensions WHERE w_ft IN (?, ?, ?);
$collection = $connection
->getMapFor('\Database\Schema\MainProductsCommonDimensions')
->findWhere($where); // Return an Iterable cursor over results
// display 48, 12 and 66 fetching one result at the time in memory:
foreach($collection as $object)
{
printf("W_FT = '%d'.\n", $object['w_ft']);
}
Using those layers above PDO offers numerous advantages, the main one is to focus more on what you want instead of dealing with weird APIs (yes PDO is weird as almost any lib in PHP). Furthermore, since PDO is just an access layer it will return results as arrays of strings (binary or not). Boolean in Postgres are 't' and 'f' and thus will need to be converted to PHP proper Boolean (sic) type to be used. ORMs and OMMs do propose such translation mechanisms and Pomm as being dedicated to Postgres also support Arrays, HStore, LTree, geometric and composite types conversions and more.
Where and when do you use the quote method in PDO? I'm asking this in the light of the fact that in PDO, all quoting is done by the PDO object therefore no user input should be escaped/quoted etc. This makes one wonder why worry about a quote method if it's not gonna get used in a prepared statement anyway?
When using Prepared Statements with PDO::prepare() and PDOStatement::execute(), you don't have any quoting to do : this will be done automatically.
But, sometimes, you will not (or cannot) use prepared statements, and will have to write full SQL queries and execute them with PDO::exec() ; in those cases, you will have to make sure strings are quoted properly -- this is when the PDO::quote() method is useful.
While this may not be the only use-case it's the only one I've needed quote for. You can only pass values using PDO_Stmt::execute, so for example this query wouldn't work:
SELECT * FROM tbl WHERE :field = :value
quote comes in so that you can do this:
// Example: filter by a specific column
$columns = array("name", "location");
$column = isset($columns[$_GET["col"]]) ? $columns[$_GET["col"]] : $defaultCol;
$stmt = $pdo->prepare("SELECT * FROM tbl WHERE " . $pdo->quote($column) . " = :value");
$stmt->execute(array(":value" => $value));
$stmt = $pdo->prepare("SELECT * FROM tbl ORDER BY " . $pdo->quote($column) . " ASC");
and still expect $column to be filtered safely in the query.
The PDO system does not have (as far as I can find) any mechanism to bind an array variable in PHP into a set in SQL. That's a limitation of SQL prepared statements as well... thus you are left with the task of stitching together your own function for this purpose. For example, you have this:
$a = array(123, 'xyz', 789);
You want to end up with this:
$sql = "SELECT * FROM mytable WHERE item IN (123, 'xyz', 789)";
Using PDO::prepare() does not work because there's no method to bind the array variable $a into the set. You end up needing a loop where you individually quote each item in the array, then glue them together. In which case PDO::quote() is probably better than nothing, at least you get the character set details right.
Would be excellent if PDO supported a cleaner way to handle this. Don't forget, the empty set in SQL is a disgusting special case... which means any function you build for this purpose becomes more complex than you want it to be. Something like PDO::PARAM_SET as an option on the binding, with the individual driver deciding how to handle the empty set. Of course, that's no longer compatible with SQL prepared statements.
Happy if someone knows a way to avoid this difficulty.
A bit late anwser, but one situation where its useful is if you get a load of data out of your table which you're going to put back in later.
for example, i have a function which gets a load of text out of a table and writes it to a file. that text might later be inserted into another table. the quote() method makes all the quotes safe.
it's real easy:
$safeTextToFile = $DBH->quote($textFromDataBase);
I'm in the process of building a site with CodeIgniter. This is the 1st site that I've built myself that interacts with a database. I'm using MySQL for this project. How can I tell if data needs to be escaped before saving it to the database?
I would advice you to accustom yourself to use prepared statements. Especially since you are new to working with databases. The sooner you start using these, the easier it becomes a second nature.
I, for instance, didn't know about prepared statements when I started with databases. And I experienced my own stubborness when I came in touch with them. Because I had accustomed myself to another way of doing things already. Now, this might not be a character trade of yourself, but it doesn't hurt to start as soon as possible with it either way.
Prepared statements allow you to use placeholders in queries. These placeholders can then be substituted with actual values by binding them to the placeholders. This process of binding, automatically escapes the values.
Here's a (simple) PDO example:
$db = new PDO( /* some database parameters */ );
$statement = $db->prepare( 'INSERT INTO table VALUES( :username, :password )' );
$statement->bindValue( ':username', $dirtyUsername );
$statement->bindValue( ':password', $dirtyPassword );
$result = $statement->execute();
// result checking ommited for brevity
There's lot's more possibilities with PDO and prepared statements. For instance you can easily reuse the prepared statement in a loop, as such:
$statement = $db->prepare( 'INSERT INTO table VALUES( :username, :password )' );
foreach( $users as $dirtyUser )
{
$statement->bindValue( ':username', $dirtyUser->username );
$statement->bindValue( ':password', $dirtyUser->password );
$result = $statement->execute();
// result checking ommited for brevity
}
Or pass the placeholder bindings to the execute method, like so:
$statement = $db->prepare( 'INSERT INTO table VALUES( :username, :password )' );
$result = $statement->execute( array(
':username' => $dirtyUsername,
':password' => $dirtyPassword
) );
// result checking ommited for brevity
... etc., etc.
Don't worry about escaping yourself (you WILL screw it up). Use a DB layer where you prepare the statement first, and then add data to it.
In PHP you should use PDO. You write
SELECT * FROM table WHERE key = :key AND value = :value
and then add the data in by calling functions.
If you're using the database class with query bindings, you don't have to do any manual escaping:
The secondary benefit of using binds
is that the values are automatically
escaped, producing safer queries. You
don't have to remember to manually
escape data; the engine does it
automatically for you.
If the data is a string, it must always be escaped.
However, it's better to use parameters instead.
If you are generating SQL yourself rather than using something like PDO, then you must always escape strings.
Escaping strings is a basic requirement of the SQL language. It's what allows you to use characters like apostrophes or backslashes in a string without everything going bad. There is no situation at all in which escaping strings is not required.
Even non-strings will have to be filtered to ensure that they are, indeed, non-strings.
If you are learning, please seriously consider learning something like PDO as many others have said, rather than escaping your own strings.
When in doubt, escape it all. Can't be too safe.
Alright, alright. I get it
ALWAYS ESCAPE
You escape a MySQL query string when any of the string is made up of user input, for example:
in PHP:
$username = ;//VALUE FROM USER INPUT
then your query string is:
"INSERT INTO table ('username') VALUES (".$username.")"
You would have to escape this mySQL query due to the fact the $username variable could potentionally have malicous code inserted by the client to be injected into your database.
When to escape? As soon as your site goes public.