Best way to set permissions for a user - php

(Using PHP + mySQL)
I'm hoping someone can give me an idea as to the best way to handle this situation.
I have two tables, users and forms. The users table holds username, password, name, etc. and then the forms table holds various different html forms.
I want to specify which forms a user has access to, on a per user basis. I was thinking about creating a new field in the users table which would be 'forms_allowed' and then storing the form_id of each form the user is allowed to access, separated by commas. Something like 3,6,8,15
Then when I want to check what forms the user is allowed to access and whether they can access the form requested (etc.) i'd grab that field, explode it and check for the form_id.
This seems like a hassle and ineffective way of doing it. Does anyone have a better idea?
Thanks!

Create another table that will hold user_id and form_id pair. This is many-many relationship.
tblUsers:
user_id | name |...
tblForms
form_id | content | ...
tblRelation:
user_id | form_id
So you can simply get info with single query:
SELECT * FROM `tblUsers` AS `t`
JOIN `tblRelation` as `r` ON (t.user_id = r.user_id)
JOIN `tblForms` as `f` ON (f.form_id = r.form_id)

Related

PHP MySQL UPDATE join tables

I have seen that there are similar questions, but they do not seem to be helping...could just be that I am not understanding correctly and able to translate their examples to my needs. Any help is appreciated.
I am trying to convert an input field on a $_POST form to my users table, specifically on the managers key, from the managers name (in the form), to the managers id (in the DB). Let me show an example.
Our DB has (among other tables) a users table and a managers name. The managers table just has the manager's id, first & last name. The users table has their own id, first_name, last_name, and associated manager id. This is how it looks:
MANAGERS
id first_name last_name
1 John Doe
2 Mary Lewis
USERS
id first_name last_name manager
1 Steve Thompson 1
I have created an edit form for the users table where this information is inputted from the database, but I have joined the two tables in my SELECT statement so that instead of the managers.id showing, it actually shows the managers.first_name and managers.last_name in the form.
So what I am trying to do is allow someone to edit the manager associated with a user, by submitting their name instead of the ID, but in the DB it associates it back to the ID. We have many managers so most people don't know what their ID in the DB is. However, they all know their names. So is it possible to have an SQL UPDATE query to achieve:
As you can see, the User Steve Thompson has manager 1 (John Doe), but the manager of this user needs to be changed to Mary Lewis. How can I enter the name 'Mary Lewis' into the Users Edit Form, and have it update the DB table using the manager's name instead of the manager's id.
I have seen people say you can't update multiple tables in one query, but I feel this is a little different as it is more like a JOIN, but I am unsure how to do it. Does anybody know if this is possible?
EDIT
I have seen this one and feel it might help...but not sure how to implement correctly. Perhaps this can help someone as well?
Update one MySQL table with values from another
After you managed to parse the managers name and split it to first and last name you can just select the managers id in a subselect
update USERS set
first_name = :user_first_name,
last_name = :user_last_name,
manager = (
select id
from MANAGERS
where first_name = :manager_first_name
and last_name = :manager_last_name
)
where id = :user_id
You can also use a (CROSS) JOIN:
update USERS u
cross join MANAGERS m
set
u.first_name = :user_first_name,
u.last_name = :user_last_name,
u.manager = m.id,
where u.id = :user_id
and m.first_name = :manager_first_name
and m.last_name = :manager_last_name
Note that it won't work if the managers name is not unique. It will also not work if no manager with that name exists.
However i would probably use a drop down selection with the managers id as value. You still can display the first and last name:
<select name="manager">
<option value="1">John Doe</option>
<option value="2">Mary Lewis</option>
</select>
This way you will display the name but get the ID on submit.

Change REPLACE SQL function in PHP to remove a contact

