This is meant to be a short, easy-to-follow tutorial to help you get started with Zend Framework 2.0 and add perhaps one of the most common modules, ZfcUser. By the end of this tutorial, you’ll have a simple ZF2 application with user registration and authentication capabilities.
Prerequisites
I’m going to assume you have the following installed:
- PHP 5.3.3+ (with pdo-sqlite or pdo-mysql)
- A web server and knowledge of how to set up a virtual host
- Git
If you have PHP 5.4+ you don’t even technically need a web server to try out ZF2, as you can simply use PHP’s new built-in development web server.
A note about composer
While composer is a supported way of setting up the skeleton, I am choosing to simply use git for the sake of this tutorial. In my opinion, this keeps things simpler, and easier to debug if anyone has issues following my tutorial.
Step 1: Getting the skeleton
The first step is to clone the skeleton application:
Next, set up a vhost pointing to the public directory of the newly cloned skeleton. You should at this point be able to go to http://yourvhost/ in your browser and see the skeleton app:

If you are using PHP 5.4 and would like to use the built-in development web server instead, simply open a new terminal, cd into the public directory, and run:
With that running, you should be able to go to http://localhost:8000/ and see the skeleton application welcome page.
Step 2: Setting up a database connection
For ZfcUser, we’ll need a database to store users. For this tutorial, I’ll cover MySQL and SQLite, though ZfcUser and Zend\Db support many other RDBMs.
Create a new file, ./config/autoload/database.local.php and put the following in it:
For MySQL:
<?php return array( 'service_manager' => array( 'factories' => array( 'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory', ), ), 'db' => array( 'driver' => 'pdo', 'dsn' => 'mysql:dbname=CHANGEME;host=localhost', 'username' => 'CHANGEME', 'password' => 'CHANGEME', ), );
Or for SQLite:
<?php return array( 'service_manager' => array( 'factories' => array( 'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory', ), ), 'db' => array( 'driver' => 'pdo', 'dsn' => 'sqlite:' . getcwd() . '/data/users.db', ) );
(For more information, see my post on sharing a database connection across modules in Zend Framework 2.)
Step 3: Installing ZfcUser
Next, we’re going to install ZfcUser. First cd into the vendor directory, then run the following:
[user@workstation vendor]$ git clone https://github.com/ZF-Commons/ZfcBase.git
Note: ZfcBase is simply a dependency of ZfcUser — it contains some common classes which are useful for many modules.
Now enable the modules by editing ./config/application.config.php and adding them to the modules array:
<?php return array( 'modules' => array( 'Application', 'ZfcBase', 'ZfcUser', ), 'module_listener_options' => array( 'config_glob_paths' => array( 'config/autoload/{,*.}{global,local}.php', ), 'module_paths' => array( './module', './vendor', ), ), );
Now we need to import the ZfcUser db schema. If you’re using SQLite, this is a simple one-line command you run from the root of the project:
(If anyone knows how to do that in Windows, let me know in the comments!)
If you’re using MySQL, import the ./vendor/ZfcUser/data/schema.sql file into the DB you configured earlier.
That should be it! Try going to http://youvhost/user and you should be greeted with a login screen:

You now have a basic ZF2 application with simple user registration and authentication capabilities!
Resources
- ZfcUser Wiki
- ZF-Commons ZfcUser RFC
- ZfcUser Concepts and Goals – This is a little out of date, but still useful, none-the-less.
Check out some of the awesome ZfcUser extension modules already available:
- BjyAuthorize – Adds ACL support for ZfcUser using Zend\Acl.
- CdliTwoStageSignup – Adds an e-mail address verification step to the signup process.
- CdliUserProfile – An extensible user profile system.
- CdliAutogenUsername – Allows for auto-generated usernames upon registration.
- ScnSocialAuth – Adds social network authentication to ZfcUser for sites like Google, Facebook, Twitter, Yahoo!, etc.
- EdpGithub – Adds Github authentication to ZfcUser. (ScnSocialAuth will eventually support Github and this will simply remain a Github API integration module).
If you’re asking yourself “what’s next?”, take a few minutes to check out Rob Allen’s excellent ZF2 tutorial and/or come chat with us in #zftalk.2 on Freenode if you have any questions.
Update: Rafael Jaques has kindly translated this post to Portuguese.

