Escalando PHP e MySQL: preparando uma startup para crescer

scaling

PHP e MySQL são excelentes alternativas para startups que planejam escalar sua infraestrutura desde a concepção do negócio.

Negócios online começam como um conceito na mente de um empresário e, geralmente, de início são implementados em um único servidor ou em um pequeno cluster. E se você for analisar, verá que realmente não faz sentido investir em uma estrutura grande se você não possui sequer um usuário. Até gigantes, como o Google, começaram assim. O hardware que eles possuíam no começo não impressionaria ninguém.

Primeiro "data center" do Google

Primeiro “data center” do Google

Nós todos sabemos o que aconteceu ao Google: em menos de cinco anos eles dominaram o mercado de buscadores e passaram a ocupar enormes data centers com design feito sob medida.

Algo semelhante, embora em uma escala menor, é o sonho da maioria dos empreendedores, mas para chegar lá é necessário pensar em escalabilidade dos servidores originais até algo que possa suportar uma carga muito mais pesada.

O plano de escalonamento deve ser desenvolvido muito antes de qualquer necessidade de crescer, porque se não houver plano, quando chegar a hora, será muito mais difícil e dispendioso – leia-se caro – do que o necessário.

Escalabilidade a partir do design

Uma maneira de escalar é ir aumentando progressivamente a capacidade do servidor com mais hardware, ou transferir gradualmente sua arquitetura para máquinas mais poderosas, mas essa abordagem possui limitações óbvias e pode demandar gastos desnecessários. Quando falamos em escalabilidade, falamos em escalabilidade horizontal, que é o processo de escalada com servidores em cluster e balanceador de carga.

PHP e MySQL comportam-se bem na construção de aplicações que podem escalar suavemente. Contudo, existem três tópicos importantes quando planejamos uma estrutura uma infraestrutura escalável para uma startup: pilha de software, cache e cluster.

Pilha de software

Escolher bem a maneira como vai empilhar seu software é crucial para uma escalada suave. Por exemplo, se você basear sua aplicação em PHP e MySQL mas não possuir um painel de controle que lhe permita adicionar mais nodes no seu MySQL Server e balancear a carga entre eles, seu negócio terá uma dificuldade considerável em crescer sem substituir pontos-chave da pilha.

Cache

O cache pode ser implementado em diversos pontos em um site ou na infraestrutura da aplicação. É importante para para melhorar o desempenho do hardware existente. Usuários de PHP e MySQL devem investigar o seguinte:

  • Memcached —É um sistema distribuído de cacheamento de objetos. Ele armazena objetos de um servidor de back-end, como um MySQL, que podem ser distribuídos através de múltiplos servidores, permitindo um grande aumento de performance quanto às consultas ao banco por dados acessados frequentemente.
  • APC (Alternative PHP Cache) — Sistema de opcode cache, que aumenta a performance de aplicações através do cacheamento dos códigos de operação de funções PHP executadas frequentemente.
  • XCache — Também é um opcode cacher, criado por um dos desenvolvedores do Lighttpd.
  • Zend Opcache — É um componente do Zend Server, que serve para acelerar a execução do PHP através do cache de opcode e otimizações em geral. Ele armazena o bytecode dos scripts pré-compilados em uma memória compartilhada e elimina a leitura de disco e compilação para acessos futuros.

Cluster

No coração de qualquer estratégia de escalada, mora a habilidade de adicionar rapidamente novos nodes de baixo custo e efetuar o balanceamento de carga entre eles. O MySQL pode ser facilmente configurado para usar um número determinado de servidores como slaves para a leitura e um master para a escrita, então se você planejar uma estratégia de escalonamento horizontal, PHP + MySQL é uma excelente combinação.

E lembre-se: planejar nos primeiros estágios de uma startup é algo essencial para assegurar a performance e disponibilidade permaneçam constantes durante a fase de crescimento, sem gerar gastos desnecessários.

Texto adaptado do original: http://www.thewhir.com/blog/php-and-mysql-scaling-preparing-a-startup-for-growth
Imagem: http://www.bitrebels.com/technology/whats-the-storage-capacity-at-google/

Curso gratuito de Segurança em PHP

