Arquivo da tag: CodeIgniter

Sparks: abrindo novos horizontes para o CodeIgniter

Fonte: Ademir Cristiano Gabardo/IMaster

O assunto não é tão novo assim, mas vem se tornando popular a cada dia e é provável que, daqui a algum tempo, tudo o que você precisar acoplar ao seu framework seja feito pelo sparks.

O CodeIgniter está se popularizando muito desde a mudança da metodologia de atualizações e da aceitação da comunidade internacional de desenvolvedores como parte colaboradora para novas funcionalidades. A velocidade com que o framework cresce e se estrutura vem ganhando proporções mais atraentes para profissionais e empresas desenvolvedoras de software.

Aplicativos que consomem serviços, uso da soluções REST, do SOAP, ORMs, sistemas de templates e, é claro, muitos “módulos” de terceiros fazem parte deste caminho. É possível encontrar bibliotecas para quase tudo, desde autenticação de usuários a templates. Essa evolução trouxe a necessidade de gerenciar a instalação desses módulos. E, com isso, surgiu o sparks.

Mas, então, o que é sparks?

Segundo o website sparks.org, “sparks é um sistema de gestão de pacotes para CodeIgniter que lhe permitirá instalar bibliotecas de alta qualidade em seus aplicativos instantaneamente”.

Que tal entender melhor na prática? Para isso, vamos criar um aplicativo capaz de exibir a sua timeline do Twitter:

1. Comece baixando a última versão do CodeIgniter. Descompacte em um caminho que possa ser acessado pelo seu servidor web. Eu escolhi uma pasta chamada “sparks”. Desse modo, posso acessar em http://localhost/sparks/. Até esse ponto, nada de diferente foi feito e nesse momento você deverá ver a tela de boas vindas do CodeIgniter.

2. Na pasta raíz do seu projeto, crie uma pasta chamada “tools”. Então, vamos seguir os passos encontrados neste artigo.

3. Baixe o arquivo spark-manager.zip aqui.

4. Descompacte o conteúdo do arquivo que você acabou de baixar. Você deverá ter na pasta “tools” um arquivo chamado spark sem nenhuma extensão.

5. Agora será necessário criar uma classe Loader, estendendo a classe Loader do CodeIgniter. Acesse aqui para obter o código fonte; copie-o para o seu editor e salve-o em “applicatton/core” com o nome de arquivo MY_Loader.php.

6. Estamos prontos para começar! Agora vamos utilizar o prompt de comando para obter os sparks seguindo os passos “Get Sparks” aqui.

Abra o seu prompt do DOS (Iniciar->Executar e digite CMD). Navegue até a pasta do projeto. No meu caso, CD C:/Webs/2012/Sparks. Obedeçam ao caminho de acordo com a instalação do seu servidor web. Você deverá ver algo como a tela a seguir:

Obs: Usuários do Linux provavelmente já sabem o que têm que fazer no Terminal.

Então, vamos utilizar o PHP via linha de comando para instalar um spark de exemplo, digitando o seguinte:

php tools\spark install -v1.0.0 example-spark

Embora apresentando um erro, o comando foi executado com sucesso exibindo ao final a mensagem “You´re on Fire!”, indicando que o conteúdo foi baixado e descompactado de acordo com o esperado.

Agora que o sparks “example” foi baixado e adicionado à pasta do projeto, você deverá ver na raíz do projeto uma pasta “sparks” com uma subpasta “example-spark” e a estrutura dos arquivos partindo da versão do spark instalado.

Para testar, abra o controlador e adicione o seguinte código ao método index da classe Welcome (estou presumindo que você não alterou nada além em seu projeto):

public function index(){      $this->load->spark('example-spark/1.0.0');
$this->example_spark->printHello(); }

Se tudo correr bem, ao acessar a URL no navegador, você deverá visualizar algo semelhante à figura a seguir:

Se você chegou até este ponto, tudo foi feito corretamente e poderemos prosseguir para nosso aplicativo.

Obtenha o CURL instalando via sparks com o seguinte comando no prompt:

php tools\spark install –v1.2.1 curl

E você deverá ver algo como a tela a seguir:

O próximo passo será, então, obter o RestClient. Do mesmo modo, digite no prompt de comando:

php tools\spark install –v2.1.0 restclient

Se tudo correr bem, ao final da operação, algo semelhante a tela a seguir será exibido:

Pronto, agora temos CURL e um cliente REST disponíveis, vamos aproveitar e utilizar para obter a timeline do Twitter. Precisamos alterar o método index da classe welcome para o seguinte código fonte:

public function index(){    $this->load->spark('curl/1.2.1');
$this->load->spark('restclient/2.1.0');
// Carregando a biblioteca Rest    $this->load->library('rest');
// Inicializando apontando o servidor do Twitter.
$this->rest->initialize(array('server'=> 'http://twitter.com/'));
// Recebendo os twitters do usuário agabardo, troque para o seu usuário.
$tweets = $this->rest->get('statuses/user_timeline/agabardo.xml');

//Exibindo na tela para propositos de teste.
echo "<pre>";    print_r($tweets);    echo "</pre>";
}

E, se tudo correr bem, você deverá visualizar a array com o conteúdo da sua timeline:

E como diriam meus amigos do Rio Grande: “mais simples que painel de Jipe”! Por isso acredito que muita coisa nova e boa deverá surgir empacotada com sparks.

Se você não tem afinidade com a linha de comando, existem outras alternativas, mas, convenhamos, digitar três ou quatro linhas no prompt do DOS ou terminal do Linux não é assim tão dolorido.

Não funcionou? Baixe os arquivos do projeto aqui.

***

Artigo original disponível em: http://codeigniter.com/news/a_quick_look_at_sparks

Abraços a todos!

Criando uma biblioteca para controle de acesso por usuário com CodeIgniter

Fonte: Ademir Cristiano Gabardo/IMasters

As aplicações PHP estão se tornando a cada dia mais complexas. Aplicações de uso comercial, acadêmico e das mais diversas finalidades fazem necessário um controle mais apurado de acesso.

No CodeIgniter, estamos, obrigatoriamente, sempre acessando uma classe e um método de um controlador. Dessa forma, é possível mapear todas as possíveis ações e/ ou caminhos disponíveis em uma aplicação e adicionar o controle de acesso aos métodos que desejamos controlar.

Eu desenvolvi uma biblioteca (library) para controlar o acesso dos usuários. O seu funcionamento se dá da seguinte forma: em uma tabela no banco de dados (sys_metodos), ficam guardados os nomes de classe e os métodos, mapeando todos os possíveis caminhos. Em outra tabela (sys_permissoes), ficam as ids dos usuários com os respectivos métodos a que eles têm acesso. Essa segunda tabela está relacionada à tabela de cadastro de usuários (tb_usuarios).

Figura 01: Estrutura das tabelas necessárias ao sistema de autenticação.

Seria bastante trabalhoso ter que popular a tabela de métodos manualmente, ou criar um Admin para ela. Dessa forma, inclui uma rotina na própria biblioteca, para que quando um método invocado por ela não seja encontrado na tabela sys_metodos, ele seja automaticamente criado. Assim, na primeira vez em que um método for acessado, ninguém terá permissão de acesso, sendo, então, necessário parametrizar o sistema uma única vez no primeiro acesso. Depois pode-se construir uma área de administração para varrer a tabela de métodos e adicionar ou remover as permissões dos usuários.

O CodeIgniter provê uma maneira de checarmos “onde estamos”, ou seja, em que classe e em que método. Para verificar o nome da classe, utilize a seguinte linha de código.

$this->router->class

E para recuperar o nome do método utilize:

$this->router->method

Podemos passar para a biblioteca o caminho completo de onde estamos da seguinte forma:

$this->auth->check_logged($this->router->class , $this->router->method);

