Archive for category Zend Framework
Workshop Online de Zend Framework – School of Net: 31/07/2010
Posted by Thiago Colares in Eventos, Zend Framework on July 1, 2010
Controle de acesso com Zend_Acl
Posted by Thiago Colares in PHP, Zend Framework on May 5, 2010
A muito tempo não posto um bom “php” por aqui, então vamos lá… A algum tempo postei sobre Zend_Auth e fiquei devendo um post sobre Zend_Acl.
Problemas com controle de acesso viram soluções com Zend_Acl. A alguns meses precisei implementar o controle de acesso para um sistema com ZF e me encantei com a facilidade e praticidade do Acl. Primeiro, alguns conceitos básicos…
Roles: São os perfis definidos. Basicamente, quem tem ou não acesso.
Resources: São as funcionalidades a serem controladas.
Usarei como exemplo o código que implementei já citado anteriormente. Criamos uma tabela simples para as funcionalidades, uma para perfis e duas tabelas associativas: uma entre perfis e funcionalidades e outra entre usuários e funcionalidades. Para abreviar, vou mostrar somente a tabela de funcionalidades:
-
cd_funcionalidade NUMBER NOT NULL,
-
descricao VARCHAR2(150) NOT NULL,
-
funcionalidade VARCHAR2(200) NOT NULL,
-
PRIMARY KEY(cd_funcionalidade));
Nesta tabela de funcionalidades será cadastrado uma descrição e a url da funcionalidade (resource). Ex: /usuarios ou /administracao/perfil
Assim que o usuário se autentica no sistema, redireciono ele para um controller chamado “acesso” para montar o objeto Acl. Neste exemplo, o usuário pode ter as funcionalidades definidas pelo perfil ou definidas diretamente para ele. Da seguinte forma…
-
-
//Model da tabela associativa entre Usuário e Perfil
-
$objPerfilUsuario = new PerfilUsuario();
-
-
//Model da tabela de funcionalidades
-
$objFuncionalidade = new Funcionalidade();
-
-
//Dados da autenticação do usuário…
-
$nsAutenticacao = new Zend_Session_Namespace('autenticacao');
-
-
$idUser = $nsAutenticacao->id;
-
-
//Recuperando os dados do perfil do usuário
-
$arrPerfil = $objPerfilUsuario->getPerfilUsuario($idUser);
-
-
$nsAutenticacao->idPerfil = $arrPerfil['idPerfil'];
-
$nsAutenticacao->perfil = $arrPerfil['perfil'];
-
-
//Criando o objeto Acl
-
$acl = new Zend_Acl();
-
-
//Crio uma role com o nome do perfil do usuário
-
$acl->addRole(new Zend_Acl_Role($arrPerfil['perfil']));
-
-
//Funcionalidades definidas por perfil
-
-
//Recupero as funcionalidades definidas para o perfil…
-
$arrFuncionalidades = $objFuncionalidade->getFuncionalidadesAcl($arrPerfil['idPerfil']);
-
-
//Em um foreach, adiciono ao objeto Acl as funcionalidades (resources) e a permissão
-
foreach($arrFuncionalidades['allow'] as $array) {
-
$acl->add(new Zend_Acl_Resource($array));
-
$acl->allow($arrPerfil['perfil'],$array);
-
}
-
-
if(isset($arrFuncionalidades['deny'])){
-
foreach($arrFuncionalidades['deny'] as $array) {
-
$acl->add(new Zend_Acl_Resource($array));
-
$acl->deny($arrPerfil['perfil'],$array);
-
}
-
}
-
-
//Funcionalidades definidas por usuário
-
-
//Model da tabela associativa entre usuário e funcionalidade…
-
$objUserFunc = new UsuarioFuncionalidade();
-
-
//Recupero as funcionalidades definidas para o usuário
-
$arrFuncUser = $objUserFunc->getFuncionalidadesAcl($idUser);
-
-
//Como a role já está criada no objeto Acl, apenas adiciono as permissões…
-
foreach($arrFuncUser as $arr) {
-
$acl->allow($arrPerfil['perfil'],$arr);
-
}
-
-
//Crio um namespace para o objeto Acl
-
$ns = new Zend_Session_Namespace();
-
$ns->acl = $acl;
Obs: Nos métodos getFuncionalidadesAcl() das modelos utilizadas retorno um array com a seguinte estrutura: array(’idDaFuncionalidade’ => ‘Url da funcionalidade’). No caso da model Funcionalidades, existe uma particularidade: o array “deny”:
-
-
public function getFuncionalidadesAcl($idPerfil) {
-
-
$select = 'Seu sql';
-
-
$rs = $this->fetchAll($select)->toArray();
-
$arrFinal = array();
-
-
foreach($rs as $arrAllow) {
-
-
$arrFinal['allow'][$arrAllow['cd_funcionalidade']] = $arrAllow['TX_URL'];
-
-
}
-
-
unset($rs);
-
-
$rs = $this->fetchAll()->toArray();
-
-
/** Neste foreach eu verifico se existe alguma funcionalidade que está cadastrada na tabela funcionalidades
-
* mas não está definida para o perfil. Se existir, precisamos tirar a permissão de acesso a ela.
-
* Toda funcionalidade que não estiver cadastrada na tabela de funcionalidades tem seu acesso liberado.
-
*/
-
-
-
foreach($rs as $arrDeny) {
-
if((!array_key_exists($arrDeny['cd_funcionalidade'], $arrFinal['allow'])) AND ($arrDeny['funcionalidade'])) {
-
$arrFinal['deny'][$arrDeny['cd_funcionalidade']] = $arrDeny['funcionalidade'];
-
}
-
}
-
-
return $arrFinal;
-
-
}
Pronto, o objeto Acl está criado e com as permissões setadas. Agora basta fazer a verificação sempre que o usuário tentar acessar os controllers do sistema. No caso deste exemplo, temos uma classe que extende da Zend_Controller_Action, ou seja, qualquer redirecionamento do sistema passará por ela. Nesta classe, adicionei o seguinte código para realizar a verificação da permissão:
-
-
//Recupero o objeto Acl do namespace…
-
$ns = new Zend_Session_Namespace();
-
-
if(isset($ns->acl)) {
-
$acl = $ns->acl;
-
//Monto a Url que está tentando ser acessada para a verificação…
-
$url = '/'.$this->_request->getControllerName().'/'.$this->_request-getActionName();
-
-
if($acl->has($url)) {
-
-
//Recupero os dados de autenticação do usuário…
-
$nsAutenticacao = new Zend_Session_Namespace('autenticacao');
-
-
//Verifico se o perfil do usuário tem acesso à url
-
if(!$acl->isAllowed($nsAutenticacao->perfil, $url)) {
-
-
//Caso não seja, redireciono o usuário para algum lugar avisando que ele não tem acesso…
-
$this->_redirect('/index/sem-acesso');
-
}
-
}
-
}
Caso o usuário tenha o acesso, não preciso fazer nada… Apenas deixo a requisição continuar a sua execução e o usuário chegará à url.
Simples, não? Caso tenha alguma dúvida ou tenha alguma crítica ou sugestão para melhorar, deixe seu comentário ou entre em contato por email
Um abraço!
Zend Framework Tutorial Series (por Adler Medrado)
Posted by Thiago Colares in PHP, Zend Framework on January 20, 2010
Programar em PHP profissionalmente sem um framework decente é impráticavel. Em 2008 comecei a estudar (na teoria) o Zend Framework e em 2009 participei pela primeira vez em um projeto de grande porte utilizando o ZF. Hoje indico o ZF a todos que estiverem procurando um framework completo e descomplicado.
Estava pensando em escrever um tutorial básico sobre o ZF, mas ao acessar o blog do Adler Medrado hoje ví que ele está preparando uma série de tutoriais semanais sobre o ZF, do básico ao avançado. Não vou escrever um tutorial só pra ter o meu nome nele. Aproveitem e se deliciem com essa série que tenho certeza que vai ser ótima!
Parabéns ao Adler pela iniciativa! Vou atualizando o post à medida que forem saindo os outros capítulos…
Zend Framework Tutorial Series – Capítulo 1
Zend Framework Tutorial Series – Capítulo 2
Autenticação com Zend_Auth
Posted by Thiago Colares in PHP, Zend Framework on November 10, 2009
Falar em Zend Framework sem citar o Zend_Auth é impossível. Afinal, qual sistema não possui autenticação de usuários? Nesse post darei um exemplo prático do uso do Zend Auth.
É importante lembrar a diferença entre o Zend_Auth e o Zend_Acl, pois apesar deles se complementarem, tem funções totalmente diferenes. O Zend_Auth é responsável somente pela autenticação, e o Zend_Acl é responsável por mapeamento de permissões do sistema. Falaremos do Zend_Acl em outra oportunidade.
Inicialmente, temos a configuração inicial no bootstrap:
-
-
//Criando um objeto Registry para utilização posterior
-
$registry = Zend_Registry::getInstance();
-
-
//Determinando a conexão através de um arquivo INI (ou qualquer outra forma à sua escolha)
-
$configDb = new Zend_Config_Ini('./application/config/db.ini', 'identificador') ;
-
$db = Zend_Db::factory ( $configDb->db->adapter, $configDb->db->config->toArray() ) ;
-
-
//Setando no registro a conexão criada
-
$registry->set( 'dbSistema', $db ) ;
-
-
//Definição do Zend_Auth
-
$authAdapter = new Zend_Auth_Adapter_DbTable($db);
-
$registry->set( 'authAdapter', $authAdapter ) ;
Não vamos entrar na questão do formulário, vamos direto para a action do controller, onde só chamaremos uma função do model e verificaremos o seu retorno:
-
-
$login = new User();
-
$result = $login->login($_POST);
-
-
if($result){
-
//Usuário autenticado
-
} else {
-
//Autenticação inválida
-
}
Agora a parte mais importante, a função da model:
-
public function login($objPost){
-
//Recuperando o objeto que registramos no bootstrap
-
$authAdapter = Zend_Registry::get('authAdapter');
-
//Setando a tabela e as colunas de identificação do usuário no banco
-
$authAdapter
-
->setTableName('USUARIO')
-
->setIdentityColumn('LOGIN')
-
->setCredentialColumn('SENHA');
-
-
//Recebendo os dados do POST
-
$authAdapter
-
->setIdentity(strtolower($objPost['input_usuario']))
-
->setCredential(md5($objPost['input_senha']));
-
-
//Autenticação
-
$result = $authAdapter->authenticate();
-
-
//Verificando a autenticação…
-
if($result->isValid()){
-
-
return true;
-
}
-
else{
-
return false;
-
}
-
}
Simples, não? Espero ter ajudado… Um abraço a todos!
Documentação oficial do Zend_Auth: http://framework.zend.com/manual/en/zend.auth.html
Implementação de cache automático com Zend_Cache
Posted by Thiago Colares in PHP, Zend Framework on September 21, 2009
Trabalhando em uma estrutura Zend Framework a alguns meses atrás, tivemos a necessidade de um sistema de cache automático para a grande maioria das consultas de um sistema. Depois de pesquisar bastante chegamos à conclusão de que não havia essa possibilidade no ZF, então desenvolví uma solução que atendeu muito bem à nossa necessidade e creio que também vai atender à outras pessoas, fazendo com que o cache seja uma propriedade do objeto model. Vamos lá.
Classe abstrata que extende da Zend_Db_Table_Abstract
-
abstract class Base_Db_Table extends Zend_Db_Table_Abstract{
-
/**
-
* Definições das configurações de cache
-
*
-
* @var $cacheFrontendOptions
-
* @var $cacheBackendOptions
-
* @var $cacheName
-
* @var $cacheObject
-
*/
-
-
protected $cacheFrontendOptions = array();
-
protected $cacheBackendOptions = array();
-
protected $cacheName;
-
protected $cacheObject;
-
-
public function init(){
-
//Iniciando cache automaticamente
-
$this->startCaching();
-
}
-
-
/* Seta o prefixo do nome do arquivo cache
-
* @param string $cacheName
-
*/
-
public function setNameCaching($cacheName) {
-
$this->cacheName = $cacheName;
-
}
-
-
/* Seta as configurações de cache
-
* @param array $cacheFrontendOptions – Array de configurações de frontend
-
* @param string $cacheName – Nome do prefixo do arquivo cache
-
*/
-
public function setCaching($cacheFrontendOptions = null, $cacheName = null) {
-
-
if($cacheFrontendOptions == null) {
-
-
$frontendOptions = array(
-
'lifetime' => 7200,
-
'automatic_serialization' => true);
-
-
} else {
-
$frontendOptions = $cacheFrontendOptions;
-
}
-
-
if($cacheName == null) {
-
$cacheName = $this->_name.'_'.date('dmy');
-
}
-
-
$cacheBackendOptions = array('cache_dir' => './application/cache_dir/');
-
-
$this->cacheFrontendOptions = $frontendOptions;
-
$this->cacheBackendOptions = $cacheBackendOptions;
-
$this->cacheName = $cacheName;
-
-
$this->startCaching();
-
}
-
-
/* Verifica se a cache está ativa no objeto Model
-
* @return bool
-
*/
-
public function isCaching() {
-
if($this->cacheObject) {
-
return true;
-
} else {
-
return false;
-
}
-
}
-
-
/* Retorna um array com as configurações de cache
-
* @return array $arrayCacheConfigs
-
*/
-
public function getCaching() {
-
if($this->cacheFrontendOptions) {
-
$arrayCacheConfigs = array(
-
'cacheFrontendOptions' => $this->cacheFrontendOptions, 'cacheBackendOptions'=>$this->cacheBackendOptions, 'cacheName' => $this->cacheName);
-
return $arrayCacheConfigs;
-
} else {
-
return false;
-
}
-
}
-
-
/* Inicia o cache
-
*/
-
public function startCaching() {
-
if($this->isCaching()) {
-
echo "
-
<pre>";
-
print_r('Cache já iniciada anteriormente: startCaching()');
-
print_r("
-
");
-
die(__FILE__.' – Linha '.__LINE__);
-
}
-
else {
-
if(!$this->getCaching()) {
-
$this->setCaching();
-
}
-
$cache = Zend_Cache::factory('Core',
-
'File',
-
$this->cacheFrontendOptions,
-
$this->cacheBackendOptions);
-
$this->cacheObject = $cache;
-
}
-
}
-
-
public function removeCaching() {
-
$this->cacheObject->remove($this->cacheName);
-
$this->cacheObject = null;
-
}
-
-
public function disableCaching() {
-
$this->cacheName = null;
-
$this->cacheFrontendOptions = null;
-
$this->cacheBackendOptions = null;
-
$this->cacheObject = null;
-
}
-
-
public function saveCaching($param) {
-
if($this->isCaching()) {
-
$this->cacheObject->save($param, $this->cacheName);
-
} else {
-
echo "
-
<pre>";
-
print_r('Cache não iniciada: saveCaching()');
-
print_r("
-
");
-
die(__FILE__.' – Linha '.__LINE__);
-
}
-
}
-
-
public function fetchAll($where = null, $order = null, $count = null, $offset = null)
-
{
-
if (!($where instanceof Zend_Db_Table_Select)) {
-
$select = $this->select();
-
-
if ($where !== null) {
-
$this->_where($select, $where);
-
}
-
-
if ($order !== null) {
-
$this->_order($select, $order);
-
}
-
-
if ($count !== null || $offset !== null) {
-
$select->limit($count, $offset);
-
}
-
-
} else {
-
$select = $where;
-
}
-
-
if($this->isCaching()) {
-
if(!$result = $this->cacheObject->load($this->cacheName)) {
-
$rows = $this->_fetch($select);
-
$data = array(
-
'table' => $this,
-
'data' => $rows,
-
'readOnly' => $select->isReadOnly(),
-
'rowClass' => $this->_rowClass,
-
'stored' => true
-
);
-
-
if (!class_exists($this->_rowsetClass)) {
-
require_once 'Zend/Loader.php';
-
Zend_Loader::loadClass($this->_rowsetClass);
-
}
-
-
$result = new $this->_rowsetClass($data);
-
$this->saveCaching($result);
-
}
-
-
} else {
-
-
$rows = $this->_fetch($select);
-
$data = array(
-
'table' => $this,
-
'data' => $rows,
-
'readOnly' => $select->isReadOnly(),
-
'rowClass' => $this->_rowClass,
-
'stored' => true
-
);
-
-
if (!class_exists($this->_rowsetClass)) {
-
require_once 'Zend/Loader.php';
-
Zend_Loader::loadClass($this->_rowsetClass);
-
}
-
-
$result = new $this->_rowsetClass($data);
-
}
-
-
return $result;
-
}
Com esta implementação, todas as consultas realizadas com o método fetchAll() serão salvas em cache no arquivo que foi definido no $cacheBackendOptions (linha 52). Se o nome do arquivo cache não for definido pelo desenvolvedor, será definido automaticamente na linha 44. Antes de realizar a consulta no banco, é verificado se já existe o arquivo no cache, caso não exista a consulta é realizada e o arquivo é criado no cache, caso existe, s resultado é retornado do cache.
Criando as configurações manualmente
Caso haja a necessidade de alterar qualquer configuração de front-end manualmente, não é necessário alterar a classe abstrata. Todas as configurações podem ser enviadas como argumento através do método setCaching() (linha 32).
Exemplo:
-
$objModel = new ObjModel();
-
-
$frontendOptions = array(
-
'lifetime' => 120,
-
'automatic_serialization' => false);
-
-
$cacheName = "Nome_do_arquivo";
-
-
$objModel->setCaching($frontEndOptions, $cacheName);
Se por algum motivo você precisar desabilitar o cache para um determinado model, utilize o método disableCaching().
Exemplo:
-
$objModel = new ObjModel();
-
$objModel->disableCaching();
Para verificar se o cache está habilitado para determinada model, utilize o método isCaching().
Exemplo:
-
$objModel = new ObjModel();
-
if($objModel->isCaching()) {
-
echo "Cache habilitada!";
-
} else {
-
echo "Cache desabilitada!";
-
}
Para a minha necessidade não precisei criar a definição manual do diretório em que os arquivos serão salvos, mas se você precisar, apenas dinamize a definição das configurações de back-end.
Enfim, é isso. Espero que seja útil. Caso tenha alguma crítica ou sugestão para a melhoria, terei prazer em recebê-la!
Documentação oficial do Zend_Cache: http://framework.zend.com/manual/en/zend.cache.html




