Todo mundo conhece o tal Proxy. Quer queira quer não, na maioria das vezes as empresas utilizam um proxy como intermediador entre seus usuários e a Internet em geral. Enquanto o firewall bloqueia todo o acesso externo, deixa apenas essa brecha para os clientes conectarem no Proxy, então este controla tudo o que entra e sai pela Web.
Esse controle do Proxy geralmente tem como objetivo não deixar as pessoas usar sites indevidos. Em algumas empresas, isto é verdade também para os servidores. Forçando os servidores a sair pra internet apenas por um proxy, os administradores tem um controle e logs do que os servidores fazem, podem mensurar e ainda colocam uma camada de segurança a mais, onde possíveis códigos maliciosos nas aplicações web não consigam sair para a internet.
O WordPress tem sido uma predileção minha. Dentro de uma empresa, tive que levantar porque de algumas coisas não estarem funcionando em uma instalação do WordPress. Consegui identificar alguns erros causados pela falta de proxy:
- Alguns templates usavam includes de outros servidores fora da rede interna, esses includes não funcionavam;
- Na hora de agendar posts para o futuro, alguns blogs não postavam na hora e no post aparecia a mensagem “Agenda perdida”, ou “Miss Schedule”;
- Alguns widgets do dashboard (painel de administração) não funcionavam;
- Anti-SPAM Akismet não funcionava de maneira correta.
Todos estes problemas têm em comum a ação de sair para a Internet via porta 80 para pegar alguma informação: um pedaço de template, o webservice do akismet para anti-spam, o arquivo de cron do wordpress para posts agendados, atualizações e notícias externas do WordPress, entre outros. Na empresa, o servidor só podia sair para estes lugares por um proxy.
Pesquisando por aí, inclusive no oráculo, descobri através da API HTTP no WordPress Codex que desde a versão 2.7 do WordPress, os métodos de requisição externos do WordPress suportavam proxy, mas isso está relativamente não-documentado e me pareceu bem desconhecido durante algum tempo. Como não gosto de usar coisa velha, vou falar aqui como utilizar a partir da versão 2.8.
Configuração
Para configurar um proxy no WordPress 2.8+, edite o arquivo wp-config.php e inclua as seguintes linhas:
define('WP_PROXY_HOST', '192.168.0.1'); define('WP_PROXY_PORT', '3128'); define('WP_PROXY_USERNAME', 'usuario'); define('WP_PROXY_PASSWORD', 'senha'); define('WP_PROXY_BYPASS_HOSTS', 'localhost, www.example.com');
Sendo que as linhas 3 a 6 são opcionais. Se o seu proxy não tiver qualquer tipo de autenticação, é só indicar as linhas de Host e Porta do Proxy. A última opção corresponde aos hosts que o WordPress precisa ir direto, sem passar por proxy algum, ou seja, uma lista de excessões.
As configurações acima servem para todo tipo de chamada que o WordPress faz internamente. A aplicação em si tem uma API HTTP que ela usa para fazer essas requisições externas. Alguns exemplos de funções que usam esta API são:
- wp_remote_get() – Faz uma requisição de URL usando o método HTTP GET.
- wp_remote_post() – Faz uma requisição de URL usando o método HTTP POST.
- wp_remote_head() – Faz uma requisição de URL usando o método HTTP HEAD.
- wp_remote_request() – Faz uma requisição de URL usando o padrão GET ou um método HTTP personalizado (use sempre maiúsculo) que você especificar.
- wp_remote_retrieve_body() – Pega apenas o corpo da resposta da requisição.
- wp_remote_retrieve_header() – Obtém um cabeçalho HTTP baseado em nome, da resposta da requisição.
- wp_remote_retrieve_headers() – Obtém todos os cabeçalhos HTTP em uma array para processamento.
- wp_remote_retrieve_response_code() – Obtém o número da resposta HTTP. Geralmente é 200, mas pode ser 4xx ou até 3xx em algumas falhas.
- wp_remote_retrieve_response_message() – Obtém a mensagem de resposta baseada no código de resposta.
E para o PHP…
E se você precisar configurar o PHP para também utilizar um proxy para suas chamadas de arquivos externos, também há alguns truques. Este foi um pouco mais difícil de encontrar e o achei obscuramente nesta entrada de request do php. Legal seria se isso virasse realmente uma opção do php.ini, mas por enquanto ainda não tem.
O jeito agora, pelo menos a partir do PHP 5.1, é adicionar as seguintes linhas antes de qualquer código que vá usar uma requisição externa, que no caso do WordPress, pode ser no wp-config.php:
$context = stream_context_get_default(); stream_context_set_option($context, 'http', 'proxy', 'tcp://192.168.0.1:3128');
Onde na segunda linha, você coloca o endereço e porta do servidor proxy na forma tcp://endereço-ip:porta. Agora as funções do PHP que utilizarem os wrappers de protocolo HTTP agora vão passar pelo proxy. Alguns exemplos de funções que vão passar pelo proxy:
- fopen(“http://www.example.com/page.html”,r);
- readfile(“http://www.example.com/page.html”);
- file(“http://www.example.com/page.html”);
- file_get_contents(“http://www.example.com/page.html”);
Em meus testes, porém, as seguintes funções não passaram:
- include(“http://www.example.com/page.html”);
- require(“http://www.example.com/page.html”);
Então fique ligado nessas funções, e se for usar uma nova, teste antes para ver se realmente passa pelo proxy de forma correta.
Templates do WordPress
Uma vez configurado o proxy no wp-config.php via as constantes WP_PROXY_*, é preferível que em qualquer código que você faça no wordpress, usar sempre a API HTTP dele para fazer chamadas externas.
Antes de mais nada, não é nada legal utilizar, por exemplo, um include() ou um require() externo, pois você estará executando código PHP de um servidor externo. Neste caso, só se usa este tipo de instrução se você confiar totalmente no servidor externo (e de preferência, tiver o controle dele também).
Agora se você estiver fazendo um template WordPress e quiser pegar partes de páginas em um lugar externo, como por exemplo um rodapé, um banner, uma barra de menu, entre outros, ao invés de usar um include() ou require(), utilizar sempre assim:
echo wp_remote_retrieve_body(wp_remote_get('http://www.example.com/page.html'));
Desta forma, você apenas mostra na tela o conteúdo dessa página externa, sem interpretar códigos PHPs caso existam.
Referências
Óbvio que não tem como a gente aprender as coisas do vácuo, então aqui vão as referências que usei para obter esse conhecimento:
- API HTTP do WordPress
- Este Request Entry no PHP.net
- How to make HTTP requests with WordPress por Ozh