PDO multiple checkboxs inserting or delete - php

I need help to link between three tables by checkboxe:
features table ( id, title, sulg )
posts table (id, title, slug, added )
posts_features ( fea_id, post_id )
<input type="text" name="title" value="$post->title">
<input type="text" name="slug" value="$post->slug">
// importing all features
<input type="checkbox" name="featuresid[]" value="$features->id">
If checked ( insert ) if not exist.
foreach ($_POST['featuresid'] as $choice) {
$sql = $dbh->prepare("INSERT INTO posts_features (fea_id, post_id) VALUES ($choice, $id)");
$sql->execute();
}
and if un-checked ( delete ) from posts_features
$sql = $dbh->prepare("delete form posts_features where ........
Thanks in advance.

A checkbox doesn't $_POST if it's not checked, so you would not have a way to see (from the $_POST, anyway) which features where not checked.
There's several ways to do this, but without more information about your application, it's hard to make the "best" suggestion, but here's one method that will leverage $_POST:
Add an additional "hidden" input, with the corresponding $features->id, to set up the "existing" entries:
Note: I'm following your conventions in your code above to demonstrate this, even though they are clearly pseudo-code, and won't work properly.
<input type="checkbox" name="featuresid[]" value="$features->id">
<input type="hidden" name="existing[]" value="$features->id">
Then, you can leverage your loop like so:
foreach ($_POST['featuresid'] as $choice) {
$sql = $dbh->prepare("INSERT INTO posts_features (fea_id, post_id) VALUES ($choice, $id)");
$sql->execute();
}
// loop through ALL feature ids listed on the page
foreach( $_POST['existing'] AS $features_id ) {
// if the feature id wasn't in the checkboxes, then delete
if ( ! in_array( $features_id, $_POST['featuresid'] ) ) {
$sql = $dbh->prepare("DELETE FROM posts_features WHERE ........");
}
}

Un-checked checkboxes are not sent to PHP. So as you iterate through $_POST['featuresid'], you will only see the checkboxes that were checked. This means that to delete unchecked features really means to delete all features that are not in the checked group.
First, insert the selected features: important don't execute DB queries in a loop; they will really slow down your script. Instead, insert all records at once. You should also use parameterized queries; never insert user-supplied values directly into your DB queries!
After the insert, delete those features that were not selected:
DELETE FROM posts_features WHERE fea_id NOT IN (?, ?, ?, ?)
Each of the ? corresponds to a value in $_POST['featuresid']
An alternative, if you want PHP to receive an explicit selected/unselected value for each feature is to use Yes/No radio buttons or dropdown list for each feature in the HTML.

Related

Problem with query to update foreign key column

I am working on a cms for properties/ads in oop php for learning purposes. I have three tables that are connected with pivot table.
photos (id, name, extension),
property_photo (id, property_id, photo_id),
properties (id, title, description, main_photo_id)
I have a gallery of photos for every property and I am trying to be able to insert main photo (one of existing photos in gallery) for each property through foreign key (main_photo_id) and display that photo on a different page. I am having trouble writing function (query) in model. Any help is much appreciated. Here is some of my code:
AdModel:
public function MainPhotoInsert($id)
{
$this->db->query('INSERT INTO properties (main_photo_id) VALUES (:main_photo_id) SELECT id FROM PHOTOS WHERE id = :id LIMIT 1');
$this->db->bind(':id', $id);
$row = $this->db->single();
return $row;
}
AdsController:
public function galleryAction()
{
if (!isset($_GET['id'])) {
$photo_id = $_SESSION['photo_id'];
} else {
$photo_id = $_GET['id'];
}
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
if(isset($_POST['radio']))
{
$this->AdModel->MainPhotoInsert($photo_id);
redirect('ads/index');
}
}
$data = $this->AdModel->getPhotosForProperty($photo_id);
$data1 = $this->AdModel->MainPhotoData($photo_id);
$this->view->render('ads/gallery', $data, $data1);
}
gallery.php:
<form action="/ads/gallery?id=<?php echo $_GET['id']; ?>" method="POST">
<?php foreach ($data as $key => $value) : ?>
<img src="<?php echo '/public/photos/'.$value->name.'.'.$value->extension ?>" class="img-fluid img-thumbnail" width="250" height="250">
<input type="radio" name="radio" value="<?php echo $value->photo_id; ?>" >Make main
<br>
<?php endforeach; ?>
<br>
<br>
<button type="submit" name="submit" value="submit" class="btn btn-success form-control">Submit</button>
</form>
You shouldn't have a select clause in your insert statement (at least not for what you are trying to do). IF you only ever need to set it once then you need to tweak the query to include the other two values (title and description) or they will always be blank. It should end up looking something like this:
INSERT INTO properties (main_photo_id, title, description) VALUES (:main_photo_id, : title, : description)
More likely, you want an upsert (update if a relevant row already exists, insert if one doesn't). In MySQL the syntax is insert ... on duplicate key update. This means you are going to need a primary key on the properties table (it's unclear if you already have one). The syntax is pretty similar to the insert above but without knowing the exact structure of the table I can't give you the exact query.
Update:
The on duplicate key syntax would look something like this (it depends on how you have your primary key set up on the table, e.g. if main_photo_id is the primary key then this likely won't work):
INSERT INTO properties
(id, main_photo_id, title, description)
VALUES
(:id, :main_photo_id, : title, : description)
ON DUPLICATE KEY UPDATE
main_photo_id = :main_photo_id,
title = :title,
description = :description
Side note:
gallery.php is also going to produce a separate HTML form for each image with one radio button on the form which isn't really what you want. You should move the form to wrap around the entire foreach loop so that you have one form. Then you should put the image ID as the value for the radio button.

Storing multiple inputs in database in single query

<form method="post" action="formProcessing.php">
<input type="text" name="uses[]">
<input type="text" name="uses[]">
<input type="text" name="uses[]">
</form>
I have two database tables one called info other uses. info table contain column name inf_num, Is there a way where i can get the last row inf_num and insert the above inputs in uses in one query. For instance if i was to do it manually i would check the last row myself so if it's 10 i would do the below:
INSERT INTO uses (id, uses) VALUES (10, 'useZero'), (10, 'useOne'), (10, 'useTwo');
How would i go about doing it dynamically with php using the above form:
you can create trigger on uses table to set last inserted id of info table.
CREATE TRIGGER uses_before_insert_trigger BEFORE INSERT ON `uses` FOR EACH ROW
BEGIN
SET NEW.id = (select id from info order by id desc LIMIT 1);
END
After, create trigger you can execute insert query directly.
INSERT INTO uses (uses) VALUES ('10'),('20'),('26');
INSERT INTO user( id, uses )
SELECT MAX(id), 'userOne' FROM info
UNION ALL
SELECT MAX(id), 'userTwo' FROM info;
Try To Make A Query Like This
<?php
//Your input is array of your input.
$yourInput = array(10,20,26);
$query = "INSERT INTO uses (id, uses) VALUES ";
foreach($yourInput as $value ){
$query .= "(10, '$value')".",";
}
echo $query;
//Output
INSERT INTO uses (id, uses) VALUES (10, '10'),(10, '20'),(10, '26')
Tested Here
Than Execute this Query
But Remember Youe code is not secure. it is possible to do a sql injection so kindly read this note. and make it more secure.
We can make it possible via query as well.
INSERT INTO uses( id, uses ) VALUES ((SELECT MAX(inf_num) from info),
'useOne', (SELECT MAX(inf_num) from info), 'useTwo', (SELECT MAX(inf_num) from
info), 'useThree')

Send delimited string via JSON to PHP for prepared statements

For example i send the following id:
$user->id = '1{3}4{5}6';
Represents:
$user->id(=1{3}4{5}6){$option(=3)}$value(=4){$option(=5)}$value(=6)
I now need to insert to database using prepared statements for each $option and $value pair.
the sql looks as following:
if ($user->attr == 1) {
$sth = $this->dbh->prepare("insert into customers_basket_attributes
(customers_id,
products_id,
products_options_id,
products_options_value_id)
values ('1', ?, ?, ?)");
$sth->execute(array($user->id, $option, $value));
return json_encode(1);
}
I want to avoid falling back to jQuery for each db insertion.
as far as I understand, this $user->id = '1{3}4{5}6'; decomposes:
Product_id = 1
Option_3 = 4
Option_5 = 6
and you want to store that in to records like:
products_id products_options_id products_options_value_id
1 3 4
1 5 6
From my point of view, you basically need as much inserts as you have rows above. You may combine that in to one insert with multiple rows:
insert into customers_basket_attributes
(customers_id,
products_id,
products_options_id,
products_options_value_id)
values (nn, 1,3,4),(nn, 1,5,6)
putting this into a prepared statement is somehow fiddling around with arrays, but should be achievable. Probably its clearer to just issue one insert per row, the cost is marginal anyway.

Insert Muliple Rows in Categories Cross Table but with same Auto Increment ID

I am an amateur hobbying a video site, where users can submit video urls. Everything works, but now I want multiple categories to be able to be selected for one same video. Categories are stored in seperate tables. I am sure you will understand from the code:
mysql_query("INSERT INTO videos
(title, source, thumb_large, author, email_by) VALUES('$title', '$video_url', '$thumb_url', '$author', '$email') ") or die(mysql_error());
mysql_query("INSERT INTO videos_categories
(category_id) VALUES('$category_name_id') ") or die(mysql_error());
What I want to do is to add another category for the same video ID the tables are both on AUTO INCREMENT synced with each other at the moment:
mysql_query("INSERT INTO videos_categories (category_id) VALUES('$category_name_id_two') ") or die(mysql_error());
The variable is currently registered as:
$category_name_id = mysql_real_escape_string(htmlspecialchars($_POST['category_id']));
And is currently selected through dropdown (select with name: category_id) and it works fine. However, I want to change this ofcourse into select boxes, so mulitple, or upto 3 categories can be selected, instead of having 3 dropdown menus.
I hope you can help me out with this, I am stuck here.
Edit:
I wanted to add that there are three tables, one from which categories are retrieved, one that stores the video_id+category_id which should make at possible to have multiple categories per video, and one with the videos.
Thanks
So you need to change the select box to something like this:
<select name="category_id[]" multiple="multiple">
<!-- Options -->
</select>
...
In backend, After this query:
mysql_query("INSERT INTO videos
(title, source, thumb_large, author, email_by) VALUES('$title', '$video_url',
'$thumb_url', '$author', '$email') ") or die(mysql_error());
Do:
$video_id = mysql_insert_id();
$categories = $_POST['category_id'];
$values = '';
foreach($categories as $category_id) {
$values .= "('$video_id', '$category_id'),";
}
$values = rtrim($values, ',');
$query = "INSERT INTO videos_categories(video_id,category_id) VALUES $values";
mysql_query($query);
Few Suggestions:
Since mysql_* apis are deprecated, please don't use them. Switch to mysqli.
Do the validation and sanitization of the data before using in sql queires.

How to dynamically update tables in PHP

I'm building an application where users can add, edit and delete users from the database.
I've done the 'View Users' ( Select statement returning joined tables ) and the 'Add Users' ( Returns a form for user to fill in and INSERTS into database after validation of course )
But I'm having trouble with the 'Edit Users'.
My Edit form is the SAME as the add form but the values for the text boxes are filled in with values from the database.
Upon submit, the logic checks for mismatches between the user input and the database values (So we know what we're actually updating in the database)
So I end up with an array of all the values that need to be changed, example:
$values_to_update = array (
"telephone" => "07788991010"
"email_address" => "my_new_email_address#host.com"
);
The values in this array are dynamic and I need to thing of a way to dynamically update each field.
Also, the fields may also come from different tables.
I DON'T want to do:
if ( isset ( $values_to_update[ "telephone" ] ) )
$database->update("UPDATE users SET telephone = '{$values_to_update[ "telephone" ]}' WHERE user_id = $user_id");
else if ( isset ( $values_to_update[ "email_address" ] ) )
$database->update("UPDATE authentication SET email_address = '{$values_to_update[ "email_address" ]}' WHERE user_id = $user_id");
else if ( /* ... */)
// etc etc etc
Does anybody have any ideas of a better way I could do this?
I was thinking maybe I could use one HUGE update statement uses the same select statment that fetches the data. but i dont know how this would work.
Is it a standard practise for applications to store an array of fields to tables for dynamic query generation?
A clean way I've found of doing this in PDO-style ORM mappers (which is also used in Zend Framework):
public function save($model) {
// Possible values to insert
$values = array(
":id" => $model->id,
":name" => $model->name,
//...
":contact_number" => $model->telephone
);
// If model id is set, we are updating a record, otherwise inserting
if (isset($model->id)) {
$sql = "UPDATE tbl SET name = :name, ..., contact_number = :contact_number WHERE id = :id LIMIT 1";
} else {
// Don't pass the ID when it isn't in the query
unset($values[":id"]);
$sql = "INSERT INTO tbl (name, ..., contact_number) VALUES (:name, ..., :contact_number)";
}
// Execute the query with our values (below is a PDO example)
$stmt = $this->db->prepare($sql);
$stmt->execute($values);
$stmt->closeCursor();
// Get the new ID if we inserted
if (!isset($model->id)) {
$model->id = $this->db->lastInsertId();
}
return $model;
}
Usually this amounts to writing a single save method for each model. You could extend this in UPDATE situations by keeping a copy of the originally-retrieved model, so that you only update the columns that have changed, however I don't see any huge overhead by updating all columns.

Categories