Auth é o nome da biblioteca e check_logged é o método que estamos acessando. Como essa biblioteca será acessada em muitas classes e métodos, é preferível carregar no autoload para que ela esteja sempre disponível em qualquer parte da aplicação. Para proteger um método, basta incluir a linha de código:

<?php
class AreaRestrita extends Controller {
function __construct(){
parent::Controller();
}
function index(){
$this->auth->check_logged($this->router->class , $this->router->method);
}
}
?>

Vejamos, então, como fica o código fonte da biblioteca. Salve-o com o nome de arquivo auth.php na pasta system/application/libraries:

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Auth
{
private $ci;
public function __construct(){
$this->ci = &get_instance();
}
 
function check_logged($classe,$metodo)
{
/*
* Criando uma instância do CodeIgniter para poder acessar
* banco de dados, sessionns, models, etc...
*/
$this->CI =& get_instance();
 
/**
* Buscando a classe e metodo da tabela sys_metodos
*/
$array = array('classe' => $classe, 'metodo' => $metodo);
$this->CI->db->where($array);
$query = $this->CI->db->get('sys_metodos');
$result = $query->result();
 
// Se este metodo ainda não existir na tabela sera cadastrado
if(count($result)==0){
$data = array(
'classe' => $classe ,
'metodo' => $metodo ,
'apelido' => $classe .  '/' . $metodo,
'privado' => 1
);
$this->CI->db->insert('sys_metodos', $data);
redirect(base_url(). $classe . '/' . $metodo, 'refresh');
}
//Se ja existir tras as informacoes de publico ou privado
else{
if($result[0]->privado==0){
// Escapa da validacao e mostra o metodo.
return false;
}
else{
// Se for privado, verifica o login
$nome = $this->ci->session->userdata('nome');
$logged_in = $this->ci->session->userdata('logged_in');
$data = $this->ci->session->userdata('data');
$email = $this->ci->session->userdata('email');
$id_usuario =  $this->ci->session->userdata('id_usuario');
 
$id_sys_metodos = $result[0]->id;
 
// Se o usuario estiver logado vai verificar se tem permissao na tabela.
if($nome && $logged_in && $id_usuario){
 
$array = array('id_metodo' => $id_sys_metodos, 'id_usuario' => $id_usuario);
$this->CI->db->where($array);
$query2 = $this->CI->db->get('sys_permissoes');
$result2 = $query2->result();
 
// Se não vier nenhum resultado da consulta, manda para página de
// usuario sem permissão.
if(count($result2)==0){
redirect(base_url().'home/sempermissao', 'refresh');
}
else{
return true;
}
}
// Se não estiver logado, sera redirecionado para o login.
else{
redirect(base_url().'home/login', 'refresh');
}
}
}
}
 
/**
* Método auxiliar para autenticar entradas em menu.
* Não faz parte do plugin como um todo.
*/
function check_menu($classe,$metodo){
$this->CI =& get_instance();
$sql = "SELECT SQL_CACHE
count(sys_permissoes.id) as found
FROM
sys_permissoes
INNER JOIN sys_metodos
ON sys_metodos.id = sys_permissoes.id_metodo
WHERE id_usuario = '" . $this->ci->session->userdata('id_usuario') . "'
AND classe = '" . $classe . "'
AND metodo = '" . $metodo . "'";
$query = $this->CI->db->query($sql);
$result = $query->result();
return $result[0]->found;
}
}

Note que a biblioteca se encarrega de inserir os dados de métodos e classes que ainda não estão cadastrados na tabela sys_metodos.

Quando um usuário tentar acessar uma área do site ou sistema no qual ele não tenha privilégios, ele será redirecionado para uma página específica:

redirect(base_url().'home/sempermissao', 'refresh');
 

E, quando ele não estiver logado, será redirecionado para a página de login:

redirect(base_url().'home/login', 'refresh');

Incluí também um método na biblioteca para checar se o usuário logado no sistema tem permissão para acessar um determinado método de uma classe chamado check_menu. Para utilizar a autenticação no menu, basta checar se o usuário tem permissão para o caminho. Isso pode ser feito diretamente na view do menu:

 
<?php
if($this->auth->check_menu('home','index')==1){
echo "<li><a href='". base_url() ."home'>Home</a></li>";                }
?>