icon-securephp-400

Fala galera! Venho aqui hoje pra compartilhar uma mega novidade!

Já pensou em fazer um curso de Segurança em PHP totalmente grátis?

Sua hora chegou! Em comemoração aos 5 anos do PHPit, fiz uma super parceria com o Code Squad e estamos lançando hoje o curso Segurança PHP – Proteção Backend no combate à linha de frente. E o melhor: 100% na faixa!

Mas como isso é possível? É uma iniciativa nossa, para que os programadores não desenvolvam mais aplicações capengas com a desculpa de que não têm como se aperfeiçoarem.

Em troca, a única coisa que pedimos é uma singela divulgação do nosso curso através de Facebook ou Twitter.

E aí, tá esperando o quê pra começar o curso? Acesse agora mesmo e comece a estudar!

Um bom curso a todos, fiquem com Deus e um forte abraço!

Rafa Jaques

Zend Framework 2 – Hydrators, Models e o Padrão TableGateway

hydrator3

Introdução

O Zend Framework 2 vem embalado com uma variedade de novos recursos e funcionalidades que agilizam o desenvolvimento em alguns cenários comuns, tais como a interação com bancos de dados, sistema de template, cache, etc.

Não importa se estamos falando dos novos elementos de formulário HTML5 e seus view helpers, a nova implementação do Zend\Http, o Service Manager, o Event Manager ou de tantos outros módulos – é possível perceber que o ZF2 anda arrebentando a boca do balão!

Mas existem alguns recursos que se sobressaem perante aos outros e, recentemente, têm me feito sorrir! Estou falando de: Hydrators, Models e Table Gateways. Se você é novo no ZF2 ou nunca utilizou interação de frameworks com bancos de dados, este artigo foi escrito pra vocês, pois dá uma boa introdução à utilização desses dois juntos.

Alguma vez você já se perguntou para que servem Hydrators ou Table Gateways? Hoje veremos esses componentes mais de perto!

Nós iremos trabalhar com um código de exemplo que ensinará como criar models desacoplados da lógica do recebimento de dados através de uma configuração simples no ServiceManager. Veremos também um não-tão-complexo hydrator que será capaz de extrair informações de uma consulta no banco de dados e preencher o model automaticamente.

Por que essa abordagem?

No Zend Framework 1, quando você precisava ter uma camada de modelo independente da fonte de dados, nem sempre era simples de implementar. Embora se fale muito em PHP e MySQL, todos sabemos que existe uma infinidade de opções, tais como: MongoDB, CouchDB, PostgreSQL, Cassandra, Redis e muito, muito, muito mais.

Algumas aplicações que desenvolvemos, podem começar com necessidades simples, modestas. No começo, talvez um SGBD básico seja suficiente. Mas, conforme suas necessidades mudam e crescem, é bom saber que, sem muita refatoração de código, será possível adaptar seu sistema.

O que veremos hoje é isso! Permitiremos uma fonte de dados quase transparente, pois a camada de modelo não saberá nada sobre essa fonte. Isso vai nos ajudar a assegurar que, independentemente de qual local venha a informação, ela será transformada de uma maneira que o model seja capaz de utilizá-la.

Como funciona?

hydrator_uml
Vou tentar explicar em poucas palavras como funciona. Primeiro, a classe TableGateway realiza a interação específica com a base de dados, como buscar, adicionar, atualizar ou remover dados. Nesse caso, vamos trabalhar com um banco MySQL 5. Então, a classe Hydrator irá mapear (e transformar, quando necessário) a informação recuperada da TableGateway para classe Model.

No método getServiceConfig na nossa classe Module, as duas são unidas e o Hydrator é configurado. Por fim, em uma action do controller poderemos acessar fonte de dados, consultar registros, auto-popular nossa Model e então trabalhar sobre os registros retornados. Ótima ideia, não?

Então vamos lá!

A classe TableGateway

Aqui nós temos a classe TableGateway. Eu a chamei de UserTable, pois ela é responsável por gerenciar informações em uma tabela de usuários. Mantive simples, focando apenas em retornar os registros, deixando de lado as outras operações de CRUD.