I recently cleaned up my web app's code. My web app is a simple social network with Add,Remove,etc procedures. I have a php file which I call when a user want to remove a contact from his friend list.
I came up with a strange bug in my application that I haven't estimate the time I wrote it.
The Bug
Let's say we have two friend emails in our list.
georgeMARK#email.com
MARK#email.com
The contact emails are stored in a MYSQL DB column with name Contacts and every email is separated by a semicolon (;) symbol. So our example's column will look like this (depend on which user has added lastly it can be vice versa):
georgeMARK#email.com;MARK#email.com;
So assume that our user wants to remove MARK from his contacts. He presses the button and ... both email's have gone.!
Have a look in my PHPMyAdmin Panel I found that what has left from the column is this:
george
The problem is in my PDO SQL statement that I use to remove accounts from my column.
$STH = $DHB->prepare("UPDATE `Users` SET `Contacts` = REPLACE(`Contacts`, :email, '') WHERE `UserEmail` = :my_email");
The REPLACE function just replaces all the instances of the :email and thats awful. I use the same approach many times in my application and I understand that this will cause my the same bug to appear elsewhere too.
My question is how can I delete a user's email without affecting the others 'instances'? Do I have to change my point of view and how what do I need to do?
The fast dirty way is to prepend a semicolon to all Contacts field, so that entries as like this:
;georgeMARK#email.com;MARK#email.com;
then you can replace it in this way:
$emailToDelete = ";$emailToDelete;"
... REPLACE(`Contacts`, :email, ';') ...
A better approach can be to store contacts data in a more suitable format (like JSON).
The best solution is to create a relationships table and delete all the entries relative to contact to delete.
Structure
Maybe create a structure like this:
Table Users
id | Name | Email
-----------------
1 | John | john#example.com
2 | Jane | jane#example2.com
Table Friendships
User1_id | User2_id
-------------------
1 | 2
Select users
SELECT * FROM Users WHERE name=:name
Select friends
SELECT
*
FROM
Friendships
LEFT JOIN
Users
ON
Friendships.User1_id = Users.id
WHERE
User1_id=:user_id
Delete friendship
DELETE FROM Friendships WHERE User1_id=:current_user_id AND User2_id=:friend_to_remove_id

PHP And MySQL Search Based on two fields

Alright, so I understand how to do a mysql query to return results based on one search parameter. But I have a table that contains usernames and data. The data should be unique to each username, but I want to return any instances where that data might overlap over multiple usernames. An example would be
Username | Data Field
----------------------------------------------
Test | Abcd1234
Test2 | efgh5678
Test3 | Abcd1234
Test4 | efgh5678
I want my php script to return all instances where duplicate entries are found in the data field. Note that, neither the data field nor username field are unique in this table. The table gets populated whenever the user completes an action, so there should be many entries for each username, but each time they should have the same data field. I only want to check when two different usernames have the same data field. Does anyone have any idea how this can be done in php or a mysql select statement? It may take more than one query and that is okay. I've tried searching on how to find duplicate emails based on usernames, but the results I found were more on preventing duplicate registrations in the first place.
Basically, you want to count the number of unique users for each data field. This is an aggregation query:
select data, count(distinct username) as numusers
from table t
group by data;
You should be able to get the unique user names with this query:
select data, count(distinct username) as numusers,
group_concat(distinct username) as users
from table t
group by data
having count(distinct username) > 1;
This will create a comma separated list of users "using" the same data.

Trying to find how to link three tables together

At the moment I have three tables that I am trying to connect and figure out what queries will get the results I need and also follow best practices. MySQL is still pretty new to me, and this is my first stumbling block that I can't figure out.
I am trying to build a simple URL shortener that can "link" multiple long URLs to one short URL. I basically want to have a link www.example.com/google then have google.com, google.co.uk, google.it, etc... and GEO target when the user accesses the link.
My three tables are set up as:
short_id | user_id | short_url //Short URL Table
long_id | user_id | long_url | country_code //Long URL table
user_id | name | password | email | created //User table
I am not sure if foreign keys are the best route. Also, I understand how to add a user, but what queries would I have to run to have a user add a short/long url and have the user_id field in "user" table match the user_id fields in the other tables.
Thanks for the help.
select * from short_url_table
left join long_url_table
using (user_id)
left join user_table
using (user_id) ;

