While trying to insert data into the database using prepared statement the prepared statement always returns false and not complete the connection.
I'm using this connection on cpanel (not sure if that's related) tried to change the order tried to change the data type.
$conn = mysqli_connect($servername,$username,$password,$database);
// $sql=$conn->prepare("insert into asset 'assetName'=?, 'grp' ='?' ,'Descrip' = '?' , 'enteredValue' = '?', 'depreciationRate' = '?','entrydate'='?' 'availability'= '?' ,'enteredBy' = '?' , 'updatedOn' = '?' , 'isPeriodic' = '?' , 'assetType' = '?','Frequency'='?','ExitDate'='?'");
if($sql = $conn->prepare("INSERT INTO `asset`(`id`, `assetName`, `grp`, `Descrip`, `enteredValue`, `depreciationRate`, `entrydate`, `availability`, `enteredBy`, `updatedOn`, `isPeriodic`, `assetType`, `Frequency`, `ExitDate`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)")){
$sql->bind_param("sssssssssss",$name,$group,$value,$depreciation,$entryDate,$availability,$enteredBy,$updatedOn,$isPeriodic,$type,$frequency,$exitDate);
$sql->execute();
always return false and nothing has been inserted in the database.
As I said in the comments:
Well you have 14 ? and 11 s by my count. OR sssssssssss and ?????????????? Which as most of us know, is gonna throw an error as your placeholder count doesn't match your values
If you can put your data in an array you can use that array to build your query.
if($sql = $conn->prepare("INSERT INTO `asset`(`id`, `assetName`, `grp`, `Descrip`, `enteredValue`, `depreciationRate`, `entrydate`, `availability`, `enteredBy`, `updatedOn`, `isPeriodic`, `assetType`, `Frequency`, `ExitDate`) VALUES (".implode(',', array_fill(0,count($data), '?')).")")){
$sql->bind_param(str_repeat('s', count($data)),...$data);
Lets walk thought this a bit
Basically you can create your arguments with the same length as the $data with these 2 pieces of code:
implode(',', array_fill(0,count($data), '?')) //implode "?" with "," equal to the length of data
str_repeat('s', count($data)) //create 's' equal to the length of data
Then the real magic happens here with the ... "variadic" (variable length arguments):
$sql->bind_param(str_repeat('s', count($data)),...$data);
In PHP v5.6+ you can just inject the data using ... in and it will unwind it for you. Or in other words, put each array item in as a new argument.
For the fields (columns)
If you want to do the fields too, that is a bit more tricky. You have to be careful of what is in those if you put that data directly into the SQL. For example a User could edit the keys used in a $_POST request in such a way as to do SQLInjection if you just concatenate the Post Keys into the SQL.
One of the simplest ways to solve this is to have a whitelist of fields like so (matched to the column names):
//all allowed column names for this query (case sensitive)
$whitelist = ["id", "assetName", ...];
You can use array_intersect_key to retain only the data you want for the query (assuming the data has matched keys). The keys will be safe to use now in the query as they must match what is in the $whitelist.
//remove unknown keys form input data (~ retain only known ones)
//array_flip($whitelist) = ["id"=>0, "assetName"=>1, ...];
$data = array_intersect_key($_POST, array_flip($whitelist));
if($sql = $conn->prepare("INSERT INTO `asset`(`".implode("`,`", array_keys($data))."`)VALUES(".implode(',', array_fill(0,count($data), '?')).")".)){
$sql->bind_param(str_repeat('s', count($data)),...$data);
Other things
The only thing this doesn't cover is if you want all the fields in $whitelist to always be present. You can solve this with validation of the incoming data or you can merge in some empty fields to insure that all the data is present.
$default = array_fill_keys($whitelist, ''); //["id"=>"", "assetName"=>"", ...] ~ create empty "default" row
//$default['updatedOn'] = date('Y-m-d'); //you can also manually set a value
$data = array_intersect_key(
array_merge(
$default,
$_POST //["id"=>"1", ...] ~ missing assetName
), array_flip($whitelist)); //-> ["id"=>"1","assetName"=>""]
Array fill keys (similar to array fill from before) takes a list of keys, and adds a value in for each. So that gives us an array who's keys are the the values of $whitelist and an empty string for each items value. I call this a default row.
Then we merge this with our original data. Data in the first array will be overwritten by any data with matched keys for the second array ($_POST in my example). So if a key is present like id in the example above, it overwrite the empty one.
Anything not overwritten keeps the empty value from the default row we made. Then the array intersect key removes anything extra like before.
*PS I didn't test any of this so please forgive any syntax errors.
Enjoy!
You have to execute the statement once you've bound the data.
$sql->execute();
The number of parameters are also inconsistent as pointed out by the comments.
I think you don't execute your query calling the execute method :
$conn = mysqli_connect($servername,$username,$password,$database);
// $sql=$conn->prepare("insert into asset 'assetName'=?, 'grp' ='?' ,'Descrip' = '?' , 'enteredValue' = '?', 'depreciationRate' = '?','entrydate'='?' 'availability'= '?' ,'enteredBy' = '?' , 'updatedOn' = '?' , 'isPeriodic' = '?' , 'assetType' = '?','Frequency'='?','ExitDate'='?'");
if($sql = $conn->prepare("INSERT INTO `asset`(`id`, `assetName`, `grp`, `Descrip`, `enteredValue`, `depreciationRate`, `entrydate`, `availability`, `enteredBy`, `updatedOn`, `isPeriodic`, `assetType`, `Frequency`, `ExitDate`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)")){
$sql->bind_param("sssssssssss",$name,$group,$value,$depreciation,$entryDate,$availability,$enteredBy,$updatedOn,$isPeriodic,$type,$frequency,$exitDate);
sql->execute();
sql->close(); // close connection
im trying to find and replace some string in all my rows in a database
first i get all tables and loop through them and get all columns
then i execute this query
if ($column_name !== 'id')
{
$replcace_q = $database->query("UPDATE $table_name SET $column_name = REPLACE('$column_name','$old','$new')") or die($database->error);
}
the loop is ok and i go to each table successfully
but
the result of executing the command is when it updates a column it replaces the content with the column name
for example if column_name is username
the content will change to username.
what am i doing wrong ?
Your query is good,
but there is a single silly mistake in it.
if ($column_name !== 'id')
{
$replcace_q = $database->query("UPDATE $table_name SET $column_name = REPLACE($column_name,'$old','$new')") or die($database->error);
}
try this one and check it will work.
I am trying to make a database of Users. One user can have an indefinite number of phone numbers. So in the form I’ve created a js function that will give me new input fields and they put the information into a nestled array.
I am doing a double foreach loop to go through my array, and add SQL queries to it based on if the id already exists and just needs to be updated or if it's entirely new and needs to be inserted. I add these SQL queries to a variable $phoneSql . When I echo that variable, it does contain a valid SQL query which works if I try it directly in phpMyAdmin.
This is the foreach loop code:
$phoneSql = 'SELECT id FROM user WHERE id = '.$id.' INTO #id;';
foreach($_POST['phone'] as $key => $value) {
foreach($_POST['user'][$key] as $id => $number) {
if($id == 0 && !$number == ''){
$phoneSql .= 'INSERT INTO phone_number (id, user_id, number) VALUES (NULL, #id, "'.$number.'");';
} else if (!$number == '') {
$phoneSql .= 'UPDATE phone_numbers SET user_id = #id, number = "'.$number.'" WHERE id = '.$id.';';
}
}
}
I have one edit.php page with the form, which posts to update.php where I have the foreach loop from above and following code:
$db->updatePhoneNumber($phoneSql);
It also gets the $id from the user I’m editing at the moment. Then it gets sent to db.php and into this function:
public function updatePhoneNumbers($phoneSql) {
$ phoneSql = $ phoneSql;
$sth = $this->dbh->prepare($phoneSql);
$sth->execute();
if ($sth->execute()) {
return true;
} else {
return false;
}
}
But this is not working. Can I add a variable with sql queries into a function like that or do I have to do it some other way? I’m quite new to this so I’m not sure how to proceed. I’ve tried searching for a solution but haven’t found any. I’m thankful for any advice.
What you should be doing is using an INSERT ... ON DUPLICATE KEY UPDATE ... construct, saving you a lot of that logic.
e.g.
INSERT INTO phone_number (id, user_id, number) VALUES (...)
ON DUPLICATE KEY UPDATE user_id=VALUES(user_id), number=VALUES(number)
With this, no need to select, test, then insert/update. You just insert, and MySQL will transparently convert it into an update if a duplicate key error occurs.
I need to know the proper way of doing this.
I have a form where someone can fill in 3 different inputs to update their data.
they can leave one blank if they want and just update the other two or just one. Whatever.
so if i update as:
mysql_query("UPDATE table SET field1=input AND field2=BLANK AND filed3=input WHERE ID=123);
will it leave the blank fields unchanged? just skip over them? or will it replace the field with an empty string/blank field?
If this is the wrong way, what is the correct method?
Thank You!
It will replace them with blank values. The correct way to do it is not to put those items in the query at
all:
if (empty($field1) && empty($field2) && empty($field3) {
// show error message, nothing to do
return;
}
$updates = array();
if (!empty($field1))
$updates[] = 'field1="'.mysql_real_escape_string($field1).'"';
if (!empty($field2))
$updates[] = 'field2="'.mysql_real_escape_string($field2).'"';
if (!empty($field3))
$updates[] = 'field3="'.mysql_real_escape_string($field3).'"';
$updates = implode(', ', $updates);
mysql_query("UPDATE table SET $updates WHERE ID=123");
Obviously it would be cleaner to put the changes in an associative array or object, and then loop through them.
The following UPDATE statement should leave the fields unchanged if the user uses '' as their input, otherwise, it will use the input given to update the field.
UPDATE table
SET field1 = CASE
WHEN input = '' THEN field1
ELSE input
END
, field2 = CASE
WHEN input2 = '' THEN field2
ELSE input2
END
, field3 = CASE
WHEN input3 = '' THEN field3
ELSE input3
END
WHERE ID = 123
This is done with the CASE statement. The WHEN conditions check to see what the input it, and if it is '' (omitted basically) it will use the current value of field1 to update field1 with, basically leaving it unchanged. If there is a value, it will use that new value instead.
If you do not wish to update a certain field you will have to remove the field from your UPDATE statement.
UPDATE table
SET field1=input AND filed3=input
WHERE ID=123
$url = mysql_real_escape_string($_POST['url']);
$shoutcast_url = mysql_real_escape_string($_POST['shoutcast_url']);
$site_name = mysql_real_escape_string($_POST['site_name']);
$site_subtitle = mysql_real_escape_string($_POST['site_subtitle']);
$email_suffix = mysql_real_escape_string($_POST['email_suffix']);
$logo_name = mysql_real_escape_string($_POST['logo_name']);
$twitter_username = mysql_real_escape_string($_POST['twitter_username']);
with all those options in a form, they are pre-filled in (by the database), however users can choose to change them, which updates the original database. Would it be better for me to update all the columns despite the chance that some of the rows have not been updated, or just do an if ($original_db_entry = $possible_new_entry) on each (which would be a query in itself)?
Thanks
I'd say it doesn't really matter either way - the size of the query you send to the server is hardly relevant here, and there is no "last updated" information for columns that would be updated unjustly, so...
By the way, what I like to do when working with such loads of data is create a temporary array.
$fields = array("url", "shoutcast_url", "site_name", "site_subtitle" , ....);
foreach ($fields as $field)
$$field = mysql_real_escape_string($_POST[$field]);
the only thing to be aware of here is that you have to be careful not to put variable names into $fields that would overwrite existing variables.
Update: Col. Shrapnel makes the correct and valid point that using variable variables is not a good practice. While I think it is perfectly acceptable to use variable variables within the scope of a function, it is indeed better not use them at all. The better way to sanitize all incoming fields and have them in a usable form would be:
$sanitized_data = array();
$fields = array("url", "shoutcast_url", "site_name", "site_subtitle" , ....);
foreach ($fields as $field)
$sanizited_data[$field] = mysql_real_escape_string($_POST[$field]);
this will leave you with an array you can work with:
$sanitized_data["url"] = ....
$sanitized_data["shoutcast_url"] = ....
Just run a single query that updates all columns:
UPDATE table SET col1='a', col2='b', col3='c' WHERE id = '5'
I would recommend that you execute the UPDATE with all column values. It'd be less costly than trying to confirm that the value is different than what's currently in the database. And that confirmation would be irrelevant anyway, because the values in the database could change instantly after you check them if someone else updates them.
If you issue an UPDATE against MySQL and the values are identical to values already in the database, the UPDATE will be a no-op. That is, MySQL reports zero rows affected.
MySQL knows not to do unnecessary work during an UPDATE.
If only one column changes, MySQL does need to do work. It only changes the columns that are different, but it still creates a new row version (assuming you're using InnoDB).
And of course there's some small amount of work necessary to actually send the UPDATE statement to the MySQL server so it can compare against the existing row. But typically this takes only hundredths of a millisecond on a modern server.
Yes, it's ok to update every field.
A simple function to produce SET statement:
function dbSet($fields) {
$set='';
foreach ($fields as $field) {
if (isset($_POST[$field])) {
$set.="`$field`='".mysql_real_escape_string($_POST[$field])."', ";
}
}
return substr($set, 0, -2);
}
and usage:
$fields = explode(" ","name surname lastname address zip fax phone");
$query = "UPDATE $table SET ".dbSet($fields)." WHERE id=$id";