No construtor, passamos um objeto TableGateway que será disponibilizado na configuração do ServiceManager. Isso nos fornece um modo simples de acessar o banco de dados. No método fetchAll(), recuperamos um result set chamado o método select() no objeto TableGateway.

As chamadas de buffer() e next() não são exatamente necessárias, mas precisamos incluí-las já que, na ação da listagem, um objeto Paginator é retornado. Erros serão lançados se esses dois métodos não forem chamados.

namespace Phpit\Model;

use Zend\Db\TableGateway\TableGateway;

class UserTable
{
    protected $tableGateway;

    public function __construct(TableGateway $tableGateway)
    {
        $this->tableGateway = $tableGateway;
    }

    public function fetchAll()
    {
        $resultSet = $this->tableGateway->select();
        $resultSet->buffer();
        $resultSet->next();
        return $resultSet;
    }
}

A classe Modelo

Agora temos a classe User. Como você pode ver, esta classe não tem nenhum código referenciando qualquer tipo de fonte ou banco de dados. Aqui estamos preocupados apenas com os dados que desejamos trabalhar, que neste caso são:

  • userId: id do usuário
  • userName: nome
  • userActive: flag de ativo/inativo
  • createdDate: data de criação do registro

O método exchangeArray é comumente utilizado no ZF2 para passar um dataset, nesse caso um array para auto-popular o objeto. É possível ver que eu estabeleci todas as propriedades relacionadas com as chaves respectivas do array. Fácil, limpo e simples.

namespace Phpit\Model;

class User
{
    public $userId;
    public $userName;
    public $userActive;
    public $createdDate;

    public function exchangeArray($data)
    {
        if (isset($data['userName'])) {
            $this->userName = $data['userName'];
        } else {
            $this->userName = null;
        }

        if (isset($data['userActive'])) {
            $this->userActive = $data['userActive'];
        } else {
            $this->userActive = null;
        }

        if (isset($data['userId'])) {
            $this->userId = $data['userId'];
        } else {
            $this->userId = null;
        }

        if (isset($data['createdDate'])) {
            $this->createdDate = $data['createdDate'];
        } else {
            $this->createdDate = null;
        }
    }

    public function getArrayCopy()
    {
        return get_object_vars($this);
    }
}

O Hydrator

O Hydrator é o aspecto-chave da configuração. É o que mapeia e faz a ligação entre os nomes dos campos no banco de dados e as propriedades da entidade no outro. No entanto, ele não armazena essas informações internamente (como você verá). Tentei ir para uma abordagem mais genérica, uma classe que possa ser aplicada em qualquer tabela.

Com isso nós podemos passar um array de Nomes de Colunas -> Propriedades da Entidade e, quando o método de hydrate for chamado, transferir a informação respectiva da fonte de dados para o objeto de modelo.

namespace Phpit\Hydrator;

use ReflectionMethod;
use Traversable;
use Zend\Stdlib\Exception;
use Zend\Stdlib\Hydrator\AbstractHydrator;
use Zend\Stdlib\Hydrator\HydratorOptionsInterface;

class TableEntityMapper
    extends AbstractHydrator
    implements HydratorOptionsInterface
{
    protected $_dataMap = true;

    public function __construct($map)
    {
        parent::__construct();
        $this->_dataMap = $map;
    }

    public function extract($object) {}

No método de hydrate, passamos a fonte de dados e o modelo. Se o modelo não for um objeto, nós lançamos uma excessão do tipo BadMethodCallException. Se for, prosseguimos e começamos a iterar sobre os dados disponíveis.

Se não houver um mapeamento disponível, vamos determinar qual campo no modelo corresponde a determinado campo na fonte de dados. Se isso não precisaremos realizar essas determinações (se nenhum mapeamento for necessário), vamos definir a propriedade diretamente. Quaisquer propriedades desconhecidas ou ausentes são silenciosamente ignoradas.

    public function hydrate(array $data, $object)
    {
        if (!is_object($object)) {
            throw new Exception\BadMethodCallException(sprintf(
                '%s expects the provided $object to be a PHP object)',
                __METHOD__
            ));
        }

        foreach ($data as $property => $value) {
            if (!property_exists($this, $property)) {
                if (in_array($property, array_keys($this->_dataMap))) {
                    $_prop = $this->_dataMap[$property];
                    $object->$_prop = $value;
                } else {
                    // unknown properties are skipped
                }
            } else {
                $object->$property = $value;
            }
        }

        return $object;
    }
}