Is this tutorial working with ZF2 beta5? I actually have beta 5, and I get the following error message: PHP Fatal error: Class ZfcUser\Module contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Zend\ModuleManager\Feature\ServiceProviderInterface::getServiceConfiguration) in C:\ZZZ\vendor\ZfcUser\src\ZfcUser\Module.php on line 130. Thanks
I can confirm this tutorial has been working since around beta5. It’s possible that you cloned ZF2 and/or ZfcUser at a bad time and there just happened to be a bug. Such is life with beta software!
Edit: Sorry for the delay, I’m still getting used to responding to blog comments!
hi when tried to put this zfcuser module in application using composer my doctrine module gets removed and when installing doctrine zfcuser get removed how can i solve this how can i use both of this please help
thank you
Hi , I modified user_entity_class with my own User class but this one have many other fields that default class haven’t. So how can i manage that? Do i have to install CdliUserProfile? (i see this module have a ‘field_settings’ param)
David
Your user entity must implement \ZfcUser\Entity\UserInterface and in your config/autoload/zfcuser.global.php define the user_entity_class to be your own entity rather than the default one.
Hello,
(If anyone knows how to do that in Windows, let me know in the comments!) To run linux style commands on windows, simply install cygwin (cygwin.com)
Hardie
Thanks Hardie. I was going to recommend cygwin, but wasn’t sure if it came with a version of SQLite that would work out of the box without further instruction. Now that I’m thinking about it, you may simply be able to run
type vendor/ZfcUser/data/schema.sqlite.sql | sqlite3 data/users.db, assuming you have SQLite installed on Windows.I would actually suggest just using the version of bash that is installed when you install git on a windows machine. Then I would put the client you get from http://www.sqlite.org/sqlite-shell-win32-x86-3071500.zip in your path somewhere (git’s bin folder works nicely), then just run your command.
I’ve found that git’s bash can be handy for all kinds of stuff like this… if you want just that little bit of unix flavor in your windows install without the full on invasion from cygwin.
how to control acces to my app.
redirect to registration form (using ZfcUser module ) from other modules if user is not loged
Thank you
Just for the sake of reference, this is answered here.
can you please help me to understand the class , objects map of zfcuser module.
Can’t get it to work correctly http://myhost/user gives me 404 “The requested URL could not be matched by routing.” error.
i’ve double-checked my application.config.php and all is ok there, even tried to override default routing settings from /user to /member and still nothing.
Hi, Nice post Am having the same probs as vt. thanks
Make sure that you have AllowOverride All in your VirtualHost to enable .htaccess file for Rewrite rules.
Hi,
My goal is to authenticate the user against LDAP first and then against Db if LDAP fails. So I wrote a LDAP auth adapter and “registered” it in the AdapterChain via my own AdapterChainServiceFactory like this :
class AdapterChainServiceFactory implements FactoryInterface { public function createService(ServiceLocatorInterface $serviceLocator) { $chain = new AdapterChain; $ldapAdapter = $serviceLocator->get('UnicaenUser\Authentication\Adapter\Ldap'); $dbAdapter = $serviceLocator->get('ZfcUser\Authentication\Adapter\Db'); $chain->getEventManager()->attach('authenticate', array($ldapAdapter, 'authenticate'), 2); $chain->getEventManager()->attach('authenticate', array($dbAdapter, 'authenticate'), 1); return $chain; } }Looking at ZfcUser code, I see that my LDAP auth adapter can return a Response instance in order to “return early” from the controller auth process. Here is an excerpt of the “authenticate” method in my LDAP auth adapter doing this :
public function authenticate(AuthEvent $e) { ... // Success! $userObject = new \UnicaenUser\Model\Ldap\PeopleAdapter($userObject); $e->setIdentity($userObject); $this->setSatisfied(true); $storage = $this->getStorage()->read(); $storage['identity'] = $e->getIdentity(); $this->getStorage()->write($storage); $e->setCode(AuthenticationResult::SUCCESS) ->setMessages(array('Authentication successful.')); // return HTTP response /* @var $cpm \Zend\Mvc\Controller\PluginManager */ $cpm = $this->getServiceManager()->get('controllerpluginmanager'); /* @var $f \Zend\Mvc\Controller\Plugin\Redirect */ $f = $cpm->get('redirect'); $response = $f->toRoute('home'); return $response; }Unfortunately, it seems to me that the user controller “authenticateAction” method returns too early after receiving the Response from the adapter : it should call
$auth = $this->zfcUserAuthentication()->getAuthService()->authenticate($adapter);immediately after$result = $adapter->prepareForAuthentication($request);in order to populate auth service storage with authenticated user identity. If not, authenticated user identity provided by an other auth adapter (like my LDAP one) won’t be persisted by auth service and ZfcUser view helpers won’t be able to retrieve it (for example).Am i wrong ?
Thank you. Regards. Bertrand
Hello,
This is great!, really work in mine. I’m just new user of zf2 and I have some questions. How can I make the login as a default view? is there a way to make it? please guide.
Thanks, Eugene
In
\module\Application\config\module.config.phpChange'controller' => 'Application\Controller\Index',to'controller' => 'zfcuser',Hi, i was trying to set up zfcUser with Doctrine 2 ORM but i was unsuccessful. There isn’t any tut on zfcUser git. Can You give my some advice on this topic? Thanks:)
Hi Evan,
thank you at first for your tutorial. I followed it with much excitement!
Anyhow, i am encountering a problem with the database connection. 1) I can’t register a new user via the website because this gives me the error:
File: /opt/ZendFramework-2.0.2/library/Zend/Db/Adapter/Driver/Pdo/Statement.php:220 Message: Statement could not be executed
Stack:
0 /var/www/zf2-tutorial/vendor/ZfcBase/src/ZfcBase/Mapper/AbstractDbMapper.php(141): Zend\Db\Adapter\Driver\Pdo\Statement->execute()
1 /var/www/zf2-tutorial/vendor/ZfcUser/src/ZfcUser/Mapper/User.php(48): ZfcBase\Mapper\AbstractDbMapper->insert(Object(ZfcUser\Entity\User), NULL, NULL)
2 /var/www/zf2-tutorial/vendor/ZfcUser/src/ZfcUser/Service/User.php(86): ZfcUser\Mapper\User->insert(Object(ZfcUser\Entity\User))
3 /var/www/zf2-tutorial/vendor/ZfcUser/src/ZfcUser/Controller/UserController.php(182): ZfcUser\Service\User->register(Array)
4 /opt/ZendFramework-2.0.2/library/Zend/Mvc/Controller/AbstractActionController.php(87): ZfcUser\Controller\UserController->registerAction()
Somehow it tries to insert the Object(ZfcUser\Entity\User, NULL, NULL into the database. Are those two NULL parameters what they should be like? The AbstractDbMapper requires it like this though. Can you give a short explanation to this?
greetings, Robert
What database are you using? I had some problems with postgres not accepting null to insert into auto_increment key. I had to change the extract method in the UserHydrator, not to set the ID = null value:
public function extract($object) { if (!$object instanceof UserEntityInterface) { throw new Exception\InvalidArgumentException('$object must be an instance of ZfcUser\Entity\UserInterface'); } /* @var $object UserInterface*/ $data = parent::extract($object); unset($data['id']); //<===add this line //$data = $this->mapField('id', 'user_id', $data); //<===comment or remove this line return $data; }Evan,
Is there an easy way to change the table names so they work better with my own naming conventions?
Thx
Hi,
Trying to do the same myself, so if the is an easy and preferred way to do this, i would like to know the answer too
Hi Evan,
is there any possibility to clear all Sessions before a new login attempt? I am storing several informations in a Session and I want that each user starts with a clean session after login. I did not find a possibility to hook into the login process e.g. using an event
Works great! Tested on 14.12.2012
hi when tied to put this zfcuser module in application using composer my doctrine module gets removed and when installing doctrine zfcuser get removed how can i solve this how can i use both of this please help i am in desperate need
thank you
hi when tried to put this zfcuser module in application using composer my doctrine module gets removed and when installing doctrine zfcuser get removed how can i solve this how can i use both of this please help i am in desperate need
thank you
Hi Evan,
i tries to understand for what cases this code are intend:
namespace ZfcUser\Authentication\Adapter; ... class Db extends AbstractAdapter implements ServiceManagerAwareInterface { ... public function authenticate(AuthEvent $e) { if ($this->isSatisfied()) { $storage = $this->getStorage()->read(); $e->setIdentity($storage['identity']) ->setCode(AuthenticationResult::SUCCESS) ->setMessages(array('Authentication successful.')); return; } ...
thank you
Thanks for the example Evan! Is there any convenient way to override the password encryption? I have an existing DB table with MD5′ed passwords that my new Zend app needs to refer to.
Thanks again!
Hi, all is going perfectly here and ofcourse every one is sharing facts, that’s really fine, keep up writing.
hi friend I need your help I going your tutorial but I have an error it says,
Fatal error: Class ‘ZfcBase\EventManager\EventProvider’ not found in H:\www\local.zend.com\vendor\ZfcUser\src\ZfcUser\Authentication\Adapter\AdapterChain.php on line 12
why if I am sure copy of your code correctly please help me thankyou, I hope your answers, sorry for my english
Hi guys,
I need help, zfcuser run correctly, but now, I want to verify if an email exists into my database. Is it posible with ZfcUser? How? I don’t want to request directly my db into controller.
Thanks !!
Bad english, I know.
Question! How do you accomplish this:
If you’re using MySQL, import the ./vendor/ZfcUser/data/schema.sql file into the DB you configured earlier.
Thanks!
My spouse and I stumbled over here by a different website and thought I may as well check things out.
I like what I see so now i’m following you. Look forward to checking out your web page for a second time.
It is working fine and perfect me
Hi… I am new to Zend Framework 2. I have followed the above steps but I am getting the following error…..
Not Found The requested URL /user/public/index.php was not found on this server.