Error in mysqli->prepare with insert statement - php

I'm trying to figure out why my first prepare statement works just fine but my second one doesn't. The actual INSERT INTO syntax looks correct and works when I substitute numbers and place it in a mysql console, but the prepare statement returns false.
Just to clear away the simple questions; $db_table_prefix == "uc_" and all variables are initialized. Also, the first statement sets $results == 0 (EDIT: this was my mistake, it's really 0, not 1).
global $mysqli,$db_table_prefix;
$stmt = $mysqli->prepare("SELECT COUNT(id) FROM ".$db_table_prefix."attempts WHERE ((exp_m = ?) AND (exp_n = ?) AND (max_base <= ?))");
$stmt->bind_param("iii", $m, $n, $this->max_base);
$stmt->execute();
$stmt->bind_result($results);
$stmt->fetch();
if ($results < 1)
{
$stmt = $mysqli->prepare("INSERT INTO ".$db_table_prefix."attempts (exp_m, exp_n, base_x, max_base) VALUES (?,?,?,?)");
$stmt->bind_param("iiii", $m, $n, $x, $this->max_base);
.....
}
I've included the table structure, just in case that's the issue.
mysql> describe uc_attempts;
+----------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+---------------------+------+-----+---------+----------------+
| exp_m | bigint(20) unsigned | NO | | NULL | |
| exp_n | bigint(20) unsigned | NO | | NULL | |
| base_x | bigint(20) unsigned | YES | | NULL | |
| max_base | bigint(20) unsigned | NO | | NULL | |
| id | int(11) | NO | PRI | NULL | auto_increment |
+----------+---------------------+------+-----+---------+----------------+
I'm sure I'm just missing something simple, but after a few days of staring at the code, I needed to ask. Thanks in advance for the help. Please let me know if there is any other information I should include.

You forgot to close the first resource. I believe it can't open a second prepared statement if the first one isn't closed. I think $mysqli->prepare( ... ); will then return false and obviously false->bind_param( ... ); does not exist ;-) causing your Fatal error: Call to a member function bind_param() on a non-object-error.
global $mysqli,$db_table_prefix;
$stmt = $mysqli->prepare("SELECT COUNT(id) FROM ".$db_table_prefix."attempts WHERE ((exp_m = ?) AND (exp_n = ?) AND (max_base <= ?))");
$stmt->bind_param("iii", $m, $n, $this->max_base);
$stmt->execute();
$stmt->bind_result($results);
$stmt->fetch();
$stmt->close(); //<-- this is the problem
if ($results < 1)
{
$stmt = $mysqli->prepare("INSERT INTO ".$db_table_prefix."attempts (exp_m, exp_n, base_x, max_base) VALUES (?,?,?,?)");
$stmt->bind_param("iiii", $m, $n, $x, $this->max_base);
.....
}

Related

using one key to multiple values in php