A configuração do Module Service

Na configuração do Módulo nós iremos juntar tudo. Sem este componente, não seria possível fazer o resto. Em primeiro lugar, vamos registrar um objeto na lista de factories, que inicializará UserTable e passará o objeto para o TableGateway.

Em seguida, temos a configuração do objeto TableGateway. A abordagem que vamos utilizar é baseada no tutorial de hydration do Evan Coury. O que temos aqui é o seguinte: durante a execução o adapter do banco é retornado, nós inicializamos uma instância do hydrator e a alimentamos com o array de mapeamento; os nomes das colunas da tabela à esquerda e as propriedades do modelo à direita. Em seguida, fornecemos o User model como o protótipo a ser usado com o objeto HydratingResultSet. Se você não estiver familiarizado com ele, o HydratingResultSet é uma parte surpreendente do Zend Framework 2. Não vou tentar reinventar a roda, então vou apenas traduzir o que está escrito no manual:

Zend\Db\ResultSet\HydratingResultSet é uma versão mais flexível do objeto ResultSet que permite aos desenvolvedores escolherem uma “estratégia de hydration” (hydration strategy) para pegar dados de uma linha em um objeto-alvo. Enquanto estiver iterado sobre os resultados, HydratingResultSet pegará o protótipo de um objeto-alvo e o clonará para cada linha. O HydratingResultSet então irá preencher (hydrate) esse objeto clone com os dados da linha.

Basicamente, nós fornecemos o modelo e os dados e o hydrator cuida do resto. Depois disso, retornamos um novo objeto TableGateway especificando a tabela referente, tbluser, que será a fonte de dados, o adapter de banco de dados e o objeto de resultset que acabamos de inicializar. Agora, nós temos os dois lados da equação bem unidos. Caso ocorra mudança no nome da tabela, nas propriedades ou nos nomes das colunas, só precisamos fazer pequenos ajustes aqui ou ali. Não há necessidade de tocar em outras classes ou trechos de código.

public function getServiceConfig()
{
    return array(
        'factories' => array(
            'PhpitAdmin\Model\UserTable' =>  function($sm) {
                $tableGateway = $sm->get('UserTableGateway');
                $table = new UserTable($tableGateway);
                return $table;
            },
            'UserTableGateway' => function ($sm) {
                $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                $hydrator = new \Phpit\Hydrator\TableEntityMapper(
                    array(
                        'UserID' => 'userId',
                        'UserName' => 'userName',
                        'StatusID' => 'userActive',
                        'CreatedOn' => 'createdDate'
                    ));
                $rowObjectPrototype = new \Phpit\Model\User;
                $resultSet = new \Zend\Db\ResultSet\HydratingResultSet(
                    $hydrator, $rowObjectPrototype
                );
                return new TableGateway(
                    'tbluser', $dbAdapter, null, $resultSet
                );
            }
        )
    );
}

O Controller

Maravilha! Agora está na hora de aprender como usar. No nosso controller nós possuímos uma action de listagem. Ela irá retornar os registros e nós iremos iterar sobre eles.

namespace PhpitManagementAdmin\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Phpit\Model\User;
use Phpit\Form\AddUserForm;
use Phpit\Form\EditUserForm;

class userController extends AbstractActionController
{
    protected $userTable;
    protected $_createUserForm;