I need some advice on storing data in mysql, where one needs to store more than one, let say userids for a single post?

In cases when some one needs to store more than one value in a in a cell, what approach is more desirable and advisable, storing it with delimiters or glue and exploding it into an array later for processing in the server side language of choice, for example.
$returnedFromDB = "159|160|161|162|163|164|165";
$myIdArray = explode("|",$returnedFromDB);
or as a JSON or PHP serialized array, like this.
:6:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;i:5;i:6;}
then later unserialize it into an array and work with it,
OR
have a new row for every new entry like this
postid 12 | showto 2
postid 12 | showto 3
postid 12 | showto 5
postid 12 | showto 6
postid 12 | showto 8
instead of postid 12 | showto "2|3|4|6|8|5|".
OR postid 12 | showto ":6:{i:0;i:2;i:1;i:3;i:2;i:3;i:3;i:4;i:4;i:5;i:5;i:6;}".
Thanks, looking forward to your opinions :D
In cases when some one needs to store more than one value in a in a cell, what approach is more desirable and advisable, storing it with delimiters or glue and exploding it into an array later for processing in the server side language of choice, for example.
Neither. Oh goodness, neither! Edgar F. Codd is rolling in his grave right now.
Storing delimited data in a text field is no better than storing it in a flat file. The data becomes unqueryable. Storing PHP serialized data in a text field is even worse because then only PHP can parse the data.
You want a nice, happy, normalized database.
The thing you're trying to describe is a many-to-many relationship. Each user can maintain one or more posts. Likewise, each post can be maintained by one or more user. Right? Then something like this will work.
CREATE TABLE users (
user_id INTEGER PRIMARY KEY,
...
);
CREATE TABLE posts (
post_id INTEGER PRIMARY KEY,
...
);
CREATE TABLE user_posts (
user_id INTEGER REFERENCES users(user_id),
post_id INTEGER REFERENCES posts(post_id),
UNIQUE KEY(user_id, post_id)
);
-- All posts made by user 22.
SELECT posts.*
FROM posts, user_posts
WHERE user_posts.user_id = 22
AND posts.post_id = user_posts.post_id
-- All users that worked on post 47
SELECT users.*
FROM users, user_posts
WHERE user_posts.post_id = 47
AND users.user_id = user_posts.user_id
Most of the time the recommendation is that many-to-many relationships (such as posts to users) should have a mapping table with 1 row for each post-user combination (in other words, your "new row for every new entry" version).
It's more optimal for things like join queries, and lets you retrieve only the data you need.
You should only serialize data in the DB if the data is never needed to be processed by the DB. For example, you could serialize user ID in the user_id field if you never need to do a query with the user_id field; e.g. never selecting anything based on user.
If these are posts (blog/news/etc. posts?) then I'm pretty confident you'll need to be able to query them by user. Normalizing the user into another table would serve you:
CREATE TABLE posts (post_id, ....);
CREATE TABLE post_users (post_id, user_id, ...);
You can then get the users in a different query, or use group_concat: SELECT post_id, GROUP_CONCAT(user_id) FROM posts JOIN post_users USING (post_id) GROUP BY post_id. When you need to show user name, just join to the users table to get their name in the group concat.
From RDBMS point of view i would 'have a new row for every new entry'
Thats called m:n relationship table.
You can then query the data however you like.
If you need postid 12 | showto ":6:{i:0;i:2;i:1;i:3;i:2;i:3;i:3;i:4;i:4;i:5;i:5;i:6;}". you can do
SELECT postid, CONCAT(':',count(showto),':{i:',GROUP_CONCAT(showto SEPARATOR ';i:'),';}') AS showto
FROM tablename
GROUP BY postid
However if you only need the data in 1 form and not do any other kind of queries on that data then you may aswell store the string.

Categories