I'm developing a webaplicattion in php where there will be an area called 'My Products'. This area you can see the products that you listed. Lets say you placed a car to sell. You will have something like:
Model: R8
Color: Yellow
Brand: Audi
Type: Diesel
Price: 90000
CarID: 1
My problem: How can I select the carid so that I have the cardid as the key and the other values (eg. model, color, etc...) as values?
I'm using mysql to store the listings. SQL TABLE:
+---------+------------------------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+------------------------------------------+------+-----+---------+----------------+
| carid | int(11) | NO | MUL | NULL | auto_increment |
| brand | enum('Alfa Romeo','Aston Martin','Audi') | NO | | NULL | |
| color | varchar(20) | NO | | NULL | |
| type | enum('gasoline','diesel','eletric') | YES | | NULL | |
| price | mediumint(8) unsigned | YES | | NULL | |
| mileage | mediumint(8) unsigned | YES | | NULL | |
| model | text | YES | | NULL | |
| year | year(4) | YES | | NULL | |
| user | varchar(30) | YES | | NULL | |
+---------+------------------------------------------+------+-----+---------+----------------+
My pseudo code is something like this:
Fetch ID of the cars that was listed by certain user;
Use that ID as a key;
Get every other options to be the values (diesel, yellow, etc...)
I have tried some codes since array_combine to foreach inside foreach.
This is the code I have ended up so far:
$qry_id = "select carid from cars where user='$login'";
if ($car_id = mysqli_query($link, $qry_id)){
while ($row = mysqli_fetch_assoc($car_id)){
//It will fetch the iD of the user in the DB
$user_id = $row["carid"];
$qry_model = "select model from cars where carid='$user_id'";
if($model_obj = mysqli_query($link, $qry_model)){
while ($row_2 = mysqli_fetch_assoc($model_obj)){
$model = $row_2['model'];
$final_array = array($user_id => $model);
}
}
}
}
I don't know if this is the right approach since it's my first webapp I'm building.
I'm just using the model value in this code for the simplicity sakes.
$q = "SELECT * FROM cars where user=?";
if ($stmt = $pdo->preapre($q)){
$result=[];
$stmt->execute([$login]);
while ($row = $stmt->fetchObject()){
$carId = $row->carid;
unset($row->carid);
$result[$carId]=$row;
}
}
now note that $pdo is object of pdo connecttion to the database not mysqli, you can do the same thing with mysqli but i am not uses to it
also i don't recommend that you use the user name on every column you should instead store the userId as foreign key to the primary key id in the table user
that will save alot more storage make the query faster ( it's easier to look for numbers than string ) and user can change it's name without having to change his name in all other tables ( userid won't be changing of course )
also carid should be unsigned int(10) not int(11) if wondering why 10 see that post MySQL datatype INT(11) whereas UNSIGNED INT(10)?
To avoid SQL injection, use prepared statements. You can use one query to fetch all attributes for the cars:
$qry_id = "select carid, model, price, color from cars where user=?";
$stmt = mysqli_prepare($link , $qry_d) or die("SQL statement error");
// Bind the login parameter to the statement
mysqli_stmt_bind_param($stmt, "s", $login);
mysqli_stmt_execute($stmt);
// bind every column in the SELECT
mysqli_stmt_bind_result($stmt, $user_id, $carid, $model, $price, $color);
while (mysqli_stmt_fetch($stmt)){
$final_array[] = array(
"model" => $model,
"price" => $price,
"color" => $color
);
}
You may do the following
Note this query is not safe and pron to SQL Injection, I would recommend to use prepared statements or PDO
The $carArray variable will finally have the array with carid as key in it
$query = "select * from cars where user='$login'";
$result = mysqli_query($query);
$carArray = array();
while ($row = mysqli_fetch_assoc($result)){
$carArray[$row['carid']] = $row;
}

very strange duplicate entry error [duplicate]

This question already has answers here:
When to use single quotes, double quotes, and backticks in MySQL
(13 answers)
Closed 7 years ago.
I am saving data repeatedly with code. The first time I run it it doesn't complain. The second time it says Duplicate entry '$id' for key 'PRIMARY'. I am echoing $id value and they are different everytime. The table is 5min old and I guess it can't be corrupted. Is my approach wrong?
function insertData($conn,$data){
$id=$data['id'];
$name=$data['name'];
$fp=$data['first_price'];
$sp=$data['second_price'];
echo "$id<br>";
echo "$name<br>";
echo "$fp<br>";
echo "$sp<br>";
$query = 'INSERT INTO names VALUES("$id", "$name", "$fp", "$fp")';
$result = $conn->query($query);
if (!$result){
echo "nothing saved, sorry $conn->error";
}
}
table structure:
+--------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| id | varchar(15) | NO | PRI | NULL | |
| name | varchar(150) | YES | | NULL | |
| first_price | varchar(10) | YES | MUL | NULL | |
| second_price | varchar(10) | YES | MUL | NULL | |
+--------------+--------------+------+-----+---------+-------+
You're trying to insert the string literals $id etc into the table because you're using single quotes.
Here's an example that would work:
$query = "INSERT INTO names VALUES('$id', '$name', '$fp', '$fp')";
Now generally speaking you shouldn't need to insert a primary key value, just use null and it will auto increment if your table is set up that way. In your case it's not (auto_increment is not listed under "extra" for the primary key). Consider adding it.
I'll assume that the ->query() is from the PDO library, so to avoid SQL injection you should use parameter binding and your adjusted code would look like this:
$query = 'INSERT INTO names VALUES(?, ?, ?, ?)';
$stmt = $conn->prepare($query);
$stmt->execute(array($id, $name, $fp, $fp));
... or if you're using mysqli rather than PDO:
$query = 'INSERT INTO names VALUES(?, ?, ?, ?)';
$stmt = $conn->prepare($query);
$stmt->bind_param('isdd', $id, $name, $fp, $fp);
$stmt->execute();
Your query is literally inserting the string $id as you're using single quotes for your query string. Do this instead:
$query = "INSERT INTO names VALUES('$id', '$name', '$fp', '$fp')";
Just so you know the reasoning behind it, using single quotes for a string makes it so that variables are ignored.

Query returns one post late

So I have a query that gets all the posts in the database. Say I post a post, it won't show, till I post another post. So essentially there's a post delay, until you post another post. That's the best I can explain it. Here's my query
SELECT * FROM comments WHERE comment_post_id = :id
Then I create an array
//Get post comments
$cmt = $con->prepare("SELECT * FROM comments WHERE comment_post_id = :id");
$cmt->bindValue(':id', $id, PDO::PARAM_INT);
$cmt->execute();
$cmtc = $cmt->fetch(PDO::FETCH_ASSOC);
$comments = array();
while($row = $cmt->fetch(PDO::FETCH_ASSOC)){
$comments[] = array(
'comment_user' => $row['comment_user'],
'comment_ip' => $row['comment_ip'],
'comment_date' => $row['comment_date'],
'comment_content' => $row['comment_content'],
'comment_post_id' => $row['comment_post_id']
);
}
And finally display it
<?php foreach($comments as $comment){?>
<h1 class="message"><?php echo $comment['comment_content']?></h1>
<?php } ?>
I'm not getting any errors, but when I run the query in the command line I get one result. But when I visit the page I don't see any results.
Here's the structure
+-----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| comment_user | varchar(255) | YES | | NULL | |
| comment_ip | varchar(255) | YES | | NULL | |
| comment_date | varchar(255) | YES | | NULL | |
| comment_content | varchar(85) | YES | | NULL | |
| comment_post_id | varchar(255) | YES | | NULL | |
+-----------------+------------------+------+-----+---------+----------------+
Your first call to fetch automatically increments the internal pointer of the result set by one after fetching the row:
$cmtc = $cmt->fetch(PDO::FETCH_ASSOC);
The above returns the zeroth row and moves the pointer to the first row. So, when you get to your while loop, the pointer is offest by one, and nothing is found:
while($row = $cmt->fetch(PDO::FETCH_ASSOC)){
The reason is that line:
$cmtc = $cmt->fetch(PDO::FETCH_ASSOC);
You should simple remove it.
Otherwise you fetch first record and don't assign it to $comments variable and then in loop you try to get records from 2 to n
To fetch all results of your query try this:
$cmt = $con->prepare("SELECT * FROM comments WHERE id = :id");
$cmt->bindValue(':id', 1);
$cmt->execute();
$comments = $cmt->fetchAll(PDO::FETCH_ASSOC);
PS. your schema use id as primary key, but your query use comment_post_id.

SQLSTATE[HY093]: Invalid parameter number: parameter was not defined - Though No Mismatch found [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I am try to do a simple insertion in a table but I am getting the following error:
SQLSTATE[HY093]: Invalid parameter number: parameter was not defined. I know this error drops in if the no of parameters and matches are not same, but I have checked it over and over again and I was not able to find any such mismatch.
I have
No of Columns in the table: 16
No of parameters : 16
No of matches : 16
The Table description:
mysql> describe faculty;
+-----------------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+-------------+------+-----+---------+-------+
| faculty_id | varchar(8) | NO | PRI | NULL | |
| faculty_name | text | NO | | NULL | |
| department_id | varchar(8) | YES | MUL | NULL | |
| department_name | varchar(8) | NO | | NULL | |
| profile_pic | text | NO | | NULL | |
| designation | text | NO | | NULL | |
| doj | date | NO | | NULL | |
| email | text | NO | | NULL | |
| highest_qualification | varchar(10) | YES | | NULL | |
| industrial_exp_yr | smallint(6) | YES | | NULL | |
| industrial_exp_month | smallint(6) | YES | | NULL | |
| teaching_exp_yr | smallint(6) | YES | | NULL | |
| teaching_exp_month | smallint(6) | YES | | NULL | |
| area_of_interest | text | NO | | NULL | |
| national_pub | smallint(6) | YES | | NULL | |
| international_pub | smallint(6) | YES | | NULL | |
+-----------------------+-------------+------+-----+---------+-------+
16 rows in set (0.01 sec)
The Function:
public function add_faculty($f_name, $f_department, $f_pic, $f_designation, $f_email, $f_doj, $f_qualification, $f_iExp_yr, $f_iExp_mth, $f_tExp_yr, $f_tExp_mth, $f_lPub, $f_iPub, $f_interest) {
try {
$facul_id = $this -> get_facultyID();
$dept_id = $this -> get_DeptID($f_department);
$db = new PDO(DB_CONN, DB_USER, DB_PASS);
$db -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db -> setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$query = "insert into faculty (faculty_id , faculty_name , department_id , department_name ,profile_pic , designation , doj , email , highest_qualification , industrial_exp_yr ,industrial_exp_month , teaching_exp_yr , teaching_exp_month ,
area_of_interest , national_pub , international_pub) values (:facul_id , :f_name , :dept_id , :dept_name , :f_pic , :f_designation , :f_doj , :f_email , :f_qualification , f_iyr ,:f_imth , :ftyr , :ftmth , :finterest , :flpub , :fipub);";
$stmt = $db -> prepare($query);
$stmt -> bindParam(':facul_id', $facul_id, PDO::PARAM_STR);
$stmt -> bindParam(':f_name', $f_name, PDO::PARAM_STR);
$stmt -> bindParam(':dept_id', $dept_id, PDO::PARAM_STR);
$stmt -> bindParam(':dept_name', $f_department, PDO::PARAM_STR);
$stmt -> bindParam(':f_pic', $f_pic, PDO::PARAM_STR);
$stmt -> bindParam(':f_designation', $f_designation, PDO::PARAM_STR);
$stmt -> bindParam(':f_doj', $f_doj, PDO::PARAM_STR);
$stmt -> bindParam(':f_email', $f_email, PDO::PARAM_STR);
$stmt -> bindParam(':f_qualification', $f_qualification, PDO::PARAM_STR);
$stmt -> bindParam(':f_iyr', $f_iExp_yr, PDO::PARAM_INT);
$stmt -> bindParam(':f_imth', $f_iExp_mth, PDO::PARAM_INT);
$stmt -> bindParam(':f_tyr', $f_tExp_yr, PDO::PARAM_INT);
$stmt -> bindParam(':f_tmth', $f_tExp_mth, PDO::PARAM_INT);
$stmt -> bindParam(':finterest', $f_interest, PDO::PARAM_STR);
$stmt -> bindParam(':flpub', $f_lPub, PDO::PARAM_INT);
$stmt -> bindParam(':fipub', $f_iPub, PDO::PARAM_INT);
$stmt -> execute();
if ($stmt -> rowCount() > 0) {
$utils = new utils();
$admin_id = $utils -> session_user_id();
$utils -> log_admin($admin_id, "New faculty Profile Created - " .$f_name);
return true;
} else {
return false;
}
} catch (PDOException $ex) {
echo $ex -> getMessage();
//utils::log_error($ex -> getMessage());
}
}
Please help me figure out the error. I have been onto it for a few hours now. I know it might be something silly which I am not able to spot. Please let me know if you require any more details about this.
You have
:ftyr , :ftmth
in your query but set
$stmt -> bindParam(':f_tyr', $f_tExp_yr, PDO::PARAM_INT);
$stmt -> bindParam(':f_tmth', $f_tExp_mth, PDO::PARAM_INT);
in your code.
This results in that these parameters have no value.
You forgot : before the f_iyr param in your statement.
$query = "insert into faculty (faculty_id , faculty_name , department_id , department_name ,profile_pic , designation , doj , email , highest_qualification , industrial_exp_yr ,industrial_exp_month , teaching_exp_yr , teaching_exp_month ,
area_of_interest , national_pub , international_pub) values (:facul_id , :f_name , :dept_id , :dept_name , :f_pic , :f_designation , :f_doj , :f_email , :f_qualification , :f_iyr ,:f_imth , :ftyr , :ftmth , :finterest , :flpub , :fipub);";
in addition :ftyr, :ftmth is not set

PDO inserts an id as 0 for some reason

So I wrote this method, for my chrome plugin (which does an ajax request to run this method), and when it runs, file_put_contents shows an id of what ever was inserted, but then when it gets to the insert ignore into songs, it puts in 0 for the artist_id. I have no idea why... Can someone help my find the part where I am going wrong?
<?php
public function saveLyrics($artist, $title, $lyric){
$this->db->query("insert ignore into artists (artist_name) value (:artist)", array("artist" => $artist));
$artist_id = (int)$this->db->insertID();
file_put_contents(__DIR__ . "/../process/page", "artist id: $artist_id");
//return;
if($artist_id == 0){
$artist_id = (int)$this->db->getOne("select artist_id from artists where artist_name = :artist", array("artist" => $artist));
}
if($artist_id == 0){
return false;
}
$this->db->query("insert ignore into songs (artist_id, song_name) values (:aid, :title)", array("aid" => $artist_id, "title" => $title));
$song_id = (int)$this->db->insertID();
if($song_id == 0){
$song_id = (int)$this->db->getOne("select song_id from songs where artist_id = aid and song_name = :title", array("aid" => $artist_id, "title" => $title));
}
}
PDO Wrapper:
<?php
/**
* #property PDO $pdo Description
* #property PDOStatement $sql Description
*/
class DB{
protected $sql = null;
protected $pdo = null;
public function connect(){
$this->pdo = new PDO("mysql:dbname=envne;host=xxx", "xxx", "xxx");
}
public function query($query, $params = array()){
if($this->pdo === null){
$this->connect();
}
$this->sql = $this->pdo->prepare($query);
foreach($params as $key => $value){
$this->sql->bindParam($key, $value);
}
$this->sql->execute();
if(!$this->sql)
return false;
return true;
}
public function insertID(){
return (int)$this->pdo->lastInsertId();
}
public function getAll($query, $params = array()){
$this->query($query, $params);
return $this->sql->fetchAll();
}
public function getOne($query, $params = array()){
$this->query($query, $params);
return $this->sql->fetchColumn();
}
}
Artists:
mysql> describe artists;
+-------------+------------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+-------------------+----------------+
| artist_id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| artist_name | char(50) | YES | UNI | NULL | |
| add_date | timestamp | YES | | CURRENT_TIMESTAMP | |
+-------------+------------------+------+-----+-------------------+----------------+
3 rows in set (0.00 sec)
Songs:
mysql> describe songs;
+------------+------------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+-------------------+----------------+
| song_id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| artist_id | int(11) unsigned | YES | MUL | NULL | |
| album_id | int(11) | YES | MUL | NULL | |
| song_name | char(50) | YES | | NULL | |
| track_id | int(11) | YES | | NULL | |
| date_added | timestamp | NO | | CURRENT_TIMESTAMP | |
+------------+------------------+------+-----+-------------------+----------------+
6 rows in set (0.01 sec)
I just decided to put the Id directly into the query, and that works.
$artist_id = (int)$this->db->insertID();
$this->db->query("insert ignore into songs (artist_id, song_name) values ($artist_id, :title)", array("title" => $title));
Another way that works is using a question mark instead
$artist_id = (int)$this->db->insertID();
$this->db->query("insert ignore into songs (artist_id, song_name) values (?, ?)", array($artist_id, $title));
I just had the same problem : new inserted items get an id of 0 even though the ID field is set to AUTO_INCRIMENT.
The solution I found is very similar to yours. Using your code this is what we get :
$this->db->query("insert ignore into songs (artist_id, song_name) values (LAST_INSERT_ID(), :title)", array("title" => $title));
As you can see, I replaced $artist_id = (int)$this->db->insertID(); and $artist_id with SQL function LAST_INSERT_ID().
I hope this can help someone someday :)
You're placeholders are incorrectly defined: (You're missing the colons)
I would do something like this:
public function saveLyrics($artist, $title, $lyric){
$this->db->query("insert ignore into artists (artist_name) value (:artist)", array(":artist" => $artist));
$artist_id = (int)$this->db->insertID();
file_put_contents(__DIR__ . "/../process/page", "artist id: $artist_id");
//return;
if($artist_id == 0){
$artist_id = (int)$this->db->getOne("select artist_id from artists where artist_name = :artist", array(":artist" => $artist));
return false;
}
$this->db->query("insert ignore into songs (artist_id, song_name) values (:aid, :title)", array(":aid"=>$artist_id, ":title"=>$title));
$song_id = (int)$this->db->insertID();
if($song_id == 0){
$song_id = (int)$this->db->getOne("select song_id from songs where artist_id = :aid and song_name = :title", array(":aid"=>$artist_id, ":title"=>$title));
}
}
Taking a look at your PDO-wrapper you have this code:
if(!$this->sql)
return false;
Because of this you would never notice an actual error. I guess the error is about the placeholder in this case.
(If $this->db->query("insert ignore into songs (... fails $song_id would just be false if there is an error when executing the query).
Use exceptions instead and catch the errors, that would be better.
I also noticed that:
$song_id = (int)$this->db->insertID();
would cast the value twice, first in above code and then in the actual function insertID() in the PDO-Wrapper. Maybe this is an issue also to consider.

Categories