<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>phpDevelopment &#124; Blog &#187; PHP Tutorials</title>
	<atom:link href="http://phpdev.ro/category/php_tutorials/feed" rel="self" type="application/rss+xml" />
	<link>http://phpdev.ro</link>
	<description>Bringing you the best of the webdevelopement ecosphere</description>
	<lastBuildDate>Thu, 22 Jul 2010 14:06:04 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Zend Framework Tutorial Series: Part 3 – Login and Signup with (RE)Captcha</title>
		<link>http://phpdev.ro/zend-framework-tutorial-series-part-3-login-and-signup-with-recaptcha.html</link>
		<comments>http://phpdev.ro/zend-framework-tutorial-series-part-3-login-and-signup-with-recaptcha.html#comments</comments>
		<pubDate>Tue, 13 Jul 2010 12:40:43 +0000</pubDate>
		<dc:creator>Andrei Gabreanu</dc:creator>
				<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[Framework]]></category>
		<category><![CDATA[login]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[signup]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[Zend]]></category>

		<guid isPermaLink="false">http://phpdev.ro/?p=1101</guid>
		<description><![CDATA[The third part of the tutorial series will present you with a fully functionable solution for a login and signup page that activates a RECaptcha, via Zend_Captcha as a Service, when the user attempts to login/signup 3 times and fails. The tutorial will also show you how to use your models and how to structure your bussiness logic inside your module based application.]]></description>
			<content:encoded><![CDATA[<p>Continuing with the tutorial series, we will now see how to manage a login / sign up page with spam prevention via (RE)captcha provided by Zend_Captcha. We will see how to manage validation on the server side, how to contain your business logic in your models, how to prevent multiple submissions and how to communicate with your database without giving your controller any knowledge about your DAO. We will use the Repository and Factory design pattern to be able to easily Unit Test your models and to contain your business logic and database access object into separate layers. We will also see how to insert your dependencies everywhere in your objects to follow the Dependency Injection standards so that your code can be easily unit tested.</p>
<div style="padding:35px 15px 15px 15px; background-color:#DDF8CC; margin-bottom:15px;">
<h4 style="font-size:16px; text-align:center"><img src="http://www.gstatic.com/codesite/ph/images/dl_arrow.gif" /> <a href="http://code.google.com/p/zf-module-based-app/downloads/list" target="_blank">Download Sample Application from Google Code Here</a></h4>
</div>
<h2>1. The database &#038; the database config</h2>
<p>Before we start, lets create a database with a table called <strong>users</strong>. </p>
<p>The table <strong>users</strong> should contain 3 columns :</p>
<ul>
<li>id &#8211; primary key, auto increment, not null, unsigned int</li>
<li>username &#8211; varchar(128), not null</li>
<li>password &#8211; varchar(32), not null</li>
</ul>
<p>Now, in your application.ini, go to your <strong>resources.multidb.front_db</strong> and change the values to your connection string, as an example:</p>
<pre>
...
resources.multidb.front_db.adapter  = "pdo_mysql"
resources.multidb.front_db.host     = localhost
resources.multidb.front_db.username = MyDatabaseUsername
resources.multidb.front_db.password = MyDatabasePassword
resources.multidb.front_db.dbname   = MyDatabaseName
resources.multidb.front_db.default  = true
...
</pre>
<h2>2. The layouts</h2>
<p>We want to have a separate layout for the logged in users and another layout for guests. </p>
<p>To achieve this, in your <strong>/app_root/modules/frontoffice/layouts/</strong> make sure you have 2 files called: &#8220;public.phtml&#8221; and &#8220;layout.phtml&#8221; with the following contents: </p>
<p><br/></p>
<p><strong>layout.phtml</strong></p>
<pre>
	< ?php echo $this->doctype(); ?>
	< html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
	< head>
		< ?php echo $this->headMeta(); ?>
		< ?php echo $this->headTitle(); ?>
		< ?php echo $this->headStyle(); ?>
		< ?php echo $this->headLink(); ?>
		< script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js">< /script>
		< ?php echo $this->headScript(); ?>
	< /head>
	< body>
		< div class="container">
		< ?php foreach ($this->messages['error'] as $message):?>
			< div style="color:red;">< ?php echo $message?>< /div>
		< ?php endforeach;?>
		< ?php foreach ($this->messages['success'] as $message):?>
			< div style="color:green;">< ?php echo $message?>< /div>
		< ?php endforeach;?>
		< br />
		< br />
		< p>You are now logged in!< /p>
		< ?php echo $this -> layout () -> content; ?>
		< /div>
	< /body>
	< /html>
</pre>
<p>and in your <strong>public.phtml</strong></p>
<pre>
	< ?php echo $this->doctype(); ?>
	< html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
	< head>
		< ?php echo $this->headMeta(); ?>
		< ?php echo $this->headTitle(); ?>
		< ?php echo $this->headStyle(); ?>
		< ?php echo $this->headLink(); ?>
		< script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js">< /script>
		< ?php echo $this->headScript(); ?>
	< /head>
	< body>
		< div class="container">
		< ?php foreach ($this->messages['error'] as $message):?>
			< div style="color:red;"><?php echo $message?>< /div>
		< ?php endforeach;?>
		< ?php foreach ($this->messages['success'] as $message):?>
			< div style="color:green;"><?php echo $message?>< /div>
		< ?php endforeach;?>
		< br />
		< br />

		< ?php echo $this -> layout () -> content; ?>
		< /div>
	< /body>
	< /html>
</pre>
<p>This way, we can show a custom UI for the logged in users and another UI for the guests.</p>
<h2>3. The Auth Controller Plugin</h2>
<p>We now want to make sure that guests are redirected to the users/login page (we will talk about that controller/action in a moment).</p>
<p>Also, if the user is already authenticated, we do not want to allow him on the users/login page and he should be redirected to the index/index page</p>
<p>To achieve this, we will create a controller plugin in the <strong>/app_root/library/Custom/Controller/Plugin</strong> called <strong>Auth.php</strong> with the following contents:</p>
<p><br/></p>
<pre>
class Custom_Controller_Plugin_Auth extends Zend_Controller_Plugin_Abstract
{
	/**
	 * @var Zend_Auth
	 */
	protected $_auth;	

	public function __construct(Zend_Auth $auth)
	{
		$this->_auth = $auth;
	}

	public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
	{
		//Check if the user is not logged in
		if (!$this->_auth->hasIdentity())
		{
			return $this->_redirect($request, 'users', 'login', 'frontoffice');
		}

		//The user is logged in
		//Check if the authenticated user tries to access the users/login path
		if ('frontoffice' == $request->getModuleName()
			&#038;&#038; 'users' 		 == $request->getControllerName()
			&#038;&#038; 'login'		 == $request->getActionName())
		{
			return $this->_redirect($request, 'index', 'index', 'frontoffice');
		}
	}

	protected function _redirect($request, $controller, $action, $module)
	{
		if ($request->getControllerName() == $controller
			&#038;&#038; $request->getActionName()  == $action
			&#038;&#038; $request->getModuleName()  == $module)
		{
			return TRUE;
		}

		$url = Zend_Controller_Front::getInstance()->getBaseUrl();
		$url .= '/'   . $module
			 . '/' . $controller
			 . '/' . $action;

	   if (DEBUG)
	   {
	       debug_redirect($url);
	   }

	   return $this->_response->setRedirect($url);
	}
}
</pre>
<p>To run this plugin we need to go to the <strong>Application Bootstrap</strong> (the one from the <strong>app_root</strong>) and add the following function :</p>
<pre>
//init Auth Plugin
protected function _initAuthPlugin()
{
	Zend_Controller_Front::getInstance()->registerPlugin(
		new Custom_Controller_Plugin_Auth(Zend_Auth::getInstance()));
}
</pre>
<p>Now this basically tells our application to redirect to the /frontoffice/users/login in case we are not logged in (and it will avoid a redirect loop also if we are already there)</p>
<h2>4. The Users Controller</h2>
<p>The users controller will allows us to manage a signup and a login action for our guests. The controller will only handle the request and will communicate with the view to render the form and error messages. It will also communicate with the User Repository for user actions (to find out if the user already exists or if the form is valid or not).</p>
<p>Thus, in your <strong>/app_root/modules/frontoffice/controllers/</strong> create the file <strong>UsersController</strong> with the following contents:</p>
<pre>
class UsersController extends Frontoffice_Library_Controller_Action_Abstract
{
	public function indexAction()
	{
		return $this->redirect('users', 'login');
	}

	public function loginAction()
	{
		Zend_Layout::getMvcInstance()->setLayout('public');

		$form = new Frontoffice_Form_Login(
			array('userRepository' => Frontoffice_Model_Repositories_UsersFactory::factory()));

		if ($this->_request->isPost())
		{
			$data = $this->_request->getPost();
			if ($form->isValid($data))
			{
				return $this->redirect('index', 'index');
			}
			$form->setDefaults($data);
		}

		$this->view->form = $form;
	}

	public function logoutAction()
	{
		Zend_Auth::getInstance()->clearIdentity();
		return $this->redirect('users', 'login');
	}
}
</pre>
<p>This tells our application to redirect to the users/login in case we are trying to access the users/index path. If we are already on the login action, it simply instantiates a new form and injects the Users Repository.</p>
<p>If the request is actually a post and the form is valid with the data provided via the POST method, then it redirects the user to the index/index</p>
<p>Also, the action sets the layout to the public layout since the guest is not allowed to see our logged in UI.</p>
<p>You may ask yourself where are the errors treated. These are set in the form directly (either from form or model validation) and will be displayed in the view from the form so the controller is not aware of them</p>
<p>Also, if we go to users/logout we will be redirected to the users/login and our identity will be deleted</p>
<h2>5. The Login View</h2>
<p>Lets create the login.phtml view now in your <strong>/app_root/modules/frontoffice/views/scripts/users/</strong> with the following contents:</p>
<pre>
< div style="width:960px; margin:100px auto;">
	< h2>Login header</h2>

	< div style="width:500px; margin:5px; padding:0px 20px; float:left">
		< h3>Please login< /h3>

		< ?php if ($this->form->isErrors()):?>
			< ?php foreach ($this->form->getErrors() as $errors):?>
				< ?php foreach ($errors as $message):?>
					< div style="color:red"><?php echo $message;?>< /div>
				< ?php endforeach;?>
			< ?php endforeach;?>

			< ?php foreach ($this->form->getErrorMessages() as $error):?>
					< div style="color:red"><?php echo $error;?>< /div>
			< ?php endforeach;?>

		< ?php endif; ?>

		< form id="login" action="< ?php echo $this->escape($this->form->getAction()); ?>" method="< ?php echo $this->escape($this->form->getMethod());?>">

			Username: < ?php echo $this->form->username;?>< br />< br />

			Password: < ?php echo $this->form->password;?>< br />< br />

			< ?php echo $this->form->captcha;?>

			< input type="submit" value="Login" /> or < a  href="< ?php echo $this->url(array('controller' => 'users', 'action' => 'signup'), null, true);?>">Sign up< /a>
			< ?php echo $this->form->___h;?>

			< br />
			< br />

		< /form>
	< /div>
< /div>
</pre>
<p>It is a simple view which renders some form elements and the captcha (the form takes care to enable it or not)</p>
<h2>6. The Login Form</h2>
<p>The login form will allow us to define the elements we want to show; it will also be injected with the user repository so it can query it for an existent username and fail if it finds one but also user the repository to do the validation. I am not using form validation for elements that contain business logic. As an example, the &#8220;Not Empty&#8221; validation is done by the form while the requirements for the elements is done by the user repository.</p>
<p>The error messages are set in the form, by both the form and the repository, based on the source of it.</p>
<p>If the form contains errors (either from the element validators or from the business logic validators), they will be shown via the view.</p>
<p>If you the form gives an error 3 times, the captcha will be enabled and will now allow you to pass the form validation until you enter the right captcha code (note here that if you are behind a proxy, the captcha validation will not work)</p>
<p>Now lets create the form class. In your <strong>/app_root/modules/frontoffice/forms/</strong> create a file called <strong>Login.php</strong> with the following contents:</p>
<pre>
class Frontoffice_Form_Login extends Custom_Form
{
	/**
	 * @var Admin_Model_Repositories_Users
	 */
	protected $_user_repository;

	public function setUserRepository( $user_repository)
	{
		$this->_user_repository = $user_repository;
	}

    public function __construct($options = null)
    {
    	parent::__construct($options);

        $this->setName('login');

        $element = new Zend_Form_Element_Text('username', array('disableLoadDefaultDecorators' => true));
        $element->addDecorator('ViewHelper')
	            ->setRequired(true)
	            ->addErrorMessage('The username is required.');
		 $this->addElement($element);

        $element = new Zend_Form_Element_Password('password', array('disableLoadDefaultDecorators' => true));
        $element->addDecorator('ViewHelper')
                ->setRequired(true)
                ->addErrorMessage('The password is required.');
		$this->addElement($element);

        $element = new Zend_Form_Element_Hash('___h', array('disableLoadDefaultDecorators' => true));
        $element->setSalt('unique')
        		->addDecorator('ViewHelper')
        		->addErrorMessage('Form must not be resubmitted');
        $this->addElement($element);

        $captcha_session = new Zend_Session_Namespace('captcha');

        if ($captcha_session->tries > 999)
        {
	        $recaptcha = new Zend_Service_ReCaptcha('API_KEY_HERE',
	        									    'API_KEY_HERE');
	        $recaptcha->setOption('theme', 'clean');
	        $element = new Zend_Form_Element_Captcha('captcha',
													 array('disableLoadDefaultDecorators' => true,
													 	   'captcha'        => 'ReCaptcha',
														   'captchaOptions' => array('captcha' => 'ReCaptcha',
														   							 'service' => $recaptcha)));
			$element->addErrorMessage('Invalid security captcha code');
			$this->addElement($element);
        }

        $this->clearDecorators();
		$this->addDecorator('FormElements')
	         ->addDecorator('Form');
    }

    public function isValid($data)
    {
    	if (parent::isValid($data))
    	{
    		if ($this->_user_repository->authenticate($data['username'], $data['password']))
    		{
    			Zend_Session::namespaceUnset('captcha');
    			return TRUE;
    		}
    		else
    		{
    			$this->setErrors(array('Invalid username or password'));
    		}
    	}

    	$captcha_session = new Zend_Session_Namespace('captcha');
		if (empty($captcha_session->tries))
		{
			$captcha_session->tries = 0;
		}
		$captcha_session->tries = $captcha_session->tries + 1;
    	return FALSE;
    }
}
</pre>
<h2>7. The Users Repository (Model)</h2>
<p>Now lets see what the authenticate method does:</p>
<p>Go into your <strong>/app_root/modules/frontoffice/models/Repositories/</strong> and create the file <strong>Users.php</strong> with the following contents:</p>
<pre>

class Frontoffice_Model_Repositories_Users
{
	/**
	 * @var Admin_Model_Entities_User
	 */
	protected $_user_entity;

	/**
	 *
	 * @param Admin_Model_Entities_User $user_entity
	 */
	public function __construct($user_entity)
	{
		$this->_user_entity = $user_entity;
	}

	/**
	 * var array
	 */
	protected $_messages = array();

	/**
	 * Sets an error message
	 *
	 * @param string $name
	 * @param string $message
	 *
	 * @return bool
	 */
	public function setMessage($name, $message)
	{
		$this->_messages[$name] = $message;
		return TRUE;
	}

	/**
	 * Returns a list of all error messages
	 *
	 * @return array
	 */
	public function getMessages()
	{
		return $this->_messages;
	}

	/**
	 * Authenticates a user based on the username and password
	 *
	 * @param string $username
	 * @param string $password
	 *
	 * @return boolean
	 */
	public function authenticate($username, $password)
	{
		$filter = new Zend_Validate_StringLength(array('min' => 5, 'max' => 25));
		if (!empty($password) &#038;&#038; !$filter->isValid($password))
		{
			$this->setMessage('password', 'Invalid password. Length must be between 5 and 25 characters');
			return FALSE;
		}

    	if (TRUE === $this->_user_entity->loginByUsernameAndPassword($username, $password))
    	{
    		$storage = $this->_user_entity->getResultRowObject(array(
    						'id',
    						'username'));
    		$storage->name = $storage->username;

    		Zend_Session::rememberMe(60 * 60 * 24 * 7 * 2);
    		Zend_Auth::getInstance()->getStorage()->write($storage);

    		return TRUE;
    	}

    	return FALSE;
	}
</pre>
<p>The Repository uses composition and gets injected with the user entity object which provides the interface to communicate with the database.</p>
<p>The Repository holds the validation of the parameters and manages the relationship between the controller and the database model.</p>
<p>We will have one method called authenticate will use basically run the validation code of the parameters and if it passes the validation, it reaches the User Entity and tries to query it there. It always returns a boolean based on the status.</p>
<p>To call the repository, we will use the factory (below) to get the object. Create a new file in your <strong>/app_root/modules/frontoffice/models/Repositories/</strong> named <strong>UsersFactory.php</strong> with the following contents:</p>
<pre>
class Frontoffice_Model_Repositories_UsersFactory
{
	/**
	 * @var Frontoffice_Model_Repositories_Users
	 */
	protected static $_repository;

	public static function setRepository($repository)
	{
		self::$_repository = $repository;
	}

	/**
	 * @return Frontoffice_Model_Repositories_Users
	 */
	public static function factory()
	{
		if (null !== self::$_repository)
		{
			return self::$_repository;
		}

		$user_entity = new Frontoffice_Model_Entities_User();

		return new Frontoffice_Model_Repositories_Users($user_entity);
	}
}
</pre>
<h2>8. The User Entity</h2>
<p>Now we will see the actual User Entity which provides the interface which communicates with the database itself:</p>
<p>Create a file in your <strong>/app_root/modules/frontoffice/models/Entities/</strong> with the name <strong>User.php</strong> with the following contents:</p>
<pre>
class Frontoffice_Model_Entities_User extends Custom_Db_Table_Abstract
{
	protected $_name = 'users';
	protected $_use_adapter = 'front_db';

	protected $_auth_adapter;

	const PASSWORD_HASH = 'MY_PASSWORD_HASH_WHICH_SHOULD_BE_SOMETHING_SECURE';

	/**
	 * Logins a user based on his username and password
	 *
	 * @param string $username
	 * @param string $password
	 *
	 * @return Zend_Auth_Result
	 */
	public function loginByUsernameAndPassword($username, $password)
	{
		$password = $this->_encryptPassword($password);

		$this->_auth_adapter = new Zend_Auth_Adapter_DbTable( $this->getAdapter() );
		$this->_auth_adapter->setTableName('users')
						    ->setIdentityColumn('username')
						    ->setCredentialColumn('password');

		$this->_auth_adapter->setIdentity($username)
		    			    ->setCredential($password);
    	$result = Zend_Auth::getInstance()->authenticate($this->_auth_adapter);
    	return $result->isValid();
	}

	/**
     * Returns the result row as a stdClass object
     *
     * @param  string|array $returnColumns
     * @param  string|array $omitColumns
     * @return stdClass|boolean
     */
	public function getResultRowObject($returnColumns, $omitColumns = array())
	{
		return $this->_auth_adapter->getResultRowObject($returnColumns, $omitColumns);
	}

	/**
	 * Encrypts a value by md5 + static token
	 * 10 times
	 *
	 * @param string $value
	 *
	 * @return string $value
	 */
	protected function _encryptPassword($value)
	{
		for ($i = 0; $i < 10; $i++)
		{
			$value = md5($value . self::PASSWORD_HASH);
		}

		return $value;
	}
</pre>
<p>The User Entity provides methods to C.R.U.D. the database via the Repository.</p>
<p>In our case, we want to be able to run the Zend_Auth_Adapter_DbTable on our database and retrieve our needed information in order to write them in the Auth Storage.</p>
<p>Also we will use a method to encrypt our password va multi md5, in a secure way.</p>
<p>Now if you run the application you should get 5 types of error messages:</p>
<ul>
<li>Username empty</li>
<li>Password empty</li>
<li>Form cannot be resubmitted</li>
<li>Invalid captcha code</li>
<li>Invalid username or password (this is due to the fact that a hacker should <strong>not</strong> know what went wrong with his u/p combination.</li>
</ul>
<p>To test that the form works correctly check ZFDebug queries and see what it tried to search in the database (the username and password combination - the password will be encrypted. Copy paste that password and add it manually to the database, to your username. Now retry and you should get redirected to the index/index and be logged in)</p>
<h2>9. The Sign Up action</h2>
<p>Now that we have the login done, lets go to the UsersController and create our signup method:</p>
<p>Add the following code to your <strong>UsersController.php</strong></p>
<pre>

//...
//previous code here
//...
public function signupAction()
{
	Zend_Layout::getMvcInstance()->setLayout('public');

		$user_repository = Frontoffice_Model_Repositories_UsersFactory::factory();
		$form = new Frontoffice_Form_Signup(array('userRepository' => $user_repository));

		if ($this->_request->isPost())
		{
			$data = $this->_request->getPost();
			if ($id = $form->isValid($data))
			{
				$user_repository->authenticate($data['username'], $data['password']);
				return $this->redirect('index','index');
			}
			$form->setDefaults($data);
		}

		$this->view->form = $form;
}
</pre>
<p>Basically, the code is almost identical (at this level of simplicity atleast) with the login action.</p>
<p>If the form subbmision is correct, make sure to authenticate the user and redirect him to the index/index page.</p>
<h2>10. The Sign Up View</h2>
<p>Now lets see the View for the Sign Up action:</p>
<p>Go into your <strong>app_root/modules/frontoffice/views/scripts/users</strong> and create a file called <strong>login.phtml</strong> with the following contents:</p>
<pre>
< div style="width:950px; margin:5px; padding:0px 20px; float:left">
	< h2>Create account:< /h2>

	< ?php if ($this->form->isErrors()):?>
		< ?php foreach ($this->form->getErrors() as $errors):?>
			< ?php foreach ($errors as $message):?>
				< div style="color:red">< ?php echo $message;?>< /div>
			< ?php endforeach;?>
		< ?php endforeach;?>

		< ?php foreach ($this->form->getErrorMessages() as $error):?>
				< div style="color:red">< ?php echo $error;?>< /div>
		< ?php endforeach;?>
	< ?php endif; ?>

	< form id="login" action="< ?php echo $this->escape($this->form->getAction()); ?>" method="< ?php echo $this->escape($this->form->getMethod());?>">

	Username: < br />< ?php echo $this->form->username;?>< br />< br />

	Password: < ?php echo $this->form->password;?> < br />< br />

	Confirm Password: < ?php echo $this->form->confirm_password;?>< br />< br />

	< ?php echo $this->form->captcha;?>

	< input type="submit" value="Create account" /> or < a href="< ?php echo $this->url(array('controller' => 'users', 'action' => 'login'), null, true);?>">Login</a>
	< ?php echo $this->form->___h;?>

	< /form>
< /div>
</pre>
<h2>11. The Auth Plugin</h2>
<p>Currently, if we try to signup we will always get redirected to the login page. In order to allows us to view the signup page, we must go to the <strong>app_root/library/Custom/Controller/Plugin/Auth.php</strong> and there we should add the following condition in the dispatchLoopStartup :</p>
<pre>
	//Check if the user is not logged in
	if (!$this->_auth->hasIdentity())
	{
		return $this->_redirect($request, 'users', 'login', 'frontoffice');
	}
</pre>
<p>	becomes</p>
<pre>
	//Check if the user is not logged in
	if (!$this->_auth->hasIdentity()
		&#038;&#038; FALSE === (   'frontoffice' == $request->getModuleName()
					  &#038;&#038; 'users' 		 == $request->getControllerName()
					  &#038;&#038; 'signup'		 == $request->getActionName()))
	{
		return $this->_redirect($request, 'users', 'login', 'frontoffice');
	}
</pre>
<p>This gives us permissions to view the users/signup page</p>
<h2>12. The Users Repository (again)</h2>
<pre>
//previous code here
//...
	/**
	 * Creates a new user
	 *
	 * @param $username
	 * @param $password
	 *
	 * @return bool|int
	 */
	public function createUser($username, $password)
	{
		$filter = new Zend_Validate_StringLength(array('min' => 5, 'max' => 25));
		if (!$filter->isValid($password))
		{
			$this->setMessage('password', 'The password must be between 5 and 25 characters length');
			return FALSE;
		}

		if (FALSE !== $this->_user_entity->findByUsername($username))
		{
			$this->setMessage('username', 'Username already exists');
			return FALSE;
		}

		if (!$id = $this->_user_entity->create($username, $password))
		{
			$this->setMessage(null, 'An uknown error occured. Please contact the support team');
			return FALSE;
		}

		return $id;
	}
</pre>
<p>This allows us to call the createUser with the username and password and the system checks if the values are correct. We have the logic validation on the repository side while the passowrd/confirm password will be kept on the form side</p>
<p>If the validation passses, we then check to see if we don't already have another user with the same username.</p>
<p>If we don't, we try to create the user with the username and password and if this works we return back the new user id</p>
<h2>13. The Users Entity (again)</h2>
<p>Go to the <strong>/app_root/modules/frontoffice/models/Entities/User.php</strong> and add the following code after the previously added one:</p>
<pre>
	//previous code here
	//...

	/**
	 * Retrieves an User Object by its ID
	 *
	 * @param integer $user_id
	 *
	 * @return Zend_Db_Table_Row_Abstract|bool
	 */
	public function findByUsername($username)
	{
		$result = $this->fetchRow($this->getAdapter()->quoteInto('email = ?', $username));
		if (!empty($result))
		{
			return $result;
		}

		return FALSE;
	}

	/**
	 * Creates a new user object in the database with the specified
	 * column values
	 *
	 * @param string $username
	 * @param string $password
	 *
	 * return bool|integer
	 */
	public function create($username, $password)
	{
		$user = $this->createRow();

		$user->email              = $username;
		$user->password           = $this->_encryptPassword($password);

		try
		{
			$user->save();
			return $user->id;
		}
		catch (Exception $e)
		{
			debug($e);
			return FALSE;
		}
	}
</pre>
<p>These two methods provide the interface to the Database Object for the Repository via the Entity.</p>
<h2>14. Last but not least, The Sign Up Form</h2>
<p>The sign up form will be injected with the user repository, will create the username,password/confirm password elemenets, will provide validation for the empty state of the fields + check to see if the 2 password fields are identical and will enable the captcha if the form fails 3 times.</p>
<p>If the form validation is valid, it runs the repository createUser() method. If this validation fails, it will set the form error messages based on the repository messages</p>
<p>If it passes, then it will return  the $id of the newly created user</p>
<p>Once the user is created, the controller will just authenticate the user via the standard authenticate() method from the repository with the provided userame and password from the create form.</p>
<p></p>
<p>In your <strong>app_path/modules/frontoffice/forms</strong> create the file <strong>Signup.php</strong> with the following contents:</p>
<pre>

class Frontoffice_Form_Signup extends Custom_Form
{
	/**
	 * @var Frontoffice_Model_Repositories_Users
	 */
	protected $_user_repository;

	/**
	 * Sets the user repository
	 *
	 * @param Frontoffice_Model_Repositories_Users $repository
	 */
	public function setUserRepository($repository)
	{
		$this->_user_repository = $repository;
	}

    public function __construct($options = null)
    {
    	parent::__construct($options);

        $this->setName('create_account');

        $element = new Zend_Form_Element_Text('username', array('disableLoadDefaultDecorators' => true));
        $element->addDecorator('ViewHelper')
	            ->setRequired(true)
	            ->addErrorMessage('Please provide an username value');
		$this->addElement($element);

        $element = new Zend_Form_Element_Password('password', array('disableLoadDefaultDecorators' => true));
        $element->addDecorator('ViewHelper')
                ->setRequired(true)
                ->setAttrib('autocomplete', 'off')
                ->addErrorMessage('Please enter a password');
		$this->addElement($element);

        $element = new Zend_Form_Element_Password('confirm_password', array('disableLoadDefaultDecorators' => true));
        $element->addDecorator('ViewHelper')
                ->setRequired(true)
                ->addValidator(new Frontoffice_Form_Validate_IdenticalFormValues('password'), true)
                ->addErrorMessage('The two passwords do not match');
			$this->addElement($element);

        $element = new Zend_Form_Element_Hash('___h', array('disableLoadDefaultDecorators' => true));
        $element->setSalt('unique')
        		->addDecorator('ViewHelper')
        		->addErrorMessage('Form must not be resubmitted');
        $this->addElement($element);

   		$captcha_session = new Zend_Session_Namespace('captcha');
        if ($captcha_session->tries > 3)
        {
	        $recaptcha = new Zend_Service_ReCaptcha('6LeDkroSAAAAAHAe8FnYK2e9-jbLdAbk8XXn_0UK',
	        									    '6LeDkroSAAAAACLmAdTSdM9sifKJWERFDRUSB0So');
	        $recaptcha->setOption('theme', 'clean');
	        $element = new Zend_Form_Element_Captcha('captcha',
													 array('disableLoadDefaultDecorators' => true,
													 	   'captcha'        => 'ReCaptcha',
														   'captchaOptions' => array('captcha' => 'ReCaptcha',
														   							 'service' => $recaptcha)));
			$element->addErrorMessage('Invalid security captcha code');
			$this->addElement($element);
        }

        $this->clearDecorators();
		$this->addDecorator('FormElements')
	         ->addDecorator('Form');
    }

    public function isValid($data)
    {
    	if (!parent::isValid($data))
    	{
    		$this->_incrementCaptcha();
    		return FALSE;
    	}

    	if (!$id = $this->_user_repository->createUser($data['username'],
    												   $data['password']))
		{
			foreach ($this->_user_repository->getMessages() as $element_name => $message)
			{
				$this->addErrors(array($message));
			}
			$this->_incrementCaptcha();
			return FALSE;
		}

    	return $id;
    }

    protected function _incrementCaptcha()
    {
    	$captcha_session = new Zend_Session_Namespace('captcha');
		if (empty($captcha_session->tries))
		{
			$captcha_session->tries = 0;
		}
		$captcha_session->tries = $captcha_session->tries + 1;
    }
}
</pre>
<p>However, we are not done yet, since we have a custom validator that check if 2 fields are identical. Thus, lets create, in the path <strong>/app_path/modules/frontoffice/forms/Validate</strong> the file called <strong>IdenticalFormValues.php</strong> with the following contents:</p>
<pre>
class Frontoffice_Form_Validate_IdenticalFormValues extends Zend_Validate_Abstract
{
	const NOT_MATCH = 'notMatch';

	protected $_messageTemplates = array(
    	self::NOT_MATCH => 'Values don\'t match'
	);

	protected $_token_key;

	public function __construct($token_key = 'confirm_password')
	{
		$this->_token_key = $token_key;
	}

	public function isValid($value, $context = null)
	{
    	$value = (string) $value;
    	$this->_setValue($value);

    	if (is_array($context))
    	{
        	if (isset($context[$this->_token_key]) &#038;&#038; ($value == $context[$this->_token_key]))
        	{
            	return true;
        	}
    	}
    	elseif ($value == $context)
    	{
        	return true;
    	}

	    $this->_error(self::NOT_MATCH);
	    return false;
	}
}
</pre>
<h2>15. Finale</h2>
<p>This was a big tutorial but should pretty much cover everything in order to build a secure signup/login system</p>
<p>See you until next time for the next tutorial!</p>
 <img src="http://phpdev.ro/wp-content/plugins/feed-statistics.php?view=1&post_id=1101" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://phpdev.ro/zend-framework-tutorial-series-part-3-login-and-signup-with-recaptcha.html/feed</wfw:commentRss>
		<slash:comments>42</slash:comments>
		</item>
		<item>
		<title>Zend Framework Tutorial Series: Part 2 – Debugging your application</title>
		<link>http://phpdev.ro/zend-framework-tutorial-series-part-2-advanced-debugging.html</link>
		<comments>http://phpdev.ro/zend-framework-tutorial-series-part-2-advanced-debugging.html#comments</comments>
		<pubDate>Mon, 14 Jun 2010 10:19:52 +0000</pubDate>
		<dc:creator>Andrei Gabreanu</dc:creator>
				<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[Advices]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[Develop]]></category>
		<category><![CDATA[Documentation]]></category>
		<category><![CDATA[Freeware]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[Zend]]></category>

		<guid isPermaLink="false">http://phpdev.ro/?p=1055</guid>
		<description><![CDATA[Continuing with the tutorial series, we will see how to debug the application. Debugging include easy to use methods of printing data on the screen, including ZFDebug Toolbar in order to manage all errors and queries, using the logger to log messages to Firebug, using a simple debug function that will place debug messages in your ZFDebug Toolbar, in a special Debug panel [...]]]></description>
			<content:encoded><![CDATA[<p>Continuing with the tutorial series, we will see how to debug the application. Debugging includes easy to use methods of printing data on the screen, including ZFDebug Toolbar in order to manage all errors and queries, using the logger to log messages to Firebug, using a simple debug function that will place debug messages in your ZFDebug Toolbar, in a special Debug panel, using a redirect debug function in order to see what is happening during your requests, using redirect in a Controller plugin. </p>
<div style="padding:15px; background-color:#EAF2FA; margin-bottom:10px;">
<strong>Notice:</strong> Please make sure if you copy paste the code below, that all HTML code contained has been altered in order to display properly.
</div>
<div style="padding:35px 15px 15px 15px; background-color:#DDF8CC; margin-bottom:15px;">
<h4 style="font-size:16px; text-align:center"><img src="http://www.gstatic.com/codesite/ph/images/dl_arrow.gif" /> <a href="http://code.google.com/p/zf-module-based-app/downloads/list" target="_blank">Download Sample Application from Google Code Here</a></h4>
</div>
<h2>1. Utils.php</h2>
<p>In your WWW-ROOT, in your <strong>index.php</strong>, add the following line after the require_once &#8216;Zend/Application.php&#8217; :</p>
<pre>
...
// Custom functions to help development
require_once ( APP_LIBRARY_PATH . DS . 'Utils.php');
...
</pre>
<p>Create a file called <strong>Utils.php</strong> in your application_root/library with the following contents:</p>
<pre>
function debug ($object, $label = '')
{
	Custom_Controller_Plugin_Debug::debug($object, $label);
}

function logger($message, $type = Zend_Log::INFO)
{
	Custom_Controller_Plugin_Debug::logger($message, $type);
}

function array_key_exists_recursive($needle,$haystack)
{
	foreach($haystack as $key=>$val)
	{
		if(is_array($val))
		{
			if ( array_key_exists_recursive($needle,$val))
			{
				return TRUE;
			}
		}
   		elseif ($val == $needle)
   		{
   			return TRUE;
   		}
	}
	return FALSE;
}

function is_multidimensional_array($a)
{
    $rv = array_filter($a,'is_array');
    if (count($rv)>0)
    {
    	return TRUE;
    }
    else
    {
    	return FALSE;
    }
}

function array_equal($a, $b)
{
    return (is_array($a) &#038;&#038; is_array($b) &#038;&#038; array_diff($a, $b) === array_diff($b, $a));
}

function array_identical($a, $b)
{
    return (is_array($a) &#038;&#038; is_array($b) &#038;&#038; array_diff_assoc($a, $b) === array_diff_assoc($b, $a));
}

function pr($val)
{
	$debug_backtrace = debug_backtrace();

	echo 'Debug called from ' . $debug_backtrace[1]['file'] . ' (line ' . $debug_backtrace[1]['line'] . ')';
	echo "< pre>";
	print_r($val);
	echo "< /pre>";
}

function debug_redirect($url)
{
	$debug_backtrace = debug_backtrace();
	$file = '< strong> ' . $debug_backtrace[0]['file'] . '< /strong>';
	$line = '< strong>' . $debug_backtrace[0]['line'] . '< /strong>';

	echo '< div style="padding:15px 30px; margin:0px; text-align:center; font-size:16px; background-color:#ccc; ">Should redirect to: < a href="'. $url . '">' . $url . '< /a>< /div>';
	echo '< div style="padding:15px 30px; margin:0px; text-align:center; font-size:16px; background-color:#ccc; ">Called from ' . $file . ', line ' . $line . '< /div>';

	echo '< div style="background-color:yellow; border:1px solid red; padding:5px 10px; margin:20px 0px">';
	echo '< pre>COOKIES:';
	print_r($_COOKIES);
	echo '< /pre>';

	echo '< pre>SESSION:';
	print_r($_SESSION);
	echo '< /pre>';

	echo '< pre>SERVER:';
	print_r($_SERVER);
	echo '< /pre>';

	echo '< /div>';
	exit();
}
</pre>
<p>Let us examine a bit what these functions do:</p>
<p> We will skip the debug and logger for the moment. </p>
<p>The function <strong>array_key_exists_recursive</strong> is a convenience method i had to write in order to check if a key exists in a multidimensional array.</p>
<p>The function <strong>is_multidimensional_array</strong> is a method to check if an array is uni dimensional or not.</p>
<p>The function <strong>pr</strong> is a short way to call print_r but without minding of the < pre> < /pre> tags and also points out where did you call the function from (remember those days where you had 99999 lines of debug on your screen and you were asking yourself were did you put all those echos/print_r&#8217;s <img src='http://phpdev.ro/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ?)</p>
<p>The function <strong>debug_redirect</strong> takes an url as an argument, and simulates a redirect. By simulates I mean that, it doesn&#8217;t really redirect rather than print on the screen that in production mode, it would redirect and you can see where it would redirect. Moreover, it tells you all the information from your current session so that you can view exactly what happens just before the redirect was called. It also tells you where you called the redirect method.</p>
<h2>3. The Bootstrap</h2>
<p>In order to continue, we will need a way to tell the application we want the debugging to be enabled or not. But how do we do this?<br />
Easiest way is to have a <strong>DEBUG</strong> constant set to TRUE or FALSE (or different levels if you wish). But what about in production mode? How can we debug there? </p>
<p>One way is to have an <strong>IP</strong> enabled DEBUG constant. An easier method is to enable DEBUG if you have a certain cookie with a VERY secret hash key. </p>
<p>Of course, the best practice is to not have debug enabled at all in production ENV, but if you really need it, then having at least the cookie is required. You can make it more secure by adding the IP check also.</p>
<p>Here is how this would look like in your <strong>Bootstrap.php</strong></p>
<pre>
...
	#initializes the DEBUG constant to true or false based on config. settings and/or cookie
    #and stores a copy of the Zend_Logger in the Registry for future references
 	protected function _initDebug()
    {
    	$config = Zend_Registry::get('config');

    	if (isset($config->settings->debug->enabled))
    	{
    		if ($config->settings->debug->enabled == TRUE)
    		{
    			define('DEBUG', TRUE);
    		}
    		else
    		{
    			if (isset($config->settings->debug->cookie))
    			{
    				$debug_cookie = $config->settings->debug->cookie;

    				if (array_key_exists($debug_cookie,$_COOKIE))
    				{
    					define('DEBUG', TRUE);
    				}
    			}
    		}
    	}

    	if (FALSE === defined('DEBUG'))
    	{
    		define('DEBUG', FALSE);
    	}

    	$logger = new Zend_Log();
		$writer = new Zend_Log_Writer_Firebug();
		$logger->addWriter($writer);

		Zend_Registry::set('logger', $logger);
    }
...
</pre>
<h2>4. The application.ini</h2>
<p>In order to use the method from the bootstrap, we need to do the required changes in the <strong>application.ini</strong> :</p>
<pre>
[bootstrap]
	...
	settings.debug.cookie = "some_very_very_secret_hash_key_here_that_will_be_very_hard_to_add_in_the_cookie"
	...

[production : bootstrap]
	phpSettings.display_startup_errors = 0
	phpSettings.display_errors         = 0
	settings.debug.enabled             = false
	...

[development : testing]
	phpSettings.display_startup_errors = 1
	phpSettings.display_errors         = 1
	settings.debug.enabled             = true
</pre>
<p>And that is about it.</p>
<h2>5. Controller Plugins</h2>
<p>In order for the <strong>debug_redirect</strong> function to work, you will need the following code. Remember the redirect helper method that was available to all your controllers (from the file Utils.php) ?</p>
<p>Here is a new code for it:</p>
<pre>
	/**
	 * Helper method to redirect to a specific action or controller or url
	 *
	 * @param string $controller / $url which contains http in its composition
	 * @param string $action
	 * @param array  $params
	 */
	public function redirect($controller = 'index', $action = 'index', $module = 'frontoffice', $params = array(), $route = null, $reset = true )
    {
    	$this->_redirect = $this->_helper->getHelper('Redirector');

    	$current_controller = $this->_getParam('controller');
    	$current_action     = $this->_getParam('action');
    	$current_module     = $this->_getParam('module');

    	if (strstr($controller, 'http'))
    	{
    		if (DEBUG &#038;&#038; (!$this->_request->isXmlHttpRequest() &#038;&#038; !isset($_GET['ajax'])))
    		{
				debug_redirect($controller);
    		}
    		else
    		{
	    		return $this->_redirect($controller, array('code' => 301));
    		}
    	}

    	if (DEBUG &#038;&#038; (!$this->_request->isXmlHttpRequest() &#038;&#038; !isset($_GET['ajax'])))
    	{
    		if ($route !== null)
    		{
	    		$url = 'http://' . $_SERVER['HTTP_HOST']
	    			   . $this->view->url(array_merge(array('controller' => $controller, 'action' => $action, 'module' => $module), $params), $route, $reset);
    		}
    		else
    		{
    			$url = 'http://' . $_SERVER['HTTP_HOST']
	    			   . $this->view->url(array_merge(array('controller' => $controller, 'action' => $action, 'module' => $module), $params));
    		}
    		debug_redirect($url);
    	}
    	else
    	{
    		if ($route !== null)
    		{
    			$params = array_merge(array('action'     => $action,
								    	    'controller' => $controller,
                                   			'module'     => null), $params);

    			return $this->_redirect->setCode(301)
    			                       ->setExit(true)
    			                       ->gotoRoute($params, $route, $reset);
    		}

	    	return $this->_redirect->setCode(301)
	    				    	   ->setExit(true)
	                      		   ->gotoSimpleAndExit($action,
	                                             	   $controller,
	                                             	   $module,
	                                             	   $params);
    	}
    }
</pre>
<p>Basically, if you have <strong>DEBUG</strong> enabled and you are not requesting the page via AJAX (either real AJAX or fake via $_GET of &#8220;ajax&#8221;) then it will use the <strong>debug_redirect</strong> function rather than the Zend Redirect. Mind you that when doing Unit Testing, you should *not* have DEBUG enabled or at least not use use this function at all for obvious reasons.</p>
<h2>6. ZFDebug</h2>
<p>The biggest addition to our debugging arsenal now comes with <strong>ZFDebug</strong> (which you can download here: <a href="http://code.google.com/p/zfdebug/" target="_blank">http://code.google.com/p/zfdebug/</a>).</p>
<p>ZFDebug is a Symfony like debug toolbar which can be configured very easily and provides handy information&#8217;s about your application. You can read more about it on the <em>code.google.com</em>. But in the meantime, let us see how we can include it:</p>
<p>Firsts things are first: Add your ZFDebug in your library folder like this:</p>
<p><strong><br />
/library/Custom<br />
/Library/ZFDebug<br />
</strong></p>
<p>In your <strong>application.ini</strong>, add the following namespace to the autoloader:</p>
<pre>
...
Autoloadernamespaces[] = "Custom_"
Autoloadernamespaces[] = "ZFDebug_"
</pre>
<p>Finally, in your <strong>Bootstrap.php</strong> add the following method:</p>
<pre>
	...
	#initializses the ZFDebug if DEBUG is ON
	protected function _initZFDebug()
	{
		if (!DEBUG)
		{
			return FALSE;
		}

	    $options = array(
	        'plugins' => array('Variables',
	    					   'ZFDebug_Controller_Plugin_Debug_Plugin_Debug' => array('tab'   => 'Debug',
	    					   													       'panel' => ''),
	    					   'ZFDebug_Controller_Plugin_Debug_Plugin_Auth',
							   'Database',
	                           'Registry',
	                           'Exception')
	    );

	    # Setup the cache plugin
	    if (Zend_Registry::isRegistered('cache'))
	    {
	        $cache = Zend_Registry::get('cache');
	        $options['plugins']['Cache']['backend'] = $cache->getBackend();
	    }

	    # Setup the databases
	    $resource = $this->getPluginResource('multidb');
	    $databases = Zend_Registry::get('config')->resources->multidb;
	    foreach ($databases as $name => $adapter)
	    {
	    	$db_adapter = $resource->getDb($name);
	    	$options['plugins']['Database']['adapter'][$name]= $db_adapter;
	    }

	    # Init the ZF Debug Plugin
	    $debug = new ZFDebug_Controller_Plugin_Debug($options);
	    $this->bootstrap('frontController');
	    $frontController = $this->getResource('frontController');
	    $frontController->registerPlugin($debug);
	}
	...
	</pre>
<h2>7. Plugins for ZFDebug</h2>
<p>We added a custom tab to the ZFDebug. In order to make it work, go to the <strong>Debug.php from ZFDebug/Controller/Plugin/</strong></p>
<p>and replace your <strong>dispatchLoopShutdown()</strong> method with the following:</p>
<pre>
	/**
     * Defined by Zend_Controller_Plugin_Abstract
     */
    public function dispatchLoopShutdown()
    {
        $html = '';

        if ($this->getRequest()->isXmlHttpRequest())
            return;

        /**
         * Creating menu tab for all registered plugins
         */
        foreach ($this->_plugins as $plugin)
        {
      	  	if (strtolower($plugin->getTab()) == 'debug')
        	{
        		$debug_session = new Zend_Session_Namespace(Custom_Controller_Plugin_Debug::DEBUG_NAMESPACE);
				if (isset($debug_session->debug))
				{
					$plugin->setPanel( $debug_session->debug);
				}
        	}

            $panel = $plugin->getPanel();
            if ($panel == '') {
                continue;
            }

            /* @var $plugin ZFDebug_Controller_Plugin_Debug_Plugin_Interface */
            $html .= '< div id="ZFDebug_' . $plugin->getIdentifier()
                  . '" class="ZFDebug_panel">' . $panel . '< /div>';
        }

        $html .= '< div id="ZFDebug_info">';

        /**
         * Creating panel content for all registered plugins
         */
        foreach ($this->_plugins as $plugin)
        {
            $tab = $plugin->getTab();
            if ($tab == '') {
                continue;
            }
        	if (strtolower($plugin->getTab()) == 'debug' &#038;&#038; $plugin->getPanel() != '')
            {
            	$style = 'style="background-color:yellow; font-weight:bold;"';
            	Zend_Session::namespaceUnset(Custom_Controller_Plugin_Debug::DEBUG_NAMESPACE);
            }
            else
            {
            	$style = '';
            }

            /* @var $plugin ZFDebug_Controller_Plugin_Debug_Plugin_Interface */
            $html .= '< span ' .$style .' class="ZFDebug_span clickable" onclick="ZFDebugPanel(\'ZFDebug_' . $plugin->getIdentifier() . '\');">';
            $html .= '< mg src="' . $this->_icon($plugin->getIdentifier()) . '" style="vertical-align:middle" alt="' . $plugin->getIdentifier() . '" title="' . $plugin->getIdentifier() . '" /> ';
            $html .= $tab . '< /span>';
        }

        $html .= '< span class="ZFDebug_span ZFDebug_last clickable" id="ZFDebug_toggler" onclick="ZFDebugSlideBar()">&#171;< /span>';

        $html .= '< /div>';
        $this->_output($html);
    }
	</pre>
<p>Go into your <strong>/ZFDebug/Controller/Plugin/Debug/Plugin/Auth.php</strong> and at replace the <strong>getTab()</strong> method with the following:</p>
<pre>
 /**
     * Gets menu tab for the Debugbar
     *
     * @return string
     */
    public function getTab()
    {
    	$username = 'Not Authed';
    	$role = 'Unknown Role';

    	if(!$this->_auth->hasIdentity())
		{
    	    return 'Not authorized';
    	}
    	$identity = $this->_auth->getIdentity();
	    if (is_object($identity))
		{
    		$username = $identity->name;
    	}
    	else
		{
    	    $username = $identity['name'];
    	}

    	return ' ' . $username;
    }
</pre>
<p>Create a new file called <strong>Debug.php</strong> in your <strong>/ZFDebug/Controller/Plugin/Debug/Plugin/</strong> with the following contents:</p>
<pre>
class ZFDebug_Controller_Plugin_Debug_Plugin_Debug implements ZFDebug_Controller_Plugin_Debug_Plugin_Interface
{
    /**
     * @var string
     */
    protected $_tab = '';

    /**
     * @var string
     */
    protected $_panel = '';

    /**
     * Contains plugin identifier name
     *
     * @var string
     */
    protected $_identifier = 'text';

    /**
     * Create ZFDebug_Controller_Plugin_Debug_Plugin_Debug
     *
     * @paran array $options
     * @return void
     */
    public function __construct(array $options = array())
    {
        if (isset($options['tab'])) {
            $this->setTab($options['tab']);
        }
        if (isset($options['panel'])) {
            $this->setPanel($options['panel']);
        }
    }

    /**
     * Gets identifier for this plugin
     *
     * @return string
     */
    public function getIdentifier()
    {
        return $this->_identifier;
    }

    /**
     * Sets identifier for this plugin
     *
     * @param string $name
     * @return ZFDebug_Controller_Plugin_Debug_Plugin_Debug Provides a fluent interface
     */
    public function setIdentifier($name)
    {
        $this->_identifier = $name;
        return $this;
    }

    /**
     * Gets menu tab for the Debugbar
     *
     * @return string
     */
    public function getTab()
    {
        return $this->_tab;
    }

    /**
     * Gets content panel for the Debugbar
     *
     * @return string
     */
    public function getPanel()
    {
        return $this->_panel;
    }

    /**
     * Sets tab content
     *
     * @param string $tab
     * @return ZFDebug_Controller_Plugin_Debug_Plugin_Debug Provides a fluent interface
     */
    public function setTab($tab)
    {
        $this->_tab = $tab;
        return $this;
    }

    /**
     * Sets panel content
     *
     * @param string $panel
     * @return ZFDebug_Controller_Plugin_Debug_Plugin_Debug Provides a fluent interface
     */
    public function setPanel($panel)
    {
        $this->_panel = $panel;
        return $this;
    }
}
</pre>
<p>However, this will not work until we create the debug controller plugin:</p>
<p>Go into your <strong>application_root/library/Custom/Controller/Plugin/</strong> and create the file <strong>Debug.php</strong> with the following contents:</p>
<pre>
final class Custom_Controller_Plugin_Debug extends Zend_Controller_Plugin_Abstract
{
	const DEBUG_NAMESPACE = 'DEBUG_Plugin';

    public static function debug($object, $label = '')
	{
		if (FALSE === DEBUG)
		{
			return FALSE;
		}

		if (FALSE === Zend_Session::isStarted())
		{
			Zend_Session::start();
		}
		$debug_session = new Zend_Session_Namespace(self::DEBUG_NAMESPACE);

		$debug_backtrace = debug_backtrace();

		if ($object === FALSE) $object = '<span style="color:blue">FALSE</span>';
		if ($object === TRUE) $object = '<span style="color:blue">TRUE</span>';

		if ($label == '') $label = 'DEBUG';

	    $debug  = '< div id="debug_wrapper" style="clear: both; text-align: left; width: 98%; margin:10px auto; background: #FFFFD7; border: 1px dotted #008200; font-family: Tahoma;  font-size: 12px;">'; // Start of debug_wrapper
	    $debug .= '< div id="debug_content" style="padding: 10px 10px 0px 10px;">'; 

		$debug .= '< div id="debug_location" style="font-weight: bold; color: #008200; border-bottom: 1px dotted #008200; padding-bottom: 10px;">'; // Start of debug_location
	    $debug .= '< span style="color:#FFF; background-color:green;padding:0px 10px;margin:0px 10px 0px 0px; border:1px solid green; -moz-border-radius: 5px; -webkit-border-radius: 5px;">'.strtoupper($label).'< /span>Debug called from ' . $debug_backtrace[1]['file'] . ' (line ' . $debug_backtrace[1]['line'] . ')';
	    $debug .= '< /div>'; // End of debug_location

	    $debug .= '< pre>';
	    $debug .= print_r($object, true);
	    $debug .= '< /pre>';

	    $debug .= '< /div>'; // End of debug_content
	    $debug .= '< /div>'; // End of debug_wrapper

	    Custom_Controller_Plugin_Debug::logger($object, null);
    	$debug_session->debug = isset($debug_session->debug) ? $debug_session->debug . $debug : $debug;
	}

	public static function logger($message, $type = Zend_Log::INFO, $extras = array())
	{
		if (Zend_Registry::isRegistered('logger') === TRUE &#038;&#038; DEBUG === TRUE)
		{
			Zend_Registry::get('logger')->log($message, Zend_Log::INFO, $extras);
		}
	}
}
</pre>
<p>What does this method exactly do ?</p>
<p>Well, several things:</p>
<p>It provides 2 public static methods that can be called from anywhere in your application to debug or log to firebug a message.</p>
<p>These 2 public static methods are used in <strong>Utils.php</strong> for an easier way to access them:</p>
<p><strong>debug()</strong> runs the Custom_Controller_Plugin_Debug::debug() and <strong>logger()</strong> runs Custom_Controller_Plugin_Debug::logger()</p>
<p>The debug method itself takes a message and/or an optional label, wraps it nicely in a colored DIV and puts it in the SESSION. </p>
<p>Once the ZFDebug output is shown on the screen, it removes the debug from the SESSION storage. </p>
<p>Why so complicated you may ask? The obvious reason is that, when you are doing redirects or errors happen (and you get redirected to the error controller) you would still want to get your debug information in order to find out what the heck happens. This way, you could go through an unlimited number of redirects and at the end, the debug would just contain your full debug gathered on the way to the render.</p>
<p>Try it our yourself!</p>
<h2>8. Error controller</h2>
<p>Let&#8217;s see now how can our Error Controller be extended to manage more advanced issues.<br />
We want it to display all sorts of errors if we are in DEBUG mode or else, in case of 500 internal server errors, mail us the error stack trace and details.</p>
<p>In your <strong>ErrorController.php</strong> put the following content:</p>
<pre>
/**
 * @name ErrorController
 * @desc The controller to serve 404 and 500 errors and debugging stacktrace on DEV ENV
 *           or mail with the stacktrage on 500 errors in anything else than DEV ENV;
 *
 * @author Andrei
 * @filesource application/module_name/controllers/ErrorController.php
 * @version 1.0.0
 */
Class ErrorController extends Frontoffice_Library_Controller_Action_Abstract
{
    private $_notifier;
    private $_error;
    private $_environment;

    public function init()
    {
        parent::init();

        $bootstrap = $this->getInvokeArg('bootstrap');

        $environment = $bootstrap->getEnvironment();
        $error = $this->_getParam('error_handler');
        $mailer = new Zend_Mail();
        $session = new Zend_Session_Namespace();
        $cookies = $_COOKIE;

        $this->_notifier = new Custom_Service_Notifier_Error(
            $environment,
            $error,
            $mailer,
            $session,
            $cookies,
            $_SERVER
        );

        $this->_error = $error;
        $this->_environment = $environment;
   }

    public function errorAction()
    {
        switch ($this->_error->type) {
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
                $this->getResponse()->setHttpResponseCode(404);
                $this->view->message = 'Uh oh, we can\'t seem to find that page you wanted!';
                $this->_applicationError();
                break;

            default:
                $this->getResponse()->setHttpResponseCode(500);
                $this->view->message = 'Looks like something\'s gone wrong! Please refresh the page - if the problem persists please report the error';
                $this->_applicationError();
                break;
        }

        $this->view->headTitle()->prepend(  $this->view->code . ' Error' );
    }

    private function _applicationError()
    {
        $fullMessage = $this->_notifier->getFullErrorMessage();
		$this->view->stack = nl2br($fullMessage);
        $this->_notifier->notify();
    }
}
</pre>
<p>Go into your application <strong>root/library/Custom/Service/Notifier</strong> (create it if you don&#8217;t have it) and creae a new file called <strong>Error.php</strong> with the following contents:</p>
<pre>
Class Custom_Service_Notifier_Error
{
	protected $_environment;
    protected $_mailer;
    protected $_session;
    protected $_cookies;
    protected $_error;
    protected $_profilers;

    public function __construct(
        $environment,
        ArrayObject $error,
        Zend_Mail $mailer,
        Zend_Session_Namespace $session,
        Array $cookies,
        Array $server)
    {
        $this->_environment = $environment;
        $this->_mailer = $mailer;
        $this->_error = $error;
        $this->_session = $session;
        $this->_cookies = $cookies;
        $this->_server = $server;
    }

    public function getFullErrorMessage()
    {
        $message = '';

        if (!empty($this->_server['SERVER_ADDR'])) {
            $message .= "Server IP: " . $this->_server['SERVER_ADDR'] . "\n";
        }

        if (!empty($this->_server['HTTP_USER_AGENT'])) {
            $message .= "User agent: " . $this->_server['HTTP_USER_AGENT'] . "\n";
        }

        if (!empty($this->_server['HTTP_X_REQUESTED_WITH'])) {
            $message .= "Request type: " . $this->_server['HTTP_X_REQUESTED_WITH'] . "\n";
        }

        $message .= "Server time: " . date("Y-m-d H:i:s") . "\n";
        $message .= "RequestURI: " . $this->_error->request->getRequestUri() . "\n";

        if (!empty($this->_server['HTTP_REFERER'])) {
            $message .= "Referer: " . $this->_server['HTTP_REFERER'] . "\n";
        }

        $message .= "Message: " . $this->_error->exception->getMessage() . "\n\n";
        $message .= "Trace:\n" . $this->_error->exception->getTraceAsString() . "\n\n";
        $message .= "Request data: " . var_export($this->_error->request->getParams(), true) . "\n\n";

        $it = $this->_session->getIterator();

        $message .= "Session data:\n\n";
        foreach ($it as $key => $value) {
            $message .= $key . ": " . var_export($value, true) . "\n";
        }
        $message .= "\n";

        $message .= "Cookie data:\n\n";
        foreach ($this->_cookies as $key => $value) {
            $message .= $key . ": " . var_export($value, true) . "\n";
        }
        $message .= "\n";

        return $message;
    }

    public function notify()
    {
        if (!in_array($this->_environment, array('production', 'testing'))) {
            return false;
        }

        $this->_mailer->setFrom('do-not-reply@YUUR_APP_DOMAIN');
        $this->_mailer->setSubject("Exception on Zend Application Implementation");
        $this->_mailer->setBodyText($this->getFullErrorMessage());
        $this->_mailer->addTo('YOUR_SUPPORT_EMAIL_ADDRESS');

        return $this->_mailer->send();
    }
}
</pre>
<h2>9. View Helpers</h2>
<p>Here are some view helpers that will aid your development:</p>
<p>Go into your <strong>modules/MODULE_NAME/views/helpers</strong> and create the following file with the following contents:</p>
<pre>
//Xml.php
class Zend_View_Helper_ArrayToXml implements Zend_View_Helper_Interface
{
	public $view;

	public function setView(Zend_View_Interface $view)
	{
		$this->view = $view;
	}

	public function direct() {}

    public function arrayToXml($value)
    {
    	$response = $this->_convertValueToXml($value);
    	return $response;
    }

    protected function _convertValueToXml($value)
    {
    	$str = '';
    	if (!is_array($value))
    	{
    		$str .= $value;
    	}
    	else
    	{
    		foreach ($value as $tag => $tag_value)
    		{
    			$str .= '<' . $tag . '>';
    			$str .= $this->_convertValueToXml($tag_value);
    			$str .= '</' . $tag . '>';
    		}
    	}
    	return $str;
    }
}
</pre>
<p>This helper plugin helps you convert an array to an xml as following:</p>
<p>If you have an array like this :</p>
<pre>
test => array(test2 => array( test3))
</pre>
<p>then you the helper would convert it to something like:</p>
<pre>
< test>< test2>test3< /test2>< /test>
</pre>
<h2>10. Conclusion</h2>
<p>The basic module setup and this debugging system should help you manage any application for any difficulty level.<br />
The next tutorial will consist of creating a login page and signup page and protecting them with ReCaptcha.</p>
<p>Until next time,<br />
Happy Coding!</p>
 <img src="http://phpdev.ro/wp-content/plugins/feed-statistics.php?view=1&post_id=1055" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://phpdev.ro/zend-framework-tutorial-series-part-2-advanced-debugging.html/feed</wfw:commentRss>
		<slash:comments>42</slash:comments>
		</item>
		<item>
		<title>Zend Framework Tutorial Series: Part 1 &#8211; The Module Based Application</title>
		<link>http://phpdev.ro/zf-tutorial-series-part-1-module-based-app.html</link>
		<comments>http://phpdev.ro/zf-tutorial-series-part-1-module-based-app.html#comments</comments>
		<pubDate>Mon, 07 Jun 2010 15:05:32 +0000</pubDate>
		<dc:creator>Andrei Gabreanu</dc:creator>
				<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[Documentation]]></category>
		<category><![CDATA[Framework]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[Zend]]></category>

		<guid isPermaLink="false">http://phpdev.ro/?p=1012</guid>
		<description><![CDATA[These are a series of tutorials which are meant to show you or guide you through developing a complex application with Zend Framework 1.10.]]></description>
			<content:encoded><![CDATA[<h3>1. Intro &#8211; The first part of the series</h3>
<p>In this first article of the series, we will discuss about the best way (in my oppinion) to structure your Zend Application in order to have maximum flexibility but also a good defined structure of the classes/files.</p>
<p>These are a series of tutorials which are meant to show you or guide you through developing a complex application with Zend Framework 1.10.</p>
<p>The series consists of the following parts:<br />
a) Setting up a module based application<br />
b) Setting up helper plugins, methods &#038; debugging with ZFDebug<br />
c) Setting up a login page and signup page with captcha<br />
d) Setting up OpenID to login/create account<br />
e) Setting up an API to create/login an account<br />
f) Improving performance implementing Zend Cache</p>
<div style="background-color:#DDF8CC; margin-bottom:10px; padding:35px 15px 35px; font-size:18px; text-align:center;">
You can download the whole package <a href="http://zf-module-based-app.googlecode.com/files/zf_tutorial_1_structure.zip" target="_blank">from Google Code Here</a>.
</div>
<div style="padding:15px; background-color:#EAF2FA; margin-bottom:10px;">
<strong>Update:</strong> There was an issue with the Custom_Controller_Action_Abstract class with the $this->_redirect which was not initialized. The issue has been fixed below.<br/><br />
<strong>Update 2:</strong> After discussing with Paul via the comments below, I have updated the structure to be much more intuitive. Now the module library will be placed in the module folder itself proving a complete independence of the other modules.<br />
<br /> I&#8217;ve also added some new features to the preDispatch from the Frontoffice Library Controller Abstract file that helps you set in the view namespaces for the FlashMessenger (which can be used like this: <br /><br/><br />
$this->_helper->FlashMessenger->setNamespace(&#8217;success&#8217;)->addMessage(&#8216;The user has been created succesfully&#8217;);<br />
<br/><br/>You can still use the AjaxContextSwitch in your requests but it will not work if you mimin via the $_GET['ajax'] parameter
</div>
<h3>2. The WWW-ROOT</h3>
<p>The first thing you need to do is get the Zend Library. I used Zend 1.10.4 for this tutorial. </p>
<p>It is security wise to have your public www-root somewhere else than your Zend library/Application files. Thus, I have the following structure for all my applications:</p>
<p>a) Path to the www-root : ex: <strong>/var/www/my_zend_example_application/</strong><br />
b) Path to the application: ex: <strong>/var/applications/my_zend_example_application/</strong><br />
c) Path to the Zend library: ex: <strong>/var/library/Zend/1.10.4/</strong></p>
<p>Based on this list, create an <strong>index.php</strong> in your <strong>www-root</strong> folder with the following contents:</p>
<pre>
/**
 * Put errors on ON for debugging this file
 */
//ini_set('display_errors',1);
//error_reporting(E_ALL ^ E_DEPRECATED);

/*
 * Define the application environment
 */
define('APPLICATION_ENV', 'development');

/*
 * Defines the directory separator for windows or unix env
 */
define('DS', DIRECTORY_SEPARATOR);

/**
 * Define the absolute/relative paths to the library path, the app library path,
 * app path and the database configuration path
 */
define('ZEND_LIBRARY_PATH', realpath('/var/library/Zend/1.10.4'));
define('APPLICATION_PATH', '/var/applications/my_zend_example_application' );
define('APP_LIBRARY_PATH', APPLICATION_PATH . '/library');

$paths = array(
	ZEND_LIBRARY_PATH,
	APP_LIBRARY_PATH,
	get_include_path()
);

/**
 * Set the include paths to point to the new defined paths
 */
set_include_path(implode(PATH_SEPARATOR, $paths));

/** Zend_Application */
require_once 'Zend/Application.php';

// Create application, bootstrap, and run
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . DS .  'config' . DS . 'application.ini'
);

//Start
$application->bootstrap();
$application->run();
</pre>
<p>Also, make sure you have the following <strong>.htaccess file</strong> in the same place as your index.php (in the www-root):</p>
<pre>
RewriteEngine On
RewriteRule !.(js|css|ico|gif|jpg|png)$ index.php
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
</pre>
<p>This custom .htaccess will tell your http server to bypass Zend&#8217;s index.php for all requests for static files.</p>
<h3>3. The Directory Structure</h3>
<p>Once you have the library and the www-root defined, we will start setting up our application. Create the following directory structure in your application path (see above):</p>
<ul style="margin:0px; padding:0px 0px 0px 10px;">
<li style="margin:0px; padding:0px 0px 0px 10px;">/config/</li>
<li style="margin:0px; padding:0px 0px 0px 10px;">/library/
<ul style="margin:0px; padding:0px 0px 0px 10px;">
<li style="margin:0px; padding:0px 0px 0px 10px;">/Custom/
<ul style="margin:0px; padding:0px 0px 0px 10px;">
<li style="margin:0px; padding:0px 0px 0px 10px;">/Controller/
<ul style="margin:0px; padding:0px 0px 0px 10px;">
<li style="margin:0px; padding:0px 0px 0px 10px;">/Action/
<ul style="margin:0px; padding:0px 0px 0px 10px;">
<li style="margin:0px; padding:0px 0px 0px 10px;">/Helper/</li>
</ul>
</li>
<li style="margin:0px; padding:0px 0px 0px 10px;">/Plugin/</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li style="margin:0px; padding:0px 0px 0px 10px;">/modules/
<ul style="margin:0px; padding:0px 0px 0px 10px;">
<li style="margin:0px; padding:0px 0px 0px 10px;">/frontoffice/
<ul style="margin:0px; padding:0px 0px 0px 10px;">
<li style="margin:0px; padding:0px 0px 0px 10px;">/controllers/</li>
<li style="margin:0px; padding:0px 0px 0px 10px;">/library/
<ul style="margin:0px; padding:0px 0px 0px 10px;">
<li style="margin:0px; padding:0px 0px 0px 10px;">/Controller/
<ul style="margin:0px; padding:0px 0px 0px 10px;">
<li style="margin:0px; padding:0px 0px 0px 10px;">/Action/</li>
</ul>
</li>
</ul>
</li>
<li style="margin:0px; padding:0px 0px 0px 10px;">/layouts/</li>
<li style="margin:0px; padding:0px 0px 0px 10px;">/models/
<ul style="margin:0px; padding:0px 0px 0px 10px;">
<li style="margin:0px; padding:0px 0px 0px 10px;">/Entities/</li>
<li style="margin:0px; padding:0px 0px 0px 10px;">/Repositories/</li>
</ul>
</li>
<li style="margin:0px; padding:0px 0px 0px 10px;">/views/
<ul style="margin:0px; padding:0px 0px 0px 10px;">
<li style="margin:0px; padding:0px 0px 0px 10px;">/scripts/</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p></p>
<p>Perhaps you are a bit confused now with the directory structure. But lets see exactly what happens:</p>
<p>We will have a common library for all our files named &#8220;Custom&#8221; which you can just reuse in any project you develop. This Custom library will hold some basic files which will be used by all modules. These files will do some auto magical logic to simplify your development. </p>
<p>We also have a module (only 1 for now) which will be defined as the default module. All modules will be found in the &#8220;modules&#8221; directory. Each module will use its own library. This way, all modules are 100% independent from each other.</p>
<p>The logic is the following:</p>
<p>A module controller extends the module&#8217;s library parent controller which also extends the Custom library controller. </p>
<p>Example:</p>
<pre>
class IndexController extends Frontoffice_Library_Controller_Action_Abstract { ... }
</pre>
<p>and</p>
<pre>
abstract class Frontoffice_Library_Controller_Action_Abstract extends Custom_Controller_Action_Abstract { ... }
</pre>
<p>This way, you can have logic applied to:<br />
a) a particular controller<br />
b) all module controllers<br />
c) all application controllers</p>
<h3>4. The Application.ini</h3>
<p>Create a file named <strong>application.ini</strong> in your config folder from your application root with the following contents:</p>
<pre>
[bootstrap]
	Autoloadernamespaces[] = "Zend_"
	Autoloadernamespaces[] = "Custom_"

	resources.frontController.moduleDirectory = APPLICATION_PATH"/modules"
	resources.frontController.defaultModule = "frontoffice"
	resources.modules[] = ""
	resources.layout.layout = "layout"
	resources.layout.pluginClass = "Custom_Controller_Plugin_ModuleBasedLayout"
	resources.view.encoding = "UTF-8"
	resources.view.basePath = APPLICATION_PATH "/views/"

	bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
	bootstrap.class = "Bootstrap"

	;Database settings
	resources.multidb.front_db.adapter  = "pdo_mysql"
	resources.multidb.front_db.host     = CHANGE_ME
	resources.multidb.front_db.username = CHANGE_ME
	resources.multidb.front_db.password = CHANGE_ME
	resources.multidb.front_db.dbname   = CHANGE_ME
	resources.multidb.front_db.default  = true

[production : bootstrap]

	resources.multidb.front_db.profiler.enabled = false
	resources.multidb.front_db.profiler.class   = "Zend_Db_Profiler_Firebug"

	phpSettings.display_startup_errors = 0
	phpSettings.display_errors         = 0
	settings.debug.enabled             = false

	settings.application.datetime = "Etc/GMT-8"

[qa : production]

	resources.multidb.front_db.profiler.enabled = false
	resources.multidb.front_db.profiler.class   = "Zend_Db_Profiler_Firebug"

	phpSettings.display_startup_errors = 0
	phpSettings.display_errors         = 0
	settings.debug.enabled             = false

	settings.application.datetime = "Etc/GMT-8"

[testing : qa]

	phpSettings.display_startup_errors = 0
	phpSettings.display_errors         = 0
	settings.debug.enabled = false

	settings.application.datetime = "Etc/GMT-8"

	resources.multidb.front_db.profiler.enabled = true
	resources.multidb.front_db.profiler.class   = "Zend_Db_Profiler_Firebug"

[development : testing]

	phpSettings.display_startup_errors = 1
	phpSettings.display_errors         = 1

	settings.application.datetime = "Europe/Bucharest"

	resources.multidb.front_db.profiler.enabled = true
	resources.multidb.front_db.profiler.class   = "Zend_Db_Profiler_Firebug"
</pre>
<p>The Database connection string is a global environment parameter (the host/dbname/user/password) which are constants defined in a separate DB.php file included from the index.php but is not in the scope of the article.</p>
<p><strong>DEPRECATED:</strong> Moreover, we tell Zend to allow us to access our modules library via namespaces like &#8220;Frontoffice_Cool_Class&#8221;.</p>
<h3>5. The Bootstrap.php and its module childs</h3>
<p>In your application root, create a file called <strong>Bootstrap.php</strong> with the following contents:</p>
<pre>
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
	#stores a copy of the config object in the Registry for future references
	#!IMPORTANT: Must be runed before any other inits
	protected function _initConfig()
    {
    	Zend_Registry::set('config', new Zend_Config($this->getOptions()));
    }

	#Initializes the default timezone for the php ENV
	protected function _initDate()
    {
    	date_default_timezone_set(Zend_Registry::get('config')->settings
    														  ->application
    														  ->datetime);
    }

    #stores a copy of all the database adapters in the Registry for future references
	protected function _initDatabases()
    {
		$this->bootstrap('multidb');
		$resource = $this->getPluginResource('multidb');
    	$databases = Zend_Registry::get('config')->resources->multidb;
	    foreach ($databases as $name => $adapter)
	    {
	    	$db_adapter = $resource->getDb($name);
	    	Zend_Registry::set($name, $db_adapter);
	    }
    }
}
</pre>
<p>In your /modules/frontoffice/ create also a <strong>Bootstrap.php</strong> like this:</p>
<pre>
class Frontoffice_Bootstrap extends Zend_Application_Module_Bootstrap
{
        protected function _initLibraryAutoloader()
	{
		return $this->getResourceLoader()
					->addResourceType('library',
							 	   'library',
								   'library');
	}
}
</pre>
<p>You may ask yourself why have an empty module bootstrap <strong>(not empty anymore but the logic still remains)</strong> or if you will ever put code in your Module Bootstrap file:</p>
<p>The answer is no. Currently, Zend Framework loads ALL your bootstrap files, regardless of the module you are in. It is a complicated issue but in the end, it really doesn&#8217;t matter if you have code in your main bootstrap class or your module bootstrap class (actually, your module bootstrap class doesn&#8217;t have access to all items your main bootstrap class has). Moreover, for example, if you ignore the fact that zend loads all your bootstrap files, you might end up like me, having routes defined per module and then realizing that your routes for module A are being activated from module B resulting in a epic scale disaster <img src='http://phpdev.ro/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . </p>
<p>It is true you can just put something like &#8220;if module name is &#8220;frontoffice&#8221; then run this bootstrap method else don&#8217;t&#8221; but what if you change the module name? It is an issue that I fixed having NO code in the module bootstrap class.</p>
<h3>6. The Controller Plugins</h3>
<p>In order to have a 100% no-dependency between modules (well 99% since modules are linked to the Custom library in the end &#8211; but you can just remove that link in less than 1 minute) you will need to have an individual module error controller and layouts path/files.</p>
<p>In order to do this, you will need to create the following 2 classes:</p>
<p>In your Application Root, in the /library/Custom/Controller/Plugin/ create the following file, <strong>ModuleBasedLayout.php</strong> with the following contents:</p>
<pre>
class Custom_Controller_Plugin_ModuleBasedLayout
	extends Zend_Layout_Controller_Plugin_Layout
{
	public function preDispatch(Zend_Controller_Request_Abstract $request)
    {
		$this->getLayout()->setLayoutPath(
			Zend_Registry::get('config')->resources->frontController->moduleDirectory
			. DS . $request->getModuleName() . DS . 'layouts' );
    }
}
</pre>
<p>It is very important, in order for this to work to NOT initialize your Layout Plugin in the bootstrap file rather then in your application.ini or else, your layout object won&#8217;tbe available and thus, will fail with a fatal error.</p>
<h3>7. The Base Controller, the Module Base Controller and the Base Controller Action &#8220;Helper&#8221;</h3>
<p>So, now we have almost everything ready. Let&#8217;s create our first controller: The IndexController.</p>
<p>In your application root, in the /modules/frontoffice/controllers create your <strong>IndexController.php</strong> file with the following contents:</p>
<pre>
class IndexController extends Frontoffice_Library_Controller_Action_Abstract
{
	public function indexAction()
	{
	}
}
</pre>
<p>Also, lets create the <strong>ErrorController</strong> also:</p>
<pre>
Class ErrorController extends Frontoffice_Library_Controller_Action_Abstract
{
	public function errorAction()
    {
		$error = $this->_getParam('error_handler');
        switch ($error->type) {
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
                $this->getResponse()->setHttpResponseCode(404);
                $this->view->message = 'Uh oh, we can\'t seem to find that page you wanted!';
                $this->view->stack_trace = $this->_getFullErrorMessage($error);
				$this->view->code = 404;
                break;

            default:
                $this->getResponse()->setHttpResponseCode(500);
                $this->view->message = 'Looks like something\'s gone wrong! Please refresh the page - if the problem persists please report the error';
                $this->view->stack_trace = $this->_getFullErrorMessage($error);
				$this->view->code = 500;
                break;
        }

        $this->view->headTitle()->prepend( $this->view->code .  ' Error' );
    }

	protected function _getFullErrorMessage($error)
    {
		if (APPLICATION_ENV != 'development')
		{
			return '';
		}

        $message = '';

        if (!empty($_SERVER['SERVER_ADDR'])) {
            $message .= "Server IP: " . $_SERVER['SERVER_ADDR'] . "\n";
        }

        if (!empty($_SERVER['HTTP_USER_AGENT'])) {
            $message .= "User agent: " . $_SERVER['HTTP_USER_AGENT'] . "\n";
        }

        if (!empty($_SERVER['HTTP_X_REQUESTED_WITH'])) {
            $message .= "Request type: " . $_SERVER['HTTP_X_REQUESTED_WITH'] . "\n";
        }

        $message .= "Server time: " . date("Y-m-d H:i:s") . "\n";
        $message .= "RequestURI: " . $error->request->getRequestUri() . "\n";

        if (!empty($_SERVER['HTTP_REFERER'])) {
            $message .= "Referer: " . $_SERVER['HTTP_REFERER'] . "\n";
        }

        $message .= "Message: " . $error->exception->getMessage() . "\n\n";
        $message .= "Trace:\n" . $error->exception->getTraceAsString() . "\n\n";
        $message .= "Request data: " . var_export($error->request->getParams(), true) . "\n\n";

        $it = $_SESSION;

        $message .= "Session data:\n\n";
        foreach ($it as $key => $value) {
            $message .= $key . ": " . var_export($value, true) . "\n";
        }
        $message .= "\n";

        $message .= "Cookie data:\n\n";
        foreach ($_COOKIES as $key => $value) {
            $message .= $key . ": " . var_export($value, true) . "\n";
        }
        $message .= "\n";

        return '< pre>' . $message . '< / pre>';
    }
}
</pre>
<p>This error controller will basically allow you see a simple nice looking error message in your live/production environment but in development, lets you see full information about your active session (or the users one).</p>
<p>This can be extended to mail you the error details, get database query profiles and so on and so on.</p>
<p>Now, that we have these controllers, lets see what do they extend: The Module Base Controller:</p>
<p>In your application root, in the modules/frontoffice/library/Controller/Action/ create a file called <strong>Abstract.php</strong> with the following contents:</p>
<pre>
abstract class Frontoffice_Library_Controller_Action_Abstract
	extends Custom_Controller_Action_Abstract
{
	public function init()
	{
		$this->_initView();
	}

	/**
	 * Before dispatching the requested controller/action
	 * check to see if teh request is an AJAX request (via XMLHTTPREQUEST or $_GET['ajax']
	 *
	 * If it is an ajax request, remove the layout
	 *
	 * If it is not, setup the FlashMessenger
	 */
	public function preDispatch()
	{
		//if  its an AJAX request stop here - can be simulated via ?ajax GET parameter sent in the request
		if ($this->_request->isXmlHttpRequest() || isset($_GET['ajax']))
		{
			Zend_Controller_Action_HelperBroker::removeHelper('Layout');
		}

		if (!$this->getRequest()->isXmlHttpRequest())
		{
			$messages = array();
			$messages['error']   = $this->_helper->FlashMessenger->setNamespace('error')->getMessages();
			$messages['success'] = $this->_helper->FlashMessenger->setNamespace('success')->getMessages();
			$this->view->messages = $messages;
		}

		//Sets the base url to the javascripts of the application
		$script = '
			var base_url = "' . $this->view->baseUrl() . '";
		';
		$this->view->headScript()->prependScript($script, $type = 'text/javascript', $attrs = array());
	}

    protected function _initView()
    {
    	$view = new Custom_Controller_Action_Helper_View($this->view);
		$this->view = $view->init();
    }
}
</pre>
<p>The Init View method instantiates and runs the following class/object:</p>
<p>In your application root, /library/Custom/Controller/Action/Helper create a <strong>View.php</strong> with the following contents:</p>
<pre>
class Custom_Controller_Action_Helper_View
{
	public $view;

	public function __construct($view)
	{
		$this->view = $view;
	}

	public function init()
	{
    	// set encoding and doctype
		$this->view->setEncoding('UTF-8');

		$this->view->doctype('XHTML1_STRICT');

		// set the content type and language
		$this->view->headMeta()
			       ->appendHttpEquiv('Content-Type', 'text/html; charset=UTF-8');

		$this->view->headMeta()
				   ->appendHttpEquiv('Content-Language', 'en-US');

		// setting the site in the title
		$this->view->headTitle('My Cool Application');
		//	setting a separator string for segments:
		$this->view->headTitle()->setSeparator(' - ');

		return $this->view;
	}
}
</pre>
<p>Lastly, lets see the Global Base Controller. In your application root, in /library/Custom/Controller/Action/ create a file called Abstract.php with the following contents:</p>
<pre>
abstract class Custom_Controller_Action_Abstract extends Zend_Controller_Action
{
	/**
	 * Helper method to redirect to a specific action or controller from a
	 * specific module, via a specified route(or not) with specified parameters
	 *
	 * @param string $controller / $url which contains http in its composition
	 * @param string $action
	 * @param string $module
	 * @param array  $params
	 * @param string $route
	 * @param boolean $reset
	 */
	public function redirect($controller = 'index', $action = 'index', $module = 'frontoffice', $params = array(), $route = null, $reset = true )
    {
        $this->_redirect = $this->_helper->getHelper('Redirector');

    	$current_controller = $this->_getParam('controller');
    	$current_action     = $this->_getParam('action');
    	$current_module     = $this->_getParam('module');

    	if ($current_controller == $controller &#038;&#038;
    		$current_action == $action &#038;&#038;
    		$current_module == $module)
    	{
    		return TRUE;
    	}

    	if (strstr($controller, 'http'))
    	{
    		return $this->_redirect($controller, array('code' => 301));
    	}

    	if ($route !== null)
    	{
    		$params = array_merge(array('action'     => $action,
							    	    'controller' => $controller,
                               			'module'     => null), $params);

    		return $this->_redirect->setCode(301)
    		                       ->setExit(true)
    		                       ->gotoRoute($params, $route, $reset);
    	}

	    return $this->_redirect->setCode(301)
	    			    	   ->setExit(true)
	                   		   ->gotoSimpleAndExit($action,
	                                           	   $controller,
	                                           	   $module,
	                                           	   $params);
    }
}
</pre>
<p>You can use the method &#8220;redirect&#8221; anywhere in your controller to redirect either to a module/controller/action with params and with a route or without a route OR to a certain url :</p>
<p>Example: </p>
<pre>
...
return $this->redirect('http://google.com');
</pre>
<p>or</p>
<pre>
return $this->redirect('controller', 'action', 'module', arrary('param1' => 'value'), 'my-cool-route');
</pre>
<h3>8. The Layout &#038; Views</h3>
<p>The last thing before testing that everything works is to create a view and layout for your applicatio module:</p>
<p>Create in your application root /modules/frontoffice/layouts a file called layout.phtml with the following contents:</p>
<pre>
< ? php echo $this->doctype(); ? >
< html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
< head>
	< ? php echo $this->headMeta(); ?>
	< ? php echo $this->headTitle(); ?>
	< ? php echo $this->headStyle(); ?>
	< ? php echo $this->headLink(); ?>
	< script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
	< ? php echo $this->headScript(); ?>
</head>
< body>
	< div class="container">
	< ? php echo $this -> layout () -> content; ?>
	< /div>
< /body>
< /html>
</pre>
<p>Create in your application root /modules/frontoffice/views/scripts/index a file called index.phtml with the following contents:</p>
<pre>
Hello Frontoffice Index Controller World!
</pre>
<p>Now you can test your application by going to your www-root.</p>
<h3>9. Module Models</h3>
<p>Create in your application root /modules/frontoffice/models/Entities/ a file called Test.php &#8211; singular since it is an entity of the Test object &#8211; with the following contents:</p>
<pre>
class Frontoffice_Model_Entities_Test
	//extends Zend_Db_Table_Abstract
{
	public function test($message)
	{
		return 'Hello ' . $message;
	}
}
</pre>
<p>Create in your application root /modules/frontoffice/models/Repositories/ a file called Tests.php &#8211; plural since its a repository of the Tests object &#8211; with the following contents:</p>
<pre>
class Frontoffice_Model_Repositories_Tests
{
	public function test($message)
	{
		if (TRUE === empty($message))
		{
			throw new Zend_Exception('Invalid Message Provided to the Test Object');
		}

		$test_entity = new Frontoffice_Model_Entities_Test();
		return $test_entity->test($message);
	}
}
</pre>
<p>Now in your IndexController use the following code to test your model:</p>
<pre>
...
$tests_repository = new Frontoffice_Model_Repositories_Tests();
$this->view->message = $tests_repository->test('Andrew');
</pre>
<p>In your index.phtml use the following code to display your Model result:</p>
<pre>
...
echo $this->message;
</pre>
<p>If everything is setup correctly, you should see a message like &#8220;Hello Andrew&#8221; on your screen.</p>
<h3>10. Adding more modules</h3>
<p>The basic ideea of adding more modules to the application at this point is by adding 1 directory per module in your application root, in the /modules directory, using the same directory structure as the frontoffice module but with the following mandatory rule:</p>
<p>All modules that are NOT your default module, need to have the following namespace in their controllers: Modulename_ControllerName</p>
<p>Example: For an Admin module, you would have Admin_IndexController, Admin_UsersController and so on. </p>
<p><strong>DEPRECATED: You will need to have a library for each module, in your library folder, just like the Frontoffice library and that is about it.</strong></p>
<h3>11. Conclusion</h3>
<p>This basic setup should get you started in our tutorials series with our complex application.<br />
Next tutorial will consist of adding a complex debugging tool via ZFDebug customized + other helper methods.</p>
<p>You can download the example application <a href="http://phpdev.ro/wp-content/code_snippets/zf-tutorial-series-part-1-module-based-app/files.rar" target="_blank">here</a>.</p>
<p><strong>See you next time!</strong></p>
 <img src="http://phpdev.ro/wp-content/plugins/feed-statistics.php?view=1&post_id=1012" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://phpdev.ro/zf-tutorial-series-part-1-module-based-app.html/feed</wfw:commentRss>
		<slash:comments>143</slash:comments>
		</item>
		<item>
		<title>How to avoid Identity Theft in Zend Framework with Zend Auth</title>
		<link>http://phpdev.ro/how-to-avoid-identity-theft-in-zend-framework-with-zend-auth.html</link>
		<comments>http://phpdev.ro/how-to-avoid-identity-theft-in-zend-framework-with-zend-auth.html#comments</comments>
		<pubDate>Thu, 04 Mar 2010 07:00:41 +0000</pubDate>
		<dc:creator>Andrei Gabreanu</dc:creator>
				<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[auth]]></category>
		<category><![CDATA[login]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[Zend]]></category>

		<guid isPermaLink="false">http://phpdev.ro/?p=987</guid>
		<description><![CDATA[The following tutorial will show you how you can improve your overall security in your PHP application (the tutorial is based on Zend Framework 1.10 and on the use of Zend_Auth but you can easily adapt it to something for your own needs). You will learn how to extend the Zend_Auth class into a highly customizable &#038; secure Project Authentication class]]></description>
			<content:encoded><![CDATA[<p>As I am building my applications, I always try to improve the code I write in some way. Today I thought about the security issues of any PHP application that uses an authenticating system. </p>
<h2>Web application security issues</h2>
<p>The major issues with security within web application are the following:</p>
<ul>
<li><strong>Cross-site Scripting</strong> (see <a href="http://en.wikipedia.org/wiki/Cross-site_scripting" target="_blank">Wikipedia &#8211; Cross-site scripting</a> )</li>
<li><strong>Unvalidated parameters</strong></li>
<li><strong>Broken access control</strong></li>
<li><strong>Error-handling problems</strong></li>
<li><strong>Insecure use of cryptography</strong></li>
<li><strong>Web and application server misconfiguration</strong></li>
<li><strong>Broken account and session management</strong></a>
</ul>
<p>While all are major issues, there is one particular issue that bugged me for some time. The Identity theft &#8211; <em>Broken account and session management</em> issue.</p>
<p>Why can one so easily still my session id cookie and suddenly gain access to my account in one particular web application? I know it its rather impossible to make this 100% hack-proof but I strongly believe that the system should be improved as much as possible.</p>
<p>In the following few lines, I will show you how you can just do that. </p>
<h2>Our goal</h2>
<p>Our goal is to implement a Zend Auth extension that adds a new level of security to the previously mentioned class. </p>
<p>This extension &#8211; let&#8217;s call it <strong>Project_Application_Auth</strong> &#8211; would check the Zend Auth storage for the IP and/or User Agent. </p>
<p>In order to do so, these should be set in the login process in the storage. </p>
<p>If the IP is different then the initial IP from the login process and / or the User Agent is not the same as the initial User Agent from the login process, then our extension would tell us that it is not a secure identity (aka it is safe to assume it has been stolen) and thus we should disconnect the user.</p>
<h2>Reasons to use these methods</h2>
<p>I came up with this idea since I asked myself: Is there really a case where i would actually end up with the same session ID but different IP or different browser?</p>
<p>The answer is: <strong>yes</strong>. There is a chance with the first-one-mentioned. If i have a dynamic IP, this could change without me knowing, which would result in me being unauthenticated. </p>
<p>But the fact is, this happens rarely (even if you IP changes, it won&#8217;t change more then once per week, right?). </p>
<p>You might ask why should the extension that I am about to show you, check the IP also when we can just check the User Agent (since this definitely cannot be the same on a different IP since the session id cookie would exist in only one browser, not any other ). </p>
<p>The answer is: because any hacker that stole your identity might just use the same browser as you did and thus bypass our checks completely.</p>
<p>And as a final reason, yes, if the hacker has the same IP as yours, steals your identity (session cookie id) and uses the same browser, then he will bypass the system. But hey, at least we can make it harder for him!</p>
<h2>The Project Application Auth extension</h2>
<p>The following class should go into your <strong>/path/to/the/project/&#8230;&#8230;./library/Project/Application/Auth.php</strong></p>
<pre>
class Project_Application_Auth extends Zend_Auth
{
    /**
     * Singleton instance
     *
     * @var Project_Application_Auth
     */
    protected static $_instance = null;

    /**
     * Defines how much time to wait until
     * to reinitialize the session id
     */
    protected static $_session_exp_time = 5;

    /**
     * Defines if to validate a secure identity
     */
    protected static $_secure = TRUE;

    /**
     * Defines secure identity check level
     *
     * 1 - Check only IP
     * 2 - Check only UserAgent
     * 3 - Check IP &#038; UserAgent
     */
    protected static $_secure_level = 3;

    /**
     * Returns an instance of Project_Application_Auth
     *
     * Singleton pattern implementation
     *
     * @return Project_Application_Auth Provides a fluent interface
     */
    public static function getInstance()
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }

    /**
     * Sets wheter the method @see hasSecureIdentity
     * to work or not. If set to FALSE then this extension will work
     * as the normal Zend_Auth class
     *
     * @param boolean true
     */
    public function setSecure($status = TRUE)
    {
    	if ($status === TRUE)
    	{
    		self::$_secure = TRUE;
    	}

    	if ($status === FALSE)
    	{
    		self::$_secure = FALSE;
    	}

    	return TRUE;
    }

    /**
     * Sets the level of security for the @see hasSecureIdentity method
     *
     * @param integer $level (can be 1 or 2 or 3)
     */
	public function setSecureLevel($level)
    {
    	if (in_array($level, array(1, 2, 3)))
    	{
    		self::$_secure_level = $level;
    	}

    	return TRUE;
    }

    /**
     * Returns true if and only if an identity is not stolen
     *
     * Checks if IP and/or User Agent (@see $_secure_level)
     * match the initial authentication data
     *
     * @return boolean
     */
    public function hasSecureIdentity()
    {
    	if (self::$_secure === FALSE)
    	{
    		return TRUE;
    	}

    	if (FALSE == $this->getStorage()->isEmpty())
    	{
	    	$storage = $this->getStorage()->read();

	    	if (self::$_secure_level == 3)
	    	{
		    	return $storage->ip == $_SERVER['REMOTE_ADDR']
		    		&#038;&#038; $storage->user_agent == $_SERVER['HTTP_USER_AGENT'];
	    	}
	    	elseif (self::$_secure_level == 2)
	    	{
	    		return $storage->user_agent == $_SERVER['HTTP_USER_AGENT'];
	    	}
	    	elseif (self::$_secure_level == 1)
	    	{
	    		return $storage->ip == $_SERVER['REMOTE_ADDR'];
	    	}
	    	else
	    	{
	    		return FALSE;
	    	}
    	}
    	else
    	{
    		return FALSE;
    	}
    }

    /**
     * If the Zend Auth Storage
     * has been initialized and is a Session Storage
     * and the last time it has been reinitialized is bigger then
     * the @see $session_exp_time then reinitialize the session id
     *
     * @return boolean
     */
    public function reinitSecurity()
    {
    	if (isset($_SESSION['Zend_Auth']))
    	{
	   		$zend_auth_session_namespace = new Zend_Session_Namespace('Zend_Auth');
			if (!isset($zend_auth_session_namespace->initialized)
				|| $zend_auth_session_namespace->initialized + self::$session_exp_time < time() ) {
				Zend_Session::regenerateId();
				$zend_auth_session_namespace->initialized = time();
			}
    	}

    	return TRUE;
    }
}
</pre>
<p>Now, let&#8217;s stop for a second and understand what all these spooky lines do:<br />
First of all, the extension implements the singleton pattern. Then, we got 3 properties: </p>
<p>The first one -is_secure &#8211; allows us to turn on and off the whole class, leaving us with the usual Zend Auth system. </p>
<p>The second one, secure level, defines what to check for: either just IP or just User Agent or both. </p>
<p>The third one, session_exp_time defines when to reinitialize the Zend Auth Session Storage Id (aka PHPSESSID id) if the method reinitSecurity is called.</p>
<h2>How to use the class</h2>
<p>In your base controller &#8211; let&#8217;s call it Project_Application_Controller (which all controllers should extend) &#8211; you should have the following code :</p>
<pre>
abstract Class Project_Application_Controller extends Zend_Controller_Action
    /**
     * Initialize the application controller
     */
	public function init()
	{
		parent::init();
		$this->_initSession();
		debug($_SESSION);
	}

	/**
	 * Inits the User Session
	 * and refresh the session id
	 */
	protected function _initSession()
	{
		Project_Application_Auth::getInstance()->reinitSecurity();
	}
</pre>
<p>This basically just allows us to run the method reinitSecurity with each run of the application, while still allowing us to initialize the whole Front Controller.</p>
<p>Now, in your preDispatch() method you might have something like this:</p>
<pre>
if ( FALSE === Project_Application_Auth::getInstance()->hasIdentity() { //do stuff here } else { //other stuff here }
</pre>
<p>This basically just checks if the user has been authenticated previously. Exactly underneath this, add the following code:</p>
<pre>
if ( FALSE === Project_Application_Auth::getInstance()->hasSecureIdentity()
    &#038;&#038; 'users' !== $this->getRequest()->getControllerName()
    &#038;&#038; 'login' !== $this->getRequest()->getActionName()
    &#038;&#038; 'error' !== $this->getRequest()->getControllerName())
{
    Zend_Auth::getInstance()->clearIdentity();
    // redirect to login page
}
</pre>
<p>I am assuming that you have a controller named users with an action login into it (change as you wish).</p>
<p>Lastly, in your in your login process, wherever you are running your Zend_Auth authenticate() method, add the following code :</p>
<pre>
$auth = Project_Application_Auth::getInstance();

$result = $auth->authenticate($authAdapter);

if ($result->isValid())
{
    $storage = $authAdapter->getResultRowObject();
    $storage->ip = $_SERVER['REMOTE_ADDR'];
    $storage->user_agent = $_SERVER['HTTP_USER_AGENT'];

    $storage = $auth->getStorage()->write($storage);
    return TRUE;
}
else
{
    return FALSE;
}
</pre>
<p>This will put your user object in your Zend Auth Storage along side the IP and User Agent.</p>
<h2>Conclusion</h2>
<p>Hope you liked it. I am very interested in hearing your thoughts about this system so you&#8217;re invited to leave your comments below and I will respond as quick as possible.</p>
<p>See you!</p>
 <img src="http://phpdev.ro/wp-content/plugins/feed-statistics.php?view=1&post_id=987" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://phpdev.ro/how-to-avoid-identity-theft-in-zend-framework-with-zend-auth.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>How to add Ajax support in Zend Framework</title>
		<link>http://phpdev.ro/how-to-add-ajax-support-in-zend-framework.html</link>
		<comments>http://phpdev.ro/how-to-add-ajax-support-in-zend-framework.html#comments</comments>
		<pubDate>Tue, 02 Mar 2010 07:00:26 +0000</pubDate>
		<dc:creator>Andrei Gabreanu</dc:creator>
				<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[Framework]]></category>
		<category><![CDATA[Jquery]]></category>
		<category><![CDATA[Zend]]></category>

		<guid isPermaLink="false">http://phpdev.ro/?p=969</guid>
		<description><![CDATA[In this tutorial, I will talk about how to handle AJAX request in a clean &#038; simple way. Whether you use jQuery, mooTools or any other JS framework (or perhaps no framework at all) you will definitely going to love this painless solution of having an ajax view rendered without doing anything (ofcourse, after you set it up properly)]]></description>
			<content:encoded><![CDATA[<p>Currently I am working on some projects that require a lot of Ajax support. And while working with Zend and wanting it to blend nicely with AJAX based requests from jQUery or MooTools (or any other for that matter) I developed a very nice and easy system that makes handling these requests easier.</p>
<h2>The Application Controller</h2>
<p>In order to have our application clean constructed, all our controllers will extend one Application Controller (I named it <strong>Project_Application_Controller</strong> ). </p>
<p>Like this:</p>
<pre>
//This class goes into a folder like
//<strong>root/library/Project/Application/Controller.php</strong>
//where root is your application root.

abstract Class Project_Application_Controller extends Zend_Controller_Action
{
//code goes here
}

and

Class IndexController extends Project_Application_Controller
{
//code goes here
}
</pre>
<p>Why is this good? Because you can now add any method you want to be widely available to all controllers, which we are about to use.</p>
<h2>The AJAX Request</h2>
<p>In your Project Application Controller add the following code:</p>
<pre>
protected $_ajax_view = 'ajax.phtml';
//Thanks <a href="http://www.facebook.com/simionandrei" target="_blank">Andrei Simion</a> for giving me this ideea

public function preDispatch()
{
    //if  its an AJAX request stop here
    if ($this->_request->isXmlHttpRequest() || isset($_GET['ajax']))
    {
        Zend_Controller_Action_HelperBroker::removeHelper('Layout');
	$this->getHelper('ViewRenderer')->setNoRender();
	return TRUE;
    }
}

public function postDispatch()
{
    if ($this->_request->isXmlHttpRequest() || isset($_GET['ajax']))
    {
        $this->renderScript( $this->_getAjaxView() );
    }

    return TRUE;
}

protected function _setAjaxView($view)
{
    $this->_ajax_view = $view;
    return TRUE;
}
protected function _getAjaxView()
{
    return $this->_ajax_view;
}
</pre>
<p>Basically what we are doing here is to have 1 setter and 1 getter for the ajax view. If Zend determines that the current request is an AJAX request (or the parameter &#8216;ajax&#8217; from the GET params exists) it will <strong>not</strong> render the layout at all and it will render an ajax view as determined by you. You can have one ajax view by default and then add more views per your needs.</p>
<p>Then all you have to do in order to use this system is to call the functions as this:</p>
<pre>
//Controller code is here
$this->view->message = json_encode('my_cool_data');

//View code here from root/layouts/ajax.phtml
echo $this->message;

//Or if you want to have a custom ajax view
$this->_setAjaxView('my_cool_ajax_view.phtml');
$this->view->other_message = array('test');

//and in your root/layouts/my_cool_ajax_view.phtml
if ( TRUE === is_array($this->other_message))
{
    echo 'it is array';
}
else
{
    echo 'it is not an array';
}
</pre>
<p>Hope you liked it!</p>
 <img src="http://phpdev.ro/wp-content/plugins/feed-statistics.php?view=1&post_id=969" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://phpdev.ro/how-to-add-ajax-support-in-zend-framework.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Most interesting links of February 2010</title>
		<link>http://phpdev.ro/most-interesting-links-of-february-2010.html</link>
		<comments>http://phpdev.ro/most-interesting-links-of-february-2010.html#comments</comments>
		<pubDate>Mon, 01 Mar 2010 10:20:24 +0000</pubDate>
		<dc:creator>Andrei Gabreanu</dc:creator>
				<category><![CDATA[Jquery]]></category>
		<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[Various]]></category>
		<category><![CDATA[links interesting february]]></category>

		<guid isPermaLink="false">http://phpdev.ro/?p=889</guid>
		<description><![CDATA[Monthly, I will publish an article with the most interesting links that I found during that month. These links will be addressed to both designers, developers and some even to Linux system administrators. Except to find useful resources that may (or may not) help you in your future projects. Each link will contain a small intro text so you can understand what the article is all about without having to navigate to the article itself.]]></description>
			<content:encoded><![CDATA[<p>Here is my collection of best link references of February 2010:</p>
<h2>Implement a Rest API with the Zend Framework</h2>
<p><strong><a href="http://blog.realmofzod.com/2009/05/06/implement-a-rest-api-with-the-zend-framework/" target="_blank">Implement a Rest API with the Zend Framework </a></strong> is a great article posted on the &#8220;Realm of Zod&#8221; blog by Brandon, which shows you how to build your own Rest Server and Rest Client with Zend Framework. It gives you all the details required to get you started on the RESTful path of WebServices.</p>
<h2>Font type tester (includes font-face tests for CSS3)</h2>
<p><strong><a href="http://www.typetester.org/" target="_blank">Typetester &#8211; Compare fonts for the screen</a></strong> is a very very useful site for both designers and developers who want to give a nice artistic touch to their website without having to research countless hours for an appropriate font that might work or not for their needs. </p>
<h2>960 Grid System &#8211; CSS Framework</h2>
<p><strong><a href="http://960.gs/" target="_blank">960.gs</a></strong> is the leading CSS framework on the market. Even if you don&#8217;t like to use CSS Frameworks or didn&#8217;t know they existed, 960gs will provide you with core elements that will help you speed up your design2html process. For all of you who didn&#8217;t try it yet, you should definitely give it a shot. You won&#8217;t regret it.</p>
<h2>High Resolution Bokeh Texture</h2>
<p><strong><a href="http://jaicca.deviantart.com/art/High-Resolution-Bokeh-Texture-114634537" target="_blank">High Resolution Bokeh Texture</a></strong> is part of the freebies category. It includes a pack of bokeh textures to share &#038; use in your design projects. The package contains 5 textures with high resolution (240 dpi) 3456 x 2304. </p>
<h2>Out of focus 30 free bokeh textures</h2>
<p><strong><a href="http://lostandtaken.com/2008/09/out-of-focus-30-free-bokeh-textures.html" target="_blank">Out of focus 30 free bokeh textures</a></strong> is part of the freebies category again, this time with more textures for your design needs. The package contains 30 textures for your free use.</p>
<h2>Getting Started with XSL(T)</h2>
<p><strong><a href="http://net.tutsplus.com/tutorials/html-css-techniques/getting-started-with-xslt/">Getting Started with XSL(T)</a></strong> is the final interesting link of the month. It is an article written by Chad Hietala for <strong>Net Tuts Plus</strong> where he explains how to get started with the XLS(T) which is an alternative to the HTML design we all have used so far. If you are curios why even bother looking this up, you might need to know that <a href="http://www.wowarmory.com/">Blizzard World of Warcraft armory</a> is purely made on XLS(T)</p>
 <img src="http://phpdev.ro/wp-content/plugins/feed-statistics.php?view=1&post_id=889" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://phpdev.ro/most-interesting-links-of-february-2010.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>[HOW TO] Store Zend Cache results into MySql</title>
		<link>http://phpdev.ro/how-to-store-zend-cache-results-into-mysql.html</link>
		<comments>http://phpdev.ro/how-to-store-zend-cache-results-into-mysql.html#comments</comments>
		<pubDate>Tue, 09 Feb 2010 13:37:19 +0000</pubDate>
		<dc:creator>Andrei Gabreanu</dc:creator>
				<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[Advices]]></category>
		<category><![CDATA[Cache]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Develop]]></category>
		<category><![CDATA[Mysql]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://phpdev.ro/?p=928</guid>
		<description><![CDATA[This article will show you how to write / use your own Zend Cache Backend Adapter along side provide you with the Class that will allow you to store your cached data, objects and even full html pages inside a MySql database. You can read about how the class can be used, how it works (theory of operation) or you can just download it from the end of the article.]]></description>
			<content:encoded><![CDATA[<h2>Why Zend_Cache &#038; Mysql</h2>
<p>If you haven&#8217;t already started using <strong>Zend_Cache</strong>, you should definitely try it out. There is no need to explain the benefits of using it but these include <strong>an increased page load speed</strong> since the requests <strong>are balanced for all page views</strong>. If you wish to find out more about Zend_Cache, you can go to the <a href="http://framework.zend.com/manual/1.10/en/zend.cache.introduction.html" target="_blank">manual</a> and read more there since the Zend team provides excellent documentation.</p>
<p>However, sometimes, the backends (File, SQLite, memcache, apc) provided by Zend are not enough to satisfy our needs.<br />
In my case, I wanted to use Zend_Cache, but did not have at my disposal any type of backend that the Cache object supported. So I decided to write my own. </p>
<p>Thus, I have created the adapter <strong>MyApp_Cache_Backend_PDOMysql</strong> which is a backend for Zend_Cache. It does exactly what SQLite does and has some improvements over it: it is highly customizable via the constructor. You are not required to have a certain table called somehow you do not like and your table structure can be however you wanted it to be, keeping in mind you need the following in order for it to work:</p>
<ul>
<li>A text column where the serialized cache will be stored</li>
<li>A 32 char column where the signature of the cache will be stored</li>
<li>An integer column, unsigned, where the expiry time stamp will be held</li>
</ul>
<h2>Theory of Operation</h2>
<p>The Cache object, when initialized and started, checks to see if the current request signature (page load, method load, function load or any other) exists in the backend, in our case if it exists in the cache table. If it does exist and it is not expired, it fetches &#038; deserializeses the data column of that row and the requested method / page now holds this data, instead of querying / fetching the data from the server again.</p>
<p>If the signature does not exist in the Database or it has expired, it simply deletes it, waits for the method / page to load, serializes the response and saves it in the cache for later use.  </p>
<p>The PDOMysql adapter only sets up the option it needs to have in order to load and save cached data from the Mysql database. </p>
<h2>Using the PDOMysql adapter</h2>
<p>Once you have the database table setup, you can start using it as following:</p>
<p>a) Put the class file inside your <strong>Application/library/path/MyApp/Cache/Backend/PDOMysql.php</strong> file (or change the class name to reflect your directory structure)</p>
<p>b) Put the following code in your initCache(){ &#8230; } method from your bootstrap file:</p>
<pre>

//...
//Front End options go here, see documentation for more information about this

//Example FrontEnd Option:
$frontend= array(
		    'lifetime' => 3600,  //nb seconds to hold the cache
		    'automatic_serialization' => true
	    );

$backend = new MyApp_Cache_Backend_PDOMysql(
    array(
        'table_name' => 'My_Cache_Table_Name',
        'signature_column' => 'My_Signature_Column',
        'data_column' => 'My_Data_Column',
        'expiry_column' => 'My_Expiry_Column'
    )
);

$cache = Zend_Cache::factory(
        	'core',
   	        $backend,
        	$frontend,
        	array()
	    );
 Zend_Registry::set('cache',$cache);

//Other code you may have
//...
</pre>
<p><em>Note: i have added all the options to the constructor even though you may not pass them at all since you can just use the defaults (cache/signature/expiry/data)</em></p>
<p>Once you have these things done, you can just get the cache object from the registry wherever you want, before running a method which you want to get it from cache, (ex: $cache = Zend_Registry::get(&#8216;cache&#8217;); ) and then just run</p>
<ul>
<li> $cache->load( md5($method.serialize($params)) );  &#8211; to test &#038; load a cached data object</li>
<li> $cache->save($data, md5($method.serialize($params)) );  &#8211; to save a cached data object</li>
</ul>
<h2>Download &#038; Conclusion</h2>
<p>You can download the class file <a href="http://phpdev.ro/wp-content/code_snippets/how-to-store-zend-cache-results-into-mysql/PDOMysql.zip">here</a> .</p>
<p>This Class does only what it was meant to do (what I need it to do) so if you have any ideas of how to improve it or perhaps just thoughts/suggestions of what you might want it to do in order to help you, please comment below and I will do my best to update the package so that everybody can benefit out of it.</p>
 <img src="http://phpdev.ro/wp-content/plugins/feed-statistics.php?view=1&post_id=928" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://phpdev.ro/how-to-store-zend-cache-results-into-mysql.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>UnitTesting in PHP with SimpleTest in Zend Framework (the simple and fast way)</title>
		<link>http://phpdev.ro/unittesting-in-php-with-simpletest-in-zend-framework-the-simple-and-fast-way.html</link>
		<comments>http://phpdev.ro/unittesting-in-php-with-simpletest-in-zend-framework-the-simple-and-fast-way.html#comments</comments>
		<pubDate>Mon, 01 Feb 2010 09:38:09 +0000</pubDate>
		<dc:creator>Andrei Gabreanu</dc:creator>
				<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[Advices]]></category>
		<category><![CDATA[Develop]]></category>
		<category><![CDATA[Documentation]]></category>
		<category><![CDATA[Framework]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[Unit testing]]></category>
		<category><![CDATA[Zend]]></category>

		<guid isPermaLink="false">http://phpdev.ro/?p=901</guid>
		<description><![CDATA[In this post, I will show you why it is important to use Unit Testing, how to use it and how to avoid writing the same code 2 times. Also, i will show you how to do a basic Test Driven Development with SimpleTest and Zend Framework 1.10. Also, this tutorial will show you how to directly link your tests to the code of your application, without duplicating content. At the end, you will be able to extend the tests to run on any code you write.]]></description>
			<content:encoded><![CDATA[<p>Until the present, I was of the same opinion as other developers that Unit Testing in PHP is just way too much time consuming and complicated to do. So I managed all the coding and testing myself and fixed bugs as I cached up. I did try Unit testing in the past but just didn&#8217;t seem so appealing to use in all projects. </p>
<h2>Why use Unit Testing</h2>
<p>However, all that changed when I developed a very big application. From a points on, bugs started rolling out from everywhere. And while I was fixing them, almost every time I added a new feature, something else broke in the application. Before you start shouting that I just did a bad job at coding the whole application, I want to tell you that I DO agree with you from the start. But on a large scale application, you can easily start adding bugs without even knowing, and sometimes even while following best practices so this doesn&#8217;t change the fact that all those bugs could have been so easily spotted while developing (fixing bugs while writing the code is always MUCH faster then fixing them after a release). From that moment on I asked myself if I should use Unit Testing in the future. So I started reading about SimpleTest and PHPUnit .</p>
<p>In not to many words, I choose to use Unit Testing from now on because of the simple common myth that I realized is fake: You spend much more time writing in a TTD way than you would do otherwise. This myth assumes that, if you write tests for your application, you will ultimately write the code 2 times thus you spend 2 x more time coding. This is NOT true. You don&#8217;t write the code 2 times and you don&#8217;t spend 2 x more time writing the tests + application. Here is why.</p>
<p>You can run tests with the actual application files, and just validate the outcome. Once the test is passed, you already have written your application test file. All you have to do to achieve this is to make sure your application files use a Test Environment with fake data you can control. This changes everything since, once you have written the test and it passes, you are done with that feature. No more things to do, no more coding. You are completely done!</p>
<p>Also, I choose SimpleTest because it has a web based interface and you only need to copy paste its core files in order to install it (and of course because I was unable to make PHPUnit work with WAMP).</p>
<p><em>Disclaimer: I have used SimpleTest before for 1 day and i liked it. I am an amateur in terms of Unit Testing, so i would appreciate any tips or feedback you may leave in the comments below</em> </p>
<h2>Setting up SimpleTest</h2>
<p>In order to write tests you will need 2 things: a working ZF project and the <a href="http://simpletest.org/" target="_blank">SimpleTest library</a>. Once you have downloaded SimpleTest, move it in your public root directory of your ZF project like this:</p>
<p><img src="http://phpdev.ro/wp-content/code_snippets/unittesting-in-php-with-simpletest-in-zend-framework-the-simple-and-fast-way/simple_test_1.jpg" /></p>
<p>Inside the <strong>simpletest</strong> directory, you should have the contents of the SimpleTest library.</p>
<p>Once you have done that, create a directory named tests in the same place as the <strong>SimpleTest</strong> library. Inside of it, create two files named Bootstrap.php and Index.php. Also create 1 directory named &#8220;Models&#8221; like this:</p>
<p><img src="http://phpdev.ro/wp-content/code_snippets/unittesting-in-php-with-simpletest-in-zend-framework-the-simple-and-fast-way/simple_test_2.jpg" /></p>
<p>Now, go to the index.php file and add the following piece of code</p>
<pre>< h1 >Tests to run</ h1 >
< br />
< h3 >Models</ h3 >
< ul >
< ? php
$dirHandle = opendir('Models/');

while (false !== ($file = readdir($dirHandle))) {
    if ($file != '.' &#038;&#038; $file != '..')
    {
    	echo '< li >< a href="Models/'.$file.'">'. $file . '< /a >< /li >';
    }
}
?>
</ ul >
</pre>
<p>This basically will just show us when navigating to the tests directory, each individual test case we have coded. </p>
<p>Now if you go view you project in your browser and navigate to the tests directory (ex: http://localhost/myZfproject/tests/) you should see an almost empty file (except for a h1 and h2)</p>
<h2>Setting up a Bootstrap File</h2>
<p>In your bootstrap.php file (this file is <strong>different</strong> then your ZF project bootstrap file) add the following lines of code:</p>
<pre>< ?php
ini_set('display_errors',1);
error_reporting(E_ALL ^ E_DEPRECATED);

define('DS',DIRECTORY_SEPARATOR);
define('LIBRARY_PATH',realpath(dirname(__FILE__)
	. DS . '..'
	. DS . '..'
	. DS . '..'
	. DS . 'library'
	. DS . '1.10')
);
define('APPLICATION_PATH',realpath(dirname(__FILE__)
	. DS . '..'
	. DS . '..'
	. DS . '..'
	. DS . 'MyProj' )
);
define('APPLICATION_ENV','testing');

$paths = array(
	LIBRARY_PATH,
	APP_LIBRARY_PATH,
	get_include_path()
);

set_include_path(implode(PATH_SEPARATOR, $paths));

/** Zend_Loader */
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();

// Custom functions to help development
require_once (
	dirname(dirname(APPLICATION_PATH))
	. DS . 'configs'
	. DS . 'MyProj'
	. DS . 'db.php' );

$config = new Zend_Config_Ini(
	dirname(dirname(APPLICATION_PATH))
	. DS . 'configs'
	. DS . 'MyProj'
	. DS . 'application.ini',
	APPLICATION_ENV );

$dbAdapter = Zend_Db::factory($config->resources->db);
Zend_Db_Table_Abstract::setDefaultAdapter($dbAdapter);

//Tests start here
require_once('../../simpletest/autorun.php');
</pre>
<p>Notice that I set error reporting NOT to show me deprecated errors (since SimpleTest is using some old functions that PHP considers deprecated).<br />
In the bootstrap file we have just configured where the Zend Libary is located, where our application is located and what environment to use for testing.</p>
<p>We also loaded the autoloader since we want Zend to load classes for us automatically. We also setup how to connect to the database (based on the environment above selected). </p>
<p>The last thing I did was that I loaded the autorun library of SimpleTest, which allows me to run the actual test cases I will write. </p>
<p>Nothing fancy so far, but lets see the next step&#8230;</p>
<h2>Writing your first test</h2>
<p>I&#8217;ll assume you have a model named User.php . Based on this, create a file named User.php in your tests/Models directory, with the following contents</p>
<pre>< ?php
require_once '../Bootstrap.php';
require_once '/var/www/applications/MyProj/models/Db/User.php';

class TestDefault_Model_Db_User extends UnitTestCase
{
	public function Test_getUserId()
	{
		$user = new Default_Model_Db_User();
		$this->assertEqual($user->getUserId('andrei'), 5);

//We know that the user with the username 'andrei' has the id 5
//We know this because the TESTING database contains this row
	}
}
?>
</pre>
<p>With this simple piece of code, all I&#8217;ve done is to include the bootstrap file that assures the test will run and included the actual model i have in the ZF Project.</p>
<p>Then, I just created a test class (it is mandatory it starts with Test) and I have ran a simple assertion to check that the method getUserId will return the correct id based on an username. Simple right?</p>
<p>Now, if I want to add a new feature to the getUserId method, I just edit my application model and run the test again. If it fails, its clear I added a feature with at least one bug that I need to fix.</p>
<h2>Running your first test</h2>
<p>To run a test, simply call your test case file from the browser and watch the awesomeness happen on the screen . (ex: http://localhost/myZfProject/tests/Models/User.php )</p>
<h2>From here to&#8230;</h2>
<p>Of course, now you can add more test cases (or even test suites) and also extend the functionality to basically test anything you want. Yes, even controllers, plugins, helpers and so on and forth! All you have to do is make sure you develop your code in TTD manner and make sure you don&#8217;t use global variables at all (or use them as little as possible) but that is another story, for another blog post. If you want to learn more about a specific issue in TTD, you can check <a href="http://www.youtube.com/watch?v=-FRm3VPhseI" target="_blank">this video out</a> . </p>
<p>Let the tests begin!</p>
 <img src="http://phpdev.ro/wp-content/plugins/feed-statistics.php?view=1&post_id=901" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://phpdev.ro/unittesting-in-php-with-simpletest-in-zend-framework-the-simple-and-fast-way.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to integrate uploadify in Zend Framework 1.9.6</title>
		<link>http://phpdev.ro/how-to-integrate-uploadify-in-zend-framework-1-9-6.html</link>
		<comments>http://phpdev.ro/how-to-integrate-uploadify-in-zend-framework-1-9-6.html#comments</comments>
		<pubDate>Mon, 30 Nov 2009 15:44:30 +0000</pubDate>
		<dc:creator>Andrei Gabreanu</dc:creator>
				<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Jquery]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[Upload]]></category>
		<category><![CDATA[Uploadify]]></category>

		<guid isPermaLink="false">http://blog.uauzilla.ro/?p=595</guid>
		<description><![CDATA[A detailed tutorial will show you how to integrate Zend Framework version 1.9.6 with jQuery Uploadify version 2.1.0. The tutorial covers all the basic aspects of the process from installing the framework on a multi zend applications with the same library/separate configurations system to integrating the jQuery Uploadify into your website. The uploads will be made in a secure folder, outside the public area of your server from where you can manipulate the files as you wish.]]></description>
			<content:encoded><![CDATA[<p>In a <a href="http://blog.uauzilla.ro/how-to-use-uploadify-with-cakephp.html" target="_blank">previous post</a>, i talked about integrating the script <a href="http://www.uploadify.com" target="_blank"><strong>jQuery Uploadify</strong></a> into the CakePHP framework. Today, i will show you how to integrate it into Zend Framework 1.9.6.<br />
Our goal is simple: create a new zend application that uses a common library, gets its configuration files from a custom location and integrate it with Uploadify<span id="more-595"></span></p>
<h2>Application folders &amp; the public files</h2>
<p>First of all, you will need to download the Zend Framework. You can download it from the Zend site <a href="http://framework.zend.com/download/latest" target="_blank"><strong>here</strong></a>. In this tutorial, i will work with the 1.9.6 version of the framework.</p>
<p>We will now create our directory structure for the framework.</p>
<ul>
<li>Create a folder in <strong>/var/www/public_html/uploadify/</strong> named <strong>public</strong>.</li>
<li>Create two folders in <strong>/var/www/</strong> named <strong>application</strong> and <strong>library</strong>.</li>
<li>Inside the <strong>library</strong> folder, create a new folder named <strong>1.9.6</strong>. Inside this folder, add your Zend library folder, so you would have /var/www/library/1.9.6/Zend.</li>
</ul>
<p>In your <strong>public</strong> folder add a file named <strong>index.php</strong> with the following contents:</p>
<pre>define('DS',DIRECTORY_SEPARATOR);

/**
* If you followed the tutorial example paths then the following paths
* would be like : /var/www/public_html/uploadify/../../
*/
define('LIBRARY_PATH',
	realpath(dirname(__FILE__) .
	'..' . DS . '..' . DS .
	'library' . DS . '1.9.6')
);
define('APPLICATION_PATH',
	realpath(dirname(__FILE__) .
	'..' . DS . '..' . DS .
	'application' ));

define('APPLICATION_ENV','production');

$paths = array(
	LIBRARY_PATH,
	get_include_path()
);

set_include_path(implode(PATH_SEPARATOR, $paths));

/** Zend_Application */
require_once 'Zend/Application.php';

$application = new Zend_Application(
	APPLICATION_ENV,
	APPLICATION_PATH . '/configs/application.ini'
);
$application->bootstrap();
$application->run();
</pre>
<p>Add a new file called <strong>.htaccess</strong> here with the following contents:</p>
<pre>RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
</pre>
<p>Create a folder named <strong>scripts</strong> and a folder named <strong>images</strong>. Inside the scripts put the <a href="http://docs.jquery.com/Downloading_jQuery#Current_Release" target="_blank"><strong>jQuery</strong></a> library, the <a href="http://www.uploadify.com/download/" target="_blank"><strong>jQuery.uploadify.v2.1.0.min.js</strong></a>, the <a href="http://www.uploadify.com/download/" target="_blank"><strong>swfobject.js</strong></a> and create a new file named <strong>scripts.js</strong>.</p>
<p>Inside the <strong>scripts.js</strong> add the following lines.</p>
<pre>$(document).ready(function() {
	$('#upload_container').uploadify({
		'uploader' : uploadify_swf_file,
		'script'   : upload_php_file,
		'folder'   : upload_folder,
		'cancelImg': upload_cancel_img,
		'auto'     : true
	});
});
</pre>
<p>Inside the <strong>public folder</strong> put the <strong>uploadify.swf</strong> .</p>
<p>Inside the <strong>images folder </strong>put the <strong>cancel.png</strong> .</p>
<p>Now you are done with the public folder. On to the application..</p>
<h2>The application config</h2>
<p>The <strong>config file</strong> ( /configs/application.ini ) can have the default values.</p>
<pre>[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0

bootstrap.path = APPLICATION_PATH "/Bootstrap.php";
bootstrap.class = "Bootstrap";

resources.frontController.controllerDirectory = APPLICATION_PATH
"/controllers";

resources.layout.layout = "layout";
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts";

resources.view.encoding = "UTF-8";
resources.view.basePath = APPLICATION_PATH "/views/";

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
</pre>
<h2>The application controller</h2>
<p>Create a new file in your <strong>controllers</strong> folder named <strong>UploadifyController.php</strong> with the following contents:</p>
<pre>/**
 * @name UploadifyController
 * @desc The controller to serve the main page for our upload example.
 *
 * @author Andrei
 * @filesource application/controllers/UploadifyController.php
 * @version 1.0.0
 */

Class UploadifyController extends Zend_Controller_Action
{

	public function indexAction(){}

	public function uploadAction()
	{
		if (! empty ( $_FILES ))
		{
			$tempFile = $_FILES ['Filedata'] ['tmp_name'];
			$targetFile = APPLICATION_PATH . DS . 'uploads'
			. DS . $_FILES ['Filedata'] ['name'];

			move_uploaded_file ( $tempFile, $targetFile );
			echo "1";
		}
		else
		{
			echo 'No files sent';
		}
	}
}
</pre>
<p>Create a folder in your APPLICATION_PATH named <strong>uploads</strong> and make it writable by PHP (ex: chmod 0777).</p>
<p><strong>What have we done so far?<br />
</strong>Now,  we basically have an application that displays a nice empty page with the uploadify script included, have all the JS code in external files and JS variables that contain dynamic data (aka PHP variables) in our main layout.</p>
<h2>The application views</h2>
<p>Make sure you have the folder <strong>uploadify</strong> in your /views/scripts/ folder and inside it the files<strong> index.phtml</strong> and <strong>upload.phtml</strong> .</p>
<p>Inside the <strong>index.phtml</strong> make sure you have the following line somewhere (where you want to have the uploadify generated) :</p>
<pre>< div id = "upload_container" >< /div >
</pre>
<p>Inside your <strong>layout.phtml</strong> make sure you have the following code (stripped so it can be displayed properly):</p>
<pre>< script
	type="text/javascript"
	src="< ?php
		echo $this->baseUrl('/js/swfobject.js');
		?>">
</script>
< script
	type="text/javascript"
	src="< ?php
		echo $this->baseUrl('/js/jquery.uploadify.v2.1.0.min.js');
		?>">
</script>
< script type="text/javascript">
	var uploadify_swf_file = '
		< ?php
			echo $this->baseUrl(
				'/uploadify_files/uploadify.swf'
			);
		?>
	';
	var upload_php_file    = '
		< ?php
			echo $this->url(
					array(
						'controller' => 'uploadify',
						'action' => 'upload'
					)
			);
		?>
	';
	var upload_folder      = '
		< ?php
			echo $this->baseUrl(
				'/uploads/'
			);
		?>';
	var upload_cancel_img  = '
		< ?php
			echo $this->baseUrl(
				'/uploadify_files/cancel.png'
			);
		?>';
< /script>
< script
	type="text/javascript"
	src="< ?php echo $this->baseUrl('/js/script.js'); ?>">
</script>
</pre>
<h2>Conclusion</h2>
<p>Now, everything should work. If you browse your application at <strong>example.com/uploadify/</strong> you should see the uploadify button here.</p>
<p><strong>If you have any problems implementing the tutorial, feel free to contact me via comments below and I&#8217;ll try to help you fix them.</strong></p>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 693px; width: 1px; height: 1px;">$(document).ready(function() {<br />
$(&#8216;#upload_container&#8217;).uploadify({<br />
&#8216;uploader&#8217; : uploadify_swf_file,<br />
&#8217;script&#8217;   :  upload_php_file,<br />
&#8216;folder&#8217;   : upload_folder,<br />
&#8216;cancelImg&#8217;: upload_cancel_img,<br />
&#8216;auto&#8217;     : true,<br />
&#8216;onError&#8217;: function (event, queueID ,fileObj, errorObj) {<br />
var msg;<br />
if (errorObj.status == 404) {<br />
alert(&#8216;Could not find upload script. Use a path relative to: &#8216;+&#8217;;');<br />
msg = &#8216;Could not find upload script.&#8217;;<br />
} else if (errorObj.type === &#8220;HTTP&#8221;)<br />
msg = errorObj.type+&#8221;: &#8220;+errorObj.status;<br />
else if (errorObj.type ===&#8221;File Size&#8221;)<br />
msg = fileObj.name+&#8217;<br />
;&#8217;+errorObj.type+&#8217; Limit: &#8216;+Math.round(errorObj.sizeLimit/1024)+&#8217;KB&#8217;;<br />
else<br />
msg = errorObj.type+&#8221;: &#8220;+errorObj.text;<br />
alert(msg);<br />
$(&#8220;#fileUpload&#8221; + queueID).fadeOut(250, function() { $(&#8220;#fileUpload&#8221; + queueID).remove()});<br />
return false;<br />
},</p>
<p>});<br />
});</p>
</div>
 <img src="http://phpdev.ro/wp-content/plugins/feed-statistics.php?view=1&post_id=595" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://phpdev.ro/how-to-integrate-uploadify-in-zend-framework-1-9-6.html/feed</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
		<item>
		<title>Sending complex unknown object types via WebServices in NuSoap</title>
		<link>http://phpdev.ro/sending-complex-unknown-object-types-via-webservices-in-nusoap.html</link>
		<comments>http://phpdev.ro/sending-complex-unknown-object-types-via-webservices-in-nusoap.html#comments</comments>
		<pubDate>Sat, 19 Sep 2009 22:01:48 +0000</pubDate>
		<dc:creator>Andrei Gabreanu</dc:creator>
				<category><![CDATA[PHP Tutorials]]></category>
		<category><![CDATA[Advices]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[Develop]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[Web services]]></category>

		<guid isPermaLink="false">http://blog.uauzilla.ro/?p=308</guid>
		<description><![CDATA[A small tutorial about sending PHP Objects via S.O.A.P. WebServices. The Objects are of an uknown type and must be constructed dinamycally.]]></description>
			<content:encoded><![CDATA[<p>In the past, i have wrote an article about using the <a title="Soap Web Services in CakePHP" href="http://blog.uauzilla.ro/soap-webservices-in-cakephp.html" target="_self"><strong>NuSoap library to create a server and a client</strong></a> that accepts requests and sends responses via SOAP Web Services.  There are alternatives to <a title="NuSOAP - SOAP Toolkit for PHP" href="http://sourceforge.net/projects/nusoap/" target="_blank"><strong>NuSoap</strong></a> when it comes to making SOAP requests but this library is the most common one. However, the documentation for it is very poor and a php beginner might have problems in understanding and going through it.  Even if you are a php beginner or an advanced programmer (not necessarily php!), after you&#8217;ve read this article, you might find out some useful things that you may include in your future project. The thesis of this article is to make a NuSoap client that makes a request to a SOAP server, knowing only the parameters to send, the method to use and the WSDL url, <strong>without knowing what the method, WSDL url or parameters values are</strong>.<span id="more-308"></span></p>
<h2>1. Creating a basic NuSoap client</h2>
<p>First of all, lets create our workspace.</p>
<p>Create a folder named NuSoap_Sample. Inside of it put your copy of nusoap.php (<a title="Download NuSoap Library from SourceForge" href="http://sourceforge.net/projects/nusoap/files/nusoap/0.7.3/nusoap-0.7.3.zip/download" target="_blank">download link here</a>)</p>
<p>Create a file in your favorite PHP editor named <strong>myClient.php</strong> inside the &#8220;NuSoap_Sample&#8221; folder . Add the following lines inside of it:</p>
<pre>&lt;?php

class SampleObject {

public $name = '';

}

require_once('nusoap.php');
$wsdl = 'My Sample WSDL';
$client = new nusoap_client($wsdl , true);
$proxy   = $client-&gt;getProxy();

$obj = new SampleObject;
$obj-&gt;name = 'Andrew';

$result = $proxy-&gt;whatIsMyName($obj);
echo "&lt;pre&gt;";
print_r($result);
echo "&lt;/pre&gt;";

?&gt;</pre>
<p>Ok so lets talk about what this script does:</p>
<ol>
<li>We include the nusoap library</li>
<li>We assign the WSDL URL to the variable $wsdl (you need to get this from your service provider. <a title="Weather.gov - Forecasts WSDL file" href="http://www.weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl" target="_blank">An example is here</a>)</li>
<li>We make a new NuSoap client with the $wsdl file from above.</li>
<li>In order for our script to work on all environments, we force it to use a proxy via the <strong>getProxy</strong> method.</li>
<li>We want to send an object via the Web Service so we create a new object of our SampleObject and set our name to the $name attribute of this object.</li>
<li>Lastly, we make the request and print our the result (in a pretty string) </li>
<p><br/></p>
<p>This is very nice but&#8230;Lets see the downside of this example: If we want to send a complex object via the Web Service, we need to provide each parent attribute with a child class and create an object of each one. This will lead to a lot of files and a lot of code to be written.  Furthermore, we need these classes defined which again puts us in trouble if we don&#8217;t know these and thus we cannot code them.</p>
<p>Can there be no other way to resolve this?!</p>
<h2>2. Getting our hands dirty</h2>
<p><img class="alignleft size-thumbnail wp-image-277" style="margin: 10px; float: left;" title="Writing PHP code for SOAP" src="http://blog.uauzilla.ro/wp-content/uploads/php.png" alt="pattern" width="200" height="150" /></p>
<p>Let&#8217;s imagine a hypothetical case where we want to make a service that sends SOAP requests via a request from a user. Lets focus on this and explain in more detail what we want to achieve:  We want <strong>ANY</strong> user to be able to make requests without us caring about what the content is or where the user wants to send his request.</p>
<p>This being said, the above example would obviously fail since we won&#8217;t know what classes to define or what objects to create. Also, we won&#8217;t know what attributes to assign to each class/object. We might as well ask each client to wait 24 hours and start adding their classes in a file and then when they want to modify, they need to contact us via mail or phone and we can change their class files. Or wait&#8230;</p>
<p>Lets assume we present the user a form where they can input the WSDL address and method to use in the Web Service, and allow them to add any number of fields for the request. So we would have something like this:</p>
<pre>$wsdl = 'user_inputed_WSDL';
$method = 'user_inputed_METHOD';
$params  = array('field1 =&gt; 'value1', 'field2' =&gt; 'value2');</pre>
<p>We would now need to make a new object of the $method string. We would need to have a class named as $method says so, and that class to have attributes as $params says. Furthermore, if the service provider wants us to send complex data, and we need to encode the field1 and field2 into a &lt;paramaters&gt; tag then we are really in a bad situation.</p>
<p>But what happens if we do the following?</p>
<p>(to fulfill both of the cases explained above, we will assume we have a $encode variable with the value set by the user (example &#8216;&lt;parameters&gt;&#8217; and we want our  parameters to be wrapped in this variable) :</p>
<pre>&lt;?php

$wsdl = 'user_inputed_WSDL';
$method = 'user_inputed_METHOD';
$params = array('field1 =&gt; 'value1', 'field2' =&gt; 'value2');
$encode = '&lt;parameters&gt;';

require_once('nusoap.php');
$client = new nusoap_client($wsdl , true);
$proxy   = $client-&gt;getProxy();

$params = !empty($encode) ? array( $encode =&gt; $params); : $params;

$obj = (object) $params;

$result = $proxy-&gt;$method($obj);
echo "&lt;pre&gt;";
print_r($result);
echo "&lt;/pre&gt;";

?&gt;</pre>
<p>Wow! It sent our request exactly how we want it! Field1 and field2 were encoded in a &lt;parameters&gt; tag and the script did not fail since we did not create a new object.</p>
<p>Let me explain what we did here:</p>
<p>1. We setup our known parameters (the WSDL url, the method to use, the parameters to send and the encode tag to use.<br />
2. We make a new NuSoap client based on the WSDL provided<br />
3. We setup or parameters to become a nested array where the primary key is the encoded tag and its value are the fields we want to send (if we have an encode parameter)<br />
4. We fake create an object based on the resulting $params array.<br />
5. We make the request via the method provided sending our fake object to the service provider.</p>
<h2>3. Conclusion</h2>
<p><img class="alignleft size-thumbnail wp-image-277" style="margin: 10px; float: left;" title="Making the wheels spin. Putting it all together." src="http://blog.uauzilla.ro/wp-content/uploads/web-services.png" alt="pattern" width="150" height="150" /></p>
<p>Although the service providers usually expect an object to be sent via their Web Services, remember that <strong>the</strong> <strong>definition of Web Service tells us that the server needs not to care about the programming language the requests are coming from and needs to respond in the same manner (thus the hard to understand XML RPC system).</strong> What does this mean? It means that, if we send a request that contains an object then the whole system will work. It DOESN&#8217;T matter how we accomplish this as long as the request is good. If we want to send arrays or pure objects, its on our side to care not on the Web Service server side.<br />
So from writing TONS of complex code just to make an ordinary request to a web service provider, you can now just use this method in an easier way  (arrays are the good thing our programming heaven gave us) and much easier to debug.</p>
<p>Now go and test it yourself and try to variate your tests in order to fully understand the system.</p>
 <img src="http://phpdev.ro/wp-content/plugins/feed-statistics.php?view=1&post_id=308" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://phpdev.ro/sending-complex-unknown-object-types-via-webservices-in-nusoap.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
