Archive for the ‘php’ category

Apache2 + PHP-FPM no Ubuntu

abril 16th, 2013

As vezes precisamos de um servidor web com performance excelente porém ficamos presos a necessidade do famoso htaccess do apache, então vamos configurar o Apache2 para trabalhar com o PHP-FPM no Ubuntu.

Primeiro vamos instalar o apache2, o php e alguns módulos:

sudo apt-get install apache2-mpm-worker libapache2-mod-fastcgi php5 php5-fpm php5-cgi php-apc

Agora vamos configurar nosso apache para encaminhar as requisições para serem executadas pelo fpm:

Primeiro habilite os módulos que iremos utilizar:

sudo a2enmod actions fastcgi alias rewrite

É necessário um script para que o apache consiga se comunicar com o php-fpm, crie o arquivo /usr/bin/php5-fcgi:

sudo nano /usr/bin/php5-fcgi

E coloque o seguinte conteúdo:

#!/bin/sh
exec /usr/bin/php5-cgi

Agora faça com que este arquivo seja executável:

chmod +x /usr/bin/php5-fcgi

Edite o arquivo /etc/apache2/conf.d/httpd

sudo nano /etc/apache2/conf.d/httpd

E coloque as configurações padrões para todos os vhosts:

<IfModule mod_fastcgi.c>
        AddHandler php5-fcgi .php
        Action php5-fcgi /php5-fcgi
        Alias /php5-fcgi /usr/bin/php5-fcgi
        FastCgiExternalServer /usr/bin/php5-fcgi -socket /var/run/php5-fpm.sock -pass-header Authorization
</IfModule>
<Directory />
	Options FollowSymLinks
	AllowOverride None
</Directory>
<Directory /var/www/>
	Options Indexes FollowSymLinks MultiViews
	AllowOverride All
	Order allow,deny
	allow from all
</Directory>

Edite o arquivo /etc/apache2/sites-enabled/000-default e deixe assim:

<VirtualHost _default_:80>
	DocumentRoot /var/www/
</VirtualHost>

Reinicie o apache:

sudo apache2ctl restart

Crie um arquivo de testes em /var/www/info.php e coloque o seguinte conteúdo

<?php
phpinfo();

Agora é só testar no seu browser, acessando o endereço: http://localhost/info.php

Pegando a temperatura de qualquer cidade

julho 29th, 2010

Me surgiu um trabalho aqui pelo qual preciso exibir a temperatura atual da cidade, e como estava com insônia decidi brincar um pouco e criar uma solução para isso, fui para o google e pesquisei por “Previsão do Tempo“, me surgiram alguns resultados, porém, gostei mais do UOL.

Depois disso foi correr para a criação do script para ler o HTML e retornar um objeto contendo as informações da temperatura no momento, segue o código escrito em php:

function loadTemp($cidade='Palmas-TO'){
	// variavel para dados de retorno
	$ret = array('url' => "http://tempoagora.uol.com.br/previsaodotempo.html/brasil/$cidade/");
 
	// carrega o html do tempoagora
	$html = file_get_contents($ret['url']);
 
	// Pegamos apenas a parte que interessa do html
	$iniflag = '<!-- Insere dados Atuais de AeroPortos ou Est. Meteorologica -->';
	$fimflag = '<!-- FIM Insere dados Atuais de AeroPortos ou Est. Meteorologica -->';
	$ini = strrpos($html, $iniflag ) + strlen($iniflag);
	$fim = strpos($html, $fimflag, $ini);
	$html = substr($html, $ini, ($fim-$ini));
 
	// pegamos a url do icone
	preg_match('@<img src="/(imagens/icones/[a-zA-Z\-]+.gif)"@', $html, $mat);
	$ret['icone'] = 'http://tempoagora.uol.com.br/' . $mat[1];
 
	// Limpa o código html
	$content = strip_tags($html);
	$content = str_replace('&nbsp;', ' ', $content);
 
	// quebra o que sobrou em um vetor
	$content = explode("\n", $content);
 
	// limpa espaços e linhas em branco
	foreach ($content as $k => &$v){
		$v = trim($v);
		if ($v==='') unset($content[$k]);
	}
 
	// pega horário da verificação
	$lin = array_shift($content);
	preg_match('@[0-9]{1,2}:[0-9]{1,2}@', $lin, $mat);
	$ret['verificado']  = $mat[0];
 
	// pega insidência de nuvens
	$ret['nuvens'] = array_shift($content);
 
	// define nomes melhores para as próximas propriedades
	$keys = array('temperatura', 'sensacao', 'vento', 
			'pressao', 'umidade', 'visibilidade');
 
	// reseta as chaves do vetor
	$content = array_unique($content);
 
	// percorre chaves impares e aplica as propriedades definidas acima
	for ($x=1; $x<=11; $x=$x+2){
		$ret[array_shift($keys)] = $content[$x];
	}
 
	// retorna os dados como um objeto
	return (object)$ret;
}

