Build a better Login with Adobe Flex, Zend_Amf, Zend_Auth, and Zend_Acl – On The PHP Side
This is the server setup procedures for my tutorial Build a better Login with Flex, Zend_Amf, Zend_Auth, and Zend_Acl - On The Flex Side. Consult the first part of this tutorial for project requirements.
We previously created a folder under the MAMP installation called frameworks to serve as the home for the Zend library. Now we need to create a new folder to be the home for our applications server code.
Create a folder in the MAMP/htdocs dir named AccessControlExample.
Create a new folder in AccessControlExample dir and name it phplib, phplib will be the home of our applications main files.
In our main AccessControlExample dir, create a new file called index.php, this is known as the bootstrap file, if you need further clarification about the bootstrap file or any of the Zend Framework, please consult the Zend Framework Reference Guide.
Replace the contents of index.php with the following
<?php
// Error Reporting
error_reporting(E_ALL|E_STRICT);// Turn to off when released to production
ini_set("display_errors","on");// Modify include_path to include the
Zend library and the utils dir
ini_set("include_path", ini_get("include_path")
.PATH_SEPARATOR."../../frameworks/".
PATH_SEPARATOR."../../utils/");// Zend Framework Includes
require_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();require_once 'Zend/Amf/Server.php';
require_once 'ConnectionHelper.php';
require_once 'phplib/LoginVO.php';
require_once 'phplib/LoginManager.php';$server = new Zend_Amf_Server();
$server->setClass('LoginManager');
$server->setClass("LoginVO");// Change this to true when released to production
$server->setProduction(false);//Mapping the ActionScript VO to the PHP VO
//you don't have to add the package name
$server->setClassMap("LoginVO","LoginVO");echo($server->handle());
Basically this file provides a path to the Zend framework and any custom libraries we build that our application will need to function. We also map our PHP value Objects with our Actionscript value Objects here as well. Transferring data as Objects is much more efficient than making multiple calls for every piece of data.
Create a new PHP class inside the MAMP/utils dir named ConnectionHelper.php with the following code
<?php
class ConnectionHelper
{
public function __construct() {$this->host='localhost';
$this->dbname='AccessControlExample';
$this->username ='root';
$this->password = 'root';}
}
Modify this file according to your particular needs.
Close ConnectionHelper.php.
Okay, we now need to create the 3 main php class files our application needs.
- LoginManager.php - this is the brains of the server side code. This is where we pass our users credentials to in order to authenticate and authorize the user to use our application. Remember Authenticate (Zend_Auth) and Authorize (Zend_Acl) are two different things.
- LoginVO.php - this is a value object, a very simple structure that describes our users login attributes.
- AccessPrivsVO.php - this is a value object, a very simple structure that describes our users role privileges.
Inside LoginManager.php paste the following,
<?php
require_once 'ConnectionHelper.php';
require_once 'LoginVO.php';
require_once 'AccessPrivsVO.php';
require_once 'Zend/Auth.php';
require_once 'Zend/Acl.php';/*
* LoginManager
*
* Verify's the users login credentials and
checks the users role against the ACL for access rights.
*
* @return Access Privileges
*/
class LoginManager {private $dbAdapter;
private $authAdapter;/**
* @return mixed
*/
public function __construct() {// Get a reference to the
singleton instance of Zend_Auth
$this->auth = Zend_Auth::getInstance();// Create database connection
try {
$conn = new ConnectionHelper();
$this->dbAdapter =
Zend_Db::factory('Mysqli',array('host' => $conn->host,
'dbname' => $conn->dbname,
'username' => $conn->username,
'password' => $conn->password));
}
catch ( Zend_Db_Exception $e){
return "Caught exception: " . get_class($e) .
"\n Message: " . $e->getMessage() . "\n";
}
}// test
/**
* @return void
*/
public function test() {
return "Success! Test Completed Normally";
}/**
*
* Authenticates the user
*
* @todo add routine to verify using SSO
*
* @return mixed
*
*/
public function verifyUser(LoginVO $user) {$userRole='';
// Configure the instance
with constructor parameters...
$authAdapter = new Zend_Auth_Adapter_DbTable(
$this->dbAdapter,
'admin',
'username',
'password');$usr=htmlspecialchars($user->username);
$pwd=htmlspecialchars($user->password);
if($usr == ''){
$authAdapter
->setIdentity('guest')
->setCredential('guest');
}else{
$authAdapter
->setIdentity($usr)
->setCredential($pwd);
}
$result = $authAdapter->authenticate();switch ($result->getCode()) {
case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND:
$userRole = "guest";
break;case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
$userRole = "guest";
return "FAILURE_CREDENTIAL_INVALID";
break;case Zend_Auth_Result::FAILURE:
$userRole = 'guest';
break;case Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS:
$userRole = 'guest';
break;case Zend_Auth_Result::FAILURE_UNCATEGORIZED:
$userRole = 'guest';
break;case Zend_Auth_Result::SUCCESS:
$this->sessionid=$this->getSessionID(); //revised 2/22/2009
// We need to return the authenticated
users role, this will be passed into the Zend_Acl
// getResultRowObject returns a stdClass
object so we need to dereference the role in this manner.
$r=$authAdapter->getResultRowObject(array('role'));
$userRole = $r->role;
break;default:
return "Internal Error! If this problem persist,
please contact your network administrator";
break;
}// Set up the ACL (Access Control List)
$acl = new Zend_Acl();
// Add groups to the Role registry using Zend_Acl_Role
// Guest does not inherit access controls.
// Order matters here, we go from the most
restricted to the least restricted
$acl->addRole(new Zend_Acl_Role('guest'));
$acl->addRole(new Zend_Acl_Role('manager'), 'guest');
$acl->addRole(new Zend_Acl_Role('admin'), 'manager');// Administrator does not inherit access controls,
All access is granted
$acl->addRole(new Zend_Acl_Role('Super'));// setup the resource privs
$acl->add(new Zend_Acl_Resource('viewPublicUI'));
$acl->add(new Zend_Acl_Resource('viewRestrictedUI'));
$acl->add(new Zend_Acl_Resource('viewLogs'));
$acl->add(new Zend_Acl_Resource('createManager'));// Guest may only view the public interface
$acl->allow('guest', null, 'viewPublicUI');// manager inherits viewPublicUI privilege from guest,
but also needs additional
// privileges
$acl->allow('manager', null, array('viewRestrictedUI'));// admin inherits viewRestrictedUI privilege from
// manager, but also needs additional privileges
$acl->allow('admin', null, array('createManager'));// Super inherits nothing, but is allowed all privileges
$acl->allow('Super');// userRoleVO to Privs Map
$userRolePrivs = new AccessPrivsVO();
$userRolePrivs->userRole = $userRole;
$userRolePrivs->viewPublicUI =
$acl->isAllowed($userRole, null, 'viewPublicUI') ?
"allowed" : "denied";
$userRolePrivs->viewRestrictedUI =
$acl->isAllowed($userRole, null, 'viewRestrictedUI') ?
"allowed" : "denied";
$userRolePrivs->createManager =
$acl->isAllowed($userRole, null, 'createManager') ?
"allowed" : "denied";
$userRolePrivs->viewLogs =
$acl->isAllowed($userRole, null, 'viewLogs') ?
"allowed" : "denied";return $userRolePrivs;
}
}
Inside LoginVO.php paste the following,
<?php
class LoginVO
{
//public $_explicitType = 'LoginVO';
public $userName='';
public $password='';
}
The variable $_explicitType is another way you could map the Actionscript VO to the PHP VO.
Inside AccessPrivsVO.php paste the following,
<?php
class AccessPrivsVO
{
public $userRole='';
public $viewPublicUI='';
public $createManager = '';
public $viewRestrictedUI = '';
public $viewLogs = '';}
You may have noticed I purposely left off the php closing tag ?>, this is to avoid troublesome errors caused by extra white space.
That's it. You now have a robust login system that can be modified to meet your needs using Flex, PHP, Zend_Auth and Zend_Acl. Enjoy!


