SitePoint Sponsor

User Tag List

Results 1 to 10 of 10
  1. #1
    SitePoint Enthusiast xhat's Avatar
    Join Date
    Jun 2004
    Location
    USA
    Posts
    42
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Question Technique for handing existing class HTML form data

    OK, I'm new to OOP and PHP classes in particular. I've got a pretty good handle on PHP programming, and I want to upgrade my code to abstraction and using objects. To that end, I'm writing a login class. The class will build an HTML login form (user id, password and a submit button) and then take the submitted data and authenticate the user against the database.

    I've searched the threads on this site, posted on experts-exchange and Googled the web. I find either very basic class tutorials, or discussions and threads akin to Byzantine monks arguing over how many angels can dance on the head of a pin. I'm not looking to be spoon-fed, but if someone could show me where the spoons are.... (Then I remember the Oracle's children, "There is no spoon." Ye Gods!)

    I could easily do this the "old" way with a logon page and testing some variables for being set or empty or whatever and authenticating. A lot of if statements to control page flow. But trying to stick to the cleanest, least hassle-free way for others to re-use this bit of code, I want to include the authentication procedure as part of the class. All fine and well. I can code the authentication procedure without a problem.

    Where I'm hung up, though, is trying to figure out how to make the submitted form call the authenticate method of the class. If the page that makes the class is the page that is called by the form's action variable, how do I give the original object the form data without making a new object? Example:

    Below is the code that uses the class to make the form...
    //test.php
    PHP Code:
    <?PHP
         
    include "secureLog.php";
         
    $mast = new secureLog("new""Test Page");   //instantiate class; set style and title
         
    $mast->setMastHead();                                  //form html with styling, javascript includes, etc...
         
    $mast->makeForm("test.php""Enter User ID and Password...");   //set action variable value and helpful script for users...
         
    $mast->makeFoot();                                      //build page footer
    (ideal situation to follow.....)

    ...after the login form loads and the user enters his data into the form fields and submits, ideally what I would like to see happen is this....
    PHP Code:
            $mast->secureUser($user_id$password);      //pass form data to authenticate method 
    ....the page used to build the form receives the form data and the authenticate method is called. Neat and tidy. However, I see two problems:

    1. If I call the same page that builds the login form, then the whole page would load, including the call to the secureUser() method, sending a blank id and password to the database to be authenticated and returning a bad login.
    2. If you ever managed to get the form to load without sending blank data, wouldn't the form's action call to the page create another secureLog object, setting off an endless loop of logging in, then logging in, then loggin...?

    As you can see, I am a noob in the woods when it comes to OOP, but intuitively I just know there's a way to do this. I thought about coding this....
    PHP Code:
    if(isset($myform))
          
    //run object instantiation code
    else
          
    //call authenticate method. 
    ...but that just didn't seem right to me. Turns out it's not, as the called page never builds the login object, so the authenticate method is invalid, undefined, whatever. Ideally, the submit button would simply call the authenticate method and display a fail message or move the user on to the next page if authenticated. Aha! one thinks. Javascript.
    Well, I'm trying to avoid using Javascript on the Submit button to call the authenticate method. If the user has turned JS off, then I'm out of luck.

    So, proceed to point out where I'm going wrong. Please, I beg you!

  2. #2
    It's been real... Forbes's Avatar
    Join Date
    Dec 2004
    Location
    Yorkshire, England
    Posts
    676
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    OK, let's take this one step at a time. Although valid, it's considered bad practice to send parameters to a constructor class. Your example:
    PHP Code:
    $mast = new secureLog("new""Test Page");
    $mast->setMastHead();
    $mast->makeForm("test.php""Enter User ID and Password...");
    $mast->makeFoot(); 
    Should really read:
    PHP Code:
    $mast = new secureLog();
    $mast->memberVariableNew "new";
    $mast->memberVariableTitle "Test Page";
    $mast->setMastHead();
    $mast->makeForm("test.php""Enter User ID and Password...");
    $mast->makeFoot(); 
    Where: 'memberVariableNew' and: "memberVariableTitle" are declared as:
    PHP Code:
    var $memberVariableNew;
    var 
    $memberVariableTitle
    In the header of your class...

  3. #3
    SitePoint Enthusiast xhat's Avatar
    Join Date
    Jun 2004
    Location
    USA
    Posts
    42
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    OK, I can correct that. I thought it was ok to send parms to a constructor. Is this a PHP quirk, or just general coding practice? What about the larger issue?
    "There is no spoon."

  4. #4
    It's been real... Forbes's Avatar
    Join Date
    Dec 2004
    Location
    Yorkshire, England
    Posts
    676
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    All of the stuff I've read, you get a big wagging finger of disapproval when the subject is brought up.

    Think of it this way: if you have a constructor method working like a function that needs a set of parameters passing to it, any time you use that class, the constructor method will always need to be sent a bunch of parameters, whether the methods you're using within the class need them or not.

    Often, it's just the methods contained within the class that make use of the member variables and not the constructor method.

    For example, here's the top of a class from an web application I'm developing:
    PHP Code:
    class Users {

        var 
    $allUsers;

        var 
    $arrayUsers = array(); // end array

        
    var $classSmarty;
        var 
    $classMessages;

        var 
    $db;
        var 
    $arrayDBtablesCommon = array(); // end array
        
    var $sqlUsers;


        function 
    Users () {

            
    // include database connection
            
    include (INCLUDES_DIR 'c_db.inc.php');

            
    $this->db $db;
            
    $this->arrayDBtablesCommon $arrayDBtablesCommon;

            
    // instantiate Smarty class
            
    $this->classSmarty = new SmartyTemplate();

            
    // instantiate Messages class
            
    $this->classMessages = new Messages();

        } 
    // end function Applications 
    The constructor method is instantiating a bunch of stuff most of the other methods will be needing...

  5. #5
    SitePoint Enthusiast xhat's Avatar
    Join Date
    Jun 2004
    Location
    USA
    Posts
    42
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ha! I can see the big finger wagging at me now!

    I see your point, but aren't you doing the same thing in your constructor? Mainly, setting up variables that you know the class will use later. The users of the class will definitely set a style, and the title parm is optional, and both will be user-determined. So, whether I set it up in the constructor, or a method call, what is the functional difference?

    I'm not trying to argue with you, just understand. If good coding practice says keep the constructor free of parms, then there must be a good reason for it. But I don't see the point of making a constructor call, then a "style-title" method call when the two ops can be combined.

    Anyhoo.... Any ideas for me about how to accomplish my goal?
    "There is no spoon."

  6. #6
    It's been real... Forbes's Avatar
    Join Date
    Dec 2004
    Location
    Yorkshire, England
    Posts
    676
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yes you are, but the constructor method doesn't need to have a bunch of parameters passed to it to begin with.

    Strictly speaking, you shouldn't really have a style when it comes to object-oriented programming.

    Procedural programming allows for this simply because it's less strict.

    You could actually pass the values to just one member variable but as an array:
    PHP Code:
    $class->memberName = array ("index" = > $value); 
    As for your problem at hand, by way of a puzzle [yes, I'm cruel like that!] here's a sample from the switch() statement I use to validate user actions:
    PHP Code:
                case "logout":

                    
    // instantiate Page class
                    
    $this->classPage = new Page();
                    
    $this->classPage->title        'Login';
                    
    $this->classPage->section    'login';
                    
    $this->classPage->DisplayPageHeader();

                    
    // include database connection
                    
    include (INCLUDES_DIR 'c_db.inc.php');

                    
    $this->classLogin->db $db;
                    
    $this->classLogin->arrayDBtablesCommon $arrayDBtablesCommon;
                    
    $this->classLogin->LoginUserDeactivate();
                    
    $this->classLogin->LogOut();
                    
    $this->classLogin->DisplayLogin();

                    
    $this->classPage->DisplayPageFooter();

                    break;
                    case 
    "login":

                    
    // instantiate Page class
                    
    $this->classPage = new Page();
                    
    $this->classPage->title        'Login';
                    
    $this->classPage->section    'login';
                    
    $this->classPage->DisplayPageHeader();

                    
    // include database connection
                    
    include (INCLUDES_DIR 'c_db.inc.php');

                    
    $this->classLogin->username $this->arrayActions['username'];
                    
    $this->classLogin->password $this->arrayActions['password'];
                    
    $this->classLogin->db $db;
                    
    $this->classLogin->arrayDBtablesCommon $arrayDBtablesCommon;

                    
    $this->classPage->DisplayPageFooter();

                    
    // if the user enters an invalid username & password...
                    
    if (!$this->classLogin->ValidateUserInput()) {

                            
    // instantiate Page class
                            
    $this->classPage = new Page();
                            
    $this->classPage->title        'Login';
                            
    $this->classPage->section    'login';
                            
    $this->classPage->DisplayPageHeader();

                            
    // display login and error dialogs
                            
    $this->classLogin->DisplayLogin();
                            
    $this->classLogin->DisplayLoginForgot();

                            
    $this->classPage->DisplayPageFooter();

                    } else {

                        
    // if the username isn't already in use...
                        
    if (!$this->classLogin->ValidateUser()) {

                            
    // instantiate Page class
                            
    $this->classPage = new Page();
                            
    $this->classPage->title        'Login';
                            
    $this->classPage->section    'login';
                            
    $this->classPage->DisplayPageHeader();

                            
    // display login and error dialogues
                            
    $this->classLogin->DisplayLogin();
                            
    $this->classLogin->DisplayLoginForgot();

                            
    $this->classPage->DisplayPageFooter();

                        } else {

                            
    // attempt to log the user in
                            
    $this->classLogin->DatabaseLoginSQL();

                            
    // if the user logs in successfully...
                            
    if($this->classLogin->DatabaseLoginQuery()) {

                                
    // instantiate Page class
                                
    $this->classPage = new Page();
                                
    $this->classPage->title        'Login';
                                
    $this->classPage->section    'login';
                                
    $this->classPage->DisplayPageHeader();

                                
    // ... enter the user to the active user table
                                
    $this->classLogin->LoginUserActivate();

                                
    $this->classPage->DisplayPageFooter();

                            } 
    // end if

                        
    // end if

                    
    // end if

                
    break; 
    Disregarding all of the class / method calls, this excerpt covers the logic you need to accomplish what you need.

    If you need more help, I should be around. But it's nearly five past eleven at night, here. I'm due for some sleep this week...

  7. #7
    SitePoint Enthusiast xhat's Avatar
    Join Date
    Jun 2004
    Location
    USA
    Posts
    42
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Forbes,

    Thanks for the puzzle. Nothing like a good Gordian knot to keep one tossing and turning all night.

    From your code snippet, it seems that you've wrapped the calls to various classes inside of a switch statement. Each time the page is called, the proper code segment runs depending upon the state of the user (logging in, logging out, invalid, etc.).

    I toyed with the idea of doing that, but was looking for a solution that didn't require building some sort of if or switch statement. What I want to achieve is for any user to simply make a new secureLog object, use the methods and be done.

    Now, your code may well do that. One thought I had (and you may be doing this as evidenced by the double -> operator) was to wrap the classes inside of other classes. Your switch statement may be inside of a class. This way, I'm still using OOP. But even with this method (and assuming I don't use if or switch statements as part of the page structure), I still can't see a way around creating an orphan or making a new object when the page is called again by the form post.

    On experts-exchange, I got a response to my query that I think resolves my issue. I'm not sure I understand exactly how it is working, but I'll tell you what I think is happening, then post the code.

    The main page calls a method of the object outside of the class. This function does some testing, which if fails, then instantiates a secureLog object. It probably violates OOP practices, but it does seem to accomplish what I'm driving at: no control structures outside of the class to implement the functionality I want. Here's the code. I'm interested in what you think of it.

    PHP Code:
    <?php //index.php
      
    require_once('secureLog.php');
      
    secureLog::check('New''Test Page''table.php','Enter user id..etc');
    ?>

    <?php //secureLog.php
    class secureLog
    {
       
    /*static*/ function check($constructor_var1$constructor_var2$form_var1$form_var2)
       {
             if(
    authenticated)
               return;

             if(
    $_SERVER['REQUEST_METHOD'] == 'POST' &&
                !empty(
    $_POST['username_field_name']) &&
                !empty(
    $_POST['password_field_name']))
                if(
    secureLog::testAndAuthenticate($_POST['username_field_name'], $_POST['password_field_name']))
                   return;

              
    $mast = new secureLog($constructor_var1$constructor_var2)
              
    $mast->setMastHead();
              
    $mast->makeForm($form_var1$form_var2);
              
    $mast->makeFoot();
              exit();
       }
       
    /*static*/ function testAndAuthenticate($user$pass)
       {
          .. 
    enter some db testing here ..
          return 
    $user_authenticated//true when user logged in succesfully, false on failure.
       
    }
     
       ..
    rest of your class
    }
    thanks for your time.
    "There is no spoon."

  8. #8
    It's been real... Forbes's Avatar
    Join Date
    Dec 2004
    Location
    Yorkshire, England
    Posts
    676
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    To be honest, what I've come up with is a little complex.

    There's all manor of checking and nested classes, so there was no simple way to show you a simple[r] version, which is unfortunate, because I would have like to have helped you more.

    Yes, the switch statement is inside a method called: 'main' which is in turn inside a class called: 'Index'.

    From here, all user input is first validated and managed in such a way that no matter whether the input is from a form or a link, all in-bound data is sifted through the switch statement, no matter what the class, no matter where it is.

    Any more problems, I'd be glad to help .. if I can!

  9. #9
    SitePoint Enthusiast xhat's Avatar
    Join Date
    Jun 2004
    Location
    USA
    Posts
    42
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hey, no problem. You did help. Got me thinking (more) seriously about nesting classes. If you've got the time and inclination, I'd be interested to read what you think about the code I posted. It looks good to me, and seems to have the "elegance" I was looking for, but I just don't know if it's good and/or valid OOP. I'll have to do a lot more reading up on the double colon, or "Paamayim Nekudotayim" (from PHP site) operator.

    Thanks again.
    "There is no spoon."

  10. #10
    It's been real... Forbes's Avatar
    Join Date
    Dec 2004
    Location
    Yorkshire, England
    Posts
    676
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Best send me a Personal Message.

    I think the best advice for object-oriented programming is to keep your classes simple, keep your methods simple so that they're not doing too much and think about making a class generic -- where possible -- so that what functionality you build in might be useful elsewhere. That's not always possible, but it's as well to keep it in mind.

    The very best thing about object-oriented programming is that it enforces a disciplined way of programming. You can't really fudge something and muddle through. More often than not, it either works or it doesn't.

    Speak to you soon...


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
  •