PHP displaying links based on user permissions? - php

I'm trying to show or not show links based on a users access level. The links will be different depending on the section of the site the user might be in. The links also may not all be in one menu. They will more than likely be in various places on the page.
Currently I have a database table that contains Users, Groups and Sections. The main menu is built from the Sections database table. I'm thinking I should create an Actions table and add a link that I'd like to show for each section in the action menu. So, my tables so far are like.
Users
user_id
Groups
group_id
group_title
Sections
section_id
section_title
Table I'm thinking of adding.
Actions
action_id
action_title
action_group_id
action_section_id
The part I'm not sure on is should I add the same link multiple times to the Actions table for each group that is allowed access. Or, just add it once and do a if group id is greater than, then show link.
Example for entering the same link multiple times.
action_id action_title action_group_id action_section_id
1 View all 1 1
2 View all 2 1
3 View all 3 1
I was hoping to not flood the page with a bunch of if/then statements. Plus, this doesn't seem like the best way to handle because it requires human interpretation as to what the access levels stand for.
Any help on this is appreciated. I could be going in the complete wrong direction here?

Create a many to many relationship with an additional table where you insert an entry for each permission the group has access to. Am I correct in assuming section is what you're creating permission to?
Table: Group_Section (Or whatever you'd like to name it)
Group_id | Section_ID
---------+-----------
1 | 1
1 | 2
1 | 3
2 | 1
2 | 3
|
You can see that the Group with ID = 1 can access sections 1,2,3 while Group with ID = 2 can access only 1,3. You can then add whatever permissions to the table you want and manage them through the use of foreign keys.
Does that make sense?

Here is a good article but the things are discussed in general http://en.wikipedia.org/wiki/Access_controlenter link description here
In your case, use what TheCapn wrote and I'll just add, that its 'best to start session for every user and just check his access level when he's trying to reach a restricted part.

Personnaly, to do this kind of thing, i set a user level in the user table and a section level in the section table.
Then you simply have to filter the section according to your user level.
You can do this by adding a statemtn to you sql like
AND section_level >= "user_level";
or then again, get all the section and filter tham with php.
foreach($section as $s){
if ($s->level >= user_level) echo $s->title
}
Of course, you'll need to adjust the <. = and > according to the hierachy of your system.
I personnaly use a lowering hierachy, meaning, the lower the level you are the more right you have. This way you can make a 'banned' user by setting his level to 99 or something.
THis would be only for your menus, make sure you control the user_level on each page as well so if someone get to the page directly it get kicked..
Hope it points your in the right direction. ;)

Related

Structuring page counter MYSQLI database

I'm going to be building a page counter for a site to determine views of different pages. Basically, I have users that I'd like to track with respect to page views of about 120 specific pages.
I'm having trouble determining the most efficient way to do this as well as the logic behind it. I was trying 3 tables, but this would end up in many unnecessary rows. I thought storing an array in a single field then updating the array, but I'm not sure this will grow or if it is even possible. Below is my way of limiting the number of requests. Basically every 100 will count 100. Any ideas for structuring this?
$sample_rate = 100;
if(mt_rand(1,$sample_rate) == 1) {
//update set query
}
Based on our conversation in the comments I would recommend the following simple design:
TblPages
--------
Page_Id (pk)
Page_URL (unique)
TblViews
--------
View_Page_Id
View_User_Id
View_Count
(pk is View_Page_Id + View_User_Id)
Whenever a user views a page, you execute a stored procedure that will either insert a record to the TblViews table if there is no record for that user and page, or update the View_Count of the existing record.
To get all the views for a page you use SUM(View_Count) and group by View_Page_Id, to get all the page views by a user you group by View_User_Id, etc.

SQL boolean relationship

I have a table dislikes which contains two columns, idone and idtwo.
These are unique ids' from users, for example:
| idone | idtwo |
-----------------
| 5 | 4 |
This means that user with id=5 does not like user with id=4. What I have in PHP is an array containing the ids' of all the users that the current user has selected as not liking them.
So say dislikes={1,2,3}, this means that the current user does not like user 1,2, or 3. There is an unknown number of users in the database.
So if user 1 chooses to dislike user 2 and user 3 (this is done via HTML dropdown), I pass dislike={2,3} to a PHP page which processes this data.
I want the PHP page to then add entries (1,2) and (1,3). Here is the first problem, how can I make sure only to add unique entries?
Also say that user 1 changes the fact that he dislikes user 2. Then I pass dislike={3} to the php page and must somehow remove all entries (1,!3), i.e. all entries in which user 1 dislikes anyone except user 3. How can I achieve this? Or is there a better way?
Since you're using MySQL the easiest thing is probably to use REPLACE INTO instead of INSERT with a primary key or unique index on the pair of columns (idone, idtwo).
Alternatively, on update, you can run a transaction that does any one of:
Remove existing rows for this user, add all rows, commit
Select existing rows, remove the rows from your local set that you would duplicate, add only new rows, commit