March 21st, 2009 - 02:37
Hi Craig,
It’s been a little while since I’ve had time to test this login beauty out and I’ve struck an error I can’t seem to get around..
When running the app and upon successful login with any valid creds, I get the PHP error:
PHP Fatal error: Call to undefined method LoginManager::getSessionID()
This seems to be relating to the line you’ve highlighted red in the above post.
My code is:
case Zend_Auth_Result::SUCCESS:$this->sessionid = $this->getSessionID();
And running Zend v1.7.2
Any ideas?
cheers
March 22nd, 2009 - 18:49
Kevin,
Hmm, not quite sure. Here’s a few things to try,
I apologize if you’ve already already done this but without seeing your actual implementation this is off the top of my head.
1. Make sure that the getSessionID() function is actually implemented.
2. Did you intend on using sessionid as an instance variable, $this->sessionid instead as in my example a property of an object
$userRolePrivs->sessionID ? This shouldn’t matter unless for some reason the instance is not being instantiated.
3. You may want to upgrade the Zend library, the current version of the framework is 1.7.6.
March 24th, 2009 - 21:01
Aha.. I thought getSessionID() was part of the Zend core.
I used Wade’s article here to implement it and it now works:
http://wadearnold.com/blog/?p=182
cheers
June 6th, 2009 - 10:28
Thanks! This was extraordinarily helpful. If you’ve downloaded the new Flash Builder 4 Beta, time for someone to refresh this whole thing using the new built-in structures for data connectivity… sigh… one more thing to re-learn.
June 8th, 2009 - 22:41
Hi Terry,
I’m glad you found this useful. I just downloaded the new Flash Builder beta. And I’m trying to come up to speed on the new Zend Framework architecture so hopefully I can make some time to upgrade the tutorials soon.
Thank you
Keith
August 24th, 2009 - 23:31
great tips. I enjoyed reading this
November 2nd, 2009 - 15:12
Really nice article thanks a lot !!!
November 2nd, 2009 - 20:33
Thank you Niko, I hope it’s useful.
Keith
November 16th, 2009 - 01:46
Hello there Keith
Thanks a lot for the wonderful tutorial. This has got me going with Cairngorm.
I am getting an error though. When press the login button, I get the following fault string…
[RPC Fault faultString="Channel disconnected" faultCode="Client.Error.DeliveryInDoubt" faultDetail="Channel disconnected before an acknowledgement was received"]
I tried checking the php service and it works fine if I use a simple RemoteObject instead of the Cairngorm setup.
What could be going in this case? Can you guide me appropriately?
With Kind Regards
Vikram
November 16th, 2009 - 04:22
Hello there Keith
First up thanks a lot for creating such a helpful tutorial. This has got me started with Zend_AMF and Cairngorm.
However, I am problem in getting the application working. After all the setup of web server and flex, the flash file opens up. It displays the login screen, but when I press the login button, it displays the following error on console…
[User Login] – Error Connecting![FaultEvent fault=[RPC Fault faultString="Channel disconnected" faultCode="Client.Error.DeliveryInDoubt" faultDetail="Channel disconnected before an acknowledgement was received"] messageId=”ECD99F34-8252-31F4-73B8-FC0E86DCC2A4″ type=”fault” bubbles=false cancelable=true eventPhase=2]
Can you give some idea where I could be going wrong – did you experience such an error while developing?
With kind regards
Vikram
November 19th, 2009 - 11:42
Hi Vikram,
First thing to check would to be to make sure your ActionScript variables match the PHP variables exactly, case sensitive. More often than not for me this error indicates something in the PHP code doesn’t match.
Keith
March 5th, 2010 - 11:06
Here is my aproach: How to use Zend_Amf_Server class with it’s built-in authentication and authorization methods.
http://www.flexphperia.net/en/programming/php/client-authentication-and-authorization-in-zend-amf-server