PHP 5.3, PHP-FPM, XCache, Nginx no Debian Lenny – Performance extrema

janeiro 15th, 2010 por Carlos André Ferrari 11 comments »

Neste post vou exemplificar os passos para configurar um Webserver que consome poucos recursos e é extremamente rápido no Debian Lenny.

PHP-FPM: é um gerenciador de processos CGI do php, similar ao Phpcgi, porém com várias vantagens como:

  • Gerenciador de Processos muito eficiente, com capacidade de parar e iniciar seus deamons caso necessário
  • Possibilidade de Iniciar processos com usuários diferentes e com arquivos php.ini diferentes
  • Uploads otimizados
  • Capacidade de reinicializar processos caso ocorra algum problema
  • Escalabilidade de processos, ele pode criar mais processos de acordo com a demanda
  • e muito mais.

XCache: é um gerenciador de cache, que armazena os scripts php em opcode para uso futuro, é extremamente rápido e muito usado no mundo em servidores com alta demanda.

Nginx: Conheci este webserver lendo o blog da boo-box, ele é um Servidor web e proxy reverso extremamente veloz e que vem ganhando mercado nos últimos meses devido a sua facilidade de uso e capacidade de carga.

Para agilizar a configuração, vamos usar alguns pacotes (php5.3, php-fpm) pré compilados e mantidos www.dotdeb.org. os testes que eu realzei usando estes pacotes tiveram um ganho de performance enorme.

Instalação:

Vamos começar adicionado os repositórios do dotdeb no /etc/apt/sources.list:

deb http://php53.dotdeb.org stable all
deb-src http://php53.dotdeb.org stable all

Vamos instalar os pacotes e algumas dependências para o nginx:

aptitude update
aptitude install php5 php5-fpm php5-xcache php5-gd php5-curl \ 
php5-mysql php5-pgsql libssl-dev libpcre3-dev build-essential -y

O único problema é que o pacote do php deles tem o apache2 como dependência e teremos que desativá-lo, pois não será usado:

apache2ctl stop
chmod -x /etc/init.d/apache2
update-rc.d -f apache2 remove

Agora temos o php instalado, vamos compilar o nginx:

cd
mkdir src
cd src
wget http://nginx.org/download/nginx-0.7.64.tar.gz
tar -zxvf nginx-0.7.64.tar.gz
cd nginx-0.7.64
./configure --prefix=/usr/local/nginx --user=www-data --group=www-data \
    --without-mail_pop3_module --without-mail_imap_module \
    --without-mail_smtp_module --with-http_stub_status_module \
    --with-http_ssl_module --http-log-path=/var/log/nginx/access.log \
    --conf-path=/etc/nginx/nginx.conf  --pid-path=/var/run/nginx.pid
make
make install

Se tudo ocorreu bem, você já tem o nginx instalado, vamos apenas coloca-lo para inicializar automáticamente, crie o arquivo /etc/init.d/nginx e coloque o conteúdo:

#! /bin/sh
 
### BEGIN INIT INFO
# Provides:          nginx
# Required-Start:    $all
# Required-Stop:     $all
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts the nginx web server
# Description:       starts nginx using start-stop-daemon
### END INIT INFO
 
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local
DAEMON=/usr/local/nginx/sbin/nginx
NAME=nginx
DESC=nginx
 
test -x $DAEMON || exit 0
 
# Include nginx defaults if available
if [ -f /etc/default/nginx ] ; then
        . /etc/default/nginx
fi
 
set -e
 
case "$1" in
  start)
        echo -n "Starting $DESC: "
        start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \
                --exec $DAEMON -- $DAEMON_OPTS || true
        echo "$NAME."
        ;;
  stop)
        echo -n "Stopping $DESC: "
        start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \
                --exec $DAEMON || true
        echo "$NAME."
        ;;
  restart|force-reload)
        echo -n "Restarting $DESC: "
        start-stop-daemon --stop --quiet --pidfile \
                /var/run/$NAME.pid --exec $DAEMON || true
        sleep 1
        start-stop-daemon --start --quiet --pidfile \
                /var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS || true
        echo "$NAME."
        ;;
  reload)
        echo -n "Reloading $DESC configuration: "
        start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/$NAME.pid \
            --exec $DAEMON || true
        echo "$NAME."
        ;;
  configtest)
        echo -n "Testing $DESC configuration: "
        if nginx -t > /dev/null 2>&1
        then
          echo "$NAME."
        else
          exit $?
        fi
        ;;
  *)
        echo "Usage: $NAME {start|stop|restart|reload|force-reload|configtest}" >&2
        exit 1
        ;;
