What did I do wrong? (PHP prepare statement) - php

First time I'm using a prepare function, and I got it to partially work. Basically, I'm copying user passwords from one database to another (part of a WordPress plugin I'm making to transfer users). The code runs and does exactly what I want, but only for the first user it finds in the wp_users table. I need it to continue running for all the users in that table so they all get their passwords transfered. This is the code I wrote below:
For getting the user password from the original database (Basically, this finds the passwords for all the users and puts them in an array. I'm posting this code just for context. This code works perfectly fine):
$i = 0;
//set $user_count-1 because $i needs to start at 0 to represent the indexes and it also prevents the statement from being looped an extra time.
while($i <= $user_count-1) {
if($result = $conn->query("SELECT * FROM wp_users")) {
if($count = $result->num_rows) {
//echo $count . ' users found.';
while($row = $result->fetch_object()) {
$user_password[] = $row->user_pass;
}
}
$i++;
}
To retrieve the index values (This is the code I'm using to actually retrieve those index values and put them in the sql query. Like I said, it works fine for the first user, but not the rest of the users):
$stmt = $conn->prepare("UPDATE `wp_plugin_development`.`wp_users` SET `user_pass` = ? WHERE `wp_users`.`user_login` = ?");
$stmt->bind_param('ss', $user_password[$i], $user_login[$i]);
$stmt->execute();
I'm thinking maybe the syntax is wrong? I don't know. I hope I made my question clear enough. Thanks for any help!

I figured it out!
Originally, I put the code to prepare the statement and the code to execute it together. prepare and bind_param needs to be placed before $i auto-increments. The execute needs to be placed after $i auto-increments. Here's the code that works:
$i = 0;
//using $user_count-1 because $i needs to start at 0 to represent the indexes and it also prevents the statement from being looped an extra time.
while($i <= $user_count-1) {
if($result = $conn->query("SELECT * FROM wp_users")) {
if($count = $result->num_rows) {
//echo $count . ' users found.';
while($row = $result->fetch_object()) {
$user_password[] = $row->user_pass;
$stmt = $conn->prepare("UPDATE `wp_plugin_development`.`wp_users` SET `user_pass` = ? WHERE `user_login` = ?");
$stmt->bind_param('ss', $user_password[$i], $user_login[$i]);
}
}
$i++;
if(!$stmt->execute()){trigger_error("there was an error....".$conn->error, E_USER_WARNING);}
}
Thank you everyone for your input!

Related

mysql query search with "If" statement

So, I have following php query:
for($i = 0; $i < sizeof($cat_result) ; ++$i) {
$query_p = "SELECT * FROM $table WHERE id = %d";
$results[] = $wpdb->get_row($wpdb->prepare($query_p, $cat_result[$i]));
}
The search relies on $cat_result which contains numerous numbers.
For example, let say $cat_result contains the following number: '1,3,5,21,35`
Using these 5 numbers, the query will look for the db info.
However, there are scenarios where some number (for example, "21") do not exist in the db.
Then, I get PHP NOTICE: trying to get property of non-object.
How do I write "if" statement so that if the id (in this case "21") does not exist, then it simply ignores the query? (It is hard to explain what I mean by "ignore". I still want the query to do the search but if it does not find what it is looking for, then simply ignore the error).
I think you should restructure your query. That way, as long as your data is sanitized (to prevent injection as im not sure if it comes from the user or not), you can just do the following:
$cat_result = implode(",", $cat_result);
$query_p = "SELECT * FROM $table WHERE id in ( $cat_result )";
$rslt = $wpdb->get_results($query_p);
// loop result
That way, it will fetch you all in that list.
Try this:
for($i = 0; $i < sizeof($cat_result) ; ++$i) {
$query_p = "SELECT * FROM $table WHERE id = %d";
$row = $wpdb->get_row($wpdb->prepare($query_p, $cat_result[$i]));
if ($row) {
$results[] = $row;
}
}
I don't know WordPress, but I suspect get_row returns false when there are no more rows of results. Your code was putting false into $results when that happened, and later code was then trying to use that as an object.

php statement for multiple users not working

I am helping in some PHP design for a friends text game and have come to a stump.
I have scheduled a cron job to call the following page / following code, which is working correctly
<?php require("connect.php"); ?>
<?php
$sql = "SELECT id, name, health FROM users";
$query = mysql_query($sql) or die(mysql_error());
$row = mysql_fetch_object($query);
while($row = mysql_fetch_object($query)) {
$id = htmlspecialchars($row->id);
$name = htmlspecialchars($row->name);
$health = htmlspecialchars($row->health);
$sql = "SELECT * FROM property WHERE living='1' AND ownerid='$id'";
$query = mysql_query($sql) or die(mysql_error());
$row = mysql_fetch_object($query);
while($row = mysql_fetch_object($query)) {
$OwnerName = htmlspecialchars($row->ownername);
$OwnerID = htmlspecialchars($row->ownerid);
$RaidPropBonus = htmlspecialchars($row->raidperc);
$RaidPropMoney = htmlspecialchars($row->raidcash);
$PropertyLvl = htmlspecialchars($row->proplvl);
$Living = htmlspecialchars($row->living);
if($PropertyLvl == '5' && $Living == '1'){
if($health < '100'){
$result = mysql_query("UPDATE users SET health=$health + '1' WHERE id='$id'")
or die(mysql_error());
} else { }
} else { }
}
}
?>
Although this only works for ONE user only. I cannot understand why this is. Any other logged in / out accounts that have met the criteria have been ignored. I can maybe only think I am missing a loop? As the ID that is being met first is number 1 and it has stopped there?
Anybody advice at all maybe?
UPDATE - It seems correct I need to get a loop in there, but am so far failing to get this loop working correct. No matter where I seem to amend / add a loop it does not help. Please may somebody suggest anything?
UPDATE2 - As requested, updated with the new version of loop
For what I've understood, the loops should be made on the mysql_fetch_object that will get the each row from the query.
Take a look at the snippet
<?php
require("connect.php");
// here prepare the $userQuery (the one that fetches all users)
// then the first loop that will read each usew row
// AFAICT this should afect all script
while($userRow = mysql_fetch_object($userQuery))
{
// prepare data fetched from the $userQuery
// prepare the $propertyQuery (the one that fetches all properties of the user)
// then the second loop to read all user property rows
// and this will afect the updates
while($propertyRow = mysql_fetch_object($propertyQuery))
{
// prepare data fetched from $propertyQuery
// add logic here
}
}
?>
Also #Matthew Carpenter had a valid point, that mysql_* is deprecated, you should consider in using mysqli_*, or in my opinion take a look at PDO

Multiple row inserts as fast as possible

I've seen multiple threads discussing this but there always has been totally different conclusion in the answers. Especially I wonder whether it is really necessary to create a own prepared statement (with the right amount of placeholders) in order to insert it as single query. I expected that when I use beginTransaction and endTransaction before and after my for loop, that pdo/php waits with the transaction until all data is collected and it will send these data's as a single query once the server hits the line endTransaction.
How would I need to rewrite such a for loop insert with multiple inserts in order to reach the best performance (it has between 1 and 300 rows usually but it also could reach 2000 rows).
for($i=0; $i<$baseCount; $i++)
{
$thLevel = $bases[$i]["ThLevel"];
$gold = $bases[$i]["Gold"];
$elixir = $bases[$i]["Elixir"];
$darkElixir = $bases[$i]["DarkElixir"];
$dateFound = $elixir = $bases[$i]["TimeFound"];
$query = $db->prepare("INSERT INTO bot_attacks_searchresults (attack_id, available_gold, available_elixir, available_dark_elixir, date_found, opponent_townhall_level)
VALUES (:attack_id, :available_gold, :available_elixir, :available_dark_elixir, :date_found, :opponent_townhall_level)");
$query->bindValue(':attack_id', $attackId);
$query->bindValue(':available_gold', $gold);
$query->bindValue(':available_elixir', $elixir);
$query->bindValue(':available_dark_elixir', $darkElixir);
$query->bindValue(':date_found', $dateFound);
$query->bindValue(':opponent_townhall_level', $thLevel);
$query->execute();
}
Prepare the statement once. MySQL lexes it once, so any subsequent call to the query will be quick since it's already lexed and juts needs parameters.
Start the transaction before the loop. This is done so your hard drive can write down all the rows in one input output operation. The default mode is that 1 insert query = 1 I/O of the hdd.
Create the loop, bind your parameters there and call the $query->execute();
Exit the loop and commit() the transaction.
Full code:
$db->beginTransaction();
$query = $db->prepare("INSERT INTO bot_attacks_searchresults (attack_id, available_gold, available_elixir, available_dark_elixir, date_found, opponent_townhall_level)
VALUES (:attack_id, :available_gold, :available_elixir, :available_dark_elixir, :date_found, :opponent_townhall_level)");
for($i = 0; $i < $baseCount; $i++)
{
$thLevel = $bases[$i]["ThLevel"];
$gold = $bases[$i]["Gold"];
$elixir = $bases[$i]["Elixir"];
$darkElixir = $bases[$i]["DarkElixir"];
$dateFound = $elixir = $bases[$i]["TimeFound"];
$query->bindValue(':attack_id', $attackId);
$query->bindValue(':available_gold', $gold);
$query->bindValue(':available_elixir', $elixir);
$query->bindValue(':available_dark_elixir', $darkElixir);
$query->bindValue(':date_found', $dateFound);
$query->bindValue(':opponent_townhall_level', $thLevel);
$query->execute();
}
$db->commit();
Here's a very crude proof of concept:
<?php
$values = array();
for($i=0;$i<10;$i++)
{
$values[] = "($i)";
}
$values = implode($values,',');
$query = "INSERT INTO my_table VALUES $values";
echo $query;
?>
outputs INSERT INTO my_table VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)
You would need to restructure this slightly to work with prepare (PHP is not my forte), but the principle is the same; i.e. you build the query inside the loop, but execute it only once.

php request of mysql query timeout

i'm trying to make a long mysql query and process and update the row founded:
$query = 'SELECT tvshows.id_show, tvshows.actors FROM tvshows where tvshows.actors is not NULL';
$result = mysql_query($query);
$total = mysql_num_rows($result);
echo $total;
while ($db_row = mysql_fetch_assoc($result))
{
//process row
}
but after 60 second give me a timeout request, i have try to insert these in my php code:
set_time_limit(400);
but it's the same, how i can do?
EDIT:
only the query:
$query = 'SELECT tvshows.id_show, tvshows.actors FROM tvshows where tvshows.actors is not NULL';
takes 2-3 second to perform, so i think the problem is when in php i iterate all the result to insert to row or update it, so i think the problem is in the php, how i can change the timeout?
EDIT:
here is the complete code, i don't think is a problem here in the code...
$query = 'SELECT tvshows.id_show, tvshows.actors FROM tvshows where tvshows.actors is not NULL';
$result = mysql_query($query);
$total = mysql_num_rows($result);
echo $total;
while ($db_row = mysql_fetch_assoc($result)) {
//print $db_row['id_show']."-".$db_row['actors']."<BR>";
$explode = explode("|", $db_row['actors']);
foreach ($explode as $value) {
if ($value != "") {
$checkactor = mysql_query(sprintf("SELECT id_actor,name FROM actors WHERE name = '%s'",mysql_real_escape_string($value))) or die(mysql_error());
if (mysql_num_rows($checkactor) != 0) {
$actorrow = mysql_fetch_row($checkactor);
$checkrole = mysql_query(sprintf("SELECT id_show,id_actor FROM actor_role WHERE id_show = %d AND id_actor = %d",$db_row['id_show'],$actorrow[0])) or die(mysql_error());
if (mysql_num_rows($checkrole) == 0) {
$insertactorrole = mysql_query(sprintf("INSERT INTO actor_role (id_show, id_actor) VALUES (%d, %d)",$db_row['id_show'],$actorrow[0])) or die(mysql_error());
}
} else {
$insertactor = mysql_query(sprintf("INSERT INTO actors (name) VALUES ('%s')",mysql_real_escape_string($value))) or die(mysql_error());
$insertactorrole = mysql_query(sprintf("INSERT INTO actor_role (id_show, id_actor, role) VALUES (%d, %d,'')",$db_row['id_show'],mysql_insert_id())) or die(mysql_error());
}
}
}
}
Should definitely try what #rid suggested, and to execute the query on the server and see the results/duration to debug - if the query is not a simple one, construct it as you would in your PHP script, and only echo the SQL command, don't have to execute it, and just copy that in to the server MySQL command line or whichever tool you use.
If you have shell access, use the top command after running the above script again, and see if the MySQL demon server is spiking in resources to see if it really is the cause.
Can you also try a simpler query in place of the longer one? Like just a simple SELECT count(*) FROM tvshows and see if that also takes a long time to return a value?
Hope these suggestions help.
There are so many problems with your code.
Don't store multiple values in a single column. Your actors column is pipe-delimited text. This is a big no-no.
Use JOINs instead of additional queries. You can (or could, if the above weren't true) get all of this data in a single query.
All of your code can be done in a single query on the server. As I see it, it takes no input from the user and produces no output. It just updates a table. Why do this in PHP? Learn about INSERT...SELECT....
Here are some resources to get you started (from Googling, but hopefully they'll be good enough):
http://www.sitepoint.com/understanding-sql-joins-mysql-database/
http://dev.mysql.com/doc/refman/5.1/en/join.html
http://dev.mysql.com/doc/refman/5.1/en/insert-select.html
What is Normalisation (or Normalization)?
Let me know if you have any further questions.

While loop refusing to work

I did make a post previously but was not able to properly explain my issue nor was I able to get it resolved. This is what I have.
$shoutlines = file($shout_file);
$aTemp = array();
foreach($matches['user'] as $user) {
$aTemp[] = "'" . $user . "'";
}
$user = implode(",", $aTemp);
$rara = "SELECT * FROM accounts WHERE username IN ( $user )"; // Tried this statment both as a query and prepared statement
$getlevel = $db->query("SELECT * FROM accounts WHERE username IN '( ".$user." )'"); // Tried this both as a query and prepared statement
//$getlevel->bind_param('s', $user);
//$getlevel->execute();
//$level = $getlevel->get_result();
//$getlevel->store_result();
while($getdb = $getlevel->fetch_assoc()){
//output the html
for($i = 0; $i < (1000); $i++)
{
if(isset($shoutlines[$i]))
{
$shoutline = preg_replace('/<\/div>\n/', ' ', $shoutlines[$i], 1);
echo showSmileys($shoutline) . "<div class='delete'><a href='javascript: delete_shoutline({$i});' title='Delele'>delete</a></div></div>";
}
}
}
I have a for loop within the while loop that will not run within it, if I move the for loop outside of the while it works fine, but I need it in the while loop to make checks of the users for post titles, abilities etc., that are saved in my database. I have shown what I have tried so far when to comes to identifying the problem, I have tried dieing out errors if the query, binds, or executes weren't showing true, but got now hits. The code for this is pulled out so there isn't too much clutter for your reading abilities, any help with this would be greatly appreciated.
When "exploding" the username, you need ot wrap each username in quotes, not the whole thing. Also make the names safe for data entry.
$aTemp = array();
foreach($matches['user'] as $user) {
$aTemp[] = '"' . mysql_real_escape_string($user) . '"';
}
$user = implode(",", $aTemp);
Then use the first query:
"SELECT * FROM accounts WHERE username IN ( $user )";
Edit: adding error checking:
$getlevel = $db->query("SELECT * FROM accounts WHERE username IN ( $user )");
if ($getlevel == false) {
// Normally you'll build into a function or class, but this is the simple example
// Never output SQL errors on a live site, but log to file or (if you can do it safely) the database.
echo 'Whoopsie<br />';
var_dump($db->errorInfo());
exit();
}
Using data binding with IN clauses is not that nice, so if you really need IN and don't care about using the old, deprecated mysql_* function, try this:
$user="'".implode("','",array_map(function($s){
return mysql_real_escape_string($s);
},$matches["user"])."'";
$rara="SELECT * FROM accounts WHERE username IN ($user)";

Categories