SitePoint Sponsor

User Tag List

Results 1 to 23 of 23
  1. #1
    SitePoint Guru ripcurlksm's Avatar
    Join Date
    Aug 2004
    Location
    San Clemente, CA
    Posts
    859
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    My First Access Levels Script -- Rip it apart please.

    I have a simple login script that has access levels (admin, full access, limited access, etc.).

    If you log in as the user "rocker" you get two rock bands. If you log in as "hippie" you two hiippie bands. If you login as "fullaccess" you get to see all bands.

    Working demo of it is here:
    http://www.psylicyde.com/_old/bandauth/login.php

    Download source files here (4 PHP files + SQL file):
    http://www.psylicyde.com/_old/bandauth/bandauth.zip

    1) What I need help with is how to handle the access levels so that it is perhaps a global function? Please inspect my get_access function. How can it be improved and implemented better?

    2) is it possible to put the user access level, username and user id into an array WITHIN the session variable so that I can call any of the three variables ($access, $username, $u_id) from any page?

    3) The login script itself is weak, and simple, please focus on the best methods for granting access levels.

    PHP Code:
    function get_access($username,$u_id){ // get access level and act according to permissions
            
        
    dbConnect();
        
    $result mysql_query("select * from user where username='$username'");
            
        while(
    $row mysql_fetch_assoc($result)){
            
    $access  $row['access'];

             
            if(
    $access == 0){             
                
    /* 
                 * Admin access
                 *
                 */
                
    echo "<p>You are an admin.<p>";
             
            } else if(
    $access == 1){ 
                
    /* 
                 * Full access - print all rows
                 *
                 */
                
    echo "<p>You have full access.<p>";
                
    $result mysql_query("SELECT * FROM band WHERE 1=1");
                
                echo 
    "<ul>";
                while(
    $row mysql_fetch_assoc($result)){
                    
    $company  $row['company'];
                    
    $description  $row['description'];
                    echo 
    "<li>$company - $description</li>";
                }    
                echo 
    "</ul>";
            
            } else if(
    $access == 2){     
                
    /* 
                 *  Limited Access - get permissions from permissions table, print rows they are allowed to see.
                 *
                 */        
                
    echo "<p>You have limited access.<p>";
                
    $result mysql_query("SELECT b.company
                                            , b.description 
                                         FROM user as u
                                       INNER
                                         JOIN permissions as p
                                           ON p.u_id = u.u_id
                                       INNER
                                         JOIN band as b
                                           ON b.b_id = p.b_id WHERE u.u_id='
    $u_id'");
                
                echo 
    "<ul>";                           
                while(
    $row mysql_fetch_assoc($result)){
                    
    $company  $row['company'];
                    
    $description  $row['description'];
                    echo 
    "<li>$company - $description</li>";
                }                           
                echo 
    "</ul>";
                
            } else if(
    $access == 3){ 
                
    /* 
                 * Registered user - no access, but allowed to log in.
                 *
                 */
                
    echo "<p>You are a registered user, but you have no access.<p>";
            }
        }

    Thanks and I hope this helps someone else too! I will repost the source code if I can get it tighter.

  2. #2
    SitePoint Guru ripcurlksm's Avatar
    Join Date
    Aug 2004
    Location
    San Clemente, CA
    Posts
    859
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    bump

  3. #3
    SitePoint Addict Trent Reimer's Avatar
    Join Date
    Sep 2005
    Location
    Canada
    Posts
    228
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Seems to do what it is designed for.

    1) What I need help with is how to handle the access levels so that it is perhaps a global function? Please inspect my get_access function. How can it be improved and implemented better?
    Currently the function is not only returning access, it is also possibly returning a music list. Normally a global function would be more generic and only concern itself with returning the access. Once you had that information you could decide how it applies to the particular page request.

    PHP Code:
    // $u_id should be adequate since it is a unique value.
    function get_access($u_id) { // get access level
        // access levels: 0=Admin, 1=Full, 2=Limited, 3=None, 4=Unregistered

        
    dbConnect();

        
    // Ensure $u_id is an integer
        
    $u_id intval($u_id);
        if (
    $u_id 1) {
            
    // We can't even perform an intelligent query with that.
            
    return 4;
        }

        
    $result mysql_query("select access from user where u_id={$u_id}");

        
    // Ensure the user is in the database
        
    if (!$result || mysql_num_rows($result) < 1) {
            
    // Not a registered user
            
    return 4;
        } else {
            
    $row mysql_fetch_assoc($result);
            return 
    $row['access'];
        }

    2) is it possible to put the user access level, username and user id into an array WITHIN the session variable so that I can call any of the three variables ($access, $username, $u_id) from any page?
    Yes. (If it needs to be secure you will also want to have plans to discourage session hijacking.)

    3) The login script itself is weak, and simple, please focus on the best methods for granting access levels.
    If you are interested, Zend_Acl is a pretty comprehensive class for managing access. It requires PHP 5.

  4. #4
    SitePoint Guru ripcurlksm's Avatar
    Join Date
    Aug 2004
    Location
    San Clemente, CA
    Posts
    859
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks Trent --

    anyone else want to chime in?

  5. #5
    Utopia, Inc. silver trophy
    ScallioXTX's Avatar
    Join Date
    Aug 2008
    Location
    The Netherlands
    Posts
    9,077
    Mentioned
    153 Post(s)
    Tagged
    2 Thread(s)
    I don't know how extensive you want to go with this class, but suppose you have the following users, who like certain music style(s), which they will be able to see when they log in using your class:

    - Alice likes Rock (suppose access level 1)
    - Bob likes Classic (suppose access level 2)
    - Clara likes Dance (suppose access level 3)
    - Dillan likes Rock and Dance

    You would have a problem because Dillan would have to have access levels 1 and 3 at the same time. There are three possibilities here (in order of complexity):

    1) Use "flags" for permissions. This means you can use permission numbers from the table of 2 and add them together. Sounds complicated, so I'll show an example:

    Rock = 1
    Classic = 2
    Dance = 4

    Dillan will now get permission 5 (4+1)

    You can extract his permissions by using a bitwise AND on the permissions:

    5 & 1 = true
    5 & 2 = false
    5 & 4 = true

    (Look into bitwise AND if you don't get that last part)

    2) Create one more table, in 1-to-many relationship to your users table. Dillan would get a record (4,1) and (4,3) (supposing Dillan has userid 4).

    3) Create two more tables, one holding the (named) user permissions. For example
    1 Rock
    2 Classic
    3 Dance

    An another table which couples userids and permissionids. For example for Dilan you would have here (4,1) and (4,3) as with the previous example, but if you couple your data right, you can ask your class if a user has the permission "rock", instead of permission "1", which is kinda abstract and a real pain in the *** if you have more than, say 10 permissions.

    Also, I agree with Trent Reimer that you should decouple the class from your website code completely. That way you can use the class again for your next project without changing any of the code!
    Rémon - Hosting Advisor

    SitePoint forums will switch to Discourse soon! Make sure you're ready for it!

    Minimal Bookmarks Tree
    My Google Chrome extension: browsing bookmarks made easy

  6. #6
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    PHP Code:
            if($access == 0){ 
    I'd prefer to see if ($access === 0 ) {

    Implicitly ensure it is the integer called Zero with === , rather than falling for false, empty string, not set etc which is all that == does.

    Overall I'd find that counter intuitive further down the script. Wouldn't you be better testing for at least 1? Getting and handling Zeros is fraught with simple errors when dealing with them in other places, I have suffered for doing that.

    Its just perhaps my perception, but the higher the number the higher the access would be easier to understand from further away, and arguably easier to document.

    As Trent points out, typecast access to an integer first too, and as he writes, handle access not being 0,1,2 or 3 ~ 4 is what? header (Location: to far away?);

    I cant help feeling you are missing a trick though.

    Read Jim Plushs bitwise tutorial and see if that gives you some ideas, it certainly did me. If you dont know anything about the bitwise operators it might inspire you. It certainly stuck in my mind.

    It might be of value if you can envisage the acl having to become more fine-grained in the future.

    Another observation/idea is that if you take Trent's comment:

    // access levels: 0=Admin, 1=Full, 2=Limited, 3=None, 4=Unregistered

    Why bother abstracting them to 0,1,2,3,4 at all?

    Why not call them that in your database?

    ENUM 'Admin' , 'Full' etc.

    -Becomes self documenting
    -You don't have to remember 1=Admin etc ( "what is zero again?" )
    -You can browse your database and see who does what.

    Some ideas that go through my mind when I think of updating the very simple acl I have.

    All that presently does is create a menu of folders the user has access to, and at every page change it goes back and checks the current folder is allowed to be viewed by this user.

    Off Topic:

    You can probably tell I am bored, tired and rambling, mainly because I drew the short straw and our young doggette is the the room next me awaiting delivery of pups. So apologies if it doesnt make a lot of sense.



    Edit:

    I dont believe it, ScallioXTX came out with the same bitwise idea, at virtually the same time. Doggon' it

  7. #7
    Utopia, Inc. silver trophy
    ScallioXTX's Avatar
    Join Date
    Aug 2008
    Location
    The Netherlands
    Posts
    9,077
    Mentioned
    153 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by Cups View Post
    Edit:

    I dont believe it, ScallioXTX came out with the same bitwise idea, at virtually the same time. Doggon' it
    Great minds ....

    Off Topic:


    What is " Doggon' it " ?
    Rémon - Hosting Advisor

    SitePoint forums will switch to Discourse soon! Make sure you're ready for it!

    Minimal Bookmarks Tree
    My Google Chrome extension: browsing bookmarks made easy

  8. #8
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    I'm not sure of the spelling, I kinda took a guess.

    I liked westerns as a kid, and its something cowboys used to say. Much the same as Dog gone it? er? I always though it was a cleaned up version of "god dam' it". Like "Shucks", or "Aw, hell".

    Anyway its not personal, it was meant as a self-slight

  9. #9
    Utopia, Inc. silver trophy
    ScallioXTX's Avatar
    Join Date
    Aug 2008
    Location
    The Netherlands
    Posts
    9,077
    Mentioned
    153 Post(s)
    Tagged
    2 Thread(s)
    okay thanks
    Rémon - Hosting Advisor

    SitePoint forums will switch to Discourse soon! Make sure you're ready for it!

    Minimal Bookmarks Tree
    My Google Chrome extension: browsing bookmarks made easy

  10. #10
    SitePoint Wizard TheRedDevil's Avatar
    Join Date
    Sep 2004
    Location
    Norway
    Posts
    1,196
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    I would not recommend the use of bitwise functions for this case. Bitwise often turn out to be more trouble unless its for simple functionality.

    It would be a better idea to go with a "level" table, which contain the different access levels each member has. By doing it this way, its very simple to for example allow a person see two or more bands without having a lot of if/else sentences doing bitwise checking.

  11. #11
    Utopia, Inc. silver trophy
    ScallioXTX's Avatar
    Join Date
    Aug 2008
    Location
    The Netherlands
    Posts
    9,077
    Mentioned
    153 Post(s)
    Tagged
    2 Thread(s)
    You don't need any if/else at all, just one simple for-loop:

    PHP Code:
    $possPermissions = array(1,2,4,8,16,32);
    $permissions = array();
    for (
    $x=0;$x<count($possPermissions);$x++)
    {
       
    $permissions[$possPermissions[$x]] = ($row['permission'] & $possPermissions[$x]);

    $permissions now contains permissions => boolean, example:

    1 => false
    2 => true
    4 => true
    8 => false
    16 => false
    32 => false

    (For $row['permission'] = 6)

    Note for those wondering about the & : The & is not a typo and should not be && , they are different things (& is bitwise AND, while && is logical AND)
    Rémon - Hosting Advisor

    SitePoint forums will switch to Discourse soon! Make sure you're ready for it!

    Minimal Bookmarks Tree
    My Google Chrome extension: browsing bookmarks made easy

  12. #12
    SitePoint Wizard TheRedDevil's Avatar
    Join Date
    Sep 2004
    Location
    Norway
    Posts
    1,196
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    You will still need to use if/else when deciding if the content should be displayed or not.

    By using a level table, all you need to do is to link towards this table when pulling the data to show on the pages.

    I.e. if you add more bands in the future, no changes will be required in the code. You would just add the band to everyones level table and it would automatically show.

    On the other hand if you use bitwise functions, then you would need to hardcode it.

  13. #13
    Utopia, Inc. silver trophy
    ScallioXTX's Avatar
    Join Date
    Aug 2008
    Location
    The Netherlands
    Posts
    9,077
    Mentioned
    153 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by TheRedDevil View Post
    You will still need to use if/else when deciding if the content should be displayed or not.

    By using a level table, all you need to do is to link towards this table when pulling the data to show on the pages.

    I.e. if you add more bands in the future, no changes will be required in the code. You would just add the band to everyones level table and it would automatically show.

    On the other hand if you use bitwise functions, then you would need to hardcode it.
    I can think of way using bitwise comparisons that can be used non-hardcoded. But, since I agree with you that your is better, and this argument is going nowhere (maybe towards a flame I'd really like to avoid) I will sit back silently and consider this discussion to be over
    Rémon - Hosting Advisor

    SitePoint forums will switch to Discourse soon! Make sure you're ready for it!

    Minimal Bookmarks Tree
    My Google Chrome extension: browsing bookmarks made easy

  14. #14
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    Stop me if I am wrong, but the bitwise operator comes into its own when the levels of access start to become more and more complex, and you need a high level of granularity.

    When starting out, I cannot say for ripcurlisms case, you need to factor in the possible complexity.

    Maybe you don't have to cater for it, that'd be bordering on PO (premature optimization), but it'd be like leaving some doors ajar.

    Given that we don't know the spec, my reason for chucking bitwise into the mix was that I can imagine that level of complexity about who does what being an issue in this case.

    What if user level "None" was able to add lyrics to songs? And lets say user level "None" was able to correct or confirm other peoples lyrics? Lets say that after 5 positive confirmations he was granted the ability to add songs now? He is still a level "None" user, he hasnt joined a band or bought a record company.

    If the system of permissions can tend grow organically, in unforeseen directions, then the bitwise route might be useful.

    If not, and it will tend to stay strictly role-based, then probably it wont be the right thing.

    I have to say I have never actually used it, so bow to TheRedDevils experience on this.

    Off Topic:

    While hammering this out the doggette finally dropped her first pup! Thank the lord, can I sleep now?

  15. #15
    SitePoint Wizard TheRedDevil's Avatar
    Join Date
    Sep 2004
    Location
    Norway
    Posts
    1,196
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    I dont know what your experience with bitwise operators are Paul, but bitwise operators has many cavecats when used in this manner.

    I might have misread your first sentence, but the bitwise operator actually become a management nightmare when the comlexity of the application go up.

    One of the major cavecats you will run into is that when you have a few options your "level" number becomes very big, you can have eight options if you have a unsigned tinyint column, sixteen options if you have a unsigned smallint column.

    Another one is that if you need several numbers set for a function to work, you would need to check them one by one, doing "$number & 3" would give true if either 1 or 2, or if both is set. So if you required both 1 and 2 you would have an difficult issue to debug if you didnt know it from the start as it would seems to be working correctly.

    We actually tried using the bitwise operator on an access system two years ago, and as the application was developed we ran into more and more issues. So in the end we rewrote it into useing a access table in mysql instead.

    Dont take me wrong, using bitwise operator like this can be great. But you need to be certain that you will not need more options/levels in the future. Or at least that you wont need a lot more of them.

    We still use them on option columns in mysql tables if there is any options that we will not access in a mysql query. I.e. options that will only be used in php after the result set has been pulled.

    For your example:
    In this case, I would actually recommend two access tables. One for the bands and one for the actual rights. You could also use the same table and just have a column telling what part of the system the access belongs under.

    You could use bitwise for the access levels since you would most probably not need too many, but if you believe that you would might require more in the future. Its easier to go with a access table solution right from the batch.

  16. #16
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    Thanks for the comprehensive reply.

    I held off posting a link to this role based access control earlier, but your reply think about it again.

    There is a classy old posting on SP somewhere which explores fully the differences between access control and access rights (permissions) but I can no longer find it.

    For me, the problem when learning something new, like the bitwise operator is that until I actually try it out I don't really understand when and where I should use it.

    I am the same with all design patterns, I have to create, or manipulate a situation where I use a particular pattern, its only when that goes right (or more importantly, wrong) that I really start to grok the nature of it, and its true use.

    Bitwise is just the same. I came across the page by Jim Plush on bitwise because I was studying for my zce.

    Thanks for taking the time to share your views on this.

  17. #17
    SitePoint Guru ripcurlksm's Avatar
    Join Date
    Aug 2004
    Location
    San Clemente, CA
    Posts
    859
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    thanks guys

  18. #18
    SitePoint Guru ripcurlksm's Avatar
    Join Date
    Aug 2004
    Location
    San Clemente, CA
    Posts
    859
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It seems to me that the best solution to this, bitwise aside, is to create two new tables for access. There are two types of users, full and limited. So we flag users 1 or 2 for instance.

    A full user is pretty straight forward.. select * bands. Done.

    A limited user has two options, and ive created two tables for this... Permissions1 table and Permissions2 table. Permissions1 is a table with user ids and band ids, this will handle all of the one-off users that have a few bands. Permissions2 is a table with user ids and genre ids.

    So for a limited user, I can get all of the genres they are subscribed to from Permissions2 and also include Permissions1 if there are any one-off bands they are allowed to use.

    This seems more clear to me and logical- although it does require more complex table joins for queries. Does anyone foresee problems doing a table join on Permissions1 AND Permissions2 to display bands?

    The reason I used a lower number for user levels, is that if we add more user types after launch the succession of numbers wont be in numerical order. (0=admin, 1=full, 2=limited, 3=special new user, 4=special new user type) VS. (3=admin, 2=limited, 1=full, 4= special new user, 5=special new user)

    EDIT: Also, what if on login, I query and store all band_ids into an array in the session? Is this bad practice? It seems like if I get a permissions list that was maintained thoughout their session, I can control what they see on any page from just one query.. for the most part

  19. #19
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    Maybe the answer is to call all admins 1-10, users 11 onwards, give you more scope to grow.

    But then were back on bitwise ground again...

    Hope it works out for you, or at least you will impart your findings on me when I come to tackle something like that.

  20. #20
    SitePoint Guru ripcurlksm's Avatar
    Join Date
    Aug 2004
    Location
    San Clemente, CA
    Posts
    859
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks Cups, what about:

    1) Does anyone foresee problems doing a table join on Permissions1 AND Permissions2 to display bands?

    2) what if on login, I query and store all band_ids into an array in the session? Is this bad practice? It seems like if I get a permissions list that was maintained thoughout their session, I can control what they see on any page from just one query.. for the most part

  21. #21
    Theoretical Physics Student bronze trophy Jake Arkinstall's Avatar
    Join Date
    May 2006
    Location
    Lancaster University, UK
    Posts
    7,062
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    It all depends on what you treasure most - session space or load time.

    Think, for example, of a system which uses an object for a user. The construct takes the user ID as an argument.

    You have two options in such a case:
    1. Store the whole object in $_SESSION['user'], ready to access on other pages straight away.
    2. Store the user ID in $_SESSION['user'], which will be used to instantiate a new user object on each load.


    The first can be used when you want to minimalise queries, and your system won't have a very large amount of users - because a session requires space and memory, and the larger the session, the less room in said memory.

    The second can be used when you may have alot of users, or don't mind running an extra query every load.
    Jake Arkinstall
    "Sometimes you don't need to reinvent the wheel;
    Sometimes its enough to make that wheel more rounded"-Molona

  22. #22
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    [QUOTE=Ripcurlksm) what if on login, I query and store all band_ids into an array in the session? Is this bad practice? It seems like if I get a permissions list that was maintained thoughout their session, I can control what they see on any page from just one query.. for the most part[/QUOTE]

    I think you are arriving at the point I did. Do a one off, maybe expensive, request that finds out what this user has access to.

    Quote Originally Posted by Cups
    Some ideas that go through my mind when I think of updating the very simple acl I have.

    All that presently does is create a menu of folders the user has access to, and at every page change it goes back and checks the current folder is allowed to be viewed by this user.
    That is ostensibly what I do.

    Identification and Verfication, then find permissions.

    In my case the acl is etremely "flat", you are either an editor or you are not.

    The question is, what parts of the app are you allowed to access, not because of levels, but because you have been granted permission to use them.

    In my case being granted permission to access and change "people" means you can go into the folder called "/people".

    Hence page by page verification is simple, is /people amongst the apps you were granted when you last logged in?

  23. #23
    Utopia, Inc. silver trophy
    ScallioXTX's Avatar
    Join Date
    Aug 2008
    Location
    The Netherlands
    Posts
    9,077
    Mentioned
    153 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by ripcurlksm View Post
    what if on login, I query and store all band_ids into an array in the session? Is this bad practice? It seems like if I get a permissions list that was maintained thoughout their session, I can control what they see on any page from just one query.. for the most part
    The main drawback of this approach is that when you revoke or add permissions to users while they are logged in, they can only see these changes reflected when they log out and back in again.
    If you don't store this info in cookies but look it up every time a reload of the page is enough to see the changes.
    Rémon - Hosting Advisor

    SitePoint forums will switch to Discourse soon! Make sure you're ready for it!

    Minimal Bookmarks Tree
    My Google Chrome extension: browsing bookmarks made easy


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •