Zend Server 5.6 is out

Kevin Schroeder writes; Zend Server 5.6 is out.  I’m actually pretty stoked about this release.  Here’s a few reasons why.

  1. Zend Server CE now contains the full Zend Server stack.  Why do I find this exciting?  Because the upgrade path from CE to the full version is stupid easy.  That means you can try out all of the features in Zend Server and if you don’t want them, just let the license expire.  I call it a gateway drug.  Seriously.  Get Studio or PDT and try the deployment feature.  If you’re not using it you’ll ask yourself “why am I not doing this?”
  2. All of you Mac users can finally stop bitching and complaining about the lack of Mac support.  We don’t (and probably won’t) support Mac for production (does anyone besides Apple actually use their server products in production?) but for dev work you now get the full stack on your Mac.  This is not GA yet but will be later on.  If you want a preview release you can go to http://forums.zend.com/viewtopic.php?f=8&t=26873 .
  3. Fault tolerance in the Job Queue through MySQL clustering.  In clustered environments job queue information has moved from local storage to remote MySQL storage.  So you can have a single MySQL server sitting there, a clustered setup or RDS or some other cloud-based DB, it doesn’t matter.  If it can be accessed using the MySQL drivers then it can be used by the new Job Queue.

via ESchrade – Pure PHP Goodness.

Zend AMF Authentication & Authorization

dkozar evolved a working method to Authenticate and Authorize a Flex based app datas service call using Zend AMF, he writes;

I’ve been struggling with it, and figured it all out – so, perhaps it could help others.

The authentication is called on the server only if credentials supplied from the client (via the remote procedure call headers). This snippet illustrates the setup of custom auth (these are the last 6 lines of gateway.php script):

// Handle request
$auth = new My_Amf_Auth(); // authentication
$server->setAuth($auth);
$acl = new Zend_Acl(); // authorization
$server->setAcl($acl);
echo $server->handle();

Now, your custom auth should extend Zend_Amf_Auth_Abstract. Since I want to authenticate users from a database, I bring the Zend_Auth_Adapter_DbTable to play. But since I cannot extend both Zend_Amf_Auth_Abstract and Zend_Auth_Adapter_DbTable, I use a composition:

< ?php require_once ('Zend/Amf/Auth/Abstract.php'); /** * AMF auth class by Danko Kozar, dankokozar.com * @author dkozar * */ class My_Amf_Auth extends Zend_Amf_Auth_Abstract { function __construct() { } public function authenticate() { $adapter = My_Db_Adapter::getInstance(); $adapter->setIdentity($this->_username);
$adapter->setCredential($this->_password);

// the adapter call
// you can wrap it into try.. catch and process DB connection errors
$result = Zend_Auth::getInstance()->authenticate($adapter);

return $result;
}
}

Here’s the adapter class:

< ?php /** * DB table adapter auth class for AMF by Danko Kozar, dankokozar.com * @author dkozar * Singleton */ class My_Db_Adapter extends Zend_Auth_Adapter_DbTable { protected static $_instance = null; /** * private! * @param My_Db_Adapter $adapter */ public function __construct(Zend_Db_Adapter_Abstract $adapter = null) { if (!$adapter) $adapter = new Zend_Db_Adapter_Mysqli( array( 'dbname' => 'test',
'username' => 'root',
'password' => '')
);

parent::__construct($adapter);

$this
->setTableName('users')
->setIdentityColumn('username')
->setCredentialColumn('password')
;

// just for testing
// $this
// ->setIdentity('username')
// ->setCredential('password')
// ;
}

/**
* @return My_Db_Adapter
*/
public static function getInstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}

public function authenticate() {

$_authResult = parent::authenticate();

// NOTE: The point is that $result->_identity is an OBJECT (of type stdClass), NOT string
// with Zend_Auth_Adapter_DbTable it is internally accomplished by calling its getResultRowObject() method
// It constructs the stdClass with properties named after table attributes

// $user = new stdClass();
// $user->role = "administrator";
// $user->username = $_authResult->getIdentity();

$identity = $this->getResultRowObject();

$result = new Zend_Auth_Result($_authResult->getCode(), $identity);

return $result;
}
}

MyService.php class. Here it is:


< ?php /** * PHP service class with authorization * by Danko Kozar, dankokozar.com * @author dkozar * */ class MyService { /** * from zend docs: * If the ACL object is set, and the class being called defines initAcl() method, * this method will be called with the ACL object as an argument. * This method can create additional ACL rules and return TRUE, * or return FALSE if no access control is required for this class. * * @param Zend_Acl $acl * @return boolean */ public function initAcl($acl) { $acl->addRole(new Zend_Acl_Role("administrator"));
$acl->addRole(new Zend_Acl_Role("user"));

//acl "allow" method takes 3 parameters (role, resource - class name, privileges - it's function name in this class)

// administrator
$acl->allow('administrator', 'MyService', 'helloWorld');
$acl->allow('administrator', 'MyService', 'getData');

// user
$acl->allow('user', 'MyService', 'helloWorld');
$acl->deny('user', 'MyService', 'getData');

//returning true to signal that we want to check privileges before accessing methods of this class
//in my tests if we don't return anything it will treat it like we will return false so better return true or false
//your intentions will be clear
return true;
}

/**
* Hello world method
*/
public function helloWorld(){
return "Hello world from MyService service";
}

/**
*
* Returns data
* @return [int]
*/
function getData()
{
$arr = array(1, 2, 3);
return $arr;
}
}
?>

Note that the authorization is being built dynamically inside the initAcl method.

On the Flex side I have an auto-generated class (MyService) which extends another auto-generated class (_Super_MyService).

The point is that the outer one is auto-generated only once (initially), and you can modify it, without worrying to be overwritten on service regeneration.

There’s a protected property _serviceControl (which is of type RemoteObject) which could be tweaked if needed.

I’m tweaking it by of setting the endpoint (with string read from a client side config in preInitializeService() method). Plus, I’m adding 2 more methods, which expose setCredentials and setRemoteCredentials methods of _serviceControl, so I can acces it from my code.


package services.myservice
{
public class MyService extends _Super_MyService
{
/**
* Override super.init() to provide any initialization customization if needed.
*/
protected override function preInitializeService():void
{
super.preInitializeService();

// Initialization customization goes here
_serviceControl.endpoint = "http://localhost/myapp/gateway.php";
}

public function setCredentials(username:String, password:String, charset:String=null):void
{
_serviceControl.setCredentials(username, password, charset);
}

public function setRemoteCredentials(username:String, password:String, charset:String=null):void
{
_serviceControl.setRemoteCredentials(username, password, charset);
}
}
}


So, before calling MyService methods, I’m setting the credentials with setCredentials() method and this runs the authentication on the PHP side:


private var service:MyService;
....
service = new MyService(); // ServiceLocator.getInstance().getHTTPService("presetLoader");
service.setCredentials("user1", "pass1");
var token:AsyncToken = service.getData();

The authentication via Zend_Amf_Server is, by the way, OPTIONAL! Meaning, with no credentials supplied, Zend_Amf_Server will NOT RUN IT. Thus you should rely on Zend_Acl (e.g. roles) to so your permissions and security!

Finally, here’s the MySQL DB table I’ve been using for authentication:

--
-- Table structure for table `users`
--
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(32) DEFAULT NULL,
`role` varchar(45) DEFAULT NULL,
`firstname` varchar(50) DEFAULT NULL,
`lastname` varchar(50) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;

--
-- Dumping data for table `users`
--
INSERT INTO `users` (`id`, `username`, `password`, `role`, `firstname`, `lastname`, `email`) VALUES
(1, 'user1', 'pass1', 'administrator', 'Danko', 'Kozar', NULL);

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Cheers!
Danko

Adobe Forums

Flex Builder 4.5.x Test Drive for Mobile Tutorials

Here is a very good multi-part tutorial on the ins and outs of mobile client / server development, that adds some quite useful functionality on Android, Apple IOS and Blackberry mobile devices.

In this Test Drive, you are going to create a Flex mobile application that retrieves, displays, and modifies database records (see Figure 1). A Flex application does not connect directly to a remote database. Instead, you connect it to a data service written in your favorite web language (PHP, ColdFusion, Java, or any other server-side technology). You will build the front-end Flex mobile application; the database and the server-side code to manipulate database records is provided for you as a PHP class, a ColdFusion component, or Java classes.

The Mobile Test Drive application running on a mobile device.

Figure 1. The Mobile Test Drive application running on a mobile device.

via Adobe Developer Connection.

You want to do WHAT with PHP? Chapter 10

With the book out and released I now reach the final chapter excerpt that I will have. As I said in one of my previous chapter excerpts, I did not write this book to cover a wide range of topics. I wrote it to cover a narrow range of topics, more fully. But the topics I chose were based off of my experiences as a Zend Consultant for several years. If you are someone with 2-5 years of experience (the typical requirement for a PHP job) you need this book. This book was born out of my experience dealing with code written by people with 2-5 years of experience, sometimes more.

This chapter is called “Preparing for success, preparing for failure”. It contains a few pseudo-rules that can go a long way to helping you manage unexpected popularity of your website. In other words, to help you in minimizing the effects of 2-5 years of programming experience. 🙂 Those rules are not complete and there are plenty of exceptions, but knowing these things will help you be more prepared for handling things like load and failure.

via You want to do WHAT with PHP? Chapter 10.

Bootstrapping Zend_Translate with a LangSelector Plugin

This entry is part [part not set] of 4 in the series Working with Zend_Translate and Poedit

As an update to the method of having everything related to Zend_Translate and Zend_Locale in the Bootstrap, here is an alternative using an Controller Plugin that does the grunt work of validating, selecting and updating the Zend_Locale, Zend_Registry & Zend_Session using Zend_Session_Namespace. And we are using poedit .po & .mo files as the source as usual.

Please comment as usual if you have a neater way of doing it 🙂

Bootstrap.php

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {

protected function _initTranslate()
{
// Get current registry
$registry = Zend_Registry::getInstance();
/**
* Set application wide source Locale
* This is usually your source string language;
* i.e. $this->translate('Hi I am an English String');
*/
$locale = new Zend_Locale('en_US');

/**
* Set up and load the translations (all of them!)
* resources.translate.options.disableNotices = true
* resources.translate.options.logUntranslated = true
*/
$translate = new Zend_Translate('gettext',
APPLICATION_PATH . DIRECTORY_SEPARATOR .'languages', 'auto',
array(
'disableNotices' => true, // This is a very good idea!
'logUntranslated' => false, // Change this if you debug
)
);
/**
* Both of these registry keys are magical and makes
* ZF 1.7+ do automagical things.
*/
$registry->set('Zend_Locale', $locale);
$registry->set('Zend_Translate', $translate);
return $registry;
}
}

This little plugin will check every request for a lang paramenter and act on it.
It does not matter if you set the lang parameter using a custom route :lang/:controller/:action
or via a get/post ?lang= etc. one or all of them will work.

library/App/Controller/Plugin/LangSelector.php


* @name App_Controller_Plugin_LangSelector
* @filesource library/App/Controller/Plugin/LangSelector.php
* @tutorial Instantiate in application.ini with;
* resources.frontController.plugins.LangSelector =
* "App_Controller_Plugin_LangSelector"
* @desc Takes the lang parameneter when set either via a
* route or get/post and switches Locale, This depends
* on the main initTranslate function in Bootstrap.php
* to set the initial Zend_Translate object.
* Inspiration from ZendCasts LangSelector.
*/
class App_Controller_Plugin_LangSelector extends Zend_Controller_Plugin_Abstract
{
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$registry = Zend_Registry::getInstance();
// Get our translate object from registry.
$translate = $registry->get('Zend_Translate');
$currLocale = $translate->getLocale();
// Create Session block and save the locale
$session = new Zend_Session_Namespace('session');

$lang = $request->getParam('lang','');
// Register all your "approved" locales below.
switch($lang) {
case "sv":
$langLocale = 'sv_SE'; break;
case "fr":
$langLocale = 'fr_FR'; break;
case "en":
$langLocale = 'en_US'; break;
default:
/**
* Get a previously set locale from session or set
* the current application wide locale (set in
* Bootstrap)if not.
*/
$langLocale = isset($session->lang) ? $session->lang : $currLocale;
}

$newLocale = new Zend_Locale();
$newLocale->setLocale($langLocale);
$registry->set('Zend_Locale', $newLocale);

$translate->setLocale($langLocale);
$session->lang = $langLocale;

// Save the modified translate back to registry
$registry->set('Zend_Translate', $translate);
}
}

Big thanks to Zend Cast for the inspiration!