PHP + Apache como proxy forward / reverse: como processar solicitações do cliente e respostas do servidor em PHP?

2

Estou tendo muitos problemas com a configuração adequada do Apache mod_proxy.so para funcionar como desejado ...

A idéia principal é criar um proxy em uma máquina local em uma rede que terá a capacidade de processar uma solicitação do cliente (cliente conectado por meio desse proxy preparado pelo Apache) em PHP. E também, ele terá a capacidade de processar as respostas do servidor no PHP também.

Essas são as duas funcionalidades, e elas são independentes umas das outras.

Deixe-me apresentar um pequeno esquema do que preciso alcançar:

Comovocêpodeveraqui,existem2maneiras:umaazuleumavermelha.

Paraoazul,eubasicamenteconecteiumcliente(MáquinaB-telefonecelular)naminharedelocal(home)eoconfigureiparapassarporumproxy,queéaMáquinaA(computadorpessoal)namesmarede.

Então,digamos(nãoDHCP):

MáquinaA:192.168.1.40->OApacheestásendoexecutadonestamáquinaeconfiguradoparaescutaraporta80.

MáquinaB(celular):192.168.1.75->configuradoparapassarporumproxy,queéoIP192.168.1.75eaporta80(basicamente,aMáquinaA).

DepoisdeconfiguraroApachecorretamente,queébasicamentepararemovero"#" do httpd.conf nas linhas do mod_proxy.so (main worker), mod_proxy_connect.so (SSL, allowCONNECT, ...) e mod_proxy_http.so (necessário para manipular solicitações / respostas HTTP) e tendo no meu caso linhas como esta:

# Implements a proxy/gateway for Apache.
Include "conf/extra/httpd-proxy.conf"

# Various default settings
Include "conf/extra/httpd-default.conf"

# Secure (SSL/TLS) connections
Include "conf/extra/httpd-ssl.conf"

O que me dá a capacidade de configurar o arquivo httpd-proxy.conf para preparar o proxy de encaminhamento ou o proxy reverso.

Então, não tenho certeza se o que eu preciso é um proxy de encaminhamento ou reverso.

Para um proxy de encaminhamento, fiz isso:

<IfModule proxy_module>
<IfModule proxy_http_module>

#
# FORWARD Proxy
#

#ProxyRequests Off
ProxyRequests On
ProxyVia On

<Proxy *>
    Order deny,allow
#   Allow from all
    Deny from all
    Allow from 192.168.1
</Proxy>

</IfModule>
</IfModule>

que basicamente passa todos os pacotes normalmente para o servidor e volta para o cliente. Eu posso rastreá-lo perfeitamente (e testar isso funciona) olhando para o "access.log" do Apache. Qualquer pedido que eu faça com o celular, aparece no log do Apache. Então funciona.

Mas aí vem o problema:

  • Eu preciso processar essas solicitações do cliente. E eu preciso fazer isso em PHP.

Eu li muito sobre isso. Eu li em detalhes o site oficial do Apache sobre o mod_proxy. E eu procurei muito nos fóruns, mas sem sorte.

Então, pensei em uma primeira aproximação:

1) Proxy de encaminhamento no Apache, passa todos os pacotes e não é possível processá-los. Isso parece ser verdade, então, que tal um proxy reverso?

Então, eu imaginei algo como:

ProxyRequests Off

<Proxy *>
Order deny,allow
Allow from all
</Proxy>

ProxyPass http://www.google.com http://www.yahoo.com
ProxyPassReverse http://www.google.com http://www.yahoo.com 

que é apenas um teste, mas isso deve causar no meu celular que, ao tentar navegar para o Google, eu deveria ir ao Yahoo, não é? Mas não. Não funciona.

Então você realmente vê que TODOS os exemplos no proxy reverso do Apache são como:

ProxyPass /foo http://foo.example.com/bar
ProxyPassReverse /foo http://foo.example.com/bar

o que significa que qualquer tipo de solicitação em um contexto local será resolvido em um local remoto.

Mas o que eu preciso é o inverso! É que ao pedir um site remoto no meu telefone, eu resolvo este pedido no meu servidor local (o Apache) para processá-lo com um módulo PHP.

Então, se é um proxy de encaminhamento, preciso passar pelo PHP primeiro. Se for um proxy reverso, preciso alterar a direção "indo" para o meu servidor local, para processá-lo primeiro no PHP.

Depois vem a segunda opção:

2) Eu vi algo como:

<Proxy http://example.com/foo/*>
SetOutputFilter INCLUDES
</Proxy>

Eu comecei a pesquisar por SetOutputFilter, SetInputFilter, AddOutputFilter e AddInputFilter .

Mas eu realmente não sei como posso usá-lo.

Parece ser bom, ou uma solução para mim, porque com algo assim, eu deveria ser capaz de adicionar um filtro de entrada para processar no PHP as requisições do cliente e mandar de volta para o cliente o que eu programo / quero (não o resposta do servidor remoto), que é o caminho BLUET no esquema, e eu deveria ter a capacidade de adicionar um filtro de saída que parece me dar a capacidade de processar a resposta do servidor remoto antes de enviá-lo ao cliente, qual deve ser o caminho RED no esquema.

