Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 50 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
50
Dung lượng
1,96 MB
Nội dung
181CHAPTER 7 • PROCESSING FORMS AND SENDING EMAIL keep in mind you need to create the directory images/captcha (the images directory residing in your application's public directory), or alternatively use Zend_Captcha_Image's setImgDir() method to explicitly specify an alternative directory. Validating the CAPTCHA Earlier I mentioned Zend_Captcha will handle the CAPTCHA validation for you. To validate a capt- cha, just tell Zend_Captcha_Image the name of the form variable which will be passed back to the controller when instantiating the class. Then when the form variable is passed back, use the isVal- id() method like you would any other validation class: 01 $captcha = new Zend_Captcha_Image(array('name' => 'gamer', 'wordLen' => 5)); 02 $captcha->setFont("/usr/share/fonts/truetype/ttf-bitstream-vera/VeraBd.ttf"); 03 $captcha->generate(); 04 $this->view->captcha = $captcha->render($this->view); 05 06 if ($captcha->isValid($this->_request->getPost('gamer'))) { 07 echo "VALID!"; 08 } Conclusion The impressive form creation, validation and ltering features offered by the Zend Framework leave you with no excuse for not properly vetting input arriving from external sources. Be sure to take ad- vantage of these time-saving (and perhaps job-saving) features no matter the type of website. Like- wise, the Zend_Mail component makes sending e-mail from your website a total breeze, replacing the tricky and error-prone strategies of the past. The next chapter tackles another important topic: user management. In this chapter you'll learn how implement user registration and login mechanisms, along with requisite features such as password recovery. Download at Boykma.Com Download at Boykma.Com CHAPTER 8 Managing Your User Community One of the most compelling aspects of the Web is it’s a two-way street. A website can disseminate in- formation almost as easily as it can ask for it, greatly expanding the attractiveness of your website in the process by allowing users to manage proles, control site preferences such as layout and content availability, and interact with other users. By providing similarly rich levels of interactivity to your users, you'll build brand loyalty, encourage users to tell their friends about the site, and be able to bet- ter respond to user needs by monitoring their behavior. Of course, your website will require a means for tying these sorts of interactions back to a specic user. The standard process for doing so is by prompting a registered user to login to the site using a username and password. Once logged in, any actions the user undertakes are then associated with the account tied to the provided username and password. As the developer, you'll need to create mechanisms for not only allowing the user to register, but also login, logout, and carry out various account-related tasks such password recovery and perhaps prole management. In this chapter you'll learn all about these tasks, building several of them with the help of the Zend_Auth framework component. You'll also learn how to create a facility for allowing users to build an onsite network by identifying certain other users as friends. Chapter Steps The goals of this chapter are accomplished in ve steps: • Step #1. Creating the Users Table and Model: Before anything can be done with user man- agement, we'll need to create a database table and model used to manage this data. We'll kick off this chapter by creating this table and model. • Step #2. Registering Users: Once the model has been created we'll want to begin populating it by providing users with an account registration form. This form will prompt users to create an account password while providing any other registration-related information you'd like to collect, such as the user's name and location. In this step we'll build upon what you learned in the last chapter by creating the registration form which collects this information. You'll also learn how to conrm registration by forcing the user to click on a link found in an e-mail sent to his account following submission of the registration form. • Step #3. Managing User Logins: The Zend Framework's Zend_Auth component makes it easy to manage user logins, providing mechanisms for logging the user into the site, main- taining the user's session as he interacts with the site, and logging the user out of the site. In this step you'll learn how these features are implemented. You'll also learn how to create a password recovery feature so the user can autonomously reset his password in the event it is forgotten. • Step #4: Displaying User Proles: Chances are you'll want to display user prole informa- tion on the website, in addition to other site content he's compiled over time. In this section Download at Boykma.Com 184 CHAPTER 8 • MANAGING YOUR USER COMMUNITY you'll learn how to do this. For the purposes of demonstration this example will only include the user's name and last login date, but it will nonetheless serve as a basis for adding addi- tional content. In fact, in the nal step (discussed next) you'll learn how to integrate the user's friends list into this prole page. • Step #5. Making Friends: In the nal step of this chapter we'll create a mechanism for giv- ing users the ability to identify other users as friends, thereby opening up the possibility for you to build features which allow friends to track the interactions of each other on the site, such as new additions to their game collection, or status updates regarding what game they're currently playing. Step #1. Creating the Users Table and Model Before creating any of the scripts used to power the aforementioned features, it makes sense to rst spend some time designing the table and model used to store and manage the user data. Let's start by creating the users table, subsequently building the Users model based on the corresponding schema. The Users Table The users table will store each user's key account information, namely the username and password, prole-related information such as his name and gender, and data which will help us gather simple usage metrics, such as when the account was created, when it was last updated, and when the user last logged into the system. The users table follows: CREATE TABLE users ( id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, email VARCHAR(255) NOT NULL, password CHAR(32) NOT NULL, registration_key CHAR(32) NOT NULL, conrmed TINYINT UNSIGNED NOT NULL DEFAULT 0, handle VARCHAR(32) NOT NULL, rst_name VARCHAR(255) NOT NULL, last_name VARCHAR(255) NOT NULL, gender ENUM('m','f') NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, last_login DATETIME NOT NULL ); Given each relevant line of this listing can be easily identied by the column name rather than a line number, I'll break from the usual protocol and instead use these names to break down the listing: • The id serves as the table's primary key which you learned all about in Chapter 4. • The email will serve double-duty not only as the vehicle for contacting each user, but also as the account's username which the user will have to supply when logging into the system. Some sites ask the user to contrive a nickname (for instance, I typically use wjgilmore), how- Download at Boykma.Com 185CHAPTER 8 • MANAGING YOUR USER COMMUNITY ever doing so requires the user to recall another piece of information when logging in. On the contrary, an e-mail address is almost certainly instantly recallable by the user, and therefore serves as an ideal username. • The password is stored as a 32-character encrypted string, created using a one-way calcula- tion based on the user's provided password. Storing the password in this fashion makes it impossible for an attacker to determine the original password text even if he somehow gets his hands on the table data. Each time the user logs in, we will encrypt the provided password and compare it to the stored encrypted string. You'll learn how this encryption process occurs in the section "Registering a New User Account". • The registration_key column stores a random 32-character string used as an important part of the registration conrmation process. You'll learn more about the role of this column in the section "Conrming Registration". • The conrmed column is set once the user has conrmed his e-mail address. You'll learn more about the role of this column in the section "Conrming Registration". • The handle column is used to refer to the gamer on the site and among friends. Think of the handle as a fun nickname, much like a gamer handle used when playing the Xbox 360. • The rst_name and last_name columns are used as alternative ways to refer to the user when we need to do for more formal reasons, such as when sending administrative emails. • The gender column identies the user's gender, and is primarily used for referring to the proper possessive grammar when talking about for instance the user's game collection (e.g. Jason has 14 games in his collection), but is also useful for determining website user trends. • The created_at, updated_at, and last_login columns are used to determine when the user's account was created, last updated, and last logged into, respectively. With the users table created, it's time to create the data model we'll use to interact with it. The Users Model As is typical, the model used to represent the users table is actually broken into two parts: the User model, which is used for performing actions against the users table writ large, and the UserRow model, which is used for accessing and manipulating the users table at the row level. In this section we'll build both models, and subsequently use them in later sections. Creating the User Model The Users model, displayed in Listing 8-1, includes basic functionality for accessing the users table. Obviously as your website grows in size and complexity, so will the Users model, however what is presented here serves as a solid starting point. Take some time to review Listing 8-1 and thoroughly review the explanation that follows it. Download at Boykma.Com 186 CHAPTER 8 • MANAGING YOUR USER COMMUNITY Listing 8-1. The User Model 01 class User extends Zend_Db_Table 02 { 03 04 /** 05 * The actual name of the table 06 * 07 * @var string 08 */ 09 protected $_name = 'users'; 10 11 /** 12 * The table's primary key 13 * 14 * @var string 15 */ 16 protected $_primary = 'id'; 17 18 /** 19 * The User class' row model 20 * 21 */ 22 protected $_rowClass = 'UserRow'; 23 24 /** 25 * Retrieve a user using his email address 26 * 27 * @param string $email 28 * @return UserRow 29 */ 30 function getUserByEmail($email) 31 { 32 $query = $this->select(); 33 $query->where('email = ?', $email); 34 $result = $this->fetchRow($query); 35 return $result; 36 } 37 38 /** 39 * Retrieve user according to his gamer handle 40 * 41 * @param string $handle 42 * @return UserRow 43 */ 44 function getUserByHandle($handle) 45 { 46 $query = $this->select(); 47 $query->where('handle = ?', $handle); 48 $result = $this->fetchRow($query); Download at Boykma.Com 187CHAPTER 8 • MANAGING YOUR USER COMMUNITY 49 return $result; 50 } 51 52 /** 53 * Calculate the total number of registered users 54 * 55 * @return integer 56 */ 57 function getUserCount() 58 { 59 $query = $this->select('id'); 60 $result = $this->fetchAll($query); 61 return count($result); 62 } 63 64 } The code review follows: • Line 01 denes the model name, and extends the model from the Zend_Db_Table class. As mentioned in Chapter 6, I prefer to use single tense for model names (because we're referring to one table), and plural tense for table names (because the table manages multiple entities presumably of the same name, for instance the users table manages multiple users). • In order to override the Zend Framework's default convention of presuming the model name matches the table name it represents, line 09 overrides the default and species the table name is users rather than user. • Line 16 identies the table's primary key. • Line 22 identies the model used to represent the rows of the table represented by the User model. We'll talk about this model next. • Lines 30-36 dene the getUserByEmail() method, which can be used to retrieve a user when all you have available is the user's e-mail address. • Lines 44-50 dene the getUserByHandle() method, which can be used to retrieve a user when all you have available is the user's e-mail address. • Lines 57-62 dene a useful method we'll use to determine the total number of users in the system. For instance, GameNomad uses this method to display the total number of registered users at the top right of each page. Creating the UserRow Model Once a user or group of users have been identied using the User model, you can begin perform- ing row-specic operations using the UserRow model. Listing 8-2 presents a simple example of this model, complete with a simple method. Later in this chapter we'll add other methods to the model as Download at Boykma.Com 188 CHAPTER 8 • MANAGING YOUR USER COMMUNITY other features are introduced. Listing 8-2. The UserRow model 01 class UserRow extends Zend_Db_Table_Row 02 { 03 04 /** 05 * Determines whether the user is male 06 * 07 * @return boolean 08 */ 09 function isMale() 10 { 11 if ($this->gender == "m") 12 { 13 return TRUE; 14 } else { 15 return FALSE; 16 } 17 } 18 19 } Let's breakdown some code: • Line 01 denes the model name ( UserRow). Note this inherits from Zend_Db_Table_Row. The Zend Framework will be able to determine the relation to the User model based on the $_rowClass assignment made in the User model. • Lines 09-17 dene the isMale() function. Note how we can refer to the user's attributes us- ing $this, although keep in mind only those attributes which were made available by way of the query are available to the UserRow model. Step #2. Registering Users To create accounts, we need to provide users with an autonomous means for registering. This is typi- cally done in two steps, the rst providing the user with a form for creating the account, and the sec- ond requiring the user to conrm registration by clicking on an emailed link. In this section I'll show you how to carry out both steps. Creating a New User Account The registration process requires the user to complete a short form which will then be validated. If all provided data is proved valid, it will be inserted into the database and the second step (validation) will ensue. Download at Boykma.Com 189CHAPTER 8 • MANAGING YOUR USER COMMUNITY Let's begin with a screenshot (Figure 8-1) of a typical registration form, which should serve to give you a visual idea of the data we're collecting: Figure 8-1. A user registration form By this point in the book the form syntax should be pretty easy to gure out, so I'll move on to where the action's at (no pun intended), namely the Gamers controller's register action. This action is rather long, so rather than simply pasting in a listing which spans several pages I'll instead focus on two select sections and leave it to you to review the entire action located in the code download. Let's begin the review with Listing 8-2, which contains the code used to validate the form elds. Listing 8-2. The register action's validation tasks 01 // If the form has been submitted, process it 02 if ($this->getRequest()->isPost()) { 03 04 // Valid email address? 05 if (! Zend_Validate::is($this->_request->getPost('email'), 'EmailAddress')) { 06 $this->view->errors[] = "Invalid e-mail address."; 07 } // end valid email 08 09 // E-mail cannot already exist in database 10 $user = new User(); 11 $foundUser = $user->getUserByEmail($this->_request->getPost('email')); 12 if ($foundUser->id != "") { 13 $this->view->errors[] = "E-mail address already in database."; 14 } 15 16 // Handle must be between 2 and 20 characters 17 $validHandle = new Zend_Validate_StringLength(2,20); Download at Boykma.Com 190 CHAPTER 8 • MANAGING YOUR USER COMMUNITY 18 if (! $validHandle->isValid($this->_request->getPost('handle'))) { 19 $this->view->errors[] = "Handle must be between 2 and 14 characters."; 20 } // end valid handle 21 22 // Handle must consist solely of alphanumeric characters 23 $validHandle = new Zend_Validate_Alnum(); 24 if (! $validHandle->isValid($this->_request->getPost('handle'))) { 25 $this->view->errors[] = "Handle must consist of letters and numbers."; 26 } // end valid handle 27 28 // Handle cannot already exist in database 29 $foundUser = $user->getUserByHandle($this->_request->getPost('handle')); 30 if ($foundUser->id != "") { 31 $this->view->errors[] = "Handle already exists in database."; 32 } 33 34 // Password must be at least 6 characters 35 $validPswd = new Zend_Validate_StringLength(6,20); 36 if (! $validPswd->isValid($this->_request->getPost('password'))) { 37 $this->view->errors[] = "Password must be at least 6 characters."; 38 } // end valid password 39 40 // First name must not be empty 41 $validFirstName = new Zend_Validate_NotEmpty(); 42 if (! $validFirstName->isValid($this->_request->getPost('rst_name'))) { 43 $this->view->errors[] = "Please provide your rst name."; 44 } // end valid rst name 45 46 // Last name must not be empty 47 $validLastName = new Zend_Validate_NotEmpty(); 48 if (! $validLastName->isValid($this->_request->getPost('last_name'))) { 49 $this->view->errors[] = "Please provide your last name."; 50 } // end valid last name 51 52 // Valid gender? 53 if (! Zend_Validate::is($this->_request->getPost('gender'), 'NotEmpty')) { 54 $this->view->errors[] = "Please identify your gender."; 55 } // end valid gender 56 57 // If errors exist, prepare the form data for inclusion in the form so 58 // the user doesn't have to repopulate the data 59 if (count($this->view->errors) > 0) { 60 61 $this->view->email = $this->_request->getPost('email'); 62 $this->view->handle = $this->_request->getPost('handle'); 63 $this->view->rst_name = $this->_request->getPost('rst_name'); 64 $this->view->last_name = $this->_request->getPost('last_name'); 65 $this->view->gender = $this->_request->getPost('gender'); 66 Download at Boykma.Com [...]... code is included into the register action, any variables found in the string assigned to $email will be interpolated in the scope of the action Therefore the variables found on lines 04, 09, and 11 will all be converted to their appropriate values before being assigned along with the rest of the string to the $email variable Once the user receives the e-mail, he can click on the confirmation link,... password is first hashed using the md5() function before saving the password to the database • Lines 45-63 execute if the user is retrieving the form for the first time (presumably by way of clicking on the link found in the password recovery e-mail) Lines 50-52 use the provided recovery key to determine whether the key exists in the database If so, the form is presented Otherwise, an error message is... accommodate both the gory details surrounding session management and the number of account backend solutions, the Zend developers created the Zend_ Auth authentication component We'll use this component to build the features introduced in this section Listing 8-4 presents the login action Take some time to review the code, and carefully read the ensuing breakdown Download at Boykma.Com Listing 8-4 The login... review the code: • Lines 06-07 store the provided e-mail address and password in more accessible variables • Line 10 performs a quick check to determine whether the user mistakenly omitted either the e-mail address or password If not the action moves on to the authentication verification step • Line 15 identifies the type of authentication adapter we'll be using, in this case a database Notice the database... assigned the values of the user's provided form field entries, so we can repopulate the form and save the user some time and frustration Otherwise, if no errors have occurred, (line 68) we'll begin the process of adding the user's registration data to the users table and preparing and sending the confirmation e-mail Next, let's take a look at the second step in the register action, in which the user's... users with the ability to view at least some part of the other registered users' profiles Of course, you might limit the display of certain parts of the profiles to just the user's friends (discussed in the next step), but attributes such as each user's first and last name, gender, and time of last login seem to be fair game You'll also want to provide users with an easy way to point others to their... to uniquely and securely identify the invitation • The inviter_id is the primary key assigned to the user who is inviting the user to join his network • The invitee_id is the primary key assigned to the user who is being invited to join the inviter's network Next let's take a look at the Invitation model Listing 8-8 The Invitation model 01 class Invitation extends Zend_ Db_Table_Abstract 02 { 03 04... 08 09 /** * Logs the user out of the application * */ public function logoutAction() { Zend_ Auth::getInstance()->clearIdentity(); $this->_redirect('/'); } Listing 8-5 The logout action This action will log the user out of the application by first deleting the session (line 07) and then redirecting the user to the website's index page Any subsequent attempts to access pages requiring authentication will... altogether out of frustration Fortunately, creating this feature is easy! VIDEO Recovering Passwords with Zend_ Auth The Zend_ Auth component makes managing user registrations and logs very easy, but the process of recovering passwords is often a bit more confusing This video discusses the factors involved in recovering user passwords, and showing you how to implement this feature using Zend_ Auth Watch the. .. video at http://www.easyphpwebsites.com/zfw/videos/ Because for security purposes the user's chosen password has been encrypted using a one-way algorithm, there is no way to simply retrieve and send it to the user Therefore we'll need to create a solution for allowing the user to explicitly reset the password In order to do so securely, the user will need to verify his identity either by responding . the scope of the action. Therefore the variables found on lines 04, 09, and 11 will all be converted to their appropriate values before being assigned along with the rest of the string to the. code: • Line 01 denes the model name ( UserRow). Note this inherits from Zend_ Db_Table_Row. The Zend Framework will be able to determine the relation to the User model based on the $_rowClass assignment. of the registration form. • Step #3. Managing User Logins: The Zend Framework& apos;s Zend_ Auth component makes it easy to manage user logins, providing mechanisms for logging the user into the