esac
 
exit 0

depois vamos torna-lo executável e atualizar o rc.d:

chmod +x /etc/init.d/nginx
update-rc.d nginx defaults

Com isso o processo de instalação está concluído, vamos configurar!

Configuração do XCache

Coloque a seguinte configuração no arquivo /etc/php5/fpm/conf.d/xcache.ini:

; configuration for php xcache module
extension=xcache.so
 
[xcache.admin]
xcache.admin.user = "secom"
; xcache.admin.pass = md5($your_password)
xcache.admin.pass = ""
[xcache]
; ini only settings, all the values here is default unless explained
; select low level shm/allocator scheme implemenation
xcache.shm_scheme =        "mmap"
; to disable: xcache.size=0
; to enable : xcache.size=64M etc (any size > 0) and your system mmap allows
xcache.size  =                64M
; set to cpu count (cat /proc/cpuinfo |grep -c processor)
xcache.count =                 1
; just a hash hints, you can always store count(items) > slots
xcache.slots =                8K
; ttl of the cache item, 0=forever
xcache.ttl   =                 0
; interval of gc scanning expired items, 0=no scan, other values is in seconds
xcache.gc_interval =           0
; same as aboves but for variable cache
xcache.var_size  =            64M
xcache.var_count =             1
xcache.var_slots =            8K
; default ttl
xcache.var_ttl   =             0
xcache.var_maxttl   =          0
xcache.var_gc_interval =     300
xcache.test =                Off
; N/A for /dev/zero
xcache.readonly_protection = Off
; for *nix, xcache.mmap_path is a file path, not directory.
; Use something like "/tmp/xcache" if you want to turn on ReadonlyProtection
; 2 group of php won't share the same /tmp/xcache
; for win32, xcache.mmap_path=anonymous map name, not file path
xcache.mmap_path =    "/dev/zero"
 
; leave it blank(disabled) or "/tmp/phpcore/"
; make sure it's writable by php (without checking open_basedir)
xcache.coredump_directory =   ""
; per request settings
xcache.cacher =               On
xcache.stat   =               On
xcache.optimizer =            On
[xcache.coverager]
; per request settings
; enable coverage data collecting for xcache.coveragedump_directory and xcache_coverager_start/stop/get/clean() functions (will hurt executing performance)
xcache.coverager =          Off
; ini only settings
; make sure it's readable (care open_basedir) by coverage viewer script
; requires xcache.coverager=On
xcache.coveragedump_directory = ""

Configuração do Nginx

Edite o arquivo em /etc/nginx/nginx.conf:

user  www-data;
 
#Coloque quantos processos simultaneos, o ideal é um para cada nucleo do sistema:
worker_processes  4;
 
error_log  /var/log/nginx/error.log;
 
events {
    # numero de conexões simultaneas por worker
    worker_connections  1024;
}
 
http {
    include       mime.types;
    default_type  application/octet-stream;
 
    access_log  /var/log/nginx/access.log;
    sendfile        on;
    # isso é interessante, dá um ganho enorme na navegação, e o nginx aguenta tranquilamente
    keepalive_timeout  60;
    tcp_nodelay        on;
 
    ## Compressão
    gzip on;
    gzip_http_version 1.0;
    gzip_comp_level 2;
    gzip_proxied any;
    gzip_min_length  1100;
    gzip_buffers 16 8k;
    # mime types para zipar e adicionar header de cache
    gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript image/gif image/jpeg image/png;
    # Desabilita compressão em algumas versões do IE6
    gzip_disable "MSIE [1-6].(?!.*SV1)";
    # Impede que servidores proxy mandem versões em gzip do arquivo para os IE6
    gzip_vary on;
 
    server {
	root  /var/www/;
	server_name     localhost;
	listen          80;
	location / {
		index  index.php index.html index.htm;
	}
 
	#error_page  404  /404.html;
	# redirect server error pages to the static page /50x.html
	error_page   500 502 503 504  /50x.html;
	location = /50x.html {
		root   /var/www/nginx-default;
	}
 
	# Joga requisições para arquivos .php para o php-fpm
	location ~ \.php$ {
		fastcgi_pass   127.0.0.1:9000;
		fastcgi_index  index.php;
		include fastcgi_params;
        	fastcgi_param SCRIPT_FILENAME /var/www/$fastcgi_script_name;
        	fastcgi_param SERVER_NAME $http_host;
        	fastcgi_ignore_client_abort on;
	}
    }
}

