2012-01-06 22 views
8

Estoy usando una conexión de socket en PHP para publicar datos en un servidor web Apache. Soy un poco nuevo en esta técnica, y no estoy seguro de cómo aislar los encabezados del cuerpo de la respuesta.Cómo aislar los encabezados HTTP/cuerpo de una solicitud de sockets PHP

Código Envío:

<?php 
// collect data to post 
$postdata = array(
    'hello' => 'world' 
); 
$postdata = http_build_query($postdata); 
// open socket, send request 
$fp = fsockopen('127.0.0.1', 80); 
fwrite($fp, "POST /server.php HTTP/1.1\r\n"); 
fwrite($fp, "Host: fm1\r\n"); 
fwrite($fp, "Content-Type: application/x-www-form-urlencoded\r\n"); 
fwrite($fp, "Content-Length: ".strlen($postdata)."\r\n"); 
fwrite($fp, "Connection: close\r\n"); 
fwrite($fp, "\r\n"); 
fwrite($fp, $postdata); 
// go through result 
$result = ""; 
while(!feof($fp)){ 
    $result .= fgets($fp); 
} 
// close 
fclose($fp); 
// display result 
echo $result; 
?> 

código del servidor:

Hello this is server. You posted: 
<pre> 
<?php print_r($_POST); ?> 
</pre> 

al exponer en un servidor, me sale:

HTTP/1.1 200 OK 
Date: Fri, 06 Jan 2012 09:55:27 GMT 
Server: Apache/2.2.15 (Win32) mod_ssl/2.2.15 OpenSSL/0.9.8m PHP/5.3.2 
X-Powered-By: PHP/5.3.2 
Content-Length: 79 
Connection: close 
Content-Type: text/html 

Hello this is server. You posted: 
<pre> 
Array 
(
    [hello] => world 
) 
</pre> 

como se esperaba. Sin embargo, quiero quitar los encabezados, y simplemente leer el cuerpo de "Hola, este es el servidor ....." en adelante. ¿Cómo puedo detectar de manera confiable el final de los encabezados y leer el cuerpo en una variable?

Además, otro servidor que he probado en las respuestas con esto:

HTTP/1.1 200 OK 
Date: Fri, 06 Jan 2012 10:02:04 GMT 
Server: Apache/2 
X-Powered-By: PHP/5.2.17 
Connection: close 
Transfer-Encoding: chunked 
Content-Type: text/html 

4d 
Hello this is server. You posted: 
<pre> 
Array 
(
    [hello] => world 
) 
</pre> 
0 

Cuáles son los "4d" y "0" en todo el texto del cuerpo ??

Gracias!

PS antes de que alguien dice que el uso CURL, no puedo por desgracia :-(

+0

No está seguro acerca de la '' 4d' y 0', pero se puede usar 'explotar ('\ r \ n \ r \ n ', $ result) 'bastante confiablemente. – Grexis

Respuesta

15

puede separar el encabezado del cuerpo mediante la división en un doble salto de línea debe ser <CRLF><CRLF> lo que esta sería normalmente trabajo:..

list($header, $body) = explode("\r\n\r\n", $response, 2); 

más fiable que puedes usar una expresión regular para capturar variaciones linebreak (super poco probable que suceda nunca):

list($header, $body) = preg_split("/\R\R/", $response, 2); 

La cosa con la 4d y 0 se llama el chunked encoding. (Son números hexadecimales separados con otro salto de línea, e inidican la longitud del siguiente bloque de contenido sin procesar).

Para aclarar eso, primero tiene que mirar los encabezados y ver si hay una entrada de acuerdo Transfer-Encoding:. Aquí es donde se vuelve complicado, y es aconsejable usar una de la miríada de clases de procesamiento de usuarios de HTTP existentes. PEAR has one.

+0

Genial, tu método para dividir los encabezados parece funcionar muy bien. Además, parece que tienes razón sobre los números. Cambian dependiendo de la duración del contenido. Ojalá pudiera usar CURL, investigaré en PEAR para procesarlo ... ¡Muchas gracias! – Rob

0

encabezados debe terminar con "\r\n\r\n" (dos veces). Estos 4d y son posiblemente parte de su respuesta php (que no forman parte de las cabeceras)

+0

Gracias, sí parece que eso funciona – Rob

+0

¿Por qué rechazar un hecho? : D – Rolice

0

En la mayoría de los casos, la respuesta de Mario debería funcionar, pero acabo de intentar aplicar este método a la respuesta de Couch DB y hay algunos casos en los que no funciona.

Si la respuesta no contiene ningún documento, Couch DB puso "\ r \ n \ r \ n" dentro del cuerpo de respuesta tratando de mantener los resultados bien formados y en este caso no es suficiente para dividir la respuesta por "\ r \ n \ r \ n "porque puede cortar accidentalmente la parte final del cuerpo.

HTTP/1.0 200 OK Server: CouchDB/1.6.1 (Erlang OTP/R16B02) ETag: "DJNMQO5WQIBZHFMDU40F1O94T" Date: Mon, 06 Jul 2015 09:37:33 GMT Content-Type: text/plain; charset=utf-8 Cache-Control: must-revalidate 
{"total_rows":0,"offset":0,"rows":[ 
// Couch DB adds some extra line breakers on this line 
]} 

Tras el análisis parece ser más fiable para Couch DB:

$parts = explode("\r\n\r\n", $response); 

if ($parts) 
{ 
    $headers = array_shift($parts); 
    $body = json_decode(implode("\r\n\r\n", $parts)); 
} 
+0

FWIW: Su respuesta todavía funcionaría para usted. La clave es el "2" en el tercer parámetro de 'explotar'. Significa que solo habrá un máximo de 2 elementos en una matriz creada con 'explosde'. Entonces en 'list ($ header, $ body)', el primer "pedazo" de la matriz se asignaría a '$ headers', y todo lo demás, independientemente de cuántos' 'existen, se asignaría a '$ cuerpo'. – Oberst

Cuestiones relacionadas