An introduction to Zend Framework 1.8 using Zend_Tool, Zend_Application, a simple DAO and a very simple model that uses that DAO.
In the end you have a fully working application
HTML Injection Attacks: Impact and Mitigation Strategies
Zend Framework 1.8 workshop
1. Zend Framework 1.8 workshop
Zend Framework
Presentation
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
2. Zend Framework 1.8 workshop
About Me:
PHP5 Zend Certified Engineer
ZF Contributor since 2008
Freelance Consultant
PHP Community active member
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
3. Zend Framework 1.8 workshop
Zend Framework
• Full Stack Framework
• Component Library
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
4. Zend Framework 1.8 workshop
How to Get It?
• Grab it from the download page:
http://framework.zend.com/download/latest
• Through Subversion:
http://framework.zend.com/svn/framework/standard/trunk/
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
5. Zend Framework 1.8 workshop
How To Install?
Add it to your php.ini include_path directive
include_path = .:/usr/local/lib/php:/PathToZendFrameworkLibrary
That’s it!
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
6. Zend Framework 1.8 workshop
Starting A New Project With Zend_Tool
First requirements:
• For *nix environments copy the zf.sh and zf.php from the ZF/bin
To the same directory as your PHP binary
• For Windows:
•copy the zf.php and zf.bat to the same directory as your
PHP binary
•add the php path to your PATH environment Var:
# Right-click My Computer and select |Properties.
# Select the Environment page.
# In the System Variables area, click on PATH.
# Add the php path to the end in the format VALUE1;VALUE2;c:php
# Click Apply.
# The changes take effect immediately.
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
7. Zend Framework 1.8 workshop
Creating the project “MyProject”
$ zf create project /path/to/non-existent-dir-called-MyProject
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
8. Zend Framework 1.8 workshop
Adding a “MyProject” vhost
Testing environment httpd.conf or httpd-vhosts.conf:
<VirtualHost *:80>
ServerName MyProject
DocumentRoot absolute-path-to-MyProject-folder
ErrorLog logsMyProject-error.log
CustomLog logsMyProject-access.log common
<Directory />
Options FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
Satisfy all
</Directory>
</VirtualHost>
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
9. Zend Framework 1.8 workshop
For windows: Add the following line to the /etc/host file
127.0.0.1 MyProject
Restart apache, fire up the browser and go to: http://MyProject
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
10. Zend Framework 1.8 workshop
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
11. Zend Framework 1.8 workshop
Creating an Action + View
Go to the MyProject directory and issue the following command
to create the helloAction in the IndexController and corresponding view:
$ zf create action hello index
For a full list of commands simply visit:
http://framework.zend.com/manual/en/zend.tool.project.create-a-project.html
Or issue the command:
$ zf --help
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
12. Zend Framework 1.8 workshop
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
13. Zend Framework 1.8 workshop
Creating a Module and Controller
$ zf create module admin
$ zf create controller index 1 admin
Note: Trying to create a controller that already exists in another
Module might result in an error. Depending on the Zend_Tool
Verion you have. The solution is to apply the patch from
ZF Issue Tracker: http://framework.zend.com/issues/browse/ZF-6853
Note: If you applied this patch, make sure all controller names in the admin
module start with Admin_
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
14. Zend Framework 1.8 workshop
Registering the Module
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initAutoloadModuleAdmin()
{
$autoloader = new Zend_Application_Module_Autoloader(array(
'namespace' => 'Admin',
'basePath' => APPLICATION_PATH.'/modules/admin',
));
return $autoloader;
}
}
The method is called automatically by Zend_Application as it starts with _init.
You can choose the remainder of the method name as you like.
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
15. Zend Framework 1.8 workshop
Registering the Module
myProject/application/configs/application.ini
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
16. Zend Framework 1.8 workshop
Setting up the Mysql Database
Add to configs/application.ini [production]
===============================
resources.db.adapter = PDO_MYSQL
resources.db.params.host = localhost
resources.db.params.username = nick
resources.db.params.password = 12345
resources.db.params.dbname = myproject
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
17. Zend Framework 1.8 workshop
Create the database table
CREATE TABLE users (
id int(11) NOT NULL auto_increment,
username varchar(100) NOT NULL,
pwd varchar(32) NOT NULL,
firstname varchar(20) NOT NULL,
PRIMARY KEY (id)
);
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
18. Zend Framework 1.8 workshop
Populate the table
INSERT INTO users (username, pwd, firstname)
VALUES
('NickBelhomme', md5('hello'), 'Nick'),
('ChanieNavez', md5('strong'), 'Chantal'),
('ElvisP', md5('presley'), 'Elvis');
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
19. Zend Framework 1.8 workshop
The Model + DAO
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
20. Zend Framework 1.8 workshop
myProject/application/modules/admin/models/dao/Interface.php
interface Admin_Model_Dao_Interface
{
public function find($id);
public function insert($username, $pwd, $firstname);
public function update($id, $username, $pwd, $firstname);
public function delete($id);
public function findAll();
}
Common interface between all DAOs.
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
21. Zend Framework 1.8 workshop
myProject/application/modules/admin/models/dao/UserDB.php
class Admin_Model_Dao_UserDB extends Zend_Db_Table
implements Admin_Model_Dao_Interface
{
protected $_name = 'users';
public function find($id)
{
Very Simple DAO
$id = (int)$id;
$row = $this->fetchRow('id = ' . $id); (Data Access Object)
if (!$row) {
throw new Exception("Count not find row $id");
}
return $row;
}
public function insert($username, $pwd, $firstname)
{
$data = array(
'username' => $username,
'pwd' => $this->hashPassword($pwd),
'firstname' => $firstname,
);
parent::insert($data);
}
//...
}
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
22. Zend Framework 1.8 workshop
myProject/application/modules/admin/models/Dao/UserDB.php
class Admin_Model_Dao_UserDB extends Zend_Db_Table
implements Admin_Model_Dao_Interface
{
//…
public function update($id, $username, $pwd, $firstname)
{
$data = array( Very Simple DAO
'username' => $username,
'pwd' => $this->hashPassword($pwd),
(Data Access Object)
'firstname' => $firstname,
);
parent::update($data, 'id = '. (int)$id);
}
public function delete($id)
{
parent::delete('id =' . (int)$id);
}
public function findAll() {
return $this->fetchAll();
}
protected function hashPassword($pwd) {
return md5($pwd);
}
}
?>
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
23. Zend Framework 1.8 workshop
myProject/application/modules/admin/models/User.php
class Admin_Model_User
{
const DAO_CLASS = 'Admin_Model_Dao_UserDB';
protected $dao;
public function __construct() {
$daoClassName = self::DAO_CLASS;
$this->dao = new $daoClassName(); The Model
} using the DAO.
public function find($id)
{
return $this->dao->find($id);
Easy Switching between
} Different data resources
public function insert($username, $pwd, $firstname)
{
return $this->dao->insert($username, $pwd, $firstname);
}
public function update($id, $username, $pwd, $firstname)
{
return $this->dao->update($id, $username, $pwd, $firstname);
}
// ...
}
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
24. Zend Framework 1.8 workshop
myProject/application/modules/admin/models/User.php
<?php
class Admin_Model_User
{ The Model
// ... using the DAO.
public function delete($id)
{ Easy Switching between
return $this->dao->delete($id); Different data resources
}
public function findAll()
{
return $this->dao->findAll();
}
}
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
25. Zend Framework 1.8 workshop
The Actions and Views
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
26. Zend Framework 1.8 workshop
Setting up the admin actions
$ zf create action add index 1 admin
$ zf create action edit index 1 admin
$ zf create action delete index 1 admin
Again if you are using a version of Zend_Tool which isn’t fully module
Aware you can patch the Zend_Tool_Project_Provider_Action with
if (self::hasResource($this->_loadedProfile, $name, $controllerName, $module))
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
27. Zend Framework 1.8 workshop
The Admin_IndexController indexAction
public function indexAction()
{
$users = new Admin_Model_User();
$this->view->users = $users->findAll();
}
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
29. Zend Framework 1.8 workshop
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
30. Zend Framework 1.8 workshop
The Admin_IndexController deleteAction
REST:
public function deleteAction() irreversible
{ action use
if ($this->getRequest()->isPost()) { POST not
$del = $this->getRequest()->getPost('del'); GET
if ($del == 'Yes') {
$id = $this->getRequest()->getPost('id');
$users = new Admin_Model_User();
$users->delete($id);
}
$this->_redirect('/admin/');
} else {
$id = $this->_getParam('id', 0);
$users = new Admin_Model_User();
$this->view->user = $users->find($id);
}
}
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
31. Zend Framework 1.8 workshop
The corresponding delete.phtml view script:
myProject/application/modules/admin/views/scripts/index/delete.phtml
<p>Are you sure that you want to delete
'<?php echo $this->escape($this->user['username']); ?>' aka
'<?php echo $this->escape($this->user['firstname']); ?>'?
</p>
<form action="<?php echo $this->url(array('action'=>'delete')); ?>" method="post">
<fieldset>
<input type="hidden" name="id"
value="<?php echo $this->escape($this->user['id']); ?>" />
<input type="submit" name="del" value="Yes" />
<input type="submit" name="del" value="No" />
</fieldset>
</form>
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
32. Zend Framework 1.8 workshop
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
33. Zend Framework 1.8 workshop
The Admin_IndexController addAction
public function addAction()
{
if ($this->getRequest()->isPost()) {
$action = $this->getRequest()->getPost('action');
if ($action == 'add') {
$username = $this->getRequest()->getPost('username');
$pwd = $this->getRequest()->getPost('pwd');
$firstname = $this->getRequest()->getPost('firstname');
$users = new Admin_Model_User();
$users->insert($username, $pwd, $firstname);
}
$this->_redirect('/admin/');
}
}
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
34. Zend Framework 1.8 workshop
The corresponding add.phtml view script:
myProject/application/modules/admin/views/scripts/index/add.phtml
<h2>Add a new User</h2>
<form action="<?php echo $this->url(array('action'=>'add')); ?>" method="post">
<fieldset>
username: <input type="text" name="username"><br/>
password: <input type="password" name="pwd"><br/>
firstname: <input type="text" name="firstname"><br/>
<input type="submit" name="action" value="add" />
</fieldset>
</form>
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
35. Zend Framework 1.8 workshop
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
36. Zend Framework 1.8 workshop
The Admin_IndexController editAction
public function editAction()
{
if ($this->getRequest()->isPost()) {
$action = $this->getRequest()->getPost('action');
if ($action == 'edit') {
$id = $this->getRequest()->getPost('id');
$username = $this->getRequest()->getPost('username');
$pwd = $this->getRequest()->getPost('pwd');
$firstname = $this->getRequest()->getPost('firstname');
$users = new Admin_Model_User();
$users->update($username, $pwd, $firstname);
}
$this->_redirect('/admin/');
} else {
$id = $this->_getParam('id', 0);
$users = new Admin_Model_User();
$this->view->user = $users->find($id);
}
}
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
38. Zend Framework 1.8 workshop
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
39. Zend Framework 1.8 workshop
Authentication:
Zend_Auth
Authentication is loosely defined as determining whether
an entity actually is what it purports to be (i.e., identification),
based on some set of credentials.
http://framework.zend.com/manual/en/zend.auth.html#zend.auth.introduction
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
40. Zend Framework 1.8 workshop
Append the DAO and User Classes
interface Admin_Model_Dao_Interface
{
// …
public function findCredentials($username, $pwd);
}
class Admin_Model_Dao_UserDB extends Zend_Db_Table
implements Admin_Model_Dao_Interface
{
// …
public function findCredentials($username, $pwd)
{
$select = $this->select()->where('username = ?', $username)
->where('pwd = ?', $this->hashPassword($pwd));
$row = $this->fetchRow($select);
if($row) {
return $row;
}
return false;
}
}
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
41. Zend Framework 1.8 workshop
Append the DAO and User Classes
class Admin_Model_User
{
// ...
public function findCredentials($username, $password)
{
return $this->dao->findCredentials($username, $password);
}
}
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
42. Zend Framework 1.8 workshop
Always use a vendor or project prefix
And inform the autoloader of library prefixes
Prepend the application bootstrap
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initAutoloadModuleDefault()
{
$autoloader = new Zend_Application_Module_Autoloader(array(
'namespace' => 'Myp',
'basePath' => dirname(__FILE__)
));
return $autoloader;
}
//...
}
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
43. Zend Framework 1.8 workshop
Create an application model: The Auth Adapter
myProject/application/models/AuthAdapter.php
class Myp_Model_AuthAdapter implements Zend_Auth_Adapter_Interface
{
protected $username;
protected $password;
protected $user;
public function __construct($username, $password) {
$this->username = $username;
$this->password = $password;
$this->user = new Admin_Model_User();
}
public function authenticate()
{
$match = $this->user->findCredentials($this->username, $this->password);
if(!$match) {
$result = new Zend_Auth_Result(Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID, null);
} else {
$user = current($match);
$result = new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $user);
}
return $result;
}
}
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
44. Zend Framework 1.8 workshop
The IndexController loginAction
$ zf create action login index 1
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
45. Zend Framework 1.8 workshop
The IndexController loginAction
public function loginAction()
{
$auth = Zend_Auth::getInstance();
if(Zend_Auth::getInstance()->hasIdentity()) {
$this->_redirect('/index/hello');
} else if ($this->getRequest()->isPost()) {
$action = $this->getRequest()->getPost('action');
if ($action == 'login') {
$username = $this->getRequest()->getPost('username');
$pwd = $this->getRequest()->getPost('pwd');
$authAdapter = new Myp_Model_AuthAdapter($username, $pwd);
$result = $auth->authenticate($authAdapter);
if(!$result->isValid()) {
switch ($result->getCode()) {
case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
$this->view->error = 'user credentials not found';
}
} else {
$this->_redirect('/index/hello');
}
}
}
}
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
47. Zend Framework 1.8 workshop
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
48. Zend Framework 1.8 workshop
The IndexController helloAction
public function helloAction()
{
if(Zend_Auth::getInstance()->hasIdentity()) {
$this->view->user = Zend_Auth::getInstance()->getIdentity();
}
}
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
49. Zend Framework 1.8 workshop
The corresponding hello.phtml view script:
myProject/application/views/scripts/index/hello.phtml
<?php if(isset($this->user)):?>
welcome <?php echo $this->escape($this->user['firstname']); ?>,
to the MyProject application.
<?php else: ?>
you need to login first.
<a href="<?php echo $this->url(array('action' => 'login')); ?>">login</a>
<?php endif; ?>
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
50. Zend Framework 1.8 workshop
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
51. Zend Framework 1.8 workshop
And that is Authentication.
if(Zend_Auth::getInstance()->hasIdentity())
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
52. Zend Framework 1.8 workshop
What about?
•Authorization (Zend_Acl)
•Filter Input, Escape Output?
•Input Validation (Zend_Validate)
•Input filtering (Zend_Filter)
•Dynamic Forms (Zend_Form)
And all the other great stuff???!!!!
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
53. Zend Framework 1.8 workshop
There is always next time!
1 hour courses, remember??? ;)
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer
54. Zend Framework 1.8 workshop
Resources
•http://blog.nickbelhomme.com
•http://www.slideshare.net/weierophinney/zend-framework-workshop-dpc09
•http://en.wikipedia.org/wiki/Zend_Framework
•http://blog.astrumfutura.com/archives/373-The-M-in-MVC-Why-Models-
are-Misunderstood-and-Unappreciated.html
Source code of this workshop available at:
http://blog.nickbelhomme.com/wp-content/uploads/workshopzf1.8.zip
Nick Belhomme
17 June 2009
PHP5 Zend Certified Engineer