I am trying understand how multi queries work in mysqli. But I confess that is not easy to understand.
Basically how I can do these queries in a multi query? The page doesn't talk about prepared statements in multi queries.
($sql = $db -> prepare("INSERT INTO users (username, email, password) VALUES (?, ?, ?)"));
$sql -> bind_param('sss', $name, $email, $hash);
$sql -> execute();
($sq = $db -> prepare("INSERT INTO activation_link_password_reset (activation_link) VALUES (?)"));
$sq -> bind_param('s', $linkHash);
$sq -> execute();
You can't use prepared statements there, and the speedup is also negligible, so go for the easier to debug seperate queries.
If you really want to do it in 1 call with prepared statements, create a PROCEDURE (even more difficult to debug...), and prepare CALL(:param1,:param2);.
I actually just figured this out a few days ago. The move to MySQLi is not a trivial one but ill go ahead and show you the query loop for prepared statements.
$db = new mysqli(...)
$statement = $db->prepare('SELECT count(*) as [hitchhikers] FROM `T_Users` WHERE `id` > ? AND `signin` like ?');
$statement->bind_param("ss", 42, '%adams');
if ($statement->execute())
{
$statement->store_result();
$statement->bind_result($hitchhikers);
$statement->fetch();
// do something with hitchhikers here
}
else
{
// there was a problem with the execution, check $db->error
}
$statement->close();
$db->next_result();
Everything here works similar to the non oo format by replacing -> with _ and passing the returned value into the new function, but this process here is pretty much what you should look to be doing with each of those statements. You can abstract it away with a mysqli wrapper class as well.
After the $db->next_result() call you are able to repeat the process again. This change has to do with the way the MySQL connection and results are handled with MySQLi. You can, of course, avoid this issue entirely by switching back to mysql_ queries and resources.
Specifically for multi_query, you separate your queries with a semicolon, in a single string. The example you linked to shows how to process the results.
MySQLi Book #PHP.net
Related
I have a PHP code that opens a CSV file using fgetcsv then reads through each rows then constructs a "Insert Into" query and attaches it to a variable named $MyQuery. This is the most understandable way for me when trying to update my database using information from a CSV file downloaded from the company website. This is working as I expected using the code below:
if (mysqli_multi_query($conn, $MyQuery))
{
do
{
/* store first result set */
if ($result = mysqli_store_result($conn))
{
mysqli_free_result($result);
}
} while (mysqli_next_result($conn));
}
Recently I learned about Prepared Statements and how they can secure your queries.
PROBLEM: How can I do multiquery with prepared statement in Procedural Mysqli way? I tried researching, a lot says it isn't possible. Some say it is possible but by creating different variables for each queries which is impossible for me as I will be inserting over 10000 records to my database from the CSV file. Is there any other ways to achieve this?
I'm thinking it can be done by looping through each records then doing a prepared-statement version of Insert Into but I thought doing 10000 Insert Into SQL commands would be very slow.
I am not 100% sure what you are asking but fallowing might work. First of all I would use pdo for connecting to a database. Fallowing is just a basic outline of what I think you want to do.
$pdo = new PDO('mysql:host=localhost;dbname=mydatabase', 'myusername', 'mypassowrd');
$query = "
INSERT INTO table (colum1, colum2, colum3)
VALUES (:info1, :info2, :info3)
";
$stmt = $pdo->prepare($query);
do
{
$stmt->execute(array(':info1'=>$my_info1, ':info2'=>$my_info2, ':info3'=>$my_info3));
} while( your condition);
There is two advantages for prepared statements. First is security and the second allows to do the same query over and over changing the values. This will make each of queries fast if you prepare them.
here is a ling that can explain more about prepared statements
http://php.net/manual/en/pdo.prepared-statements.php
I am adding a Procedural way of doing it using mysqli.
$query = "
INSERT INTO table (colum1, colum2, colum3)
VALUES (?, ?, ?)
";
if ($stmt = mysqli_prepare($conn, $query))
{
do
{
mysqli_stmt_bind_param($stmt, "sss", $my_info1, $my_info2, $my_info3);
mysqli_stmt_execute($stmt);
} while( your condition)
}
I am not sure why you are using mysqli_store_result(), mysqli_free_result(), or mysqli_next_result(). Since inserting rows produces no results.
I am new to these prepared statements (all my code so far has been procedural), and I was trying to create a function for executing prepared statements so I could save time writing a statement for every SQL query I need.
function executeQuery($stmt,$mysqli,$sql,$type,$param1,$param2,$param3){
$stmt = $mysqli -> stmt_init();
$stmt = $mysqli -> prepare($sql);
$stmt->bind_param($type,$param1,$param2,$param3);
$stmt->execute();
$stmt->close();
}
As you can see, my issue is that I would need a different function for prepared statements that only deal with 1 parameter in the query, one for 2 parameters, another for 3 and so on. I thought of making $param an array but I don't think that quite works.
Any ideas?
after stopping the use of deprecated mysql_* functions, I switched to mysqli. But then, I noticed that non-prepared statements are non-secure against SQL injection. Then, I changed again my code.
What I had was the following function that checks if the variable $ID exists in the database and prints the value of title for that row:
function showPostTitle($ID, $mysqli) {
$result = $mysqli -> query("SELECT ID, title FROM blog where ID = $ID");
$row = $result -> fetch_array(MYSQLI_BOTH);
echo $row['title'];
}
I changed it to this:
function showPostTitle($ID, $mysqli) {
$stmt = $mysqli -> prepare("SELECT ID, title FROM blog WHERE ID = ?");
$stmt -> bind_param("i", $ID);
$stmt -> execute();
$stmt -> bind_result($ID, $title);
$stmt -> fetch();
print_r($title);
$stmt -> free_result();
}
My question is: is this the correct way to implement prepared statements? Plus, am I safe now from SQL Injections? Big thanks to whoever will answer this question :)
Your mysqli logic seems fine, there are some examples in the PHP manual here in case you have not seen them.
Why are you selecting the ID when not consuming it though? Also you don't really need to bind a result when it's only going to have one row returned in the full result set as I assume will happen in this case (ID is unique index in the table), use get_result instead.
Using mysqli prepare will protect against all the common injection attacks but not 0-day style stuff which hasn't made it to the driver yet.
Take a look at this post:
Are PDO prepared statements sufficient to prevent SQL injection?
It's using PDO instead of MySQLi, which is solving the same problem by creating prepared statements.
Sorry for not answering your question, but just wanted to provide a resource for you to consider.
I am trying out prepared statements, but the below code is not working. I am getting the error:
Fatal error: Call to a member function execute() on a non-object in
/var/www/prepared.php on line 12
<?php
$mysqli = new mysqli("localhost", "root", "root", "test");
if ($mysqli->connect_errno) {
echo "Failed to connect to MySQL: " . $mysqli->connect_error;
}
$stmt = $mysqli->prepare("INSERT INTO users (name, age) VALUES (?,?)");
// insert one row
$stmt->execute(array('one',1));
// insert another row with different values
$stmt->execute(array('two',1));
?>
Also, do I need to use mysqli for prepared statements? Can anyone point me to a complete example on prepared statements from connection to insertion to selection with error handling?
From the mysqli::prepare docs:
The parameter markers must be bound to application variables using mysqli_stmt_bind_param() and/or mysqli_stmt_bind_result() before executing the statement or fetching rows.
bind_param docs.
i.e.:
$name = 'one';
$age = 1;
$stmt = $mysqli->prepare("INSERT INTO users (name, age) VALUES (?,?)");
// bind parameters. I'm guessing 'string' & 'integer', but read documentation.
$stmt->bind_param('si', $name, $age);
// *now* we can execute
$stmt->execute();
Also do I need to use mysqli for prepared statement. Can anyone point me to a complete example on prepared statement from connection to insertion to selection with error handling
You can also use PDO which I much prefer. In fact, it looks like you're confusing PDO and Mysqli in your code example.
$db = new PDO($dsn, $user, $pass);
$stmt = $db->prepare("INSERT INTO users (name, age) VALUES (?,?)");
$stmt->execute(array($name1, $age1));
$stmt->execute(array($name2, $age2));
Unlike with mysqli you don't have to call a separate binding function, although that feature is available if you prefer/want/need to use it.
Another fun thing about PDO is named placeholders which can be much less confusing in complex queries:
$db = new PDO($dsn, $user, $pass);
$stmt = $db->prepare("INSERT INTO users (name, age) VALUES (:name,:age)");
$stmt->execute(array(':name' => $name1, ':age' => $age1));
$stmt->execute(array(':name' => $name2, ':age' => $age2));
Connection
The importance of mysqli connection is often overlooked, being diminished to a single line. Whereas a correct connection code can solve a multitude of problems, from security to usability.
Given your code is the usual procedural PHP, here is a simple mysqli connection code to be included in your scripts:
$host = '127.0.0.1';
$db = 'test';
$user = 'root';
$pass = '';
$charset = 'utf8mb4';
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try {
$mysqli = new mysqli($host, $user, $pass, $db);
$mysqli->set_charset($charset);
} catch (\mysqli_sql_exception $e) {
throw new \mysqli_sql_exception($e->getMessage(), $e->getCode());
}
unset($host, $db, $user, $pass, $charset); // we don't need them anymore
The full explanation can be found in my article How to connect properly using mysqli (as well as many useful hints), but just a small citation to highlight most important parts:
setting the proper character set for the connection will eliminate the whole class of errors, such as weird characters/question marks instead of your data, empty json_encode() output, problems with storing emojis, etc.
setting the proper error reporting mode will eliminate the cryptic error messages like mysqli_fetch_assoc() expects parameter... / Call to a member function bind_param()..., giving you the actual error message from MySQL instead.
security is not a laughing matter, there should be not a chance to leak your database details to the outside
Insertion
Insert query is relatively simple, and it is already covered in the other answer.
All you need is to replace all variables (along with surrounding quotes!) in the query with question marks, then prepare the query, then shove all variables with their types into bind_param() and finally execute the query.
Only a quick tip: MySQL will gladly accept all variables as strings, so don't go nuts finding the correct type for a certain variable, simply using "s" for any.
So basically inserting would be like this
$sql = "INSERT INTO users (name, email, password) VALUES (?,?,?)";
$stmt= $conn->prepare($sql);
$stmt->bind_param("sss", $name, $email, $password_hash);
$stmt->execute();
The same principle should be used for all other query types, such as UPDATE or DELETE.
Selection
Running a select query is almost the same, but with one small trick. For some unknown reason you cannot use familiar fetch functions right off the prepared statement. So you need to get the mysqli_result first, and then you'll be able to use fetch_assoc(), fetch_obj() etc:
$sql = "SELECT * FROM users WHERE id=?"; // SQL with parameters
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $id);
$stmt->execute();
$result = $stmt->get_result(); // get the mysqli result
$user = $result->fetch_assoc(); // fetch data
Tip: there is absolutely no need for the familiar mysqli_num_rows() function. If you think of it, you can always use the data itself, to see whether your query returned any rows:
$user = $result->fetch_assoc();
if ($user) {
// found!
}
the same goes for the multiple rows, thanks to
another tip: there is a handy function fetch_all() that can get you an array of all selected rows in one go. For example, if a query returns multiple rows, you can get them into array by changing the last line to
$users = $result->fetch_all(MYSQLI_ASSOC); // fetch data
Error handling
Error handling is the most important yet somewhat surprising part. Despite what numerous articles and examples say, as a rule, you shouldn't write any error handling code at all. It sounds absolutely crazy but that's exactly how things must be done. Most of time all you need to do is just report the error. And mysqli/PHP already can do it for you, no help required. Therefore, you shouldn't write any code that verifies the query execution result - in case of error mysqli will report it automatically, thanks to the mysqli_report() function call mentioned in the #Connection part. Again, the full explanation of this principle can be found in another article, dedicated to general PHP error reporting.
On a rare occasion when you really need to handle the error, that is to perform some action in case of error instead of just reporting it, then wrap your query(es) in a try..catch.
I'm working on learning to use prepared statements with mysqli in PHP and usually, if I'm having a problem with a query I just echo it to the screen to see what it looks like as a first step.
How can I do that with a prepared statement?
I'd like to see the SQL statement after the variables are substituted.
Using prepared statements:
When you prepare the statement, it is sent to the MySQL server
When you bind the variables + execute the statement, only the variables are sent to the MySQL server
And the statement + bound variables are executed on the MySQL server -- without it re-doing the "preparation" each time the statement is executed (which is why prepared statements can be good for performance when the same statement is executed several times)
There is no "building" of an SQL query on the PHP side, so, there is no way to actually get that query.
Which means that if you want to see an SQL query, you have to use, well, SQL queries, and not prepared statements.
You can use PDOStatement->debugDumpParams to get some informations about the prepared statement (in case you're using pdo).
Prepared statements are logged in MySQL's general log:
For prepared statements that are executed with the mysql_stmt_prepare() and mysql_stmt_execute() C API functions, the server writes Prepare and Execute lines to the general query log so that you can tell when statements are prepared and executed.
[...] the server writes the following lines to the general query log:
Prepare [1] SELECT ?
Execute [1] SELECT 3
So for debugging purposes active the general log and keep an eye on that file.
edit: oh, the question has a [mysqli] tag... completely overlooked that.
If the statement isn't executed at all have you (double/tripple) checked that no error occurred along the way?
echo "<pre>Debug: start</pre>\n";
$mysqli = new mysqli('localhost', 'localonly', 'localonly', 'test');
if ($mysqli->connect_error) {
die('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
}
$result = $mysqli->query('CREATE TEMPORARY TABLE foo (id int auto_increment, x int, primary key(id))');
if ( false=== $result) {
die('error : '. $mysqli->error);
}
$stmt = $mysqli->prepare('INSERT INTO foo (x) VALUES (?)');
if ( false===$stmt ) {
die ('prepare() failed: ' . $mysqli->error);
}
$result = $stmt->bind_param('i', $x);
if ( false===$result ) {
die('bind_param() failed');
}
$x = 1;
$result = $stmt->execute();
if ( false===$result ) {
die('execute() failed: '.$stmt->error);
}
echo "<pre>Debug: end</pre>\n";
I usually do this when I need to debug a prepared sql with parameters.
Example of prepare and execute:
$sql = "SELECT VAL1, VAL2 FROM TABLE(?, '?', '?', '?', '?', ?, '?', '?', '?')";
$prep = ibase_prepare( $sql ) or die("Error");
$query = ibase_execute($prep, $param1, $param2, .....) or $err = true;
^^^^^^^^^^^^^^^^^^^^^^^
The easy way to debug the resulting SQL of the sentence it's:
printf( str_replace('?', '%s', $sql), $param1, $param2, ....);
^^^^^^^^^^^^^^^^^^^^^^
You only need to do one printf, replacing the ? on the prepared SQL string by one %s. printf will interpret all as one string, taking each parameter as placing it on each replaced %s.
I recently updated this project to include composer integration, unit testing and to better handle accepting arguments by reference (this requires updating to php 5.6).
I've created a set of classes that extend the default mysqli and mysqli_stmt classes to allow you to view a rendition of the potential query string, which should provide what you're looking for:
https://github.com/noahheck/E_mysqli
This is a (close to) drop-in replacement for you normal mysqli object that returns a custom mysqli_stmt object when you prepare() the query string. After binding your parameters, E_mysqli will allow you to view the resultant query string as a new property of the stmt object:
$mysqli = new E_mysqli($dbHost, $dbUser, $dbPass, $dbName);
$query = "INSERT INTO registration SET name = ?, email = ?";
$stmt = $mysqli->prepare($query);
$stmt->bind_param("ss", $_POST['name'], $_POST['email']);
$stmt->execute();
echo $stmt->fullQuery;
would result in:
INSERT INTO registration SET name = 'John Doe', email = 'john.doe#example.com'
There are some caveats with using this extension (explained in the README at the github project), but for troubleshooting troublesome areas of your application, or transitioning to an object oriented style from procedural, this should provide a level of help for most users.
As I've outlined in the github project, I don't have any practical experience using the mysqli extension, and this project was created at the request of users of it's sister project, so any feedback that can be provided from devs using this in production would be greatly appreciated.
Disclaimer - As I said, I made this extension.
Agreeing with Pascal MARTIN (+1) so I suggest another technique for debugging: var_dump() or log every variable you're inserting into the statement, that way you should be able to figure out if it is wrong data or logically wrong SQL.
You can use tool like Lottip. The idea is act like MySQL proxy. It parses MySQL packets, extracts query and it's params so you can see prepared statements with it's content.