    public function listAction()
    {

Em primeiro lugar, recuperamos uma cópia do objeto userTable através do Service Locator. Em seguida, chamamos o método fetchAll(), e recuperamos todas as linhas da tabela. Eu usei um filter iterator e um paginator para deixar o exemplo mais completo.

O filter iterator só retornará registros nos quais o campo userActive estiver definido como “ativo”. Todos os outros serão ignorados. Este iterator é então passado para o objeto Zend\Paginator, algumas propriedades são definidas e então é devolvido no ViewModel, pronto para ser iterado na nossa view.

        $sm = $this->getServiceLocator();
        $userTable = new \Phpit\Model\UserTable(
            $sm->get('userTableGateway')
        );

        $filterIterator = new StatusFilterIterator(
            $userTable->fetchAll(), "active"
        );
        $paginator = new Paginator(new Iterator($filterIterator));

        $paginator->setCurrentPageNumber(
            $this->params()->fromRoute('page')
        );

        $paginator->setItemCountPerPage(
            $this->params()->fromRoute('perPage', 10)
        );

        return new ViewModel(array(
            'paginator' => $paginator,
            'status' => $this->params()->fromRoute('status')
        ));
    }
}

Considerações finais

E, finalmente, estamos prontos. Com apenas um pouquinho de código, criamos um model que é capaz de interagir com uma variedade de fontes de dados e, ao mesmo tempo, conseguimos evitar um acoplamento forte. Se formos sair do MySQL para o PostgreSQL ou o Redis, então poderemos fazer algumas pequenas alterações e tudo estará funcionando novamente.

Eu não sou tão experiente com hydrators, data mappers e table gateway pattern como os outros, portanto adoraria que vocês contassem e dessem suas sugestões para melhorar essa abordagem. Aproveito e deixo a dica de um artigo sobre Strategies, escrito por Jurian Sluiman.

Espero que tenham gostado e que possa ser útil no desenvolvimento.

Um abraço a todos e fiquem com Deus!
Texto adaptado do original: http://www.maltblue.com/tutorial/zendframework2-hydrators-models-tablegateway-pattern

proc_open: Comunicando-se com o mundo lá fora

Comunicando-se com o mundo lá fora

Existem diversas maneiras de interagir com outras aplicações a partir do PHP para compartilhar dados: web services, serviço de enfileiramento de mensagens, sockets, arquivos temporários, exec(), etc. Bem, hoje eu gostaria de apresentar uma abordagem específica: proc_open(). A função executa um novo comando, mas deixa os ponteiros de arquivos abertos para enviar e receber dados, buscando comunicação interprocessos (IPC – Interprocess Communication).

O que é um Redirecionador de E/S?

Para entender como a função proc_open() envia e recebe dados, você precisa saber o que é um Redirecionador de Entrada/Saída.

A Filosofia Unix fez com que desenvolvedores escrevessem diversos pequenos programas com funcionalidades muito específicas. Estes programas compartilhavam o texto plano como formato de entrada/saíde e os usuários poderiam encadeá-los para obter funcionalidades maiores. As ligações virtuais que permitiam com que os dados corressem através de diferentes comandos ficaram conhecidas como redirecionadores de entrada/saída.

Se você já trabalhou em um shell do Unix então existe uma grande possibilidade de você já ter utilizado (talvez sem nem perceber). Por exemplo:

$ mysql -u usuario -p teste < dados.sql

Aqui chamamos a ferramenta mysql é logo após o sinal de redirecionamento indicamos um arquivo. Essa chamada fará com que todos o conteúdo de dados.sql seja enviado para a entrada padrão de mysql, como se você estivesse digitando direto do seu teclado.

Quando falamos de redirecionamento, também falamos de pipes. Pipes são encadeamentos de entradas e saídas. Existem dois tipos de pipes: anônimos and nomeados. O pipe anônimo é ad hoc (designado para uma função específica), que persiste apenas enquanto o processo estiver rodando e é destruído assim que não é mais necessário. Já o pipe nomeado recebe um nome e pode durar por tempo indeterminado. É criado utilizando comandos específicos e volta e meia aparecem com tipos de arquivos especiais no sistema de arquivos.

Independentemente do tipo, uma propriedade importante de pipes e redirecionamentos é que são estruturas FIFO (first in, first out – primeiro a entrar, primeiro a sair). Isso significa que o primeiro dado que é escrito em um pipe ou redirecionamento é o primeiro a ser lido pelo processo que está do outro lado.

Introdução à função proc_open()

A função PHP proc_open() executa um comando, bem parecido com o modo que a função exec() faz, mas com a habilidade de “canalizar” os streams de entrada e saída. Aceita alguns argumentos opcionais, mas os obrigatórios são:

  • um comando para ser executado;
  • um array que descreva os pipes que serão utilizados;
  • um array passado por referência que será preenchido posteriormente com referências aos pipes, assim você poderá enviar e receber dados;