Database Schema for News System

I have a news system I'm designing, and it seemed straight-forward at first, but as I've pushed forward with my planned schema I've hit problems... Clearly I haven't thought it through. Can anyone help?
The system requires that the latest 20 news articles be grabbed from the database. It's blog-like in this way. Each article can have sub-articles (usually around 3) that can be accessed from the parent article. The sub-articles are only ever visible when the parent article is visible -- they're not used elsewhere.
The client needs to be able to hide/display news articles (easy), but also change their order, if they desire (harder).
I initially stored the sub-articles in a separate table, but then I realised that the fields were essentially the same: Headline, Copy, Image. So why not just put them all in one big table?
Now I've hit other problems around the ordering. It's Friday evening and my head hurts!
Can anyone offer advice?
Thanks.
Update: People have asked to see my "existing" schema:
articleID *
headline
copy
imageURL
visible
pageOrder
subArticleID *
articleID
headline
copy
imageURL
visible
pageNumber
pageOrder
Will this work? How would I go about letting users change the order? It seemed the wrong way to do it, to me, so I threw this out.
I initially stored the sub-articles in a separate table, but then I realised that the fields were essentially the same: Headline, Copy, Image. So why not just put them all in one big table?
Because referential integrities are not the same.
That is, of course, if you want to restrict the tree to exactly 2 levels. If you want more general data model (even if that means later restricting it at the application level), then go ahead and make a general tree.
This would probably look something like this:
Note how both PARENT_ARTICLE_ID and ORDER are NULL-able (so you can represent a root) and how both comprise the UNIQUE constraint denoted by U1 in the diagram above (so no two articles can be ambiguously ordered under the same parent).
Based on what you've described. I would use two tables. The first table would hold all the articles and sub-articles. The second would tie the articles to their sub-articles.
The first table (call it articles) might have these columns:
+-----------+----------+------+----------+---------+------------+-----------+
| articleID | headline | copy | imageURL | visible | pageNumber | pageOrder |
+-----------+----------+------+----------+---------+------------+-----------+
The second table (call it articleRelationships) might have these columns:
+-----------------+----------------+
| parentArticleID | childArticleID |
+-----------------+----------------+
Not sure if you already accomplish this with the pageNumber column, but if not, you could add a column for something like articleLevel and give it something like a 1 for main articles, 2 for sub-articles of the main one, 3 for sub-articles of a level 2 article, etc. So that way, when selecting the latest 20 articles to be grabbed, you just select from the table where articleLevel = 1.
I'm thinking it would probably also be useful to store a date/time with each article so that you can order by that. As far as any other ordering goes, you'll have to clarify more on that for me to be more help there.
To display them for the user, I would use AJAX. I would first display the latest 20 main articles on the screen, then when the user chooses to view the sub-articles for a particular article, use AJAX to call the database and do a query like this:
SELECT a.articleID, a.headline
FROM articles a
INNER JOIN articleRelationships ar ON a.articleID = ar.childArticleID
WHERE ar.parentArticleID = ? /* ? is the articleID that the user clicked */
ORDER BY articleID
The client needs to be able to hide/display news articles (easy), but
also change their order, if they desire (harder).
On this particular point, you'll need to store client-specific ordering in a table. Exactly how you do this will depend, in part, on how you choose to deal with articles and subarticles. Something along these lines will work for articles.
client_id article_id article_order
--
1 1067 1
1 2340 2
1 87 3
...
You'll probably need to make some adjustments to the table and column names.
create table client_article_order (
client_id integer not null,
article_id integer not null,
article_order integer not null,
primary key (client_id, article_id),
foreign key (client_id) references clients (client_id) on delete cascade,
foreign key (article_id) references articles (article_id) on delete cascade
) engine = innodb;
Although I made article_order an integer, you can make a good case for using other data types instead. You could use float, double, or even varchar(n). Reordering can be troublesome.
If you don't need the client id, you can store the article ordering in the article's table.
But this is sounding more and more like the kind of thing Drupal and Wordpress do right out of the box. Is there a compelling reason to reinvent this wheel?
Create a new field in news(article) table "parent" which will contain news id of parent article. This new field will be used as a connection between articles and sub articles.
As SlideID "owns" SubSlideID, I would use a composite primary key for the second table.
PrimaryKey: slideID, subSlideID
Other index: slideID, pageNumber, pageOrder (Or however they get displayed)
One blog post I prefer to point out about this is http://weblogs.sqlteam.com/jeffs/archive/2007/08/23/composite_primary_keys.aspx as it explains why very nicely.
If you're replying on Auto_Increment, that can be handled too (with MyISAM tables), you can still set subSlideID to auto_increment.
If you're likely to go to a third level then merge - follow Branko above. But it does start to get very complicated, so keep separate for 2 layers only.

