PHP vs RoR [NA]

CJones

Final Approach
Joined
Mar 14, 2005
Messages
5,899
Location
Jawjuh
Display Name

Display name:
uHaveNoIdea
I spent the past several months teaching myself Ruby on Rails for a class project. I was officially the 'Project Manager', but my 'Technical Manager' was clueless, so I ended up doing 99% of the programming myself. *sigh*

Anywho.. I would like to rewrite my personal website and would like to do it in PHP. I've done some PHP in the past, but never a 'full' project. One thing I liked about RoR (using Aptana RadRails), was the ability to use the Rails framework for script/generate, scaffolding, etc. type of built-in tools. Is there anything comparable to this functionality in the PHP world?

It seems like there are about a zillion flavors of PHP that claim to be a MVC framework, but nothing comes close to the usability of RadRails.

Any suggestions?

I really need to use PHP b/c the job I will be starting after the first of the year will be mostly PHP, so I need to get my mindset switched from RoR to PHP.
 
OK Chris, I'm in the exact opposite position. I've been doing a fair amount of PHP and tried RoR. I am not going to argue a position but would really like to bat the ball around a few times.

RoR seems to me to be "really easy to do what I think you want" but God forbid you want something different or want to start from any place we haven't provided the path.

PHP, well if I wanted to show my age, I would call it Object Oriented Basic (assuming we're talking about PHP 5+). It works, it's supported, there are a lot of Open Source libraries and on-line tutorials.

JSP, from a language and support perspective, I think I want to know it. From a how to get from here to there, I'm lost. I'd rather write Java than PHP but Java EE seems to be more "do it my way or the highway" than Ruby on Rails.

Joe
 
Chris, there are a ton of frameworks out there for PHP that get you started without having to write from scratch.

We have used Kohana to some extent, but I'm not very happy with their decision to do a core rewrite that essentially abandons all code written for previous versions.

Take a look at Zend. Quite a few members of my programming team like their modular approach..meaning you only have to use the parts that you want to use. You might also want to take a look at CakePHP.

By the way, you can get PHP support right in Aptana. Just install the PHP plugin (PDT in Aptana v2.x).
 
OK Chris, I'm in the exact opposite position. I've been doing a fair amount of PHP and tried RoR. I am not going to argue a position but would really like to bat the ball around a few times.

I really don't have a 'position' either. I really don't know enough about ANY language to be able to call it my 'favorite'. RoR is my poison of choice right now, but that's just because it is the freshest in my head.

RoR seems to me to be "really easy to do what I think you want" but God forbid you want something different or want to start from any place we haven't provided the path.

I thought the same about RoR when I first got started. Considering a lot of what I was doing wasn't typical 'out of the box' type stuff, I had to deal with the path mapping problem. It really isn't too bad once you figure out what i's to dot and t's to cross to get it to play nice.

For me, RoR had a fairly steep learning curve. It was slow going at first, but once it clicked, it really became pretty easy to do the things I wanted. If I had to redo the project today, I could probably start from scratch and be able to have improved functionality with about 1/2 the number of lines of code just because of how much I learned along the way.

PHP, well if I wanted to show my age, I would call it Object Oriented Basic (assuming we're talking about PHP 5+). It works, it's supported, there are a lot of Open Source libraries and on-line tutorials.

The bulk of my experience in PHP has been doing simple redirect or single-function type scripts. Nothing I've ever done has had the need for any object-based functionality in PHP. Maybe that's why I don't think it's as easy as RoR - maybe I just haven't used it enough in a large project to find out its tricks.

JSP, from a language and support perspective, I think I want to know it. From a how to get from here to there, I'm lost. I'd rather write Java than PHP but Java EE seems to be more "do it my way or the highway" than Ruby on Rails.
Joe

Never used JSP, so no comment.


Chris, there are a ton of frameworks out there for PHP that get you started without having to write from scratch.

We have used Kohana to some extent, but I'm not very happy with their decision to do a core rewrite that essentially abandons all code written for previous versions.

That sounds familiar. I think I heard that from someone else in your organization. ;)

Take a look at Zend. Quite a few members of my programming team like their modular approach..meaning you only have to use the parts that you want to use. You might also want to take a look at CakePHP.

By the way, you can get PHP support right in Aptana. Just install the PHP plugin (PDT in Aptana v2.x).

I downloaded Zend, but haven't installed it yet. I did add the PHP plugin for Aptana and downloaded CakePHP. I've just barely started messing with it but haven't found where it has any built-in scaffolding.

I should have more time to mess with it later this week, but just thought I would see if anyone had a 'best' recommendation for a PHP framework.
 
I downloaded Zend, but haven't installed it yet. I did add the PHP plugin for Aptana and downloaded CakePHP. I've just barely started messing with it but haven't found where it has any built-in scaffolding.

I should have more time to mess with it later this week, but just thought I would see if anyone had a 'best' recommendation for a PHP framework.

http://book.cakephp.org/view/105/Scaffolding

http://www.askaboutphp.com/tutorials/33/cakephp-using-scaffolding.html
 
I downloaded Zend, but haven't installed it yet. I did add the PHP plugin for Aptana and downloaded CakePHP. I've just barely started messing with it but haven't found where it has any built-in scaffolding.

It = Zend, or It = CakePHP?

Zend has it, if by scaffolding you're referring to a MVC framework.

See: http://framework.zend.com/docs/quickstart
 
It = Zend, or It = CakePHP?

Zend has it, if by scaffolding you're referring to a MVC framework.

See: http://framework.zend.com/docs/quickstart

I think his "it" was CakePHP. Scaffolding != MVC. It is a benefit of using some MVC frameworks.

http://en.wikipedia.org/wiki/Scaffold_(programming)

Jason's got it (it=what I was trying to say by saying 'it' in my previous post :D).

The 'scaffolding' was referring to was the actual RoR command line command: "script/generate scaffold <object> <object attribute>:<attribute type>..." which creates the table in the database with columns each with the appropriate data type, creates the model, view, and controller for the object, and adds the routing for the object's m,v,c to the application's routing table. It makes pretty quick work of getting a base architecture in place for objects within an application.
 
Last edited:
Jason's got it (it=what I was trying to say by saying 'it' in my previous post :D).

The 'scaffolding' was referring to was the actual RoR command line command: "script/generate scaffold <object> <object attribute>:<attribute type>..." which creates the table in the database with columns each with the appropriate data type, creates the model, view, and controller for the object, and adds the routing for the object's m,v,c to the application's routing table. It makes pretty quick work of getting a base architecture in place for objects within an application.

You're more or less talking about a database abstraction layer. Understand that it also creates a few objects but personally never found that to be that super amazing. You're not really talking about saving much time because it creates a few files. As far as the routing, many of the frameworks will route by autoloading objects based on the URL. No routing table unless you want one.

In Kohana you have a basic ORM layer but it's nothing too fancy, I don't really use it. I've always thought Doctrine looked like it had potential: http://www.doctrine-project.org/ but haven't explored it that much yet.

I think for some sites the RoR approach with an ORM layer makes a lot of sense. I just haven't ever had a real reason to justify looking into them too much. Professionally, the codeset I maintain uses LDAP for the database. JesseWeather uses MySQL a little but, but I just wrote my own basic abstraction layer as it needed to be really fast (I have many many many millions of rows).
 
I'm not exactly a PHP guru, but I can use it comfortably enough to have built about half a dozen sites and some Web apps, some of which were quite unique. One of them calculated an estimate for a termite treatment based upon user-supplied data. It was incredibly accurate. The client (an exterminator) was amazed at how close the automated estimates were to his own.

That site and a couple of others also taught me a lot about never trusting user input... the hard way. But hey, live and learn. I spent a year after that fiasco studying the ins and outs of SQL injection and other potential security problems, and I'm pretty confident about the scripts I write today.

I also recently inherited a site built on PHP and was able to comfortably assume control over it in less than a day of poring over the scripts. I actually impressed myself. Good thing: The client is my dentist (ouch!). And this past weekend, I converted two of my own sites (100+ pages) to PHP-driven sites without breaking a sweat.

So my question, basically, is this: What advantages do these frameworks offer over hand-coding? PHP is a pretty simple language, even for a guy like me whose only formal technology training was in hardware electronics.

-Rich
 
So my question, basically, is this: What advantages do these frameworks offer over hand-coding? PHP is a pretty simple language, even for a guy like me whose only formal technology training was in hardware electronics.

-Rich
I'm trying to wrap my head around this also.

I think the advantage of a framework is that it does a lot of the coding to set up a skeletal project with our work being to put the meat on the bones.

My problem is I see the skeleton as being for an orangutan when I want a chimpanzee. Now if only I could visualize the problem the way the framework designers did, I could probably do what needs to be done, with a lot less work.

Looking to hear from people who have gotten them to work. I've gotten through a bunch of RoR tutorials and started a couple of real project but haven't been able to get anything useful done.

Joe
 
. . . .

My problem is I see the skeleton as being for an orangutan when I want a chimpanzee. Now if only I could visualize the problem the way the framework designers did, I could probably do what needs to be done, with a lot less work.

. . . .

Joe

Yeah, that's a great way to put it. Both sites I did this weekend had good, if somewhat outdated content, but were ugly. Also, they were a pain to do site-wide updates on. I'd started to work on them off and on using a couple of CMS systems, but could never get what what in my head on the screen.

So this time I just started building the graphics, then built single pages using XHTML and CSS, then refined it, wrote the PHP scripts to build the XHTML, and voila, there it was. After that I just bulk-imported the content, edited and updated it here and there, and there it was. I was done. The sites were exactly what I'd pictured in my head.

I tweaked a bit here and there since then (added some bevel and texture to the graphics, wrote scripts to manage and rotate the ads, etc.). But the point is that with each site, I got what I'd envisioned within a couple of hours of sitting at the computer -- using nothing but DreamWeaver and Fireworks. I just saw room for improvement once the sites were done.

I dunno... maybe it's me. My brother swears by Joomla. I couldn't make heads or tails of it. It just seemed to get in between myself and the creative process. I could get something kinda, sorta, like what I wanted, but nothing exactly like what I wanted. In the end, hand-coding was easier and faster.

But again, I guess that's just me.

-Rich
 
Last edited:
The frameworks start to make a lot of sense when you're building a large-scale site that has a lot of dynamic action in the background. More or less the framework is just there to make things easier. Libraries already available for pagination, input validation, database access, capchas, encryption, profiling, memcache, and on..and on..and on. They generally have auto-loading pre-configured for your utilities, libraries, views, etc. I haven't wrote an include or require_once statement in a LONG time.

I write a lot more object-oriented PHP these days then I used to. Originally I never saw the point, but as I started to do it, it just makes things much easier to maintain.

Here are a few snapshots of my JesseWeather code. This is more or less the code that handles the user management portion of the site. This is the method that drives the registration page (the controller):
Code:
   public function register() {
        $view = new View('user/register');
        $this->template->content = $view;
        
        //setup the nav bar
        $nav[] = navhelper::navAddItem('Home', '/', 0);
        $nav[] = navhelper::navAddItem('Notifications', '/notifications', 0);
        $nav[] = navhelper::loginOrLogout();
        $nav[] = navhelper::navAddItem('FAQ', '/faq', 0);
        $nav[] = navhelper::navAddItem('Contact Us', '/contact', 0);
        
        $this->template->nav = $nav;
        
        //no logged in users allowed.
        securityhelper::noLoggedInUsersAllowed();
        
        $form = $_POST;
        if ($form) {
            $errors = array();
            
            $username = strtolower(formhelper::assignFormElementToVariable($form, 'username'));
            $password = formhelper::assignFormElementToVariable($form, 'password');
            $verifyPassword = formhelper::assignFormElementToVariable($form, 'verifyPassword');
            $email = strtolower(formhelper::assignFormElementToVariable($form, 'email'));
            
            if ( empty($username)) {
                $errors[] = "Username is required. <br />";
            }
            
            if ( empty($password)) {
                $errors[] = "Password is required. <br />";
            }
            
            if ( empty($verifyPassword)) {
                $errors[] = "Verify Password is required. <br />";
            }
            
            if ( empty($email)) {
                $errors[] = "Email is required. <br />";
            }
            
            if (strlen($username) > 20) {
                $errors[] = "Username too long. <br/>";
            }
            if (strlen($password) > 100) {
                $errors[] = "Password too long. <br/>";
            }
            if (strlen($email) > 200) {
                $errors[] = "E-mail too long. <br/>";
            }
            if ($verifyPassword != $password) {
                $errors[] = "Your password does not match. <br/>";
            }
            
            if (strtolower($password) == $username) {
                $errors[] = "Username cannot equal password. <br />";
            }
            
            if (!formhelper::isEmail($email)) {
                $errors[] = "Your e-mail address is not valid. <br />";
            }
            
            if (UserManager::isUsernameTaken($username)) {
                $errors[] = "That username is already in use.  Please select another";
            }
            if (!UserManager::doesPasswordMeetPolicy($username, $password)) {
                $errors[] = "Your password is not secure.  It must be at least 5 characters and cannot equal your username.";
            }
            
            if (count($errors) > 0) {
                $errors = implode(PHP_EOL, $errors);
                dialoghelper::addDialog('error', $errors);
                return FALSE;
            }
            
            //create the user
            $user = new User_Model;
            $user->setUsername($username);
            $user->setEmail($email);
            $user->setPassword($password);
            $user->setIsActivated(0);
            
            //add the user
            $user = UserManager::addUser($user);
            
            //send actiation e-mail
            UserManager::sendActivationEmail($user);
            dialoghelper::addDialog('success', "Your account has been created. We just sent you an e-mail with activiation instructions.  You will need to active your account before you can sign in.");
            url::redirect('/user/login');
        }
    }
When I declare $user = new User_Model that goes and auto-loads my user model object which I then populate.

The user model looks like this:
Code:
<?php 
class User_Model {

    private $userID;
    private $username;
    private $passwordHash;
    private $email;
    private $isActivated;
    private $activationCode;
    private $salt;
    private $passwordResetCode;
    private $recentlyUsedAddresses = array();

    
    public function hashPassword($password) {
        $password = sha1($password);
        $password = $password.$this->getSalt();
        $hash = sha1($password);
        return $hash;
    }
    
    /**
     * Returns $activationCode.
     *
     * @see User_Model::$activationCode
     */
    public function getActivationCode() {
        return $this->activationCode;
    }
    
    /**
     * Returns $passwordResetCode.
     *
     * @see User_Model::$passwordResetCode
     */
    public function getPasswordResetCode() {
        return $this->passwordResetCode;
    }
    
    /**
     * Sets $passwordResetCode.
     *
     * @see User_Model::$passwordResetCode
     */
    public function setPasswordResetCode($passwordResetCode) {
        $this->passwordResetCode = $passwordResetCode;
    }
    
    /**
     * Returns $email.
     *
     * @see User_Model::$email
     */
    public function getEmail() {
        return $this->email;
    }
    
    /**
     * Sets $email.
     *
     * @param object $email
     * @see User_Model::$email
     */
    public function setEmail($email) {
        $this->email = $email;
    }
    
    /**
     * Returns $isActivated.
     *
     * @see User_Model::$isActivated
     */
    public function getIsActivated() {
        return $this->isActivated;
    }
    
    /**
     * Sets $isActivated.
     *
     * @param object $isActivated
     * @see User_Model::$isActivated
     */
    public function setIsActivated($isActivated) {
        $this->isActivated = $isActivated;
    }
    
    /**
     * Returns $passwordHash.
     *
     * @see User_Model::$passwordHash
     */
    public function getPasswordHash() {
        return $this->passwordHash;
    }
    
    /**
     * Sets $passwordHash.
     *
     * @param object $passwordHash
     * @see User_Model::$passwordHash
     */
    public function setPasswordHash($passwordHash) {
        $this->passwordHash = $passwordHash;
    }
    
    /**
     * Sets $passwordHash.
     *
     * @param object $passwordHash
     * @see User_Model::$passwordHash
     */
    public function setPassword($password) {
        $hash = $this->hashPassword($password);
        $this->passwordHash = $hash;
    }
    
    /**
     * Returns $salt.
     *
     * @see User_Model::$salt
     */
    public function getSalt() {
    
        if ( empty($this->salt)) {
            $randomString = rand(5, 100000).time().rand(5, 100000);
            $randomString = sha1($randomString);
            $randomString = md5($randomString);
            $randomString = sha1($randomString);
            $salt = substr($randomString, 0, 10);
            $this->salt = $salt;
        }
        
        return $this->salt;
    }
    
    /**
     * Returns $userID.
     *
     * @see User_Model::$userID
     */
    public function getUserID() {
        return $this->userID;
    }
    
    /**
     * Sets $userID.
     *
     * @param object $userID
     * @see User_Model::$userID
     */
    public function setUserID($userID) {
        $this->userID = $userID;
    }
    
    /**
     * Returns $username.
     *
     * @see User_Model::$username
     */
    public function getUsername() {
        return $this->username;
    }
    
    /**
     * Sets $username.
     *
     * @param object $username
     * @see User_Model::$username
     */
    public function setUsername($username) {
        $this->username = $username;
    }

    
    /**
     * Sets $activationCode.
     *
     * @param object $activationCode
     * @see User_Model::$activationCode
     */
    public function setActivationCode($activationCode) {
        $this->activationCode = $activationCode;
    }
    
    /**
     * Sets $salt.
     *
     * @param object $salt
     * @see User_Model::$salt
     */
    public function setSalt($salt) {
        $this->salt = $salt;
    }

    
    /**
     * Returns $recentlyUsedAddresses.
     *
     * @see User_Model::$recentlyUsedAddresses
     */
    public function getRecentlyUsedAddresses() {
        if ( empty($this->recentlyUsedAddresses)) {
            return array();
        } else {
            return $this->recentlyUsedAddresses;
        }
    }
    
    /**
     * Sets $recentlyUsedAddresses.
     *
     * @param object $recentlyUsedAddresses
     * @see User_Model::$recentlyUsedAddresses
     */
    public function setRecentlyUsedAddresses($recentlyUsedAddresses) {
        $this->recentlyUsedAddresses = $recentlyUsedAddresses;
    }
    
    public function addToRecentlyUsedAddresses($address) {
        $newArray = array($address);
        $oldArray = array_splice($this->getRecentlyUsedAddresses(), 0, 49);
        if(in_array($address, $oldArray)) {
            return FALSE;
        }
        $newArray = array_merge($newArray, $oldArray);
        
        $this->recentlyUsedAddresses = $newArray;
    }
}
?>
You'll also see that after I create the user model I then start running it through UserManager which is my database layer for that model. I can just pass the model into it and it'll save the user in the database.

It looks like this:
Code:
<?php 
class UserManager {
    private static function populateUser($row) {
        $user = new User_Model;
        
        $user->setUserID($row->userID);
        $user->setUsername($row->username);
        $user->setPasswordHash($row->passwordHash);
        $user->setEmail($row->email);
        $user->setIsActivated($row->isActivated);
        $user->setActivationCode($row->activationCode);
        $user->setSalt($row->salt);
        $user->setPasswordResetCode($row->passwordResetCode);
        if (! empty($row->recentlyUsedAddresses)) {
            $user->setRecentlyUsedAddresses(unserialize($row->recentlyUsedAddresses));
        }
        
        return $user;
    }
    
    public static function doesPasswordMeetPolicy($username, $password) {
        //password must be at least 5 characters
        if (strlen($password) < 5) {
            return FALSE;
        }
        
        //password must not be username
        if (strtolower($password) == strtolower($username)) {
            return FALSE;
        }
        
        //looks good
        return TRUE;
    }
    
    protected static function generateRandomCode() {
        $db = Database::instance();
        
        $unique = 0;
        while ($unique == 0) {
            $randomString = rand(5, 100000).time().rand(5, 100000);
            $randomString = sha1($randomString);
            $randomString = md5($randomString);
            $randomString = sha1($randomString);
            $activationCode = substr($randomString, 0, 40);
            
            $result = $db->query("SELECT activationCode from users WHERE activationCode='$activationCode'");
            
            if ($result->count() == 0) {
                $unique = 1;
            } else {
                $unique = 0;
            }
            
        }
        
        return $activationCode;
        
    }
    
    public static function addUser(User_Model $user) {
        $db = Database::instance();
        $username = $user->getUsername();
        $passwordHash = $user->getPasswordHash();
        $salt = $user->getSalt();
        $email = $user->getEmail();
        $isActivated = $user->getIsActivated();
        
        $activationCode = self::generateRandomCode();
        $user->setActivationCode($activationCode);
        
        $query = "INSERT INTO users (username, passwordHash, salt, email, activationCode, isActivated) VALUES ('$username', '$passwordHash', '$salt', '$email', '$activationCode', '$isActivated')";
        $result = $db->query($query);
        
        $user->setUserID($result->insert_id());
        
        return $user;
    }
    
    public static function updateUser(User_Model $user) {
        $db = Database::instance();
        
        $username = $user->getUsername();
        $passwordHash = $user->getPasswordHash();
        $salt = $user->getSalt();
        $email = $user->getEmail();
        $isActivated = $user->getIsActivated();
        $activationCode = $user->getActivationCode();
        $userID = $user->getUserID();
        $passwordResetCode = $user->getPasswordResetCode();
        $recentlyUsedAddresses = serialize($user->getRecentlyUsedAddresses());
        
        $query = "UPDATE users SET username='$username', passwordHash='$passwordHash', salt='$salt', email='$email', isActivated='$isActivated', activationCode='$activationCode', passwordResetCode='$passwordResetCode', recentlyUsedAddresses='$recentlyUsedAddresses' WHERE userID='$userID' LIMIT 1";
        $db->query($query);
        
        return $user;
    }
    
    public static function isUsernameTaken($username) {
        $db = Database::instance();
        
        $result = $db->query("SELECT username FROM users WHERE username='$username'");
        
        if ($result->count() > 0) {
            return TRUE;
        } else {
            return FALSE;
        }
    }
    
    public static function isEmailUsed($email) {
        $db = Database::instance();
        
        $result = $db->query("SELECT email FROM users WHERE email='$email'");
        
        if ($result->count() > 0) {
            return TRUE;
        } else {
            return FALSE;
        }
    }
    
    public static function sendActivationEmail(User_Model $user) {
        require_once (APPPATH.'/libraries/swiftmailer/swift_required.php');
        $email = $user->getEmail();
        $activationCode = $user->getActivationCode();
        $domain = Kohana::config_load('config');
        $domain = $domain['site_domain'];
        
        $body = 'Thank you for registering on JesseWeather.com.  Please click the below link to activate your account:'.PHP_EOL;
        $body .= 'http://'.$domain.'/user/activate/'.$activationCode;
        
        $transport = Swift_MailTransport::newInstance();
        
        $message = Swift_Message::newInstance();
        $message->setSubject('Activate Account');
        $message->setFrom('support@jesseweather.com');
        $message->setTo($email);
        $message->setBody($body);
        
        $transport->send($message);
    }
    
    public static function sendPasswordResetEmail(User_Model $user) {
        require_once (APPPATH.'/libraries/swiftmailer/swift_required.php');
        
        $email = $user->getEmail();
        $randomCode = self::generateRandomCode();
        
        //save to user
        $user->setPasswordResetCode($randomCode);
        self::updateUser($user);
        
        $domain = Kohana::config_load('config');
        $domain = $domain['site_domain'];
        
        $body = 'You may reset your JesseWeather password with the below link.'.PHP_EOL;
        $body .= 'http://'.$domain.'/user/reset/'.$randomCode.PHP_EOL;
        $body .= 'Your username is: '.$user->getUsername();
        
        $transport = Swift_MailTransport::newInstance();
        
        $message = Swift_Message::newInstance();
        $message->setSubject('Reset Password');
        $message->setFrom('donotreply@jesseweather.com');
        $message->setTo($email);
        $message->setBody($body);
        
        $transport->send($message);
    }
    
    public static function activateUser($activationCode) {
        $db = Database::instance();
        
        $query = "SELECT * from users WHERE activationCode='$activationCode'";
        $result = $db->query($query);
        
        foreach ($result as $row) {
            $user = self::populateUser($row);
            $user->setIsActivated(1);
            $user = self::updateUser($user);
            return $user;
        }
        return FALSE;
    }
    
    public static function isActivationCodeActivated($activationCode) {
        $db = Database::instance();
        
        $query = "SELECT * from users WHERE activationCode='$activationCode'";
        $result = $db->query($query);
        
        foreach ($result as $row) {
            if ($row->isActivated == '1') {
                return TRUE;
            } else {
                return FALSE;
            }
        }
        
        return FALSE;
    }
    
    public static function getUserByUsername($username) {
        $db = Database::instance();
        
        $result = $db->query("SELECT * FROM users WHERE username='$username'");
        
        if ($result->count() > 0) {
            foreach ($result as $row) {
                $user = self::populateUser($row);
                return $user;
            }
        } else {
            return FALSE;
        }
    }
    
    public static function getAllUsers() {
        $db = Database::instance();
        
        $result = $db->query("SELECT * FROM users");
        $list = array();
        
        foreach ($result as $row) {
            $list[] = self::populateUser($row);
        }
        
        return $list;
    }
    
    public static function getUserByUserID($userID) {
        $db = Database::instance();
        
        $result = $db->query("SELECT * FROM users WHERE userID='$userID'");
        
        if ($result->count() > 0) {
            foreach ($result as $row) {
                $user = self::populateUser($row);
                return $user;
            }
        } else {
            return FALSE;
        }
    }
    
    public static function getUserByEmail($email) {
        $db = Database::instance();
        
        $result = $db->query("SELECT * FROM users WHERE email='$email'");
        
        if ($result->count() > 0) {
            foreach ($result as $row) {
                $user = self::populateUser($row);
                return $user;
            }
        } else {
            return FALSE;
        }
    }
    
    public static function getUserByPasswordResetCode($resetCode) {
        $db = Database::instance();
        
        $result = $db->query("SELECT * FROM users WHERE passwordResetCode='$resetCode'");
        
        if ($result->count() > 0) {
            foreach ($result as $row) {
                $user = self::populateUser($row);
                return $user;
            }
        } else {
            return FALSE;
        }
    }
    
    public static function authenticateUser($username, $password, $rememberMe) {
        $user = self::getUserByUsername($username);
        if (!$user) {
            return FALSE;
        } else {
            $passwordHash = $user->hashPassword($password);
            if ($passwordHash == $user->getPasswordHash()) {
                $session = Session::instance();
                $_SESSION['userID'] = $user->getUserID();
                
                //set a rememberMe for a year as well if $rememberMe
                if ($rememberMe) {
                    self::setRememberMeCookie();
                }
                
                return $user;
            } else {
                return FALSE;
            }
        }
    }
    
    private static function setRememberMeCookie() {
        $rememberMeID = uuidhelper::generate();
        $rememberMeID .= '-'.uuidhelper::generate();
        $oneYearFromNow = time() + 86400 * 365;
        $domain = Kohana::config('config');
        $domain = $domain['site_domain'];
        setcookie('rememberme', $rememberMeID, $oneYearFromNow, '/', $domain);
    }
    
    public static function isUserLoggedIn() {
        $session = Session::instance();
        if (isset($_SESSION['userID'])) {
            return self::getUserByUserID($_SESSION['userID']);
        }
    }
    
    public static function logout() {
        self::deleteRememberMeCookie();
        $session = Session::instance();
        $session->destroy();
    }
    
    private static function deleteRememberMeCookie() {
        $domain = Kohana::config('config');
        $domain = $domain['site_domain'];
        setcookie('rememberme', '', time() - 86400 * 365, '/', $domain);
        return TRUE;
    }
}
?>
I also have a security helper I use to do some checks throughout the site:
Code:
<?php 
class securityhelper {
    public static function noLoggedInUsersAllowed() {
        if (UserManager::isUserLoggedIn()) {
            url::redirect('/');
        }
    }
    
    public static function mustBeLoggedIn() {
        if (!UserManager::isUserLoggedIn()) {
            dialoghelper::addDialog('error', 'You must be signed in to access that page');
            url::redirect('/');
        }
        return TRUE;
    }
    
    public static function mustBeAdminUser() {
        //must be logged in
        $user = UserManager::isUserLoggedIn();
        if (!$user) {
            url::redirect('/');
        }
        
        //must be admin
        $adminUsers = Kohana::config('adminusers');
        $adminUsers = $adminUsers['adminUsers'];
        
        if (!in_array($user->getUserID(), $adminUsers, TRUE)) {
            url::redirect('/');
        }
        
        //well..they must be an admin user!
        return TRUE;
    }
    
    public static function getUserID() {
        $user = UserManager::isUserLoggedIn();
        return $user->getUserID();
    }
    
    public static function getUser() {
        $user = UserManager::isUserLoggedIn();
        return $user;
    }
    
    public static function doesUserOwnNotification(Notification_Model $notification) {
        $user = UserManager::isUserLoggedIn();
        
        if ($user->getUserID() != $notification->getUserID()) {
            dialoghelper::addDialog('error', 'Permission denied.');
            url::redirect('/notifications');
        }
        
        return TRUE;
    }
    
    public static function doesUserOwnNotificationRule(NotificationRule_Model $notificationRule) {
        $user = UserManager::isUserLoggedIn();
        $notification = NotificationManager::getNotificationByID($notificationRule->getNotificationID());
        
        if ($user->getUserID() != $notification->getUserID()) {
            dialoghelper::addDialog('error', 'Permission denied.');
            url::redirect('/notifications');
        }
        
        return TRUE;
    }
}
?>

Don't over-think what a framework is. It just basically provides some structure for auto-loading and some libraries so you don't reinvent the wheel everywhere.

The beauty is that you can easily use the code for other projects if you get pretty OO with it.

I am in the process of re-writing some of the above user code to further secure it. The rememberme parts of it aren't completed yet and haven't been tested.
 
The more advanced the site becomes, the more I'll lean towards a framework, and the more object oriented I'll write the code.

Some things..need to just stay simple -- while others will benefit over the long run by putting more time into it from the start.
 
Okay, that makes sense. It basically does the tedious work for you.

I dunno, though... I still kinda like hand-coding. It relaxes me. Guess I'm just a geek at heart. There's just something about a PHP script I wrote working perfectly the first time I run it... that's still a real rush for me.

I guess maybe I should grow up... :D

-Rich
 
Okay, that makes sense. It basically does the tedious work for you.

I dunno, though... I still kinda like hand-coding. It relaxes me. Guess I'm just a geek at heart. There's just something about a PHP script I wrote working perfectly the first time I run it... that's still a real rush for me.

I guess maybe I should grow up... :D

-Rich

You still do a lot of hand-coding with most of the frameworks. They're just something to build on. Keep in mind that a CMS and a framework are two totally different beasts.

Nearly all of the above was hand-written. The user model's getters and setters were mostly generated by my IDE with a click.
 
Also you may notice in the above code that I'm not putting any effort towards preventing SQL injection. That is because the framework scrubs the input data before it even gets to me.
 
You still do a lot of hand-coding with most of the frameworks. They're just something to build on. Keep in mind that a CMS and a framework are two totally different beasts.

Nearly all of the above was hand-written. The user model's getters and setters were mostly generated by my IDE with a click.

You got it. A CMS is *supposedly* designed to make it so non-tech people can update their sites without having to know any code - they simply install 'modules' that have GUI's that allow them to add functionality to their site. Unfortunately, I tend to spend more time 'tweaking' those modules to get them to do what my boss wants them to do than it would take for me to write them from scratch.

A framework is supposed to provide a structure/architecture for the developer to keep things organized and sometimes provide some built-in automated script generation capabilities.

The project I did this semester had so many dang objects in it (because I was trying to keep the data as 'normalized' as possible) that it would have been a nightmare to do it without some sort of MVC framework to help me keep things separated.
 
The frameworks start to make a lot of sense when you're building a large-scale site that has a lot of dynamic action in the background. More or less the framework is just there to make things easier. Libraries already available for pagination, input validation, database access, capchas, encryption, profiling, memcache, and on..and on..and on. They generally have auto-loading pre-configured for your utilities, libraries, views, etc. I haven't wrote an include or require_once statement in a LONG time.

I write a lot more object-oriented PHP these days then I used to. Originally I never saw the point, but as I started to do it, it just makes things much easier to maintain.

--snip Jesse's code --

I like it! Looks like you can do with PHP what I've been doing with RoR. I guess I just need to get more in-depth with it than I have in the past to get the truck OO functionality out of it.
 
Also you may notice in the above code that I'm not putting any effort towards preventing SQL injection. That is because the framework scrubs the input data before it even gets to me.

Well that's a big plus.

Nonetheless, I think the size and complexity of what I do is still at a point at which I can do it by hand-coding, which is good in that it helps me keep improving. Knowledge doesn't stick as easily to a middle-aged brain, I find. But I will start looking into the frameworks mentioned to familiarize myself with them, if nothing else.

Thanks,

Rich
 
Well, I was up until 4am this morning putting the finishing touches on our RoR semester project. Made the presentation at 8am. I didn't feel very good about the presentation itself b/c I was so draggy, but both instructors came up to me afterwards and said that they were amazed at how much we got done. Considering the fact that the other team members didn't do squat for the project, no matter how much I pushed them, I consider it an individual victory rather than a team experience.

One instructor actually said he was "blown out of his seat" by the functionality we had and they were impressed at how we molded our system to meet the users' requests.

So now I can move on to stuff that *I* actually want work on for a while.
 
Congrats Chris.

One big advantage of school projects is that they end with the class. You don't have to support them forever. Enjoy the glow.

Joe
 
Well, I was up until 4am this morning putting the finishing touches on our RoR semester project. Made the presentation at 8am. I didn't feel very good about the presentation itself b/c I was so draggy, but both instructors came up to me afterwards and said that they were amazed at how much we got done. Considering the fact that the other team members didn't do squat for the project, no matter how much I pushed them, I consider it an individual victory rather than a team experience.

One instructor actually said he was "blown out of his seat" by the functionality we had and they were impressed at how we molded our system to meet the users' requests.

So now I can move on to stuff that *I* actually want work on for a while.

Sounds like my two capstone projects... Each time ended up with two people out of five who did all the work. But at least you know that YOU know your stuff. Good work! :D
 
Back
Top