Você pode encontrar mais informações sobre esse comando e os outros parâmetros no manual do PHP.

Além do comando que você deseja executar, eu diria que o array descritor que define os pipes é o argumento mais importante. A documenta explica como “Uma matriz indexada onde a chave representa o número do descritor e o valor representa como o PHP passará este descritor para o processo filho”, mas o que isso que dizer?

Os três principais fluxos (streams) de dados de um processo unix são: STDIN (standard input – entrada padrão), STDOUT (standard output – saída padrão) e STDERR (standard error – erro padrão). Ou seja, há um fluxo para entrada de dados, um para saída e um segundo para saída para mensagens de informação. Tradicionalmente STDIN é representada pelo número 0, STDOUT por 1 e STDERR por 2. Logo, a definição com a chave 0 será utilizada para configurar o stream de entrada, 1 para o stream de saída e 2 para stream de erros.

Essas definições podem tomar uma de duas formas: um recurso apontando para um arquivo aberto ou um array que descreve a natureza do pipe. Para um pipe anônimo, o primeiro elemento do array descritivo é a string “pipe” e o secundo é “r”, “w” ou “a”, dependendo se o pipe está no formato read (leitura), write (escrita) ou append (acrescentar). Para pipes nomeados, o array descritivo possui a string “file”, o nome do arquivo e então “r”, “w” ou “a”.

Uma vez chamada, a função proc_open() preenche o vetor que foi designado nos parâmetros com com referências que apontarão para o o processo. Os elementos na referência podem ser tratados como descritores de arquivos normais e trabalham tranquilamente com funções de stream como fwrite()fread()stream_get_contents(), etc.

Quando tiver terminado de interagir com o comando externo, é importante dar uma limpada em tudo. Você pode fechar os redirecionamentos criados (com fclose()) e o resource do processo (com proc_close()).

Dependendo da maneira como o comando/processo se comporta, pode ser necessário que você encerre a entrada de dados (STDIN) antes que ele comece a trabalhar (assim saberá que não deve esperar nenhuma outra entrada). Também é interessante que você feche as conexões STDOUT e STDERR antes de encerrar o processo, ou então seu processo pode ficar pendurado até que tudo esteja limpo para ser encerrado.

Um exemplo prático: convertendo marcação Wiki

Até agora eu só falei sobre como as coisas funciona, mas não apresentei nenhum exemplo utilizando proc_open() para realizar comunicação com um processo externo. Vamos ver o quão fácil é!

Vamos supor que precisamos converter uma porção de texto com marcação wiki para HTML e mostrar no navegador do usuário. Usaremos a ferramenta Nyctergatis Markup Engine (NME) para realizar a conversa, porém ela é compilada em C. Precisamos de uma maneira de executar o comando nme quando necessário e passar dados de entrada e receber dados de saída.

<?php
// array descritor
$desc = array(
    0 => array('pipe', 'r'), // 0 - STDIN
    1 => array('pipe', 'w'), // 1 - STDOUT
    2 => array('file', '/tmp/saida-erros.txt', 'a') // 2 - STDERR
);

// comando que chama a ferramenta nme
$cmd = "nme --strictcreole --autourllink --body --xref";

// inicia o processo
$p = proc_open($cmd, $desc, $pipes);

// envia o conteúdo da wiki como entrada para a ferramenta e então
// fecha o pipe de entrada, assim a ferramenta saberá que não deve
// mais esperar entradas e poderá iniciar o processo
fwrite($pipes[0], $conteudo_wiki);
fclose($pipes[0]);

// lê a saída da ferramenta
$html = stream_get_contents($pipes[1]);

// tudo pronto! hora de limpar o que ficou
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($p);

Primeiro o array descritor definido com 0 (STDIN) como pipe anônimo que será legível pela ferramenta de markup, 1 (STDOUT) como pipe anônimo com possibilidade de escrita pela ferramenta e 2 (STDERR) redirecionando qualquer mensagem de erro para um arquivo de log.