Configuração do php-fpm

Edite o arquivo: /etc/php5/fpm/php5-fpm.conf e faça os ajustes que você achar interessante, aqui eu só aumento os max_childrens (Numero de clientes CGI) de 5 para 50, esta configuração depende do seu hardware.

Configuração do Logrotate

Vamos configurar agora o logrotate para não enchermos os discos com logs do nginx, edite o arquivo /etc/logrotate.d/nginx:

/var/log/nginx/*.log {
        daily
        missingok
        rotate 7
        compress
        delaycompress
        notifempty
        create 640 root adm
        sharedscripts
        postrotate
                [ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.p$
        endscript
}

Finalizando

Agora que está tudo configurado, vamos reinicalizar os serviços:

/etc/init.d/php5-fpm restart
/etc/init.d/nginx restart

crie um arquivo /var/www/index.php e vamos testar o php:

<?php
phpinfo();

e acesse: http://ip_do_servidor/

GVT, Vivendi, Internet, TV Digital e o Futuro

novembro 15th, 2009 por Carlos André Ferrari 9 comments »

Nos últimos meses estou acompanhando notícias sobre a venda da GVT, no inicio a Vivendi fez uma oferta muito boa para a aquisição, porém a Telecômica Telefônica apareceu com uma oferta bem maior e quando tudo parecia perdido foi anunciada a compra de 57,5% das ações da GVT pela Vivendi!

A GVT é conhecida como a melhor (realmente muito melhor) operadora de telefônia, que nasceu e atua no Brasil, e ela é melhor em todos os aspectos (atendimento, preço, qualidade de serviço e qualidade de banda larga) enquanto a Telefônica compete com a Oi pelo maior numero de clientes insatisfeitos.

A Vivendi é uma empresa francesa que atua no setor de mídia e comunicação com atividades na música, televisão, cinema, editoração, telecomunicações e Internet. (por: Wikipedia)

Areas de atuação da Vivendi

Areas de atuação da Vivendi

Bom, mas o que isso significa…

Vamos considerar os seguintes pontos:

  • Governo investindo em inclusão digital
  • Qualidade dos serviços e atendimento da GVT
  • O know-how em mídias e o dinheiro da Vivendi

E juntamos isso com o fato de que a mídia da forma que conhecemos está definhando devido a Internet (RSS, Twitter, Orkut, Facebook, etc).

Com apenas isso já é possível se concluir o óbvio. A Vivendi está vindo para, além de nos prover acesso a internet com qualidade e chutar a Oi e Telefônica de vez, nos prover um serviço que pode em pouco tempo engolir também a nossa TV Digital. Ela vem para criar aqui um sistema de IPTV

Se pararmos para analisar, a TV Digital do mundo todo irá evoluir para IPTV, pois, todas as qualidades da TV Digital (FullHD, Som Surround e Interatividade) podem ser superadas pela Internet.

Daí pega outro ponto: Infraestrutura, porém, para vocês terem uma ideia, no Japão um link de 100Mb por fibra ótica custa o equivalente a 60 reais por mês. Mas acredito que a Vivendi tem cacife suficiente para engolir os lixos as empresas em que somos obrigados a depender e pagar 100 reais por meros 2mb de banda com Traffic Shaping e finalmente nos prover um serviço de “primeiro mundo”.

As questões que ficam são:

Irá no final das contas a TV digital sobreviver? Ou veremos nossas mães e irmãs assistindo as novelas e discutindo com amigas em tempo real pela TV ou pelo Computador?

Após escrever essa pergunta me surgiram outras questões:

  • Quanto tempo a TV Digital Brasileira irá sobreviver?
  • Quanto tempo vai levar até a Globo, Record ou outra emissora começar a transmitir suas programações ao vivo e em tempo real pela internet?
  • Quanto tempo irá levar para todas as mídias de massa se convergirem na Internet?

No final de tudo uma certeza eu tenho: Quem resistir vai ser engolido.

Até!

Trabalhando em Grupo em um mesmo branch no git

outubro 16th, 2009 por Carlos André Ferrari No comments »

Problema: Trabalhar em grupo em um branch que não seja o master usando git.

Solução:
Considerando que o repositório já está ok, e você já está conectado no remote:

Aqui estão os passos para criar o branch que a equipe vai trabalhar

# criar o branch
git checkout -b meu_branch
# enviar o branch para a origem
git push origin meu_branch
# vamos apagar esse branch local agora
git checkout master
git branch -D meu_branch

Agora cada um que vai trabalhar com este branch pode adicioná-lo assim:

git checkout --track -b meu_branch origin/meu_branch

Agora todo mundo da equipe pode trabalhar no “meu_branch” como se estivesse no master.

e para excluir o branch da origem faça:

git push origin :meu_branch

Até a proxima

Backup automático do postgres + rsync para outra máquina

outubro 15th, 2009 por Carlos André Ferrari 4 comments »

Aqui vou exemplificar a solução que usamos para fazer backup diário dos nossos bancos de dados, este backup é armazenado em um servidor fora do país. para fazer a sincronia, usamos o rsync.

1) Configurando login automático via chaves digitais no nosso servidor de armazenamento

Primeiro você tem que gerar as chaves no seu servidor de banco, com o usuário do banco de dados, no meu caso é o usuário “postgres”.

Você será perguntado por uma senha, deixe em branco e confirme:

$ su postgres
$ ssh-keygen -t dsa

Agora você terá sua chave, copie-a para seu servidor que irá armazenar o backup

$ scp ~/.ssh/id_dsa.pub user@server_bkp:~/

Agora acesse seu servidor via ssh e adicione a chave pública na lista de chaves autorizadas do ssh

$ ssh user@server_bkp
$ cat ~/id_dsa.pub >> ~/.ssh/authorized_keys

Volte para o seu servidor de banco no usuario do postgres e teste:

$ ssh user@server_bkp

Se você conseguiu acessar o server de backup sem digitar senha, continue no passo 2, senão, de uma revisada. qualquer dúvida comente!.

2) Instalando o rsync e script de backup

Para instalar o rsync no debian é bem simples:

$ aptitude install rsync

No nosso banco de dados os backups são feitos diariamente as 19 horas, e usamos a pasta /backup para armazena-los:

$ mkdir /backup
$ touch /backup/backup.sh
$ chmod +x /backup/backup.sh
$ chown postgres:postgres /backup -R

Agora, edite o arquivo backup.sh e coloque o conteúdo:

#!/bin/bash
 
PASTA=$(date +%m%Y)
DATA=$(date +%Y%m%d)
DIA=$(date +%d)
 
mkdir /backup/$PASTA
mkdir /backup/$PASTA/$DIA
 
LIST=$(psql -l | awk '{ print $1}' | grep -vE '^-|^\(|^List|^N[o|a]me|template[0|1]')
for d in $LIST
do
        pg_dump -i -h 127.0.0.1 -p 5432 -U postgres -F t -b -f "/backup/$DATA-$d.backup" $d
        tar -zcf /backup/$PASTA/$DIA/$DATA-$d.tar.gz /backup/$DATA-$d.backup
        rm /backup/$DATA-$d.backup
        /usr/bin/rsync -avzh --delete --progress --update /backup/ user@server_bkp:~/
done

faça um teste e rode o script com o user do postgres:

$ su postgres
$ /backup/backup.sh

Se tudo ocorrer bem, é só adicionar no crontab para executar quando você quiser:

$ su
$ pico /etc/crontab

e adicionar:

0 19    * * *   postgres    /backup/backup.sh

Reinicie o cron e o backup será feito todos os dias as 19 horas.

nginx – webserver, proxy reverso e perfeito!

outubro 15th, 2009 por Carlos André Ferrari 4 comments »

Nosso departamento é responsável por manter a identidade visual dos sites do Governo do Estado e ainda fazemos os sites dos orgãos que não possuem um.

No trabalho sempre tivemos um constante problema para hospedar nossos sites: hardware!. Contamos hoje com dois incríveis servidores IBM Pentium4 3Ghz com 2gb de memória e HDs scsi, um para hospedar mais de 40 sites e o outro onde fica postgres com os bancos de dados desses sites.

Ultimamente nosso problema tem crescido bastante, pois, a demanda por sites aumentou e ao mesmo tempo o número de visitas veio aumentando e, como não conseguimos de forma alguma (até agora) investimento em equipamento novo estavamos chegando em uma situação crítica, nosso servidor começava a sentar morrer com 200 conexões simultaneas!

Lembrei-me de um post do boo-box onde vi um servidor web chamado nginx (lê-se engineX) e decidi pesquisar mais e fazer testes em casa onde rodando um servidor e servindo uma página php com um usleep de meio segundo consegui mais de 2000 conexões simultaneas! uau!..

nginx_performance

Na segunda feira seguinte, sem pensar muito, fui para o nosso servidor de produção e apliquei a seguinte política de funcionamento:

  • nginx recebe todas as conexões pela porta 80
  • nginx faz proxy para o apache (que roda em outra porta) se a solicitação for para uma página php
  • nginx resolve sozinho usando php-cgi caso a requisição seja para:
    • uma fotografia
    • um arquivo
    • uma requisição para o webservice
    • um download do diário oficial
    • um banner do Governo
    • a barra padrão do Estado
    • ou um arquivo na nossa lib

Como resultado da experiência, nossos sites continuam morrendo, porém, aguentando 700 conexões simultaneas e esse valor só é alcançado quando tem muita pesquisa no banco de dados (Dias que sai algo sobre algum concurso público ou muita demissão no Diário Oficial) logo, fica claro, que o problema não é mais do webserver e sim do nosso servidor de Banco. Bom, o nosso webserver atualmente mal chega a 5% de uso, mesmo com as 700 conexões. Só espero conseguir uma maquina nova e mais eficiente para os nossos Bancos de Dados logo!.

Update:
Fomos atendidos, estamos com um Xeon Quad Core com 4Gb de memória para o Banco de dados, e, associado com uma otimização do cache do webservice alcançamos mais de 1000 conexões simultâneas sem nenhuma degradação na performance. Detalhe que o webserver ainda é um P4 3ghz com 1gb de memória em que a utilização de processamento não passa de 5%.

Autenticação de Usuários no Vórtice PHP

outubro 9th, 2009 por Carlos André Ferrari 6 comments »

Nesse post vou explicar como adicionar autenticação de usuários no @vorticephp, como base para o sistema vamos utilizar o exemplo que já vem com o framework.

Script de BD:

CREATE TABLE IF NOT EXISTS orgaos (
id int(11) NOT NULL AUTO_INCREMENT,
sigla varchar(50) collate utf8_unicode_ci NOT NULL,
nome varchar(150) collate utf8_unicode_ci NOT NULL,
PRIMARY KEY  (id)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8
 
CREATE TABLE IF NOT EXISTS usuarios (
id int(10) UNSIGNED NOT NULL,
nome varchar(50) NOT NULL,
email varchar(60) NOT NULL,
senha char(32) NOT NULL,
PRIMARY KEY  (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO usuarios (nome, email, senha) VALUES('Administrador', 'adm@ferrari.eti.br', md5('123'));

eu criei essa tabela com esse usuario e senha no database que já vem configurado no framework para vocês testarem localmente. Você pode configurar a conexão com o seu próprio banco de dados no arquivo app/app.php

Para iniciar vamos criar o objeto do usuário em: app/model/Usuario.php e codificar:

<?php
class Usuario{
	public function __construct($id=0, $nome='', $email='', $senha=''){
		$this->id = $id;
		$this->nome = $nome;
		$this->email = $email;
		$this->senha = $senha;
	}
}

agora que temos o objeto, vamos criar um DAO para realizar operações, crie o arquivo app/model/UsuarioDAO.php e segue o código:

<?php
class UsuarioDAO{
	public function getByEmail($email){
		$sql = "SELECT * FROM usuarios WHERE email='$email'";
		return Database::getInstance()->queryOne($sql);
	}
}

vamos para o controller de usuários, crie o arquivo app/controller/UsuarioController.php e segue o codigo inicial:

<?php
class UsuarioController extends Controller{
	public function login(){
 
	}
}

Dai a gente cria o nosso formulário de login, edite app/view/usuario/login.php:

<h2>Login</h2>
<fieldset>
	<form method="post">
		<p><label>E-mail:</label><input type="text" name="email" /></p>
		<p><label>Senha:</label><input type="password" name="senha" /></p>
		<p><input type="submit" value="Logar!" /></p>
	</form>
</fieldset>

Agora com o form criado, vamos editar a action login do controller Usuario, volte e edite o arquivo app/controller/UsuarioController.php:

<?php
class UsuarioController extends Controller{
	public function login(){
		// se um formulario foi postado	
		if (post){
			// pega as variáveis do post
			$email = addslashes(p('email'));
			$senha = md5(p('senha'));
 
			// seleciona o usuario, armazena na variavel $u
			// e ainda verifica se o usuario existe
			if ($u = UsuarioDAO::getByEmail($email)){
				// verifica se a senha digitada combina com 
				// a que está no BD
				if ($u->senha == $senha){
					// remove a senha do objeto
					$u->senha = null;
					// grava a session
					Session::set("u", $u);
					// Cria mensagem de sucesso e redireciona para o index
					Post::setSucesso("Olá {$u->nome}, você está logado", new Link(""));
				}else
					// Retorna erro
					Post::setErros("Senha incorreta!");
			}else
				// Retorna erro
				Post::setErros("e-mail não encontrado!");
		}
	}
}

Para ficar bonita a url vamos criar um route para esta action, edite o arquivo app/routes.php e adicione:

Route::add("^login$", "usuario:login");

Agora o formulário de login já está funcionando, vamos fazer o sistema obrigar o usuario estar logado para fazer qualquer coisa no sistema, para isso edite o arquivo app/controller/MasterController.php, como queremos que para todo o sistema sejá necessário o login, vamos adicionar um construtor nessa classe com o seguinte código:

function __construct(){
	// se a session "u" não existir, criar uma com um usuario vazio
	if (!Session::get("u")) Session::set("u", new Usuario());
 
	// Se a session u tiver um objeto vazio..
	// e o controller/action forem diferentes dos de login
	if (Session::get("u")->id == 0 && controller != 'usuario' && action != 'login'){
		// redireciona para a tela de login
		redirect(new Link("login"));
	}
}

Bom, com isso já deve estar tudo funcionando de forma eficiente e simples. Qualquer dúvida ou sugestão mande sem hexitar.

Vórtice PHP Framework – Introdução

setembro 21st, 2009 por Carlos André Ferrari 3 comments »

Assim como frameworks mais conhecidos, o Vórtice tem uma estrutura de pastas que visa organizar todo o sistema e facilitar na hora da reutilização de código. segue abaixo a estrutura:

1 - app
1.1 - classes
1.2 - controller
1.2 - model
1.3 - view
1.4 - error_docs
1.5 - i18n
1.6 - plugins
2 - core
3 - css
4 - js
5 - templates
5.1 - nome_do_seu_template
5.1.1 - css
5.1.2 - js

1 – App

Apesar do framework não exigir nenhuma configuração em ambientes Linux/Unix ele possui um arquivo config.php que é necessário ser usado em caso de instalação em um ambiente Windows para definir a pasta fisica e a pasta virtual do sistema. ainda na pasta app existem os arquivos app.php e funcoes.php, que podem ser utilizados para inicializar instâncias de bancos de dados, criar funções e fazer qualquer coisa que você venha a precisar globalmente no seu site. Aqui também existe o arquivo route.php onde você poderá criar rotas baseadas em expressões regulares, tem um exemplo comentado de como funciona no sistema de exemplo.

1.1 – classes

Essa é a pasta de helpers, coloque ai suas classes de Segurança, as que modificam o fluxo do framework e qualquer classe que você venha a precisar no seu sistema

1.2 – controller

Pasta onde ficam os controllers, o nome do arquivo deve ser: CarroController.php, contendo dentro uma classe CarroController extendondo a classe Controller do framework. cada metodo dessa classe será uma action.

1.2 – model

Modelos do sistema, cada model é constituido por dois arquivos: Carro.php e CarroDAO.php contendo cada um a respectiva classe dentro. A classe Carro guarda a classe de um unico objeto carro (pode extender a classe de framework DTO) e a classe CarroDAO (quepode extender a classe de framework DAO) contêm as operações relacionadas ao objeto Carro (insert, delete, list, etc)

1.3 – view

Views do sistemas, uma view é um arquivo .php que será colocado dentro do template após a execução (substituindo o comentario <!–conteudo–> dentro do framework). Cada view deve ser colocada em uma subpasta com o nome do controller que ela pertence: app/view/carro/listar.php e será carregada automaticamente após a action listar do controller carro.

1.4 – error_docs

Páginas de erro, no framework já vem dois modelos.

1.5 – i18n

Pasta onde ficam traduções do sistema (en.conf, pt.conf, jp.conf, etc). Futuramente eu escrevo um post só sobre isso.

1.6 – plugins

Nessa pasta ficam plugins, que são executados exclusivamente antes da página ser enviada ao navegador. Futuramente eu escrevo sobre ela também.

2 – core

Aqui fica o nucleo do framework, caso você tenha vários sistemas usando ele, é possível criar um link simbólico e usar apenas uma pasta para todos os sites.

3 – css

Arquivos CSS globais, que serão carregados para todos os templates

4 – js

Arquivos JS globais, assim como a pasta css

5 – templates

Templates do site, cada subpasta será um template e dentro será necessário um arquivo template.php com o html básico da página.

5.1.1 – css

Aqui ficam os arquivos CSS exclusivos desse template

5.1.2 – js

Arquivos JS exclusivos do template

Fica ai toda a estrutura, qualquer dúvida deixe um comentário.

Faça já o download e experimente: Projeto Vórtice PHP
Siga o vórtice no twitter: @vorticephp e acompanhe mais novidades seguindo @caferrari e @luanlmd

Vórtice PHP Framework – Apresentação

setembro 19th, 2009 por Carlos André Ferrari 11 comments »

Desde junho de 2008 eu e meus colegas do trabalho estamos desenvolvendo uma solução para usar nos sites do Governo do Tocantins e nos sistemas, como a gente tem problemas com a estrutura disponível (hardware!) decidimos criar um framework, que, além de agilizar nossa produção fosse extremamente rápido, consumisse o minimo de recursos possível e permitisse o reaproveitamento de código.

Com menos de 2 meses de desenvolvimento, nascia o Vórtice junto com um projeto inicial que nos direcionou inicialmente no desenvolvimento.

Dentre as diversas características do framework, as mais importantes são:

  • Velocidade;
  • Padrão MVC com Front Controller;
  • Rewrite de URL’s com suporte a regex;
  • Internacionalização com url’s únicas por idioma (queriamos que o google indexasse todas as línguas, ex: Jalapão);
  • Ferramentas para mensagens de erro eficientes, tanto com ajax quanto sem;
  • O mínimo de configuração possível (no linux não exige nenhuma configuração!);
  • Fosse possível se conectar em multiplos bancos de dados;
  • PDO!
  • Pronto para funcionar com Ajax;
  • Nos desse algo para trabalhar com versões mobile dos sites;
  • Renderização em HTML, Json, XML, phpserialize, etc..

Veja as demais características no site do projeto.

O projeto quase não foi divulgado devido a falta de Documentação, porém, hoje, como ele está extremamente estável decidi criar este post para apresentá-lo. caso você queira testar, é só baixar e brincar. Ele já vem com um projeto de exemplo que ajuda a ter uma noção legal das funcionalidades.

Para finalizar alguns projetos usando ele:

Aguardo comentários.

Navegando onde não é possível navegar, usando SSH

abril 1st, 2009 por Carlos André Ferrari 2 comments »

No trabalho o acesso a qualquer site é bloqueado durante o horario de almoço e após o expediente, hoje pesquisando uma solução com um amigo, descobrimos os Tuneis SSH.

Para criar um túnel desses você precisa ter acesso a alguma maquina em algum lugar (fora do firewall ou proxy de sua rede que bloqueia a navegação) via SSH, eu possuo contas no dreamhost.com e crio o túnel passando por lá.

o comando para criação do tunel no linux é: ssh -D [usuario]@[servidor], exemplo:

ssh -D 9999 eu@meuservidor.com

Após digitar a sua senha, o tunel estará criado e funcionando perfeitamente, só que para navegar é necessário configurar os programas (Firefox, IM) para usarem este proxy.

No firefox a opção fica em Editar->Preferências->Avançado->Rede->Conexão->Configurar, chegando na tela, marque a opção de “Configuração Manual do Proxy”, no campo SOCKS, coloque o seu IP (127.0.0.1) e a porta 9999 (definida no exemplo acima) e tudo estará funcionando.

Como eu uso isso sempre, eu configurei meu pc para se autenticar sem pedir senha e coloquei o comando no rc.local:

/usr/bin/screen -DmUS proxy /usr/bin/ssh -D 9999 [usuario]@[servidor] &

Para finalizar, pelo Putty no Windows é possivel criar tuneis quase que da mesma maneira, é só ir na opção de Tuneis dele e preencher os dados do seu servidor e da porta que você deseja usar

Espero que tenha sido útil.

Criando Tweets pelo PHP

março 4th, 2009 por Carlos André Ferrari 2 comments »

Sou responsável por um site de notícias e hoje precisei criar um meio de que quando uma notícia for inserida no site, ser criado automaticamente um tweet no twitter lincando para ela, a solução foi essa classe abaixo:

class Tweet{
	var $user;
	var $pass;
	var $json = false;
 
	function __construct($user, $pass, $texto=false){
		$this-&gt;user = $user;
		$this-&gt;pass = $pass;
		if ($texto) $this-&gt;send($texto);
	}
 
	private function testTweet($texto, $match){
		foreach ($match as $m){
			$url = $m[0];
			if (ereg("^www", $url)) $url = "http://$url";
			if (strlen($url) &gt; 19) $url = str_repeat("x", 19);
			$texto = str_replace($m[0], $url, $texto);
		}
		$texto = ereg_replace("http://(x{19,})", "\\1", $texto);
		if (strlen($texto) &gt; 140) return false;
		return true;
	}
 
	public function makeUrl($url){
		if (ereg("^www", $url)) $url = "http://$url";
		if (strlen($url) &lt;= 19) return $url;
		$url = "http://migre.me/atalho/" . urlencode($url);
		$ch = curl_init();
		curl_setopt_array($ch, array(
			CURLOPT_URL =&gt; $url,
			CURLOPT_RETURNTRANSFER =&gt; true
		));
		$o = curl_exec($ch);
		ereg ("value=\"(http://migre.me/[a-zA-Z0-9/:]+)\"", $o, $mat);
		return $mat[1];
	}
 
	public function send($texto){
		if (function_exists("curl_init")){
			// Localiza as URLs
			preg_match_all("/((https?:\/\/)|(www))([a-zA-Z0-9\/:%&amp;\?\.=\-\+]+)/", $texto, $match, PREG_SET_ORDER );
 
			// Testa se o tamanho do twitter é aceitavel
			if (!$this-&gt;testTweet($texto, $match)) throw new Exception ("Postagem muito longa!");
 
			// Cria as URLs finais
			foreach ($match as $m) $texto = str_replace($m[0], $this-&gt;makeUrl($m[0]), $texto);
			$texto = str_replace("http://http://", "http://", $texto);
 
			// Testa novamente pelo comprimento do tweet
			if (strlen($texto) &gt; 140) throw new Exception ("Postagem muito longa!");
 
			// Envia o tweet
			$ch = curl_init();
			curl_setopt_array($ch, array(
				CURLOPT_URL =&gt; "http://twitter.com/statuses/update.json",
				CURLOPT_HTTPHEADER =&gt; array('Expect:'),
				CURLOPT_POST =&gt; 1,
				CURLOPT_POSTFIELDS =&gt; array("status" =&gt; "{$texto}"),
				CURLOPT_HTTPAUTH =&gt; CURLAUTH_ANY,
				CURLOPT_RETURNTRANSFER =&gt; true,
				CURLOPT_USERPWD =&gt; "{$this-&gt;user}:{$this-&gt;pass}")
			);
			return $this-&gt;json = curl_exec($ch);
		}
		return $this-&gt;json = false;
	}
}
 
$tmp = new Tweet("username", "password");
echo $tmp-&gt;send("Eu não gosto das URLs do site da Microsoft: http://search.microsoft.com/results.aspx?form=MSHOME&amp;setlang=en-us&amp;q=office+templates&amp;mkt=en-US");

Ela faz a análise do seu texto e converte as URLs, caso necessário, para um formato resumido usando o migre.me e caso passe os 140 caracteres uma exception é jogada.