Observe também que na tabela sys_metodos existe um campo chamado privado, que tem por objetivo liberar o acesso de métodos que estejam protegidos; caso você construa um sistema de admin para gerenciar essa tabela, quando um método estiver com o campo privado definido como 1, ele estará com seu acesso restrito somente a usuários com permissão de acesso. Quando estiver ajustado como 0, estará liberado como método público.

Outro detalhe dessa tabela é um “apelido”. Ele é cadastrado em um primeiro momento como classe/método, mas poderá ser alterado para qualquer nome amigável e mais compreensível para os usuários, como, por exemplo, Home/login poderia ser substituído por Acesso à tela de login.

Para autenticar um usuário no sistema, crie um formulário com os campos usuário, cnpj e senha, e aponte para uma classe de sua preferência (eu uso a classe de nome home) com os seguintes métodos:

<?php
class Home extends Controller {
 
function __construct(){
parent::Controller();
$this->load->helper('logs');
$this->load->helper('cookie');
}
 
function index(){
redirect(base_url().'home/login', 'refresh');
}
 
function void(){
$data['js_to_load'] = null;
$this->load->view('libs/html-header',$data);
$this->load->view('libs/menu');
$this->load->view('libs/html-footer');
}
function sempermissao(){
 
echo "<html>";
echo "<title>Acesso Negado</title>";
echo "<body bgcolor='#EEEEEE'>";
echo "    <div style='padding:20px;background-color:#FFCC00;'>";
echo "<h2>Você não tem permissão para acessar esta funcionalidade.</h2>
echo "</div>";
echo "</body>";
echo "</html>";
exit();
}
 
function login(){
$this->load->view('login',$data);
}
 
function dologin(){
$usuario = $this->input->post('usuario');
$cnpj = $this->input->post('cnpj');
$senha = md5($this->input->post('senha'));
 
if($usuario=="" || $cnpj=="" || $this->input->post('senha')==""){
redirect(base_url().'home/login', 'refresh');
exit();
}
 
if(isset($_POST['lembrar'])){
setcookie("usuario", $usuario);
setcookie("cnpj", $cnpj);
setcookie("lembrar", "checked");
}
 
$sql = "SELECT id,cnpj,login,nome,email
FROM tb_usuarios
WHERE login ='" . $usuario . "'
AND cnpj ='" . $cnpj . "'
AND senha ='" . $senha . "'";
 
$query = $this->db->query($sql);
$result = $query->result();
if(count($result)<1){
redirect(base_url().'home/login', 'refresh');
exit();
}
else{
$login = array(
'id_usuario'   =>     $result[0]->id,
'cnpj'   =>     $result[0]->cnpj,
'usuario'   =>     $result[0]->login,
'nome'      =>    $result[0]->nome,
'email'     =>     $result[0]->email,
'logged_in' => TRUE,
'data' => date("d/m/Y h:i:s")
);
 
$data['ip'] = getenv("REMOTE_ADDR");
$data['usuario'] = $result[0]->id;
$this->db->insert('tb_acessos',$data);
 
$this->session->set_userdata($login);
redirect(base_url().'home/void', 'refresh');
}
}
 
function logout()
{
$this->session->sess_destroy();
$this->login();
}
}

Com isso, concluímos nosso sistema de autenticação com controle de nível de acesso por classe e método. Não é exatamente a coisa mais simples do mundo, mas também não é a mais complicada. É importante ressaltar que estou guardando as sessões do codeIgniter no banco de dados. As demais funções de cadastro de usuário e o cadastro de usuários na tabela de permissão devem ser construídos separadamente.

Implementações futuras estão previstas e um inconveniente deste sistema é que, quando você altera um nome de classe ou método, será necessário ajustar a tabela sys_metodos.

Código fonte da biblioteca disponível aqui.

Espero que o artigo lhes tenha sido útil!