Privacy in simple DB system

I am implementing a simple database system. Basically is a simple social network, everyone has his own dashboard, where you can post some random text. The problem is that I want a privacy level, I mean I want that somebody is allowed to browse only some profiles. And I'm deciding who can watch what.
The question is: How can I do that?I have to work with relation in the database or what?
Thanks for your time.
S.
What you are looking for is called "Access Control List" (ACL): Check out Nettuts tutorial on implementing an ACL: http://net.tutsplus.com/tutorials/php/a-better-login-system/
Create a secondary table where you keep who can access what. If in the main user table you have and id or something (preferably indexed) (like you should). Just make a 2 column table with id and view_id or something (both foreign keys and togeder should form a pk). And... you read from it.
Most probably you would want to set a table for your privacy like
id type
1 View All
2 View None
3 View Something
then on your table where users can be found you could call the type
user_id privacy_id
1 2
2 3
4 1
where privacy_id is the id of your privacy table, something like that.

Building Breadcrumbs in MySQL

I have a table that defines the possible categories in my website - fields look something like this:
- id
- name
- parentID
The information is stored something like this:
+-----+------+----------+
| id | name | parentID |
+-----+------+----------+
| 1 | pets | 0 |
+-----+------+----------+
| 2 | cats | 1 |
+-----+------+----------+
| 3 | dogs | 1 |
+-----+------+----------+
A parentID of 0 indicates that the category/page is on the home level. I'm looking for a way to quickly and easily generate the parent categories.
The first method that came to mind was a series of SQL queries, but I quickly realised that this would be insidiously resource intensive the more complicated the site got.
Reading through the mysql manual, I've seen that mysql can use loops and conditional statements, however I'm unsure how I'd put those into practice here.
Ideally, I'd like to have a single query that pulls up all directly related parent elements.
If I were looking at the Pets category, I would only see home because it's on the top level. As soon as I drill down (either into cats, dogs or a page under pets) then I should see pets on the bar - the same goes for subsequent child categories and pages.
What's the most efficient way to generate a list of categories using information stored in this fashion? If this question requires more clarification, please ask, and I will do my best to provide more information.
Clarification: This is part of a CMS - and as such, users are going to need the ability to make changes to categories on the fly. I've looked at several data storage schemes (such as nested sets) and they do not appear to lend themselves well to a simple form for making changes to navigation.
As such, any method needs to be easily a) understood by a user, and b) implemented easily to a user.
The categories are best described as folders on a PC, rather than tags. When you view any given category, you can see the immediate children of that category, as well as immediate child pages.
When you view a category or a page, the parent categories (but not itself are visible).
Example: I have German Shepard which resides under dogs which is under pets
When viewing *pets*: Home
When viewing *dogs*: Home -> Pets
When viewing *German Shepard*: Home -> Pets -> Dogs
Consider using "nested sets" model instead: Managing Hierarchical Data in MySQL.
Update (based on clarification to the question): The nested sets model does not have to be (in fact I have a pretty hard time imagining why would it be) exposed to end users. All directory-style operations (adding a new folder / subfolder; moving folder to a different path, etc...) can be supported in nested sets model, though some are a bit harder to implement then others. The article I've linked to provides examples for both adding and deleting of (sub)folder.
Could you have a stack or ordered set (ordered by how the user applied filters to their browsing) containing your breadcrumb, stored on the session?
I could see it getting grim when you started cross-querying, but sometimes data isn't hierarchical, but more of a soup of tags, and the above starts being your tag-soup clarification breadcrumb.
Most websites don't actually feature good (or any) tag soup drilling down. E.g., how many times have you been look at the sale CDs on a website, and wanted to drill down to just see the Metal CDs (for example), but clicking on the "Rock and Metal" link on the left took out to the top level metal category, instead of acting as a filter on your current browsing state.
So - is your problem actually a tag soup that you're applying a false hierarchy onto? Should you in fact be looking at automatic tag generation libraries that you can pass your items into, and tag lookup mechanisms? Okay, I'm sure your personal website won't be complex enough to ever require tag search, but in general terms, I think it is worth thinking about.

Categories