Caminho vermelho, é apenas para ler as respostas do servidor e brincar com elas. Mas nada mais. O caminho azul é o mais importante. Porque eu vou enviar para o cliente tudo o que eu quiser depois de processar os pedidos.

Desculpe por este post incrivelmente grande, mas eu precisava explicar isso da melhor forma possível.

Espero que alguém entenda o meu problema e me ajude a resolvê-lo!

    
por Lightworker 14.01.2011 / 21:22

2 respostas

1

Ok, então, primeiro: o Apache é a ferramenta errada!

O Apache é um servidor da web, não um servidor proxy. Sim, vem com um módulo proxy, mas acima de tudo é um servidor web.

Em vez disso, você deve procurar em um servidor proxy real como o squid. E dentro do squid você está procurando por um recurso chamado "Adaptação de Conteúdo":

link

    
por 15.01.2011 / 20:28
1

@Sarek está certo, mas a questão é sobre como lidar com requisições de proxy com PHP (do mod_proxy do Apache) não se o Apache for a ferramenta certa para isso.

Para usar o PHP com o Apache como proxy, eu uso (requer mod_proxy e mod_rewrite) em httpd.conf :

# Forward proxy server
<VirtualHost *:8080>
    ProxyRequests On
    ProxyVia On

    <Proxy *>
        Order deny,allow
        Deny from all
        Allow from 192.168

        RewriteEngine On
        RewriteCond %{REQUEST_URI} !/pac.php
        RewriteRule ^ /endpoint.php [L]
    </Proxy>
</VirtualHost>

Em seguida, em /pac.php (que define o conteúdo do arquivo PAC ):

<?php header('Content-Type: application/x-javascript-config') ?>
function FindProxyForURL(url, host)
{ 
     return "PROXY <?php echo $_SERVER['SERVER_ADDR'] ?>:<?php echo $_SERVER['SERVER_PORT'] ?>; DIRECT";
}

É usado para configuração de proxy na máquina B (cliente proxy). Use http://192.168.1.40:8080/pac.php . Com isso, o cliente sempre usará o proxy para qualquer domínio / ip (como 127.0.0.1, localhost, * .local, etc.). Nota: O IE e o .Net Apps ainda precisam escrever apenas para localhost e 127.0.0.1 o ponto final do FQDN: http://localhost. e http://127.0.0.1. .

Finalmente, em /endpoint.php :

<?php
// Don't handle domain existance
$url = $_SERVER['REQUEST_URI'];
$url_parts = parse_url($url);
// Some security checks (no local file...)
if(false === $url_parts || empty($url_parts['scheme']) || !in_array($url_parts['scheme'], array('http', 'https'))){
    die();
}

$headers_raw = '';
foreach ($_SERVER as $name => $value)
{
    if (substr($name, 0, 5) == 'HTTP_')
    {
        $name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))));
        $headers_raw .= $name . ': ' . $value . "\r\n";
    } else if ($name == "CONTENT_TYPE") {
        $headers_raw .= 'Content-Type: ' . $value . "\r\n";
    } else if ($name == "CONTENT_LENGTH") {
        $headers_raw .= 'Content-Length: ' . $value . "\r\n";
    }
}

// http://php.net/manual/en/context.http.php
$context = stream_context_create(array(
    'http' => array(
        'method' => $_SERVER['REQUEST_METHOD'],
        'header' => $headers_raw,
        'ignore_errors' => true,
        'content' => file_get_contents('php://input')
    )
));
$content = file_get_contents($url, false, $context);

$content_type = 'application/octet-stream';// "text/html"
$content_type_raw = $content_type;// "text/html; charset=UTF-8"
foreach($http_response_header as $response_header){
    if('Content-Type:' == substr($response_header, 0, 13)){
        $content_type_raw = substr($response_header, 14);
        $content_type = strstr($content_type_raw, ';', true);
        header($response_header);
    }
    elseif('Content-Encoding:' == substr($response_header, 0, 17) && 'gzip' == substr($response_header, 18, 4))
    {
        //Now lets uncompress the compressed data
        $content = gzinflate(substr($content, 10, -8));
    }
    elseif('Content-Length:' == substr($response_header, 0, 15))
    {
        //Skip it
    }
    else{
        header($response_header);
    }
}

// Content transforms
//var_dump($url_parts);exit();
if('text/html' == $content_type){
    echo str_replace('cat', 'dog', $content);
}else{
    echo $content;
}

É um exemplo, não use em produção. Não lida com domínios / ip inválidos / timeout.

Com isso, você pode reescrever o URL solicitado (o proxy pode exibir o conteúdo de http://google.com/search?q=dog do URL http://google.com/search?q=cat , uma piada engraçada) e atualizar o conteúdo (como remover anúncios, inserir JS / CSS, etc.) / p>     

por 04.02.2015 / 00:01