O “r” e o “w” na definição do pipe podem parecer contra-intuitivos à primeira vista, mas tenha em mente que são canais que a ferramenta usará e, portanto, a configuração é feita sob esse ponto de vista. Nós escrevemos no pipe de leitura porque será de lá que a ferramenta lerá dados. Nós lemos do pipe de escrita porque será lá que a ferramenta estará escrevendo.

Considerações finais

proc_open(), dependendo do que você precisa trabalhar

Existem diversos meios de interagir com processos externos. Algumas podem ser melhores do que utilizar proc_open() dependendo do que você precisa trabalhar, ou então proc_open() pode ser justamente o que o seu médico te receitou para esse caso. É óbvio que você vai implementar algo que faça sentido, mas agora você já sabe qual é a ferramenta que vai precisar para isso!

Espero que tenham gostado e que possa ser útil para as aplicações que estão desenvolvendo.

Um forte abraço a todos e fiquem com Deus!

Texto adaptado do original: http://phpmaster.com/proc-open-communicate-with-the-outside-world/

PHPit e ABRAPHP no Fórum Internacional de Software Livre

FISL

Fala, meu povo!

Estou aqui para convidá-los a participarem do XIV Fórum Internacional de Software Livre.

Na programação teremos diversas palestra sobre PHP (como sempre), mas haverá também algo muito especial: no sábado (06/07) acontecerá o encontro comunitário da Associação Brasileira de Profissionais de PHP, das 16h às 18h.

Estaremos todos lá!

Um dia antes, na sexta (05/07), apresentarei uma palestra intitulada Segurança na Era Digita: ensinando novos hábitos aos indivíduos digitais. Para quem interessar, ocorrerá na sala 41D às 14h.

Fora isso, estarei sempre ali pelo evento, geralmente no stand do TcheLinux.

Podem também entrar em contato pelo twitter e marcarmos um local pra trocar uma ideia!

Nos vemos lá!

Um forte a braço a todos e fiquem com Deus!

Layout 2013 – PHPit de cara nova!

phpit2013

Finalmente! Fazia tempo que o blog não passava por uma repaginada.

Aposentei o layout dark antigo e optei por desenvolver algo mais clean dessa vez.

Não sou a pessoa mais indicada para trabalhar com design, mas acho que o resultado final ficou bastante satisfatório.

Processo de desenvolvimento

Quero deixar aqui umas rápidas considerações sobre as ferramentas que usei no processo de desenvolvimento.

Demorei dois dias pra montar esse layout. Dentre as ferramentas, convém citar o seguinte:

  • PHP: Óbvio. Não preciso dizer o porquê.
  • WordPress: É a ferramenta que optei por utilizar desde o começo. Com ela desenvolvo o blog desde o primeiro post, em 2007. Para blogs, ouso dizer que não existe ferramenta melhor. Com um pouquinho de suor você aprende a montar templates e então não sofrerá mais na hora de migrar o layout. Demorei cerca de 30 minutos pra deixar o layout novo no ar e funcionando redondinho.
  • Bootstrap: Este é um framework para desenvolvimento front-end. Me ajudou a acelerar o desenvolvimento e disponibilizou diversos componentes pra não precisar reinventar a roda.
  • jQuery: Essencial em qualquer projeto moderno. Acelera o desenvolvimento JavaScript e assegura que seu código rodará em qualquer navegador. Utilizei diversos plugins da própria jQuery e, pras coisas que não encontrei nada pronto, desenvolvi na mão (também usando a biblioteca), como foi o caso da barra de redes sociais aqui ao lado.
  • Roots: Tema base desenvolvido com HTML5 Boilerplate e Bootstrap. Já vem com os loops prontos e com uma hierarquia bem fácil de trabalhar.
  • SimpleIcons: Precisei de ícones padronizados de redes sociais pra fazer a minha sidebar. Encontrei essa biblioteca de que é realmente muito completa.

Considerações

Desde já fico com o canal aberto para receber sugestões para adaptação e correção no layout.

Aproveito também pra deixar meu muito obrigado a todos aqueles que me deram boas dicas durante o desenvolvimento :)

 

Um forte abraço a todos e fiquem com Deus!