Analisando o site deles, notei que a temperatura é atualizada de hora em hora, então a melhor forma de utilizar essa solução é utilizando o crontab, que executa a cada hora, eu escolhi executar no quinto minuto de cada hora cheia (5:05, 6:05, etc).

segue o código php que o crontab executa:

require 'loadTemp.php';
// define nome do arquivo de cache
$cache_file = sys_get_temp_dir() . '/temp';
 
// carrega a temperatura
$temp = loadTemp();
 
// salva em cache
file_put_contents($cache_file, serialize($temp));

E para exibir no sistema eu fiz uma funçãozinha:

function temp(){
	$cache_file = sys_get_temp_dir() . '/temp';
	// se o cache existe, retorna o objeto
	if (file_exists($cache_file)) 
		return unserialize(file_get_contents($cache_file));
 
	// senão cria o cache e retorna =)
	$temp = loadTemp();
	file_put_contents($cache_file, serialize($temp));
	return $temp;
}

depois, no local específico, ficou algo mais ou menos assim:

<?php $temp = temp() ?>
<img src="<?php echo $temp->icone ?>" alt="<?php echo $temp->nuvens ?>" />
<span><?php echo $temp->temperatura ?> (<a rel="external" href="<?php echo $temp->url ?>">saiba mais</a>)</span>

Minha forma de pagar por esse uso é manter um link para o Tempoagora, o que é bastante interessante, pois meu visitante pode querer obter mais informações

É isso ai, abraço a todos

Classe, WebService e RSS para rastreamento de encomendas nos Correios em PHP

abril 10th, 2010

Olá, depois de meses sem escrever estou voltando com uma classe muito útil e simples que nunca vi em lugar nenhum. É uma classe para rastrear encomendas nos correios que eu escrevi em PHP, que retorna um vetor com cada modificação de status lá.

Vamos direto ao ponto, confira o exemplo:

http://ferrari.eti.br/correios/samples/class.php

E para deixar a brincadeira mais divertida, fiz também um webservice com suporte a Json (padrão), phpserialize, XML e um modo dump, para visualização:

http://ferrari.eti.br/correios/webservice/?q=PB151832535BR
http://ferrari.eti.br/correios/webservice/?q=PB151832535BR&f=dump
http://ferrari.eti.br/correios/webservice/?q=PB151832535BR&f=serial
http://ferrari.eti.br/correios/webservice/?q=PB151832535BR&f=xml
e claro, para quem usa Ajax:
http://ferrari.eti.br/correios/webservice/?q=PB151832535BR&callback=minhaFuncJs

Disponibilizei tanto a classe quanto o código do webservice (que tem suporte a caching!) “de grátis” e com licença BSD no github:

http://github.com/caferrari/correios/

*UPDATE* Adicionado um gerador de RSS, assim é possível usar o proprio agregador para fazer o tracking!

http://ferrari.eti.br/correios/rss/?PB151832535BR

e em homenagem aos atendentes de telemarketing: Estarei esperando forks e colaborações para a classe, além de comentários!.

Até a próxima.

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

janeiro 15th, 2010

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.

Market Share de navegadores no final de 2009

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-fpm php5-xcache php5-gd php5-curl \
php5-mysql php5-pgsql libssl-dev libpcre3-dev build-essential -y

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 >&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:

 
e acesse: http://ip_do_servidor/

nginx – webserver, proxy reverso e perfeito!

outubro 15th, 2009

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%.