Zend_Http_Client se basa en un diseño de adaptador de conexión. El
adaptador de conexión es el objeto encargado de realizar la
conexión real con el servidor, así como de escribir las peticiones
y leer las respuestas.
Este adaptador de conexión puede reemplazarse, y puede crear y
extender los adaptadores de conexión por defecto para adaptarse a sus necesidades
especiales, sin necesidad de extender o reemplazar toda la clase de cliente
HTTP, y con la misma interfaz.
Actualmente, la clase Zend_Http_Client proporciona cuatro
adaptadores de conexión incorporados:
Zend_Http_Client_Adapter_Socket(por defecto)Zend_Http_Client_Adapter_ProxyZend_Http_Client_Adapter_CurlZend_Http_Client_Adapter_Test
El adaptador de conexión del objeto Zend_Http_Client se
establece usando la opción de configuración 'adapter'. Al instanciar
el objeto cliente, puede establecer la opción de configuración 'adapter' a
una cadena que contenga el nombre del adaptador (ej. 'Zend_Http_Client_Adapter_Socket')
o a una variable que contenga un objeto adaptador (ej.
new Zend_Http_Client_Adapter_Test). También puede establecer el
adaptador más tarde, usando el método Zend_Http_Client->setConfig().
El adaptador de conexión por defecto es el adaptador
Zend_Http_Client_Adapter_Socket - este adaptador se usará
a menos que establezca explícitamente el adaptador de conexión. El adaptador Socket se basa en
la función incorporada de PHP fsockopen(), y no requiere ninguna
extensión especial o flags de compilación.
El adaptador Socket permite varias opciones de configuración adicionales que
pueden establecerse usando Zend_Http_Client->setConfig() o
pasarse al constructor del cliente.
Tabla 38.2. Parámetros de configuración de Zend_Http_Client_Adapter_Socket
| Parámetro | Descripción | Tipo esperado | Valor por defecto |
|---|---|---|---|
| persistent | Si se deben usar conexiones TCP persistentes | boolean | FALSE |
| ssltransport | Capa de transporte SSL (ej. 'sslv2', 'tls') | string | ssl |
| sslcert | Ruta a un certificado SSL codificado en PEM | string | NULL |
| sslpassphrase | Frase de paso para el archivo de certificado SSL | string | NULL |
| sslusecontext | Permite que las conexiones proxy usen SSL incluso si la propia conexión proxy no lo hace. | boolean | FALSE |
![]() |
Conexiones TCP persistentes |
|---|---|
|
Usar conexiones TCP persistentes puede acelerar potencialmente las peticiones HTTP - pero en la mayoría de los casos de uso tendrá poco efecto positivo y podría sobrecargar el servidor HTTP al que se está conectando. Se recomienda usar conexiones TCP persistentes solo si se conecta al mismo servidor con mucha frecuencia, y está seguro de que el servidor es capaz de manejar un gran número de conexiones concurrentes. En cualquier caso se le anima a evaluar el efecto de las conexiones persistentes tanto en la velocidad del cliente como en la carga del servidor antes de usar esta opción. Además, al usar conexiones persistentes se recomienda habilitar las peticiones HTTP Keep-Alive como se describe en la sección de configuración - de lo contrario las conexiones persistentes podrían tener poco o ningún efecto. |
![]() |
Parámetros de flujo SSL de HTTPS |
|---|---|
|
ssltransport, sslcert y sslpassphrase solo son relevantes al conectar usando HTTPS. Aunque los ajustes SSL por defecto deberían funcionar para la mayoría de las aplicaciones, es posible que necesite cambiarlos si el servidor al que se conecta requiere una configuración especial del cliente. En ese caso, debería leer las secciones sobre capas de transporte SSL y opciones aquí. |
Ejemplo 38.17. Cambiando la capa de transporte HTTPS
// Set the configuration parameters
$config = array(
'adapter' => 'Zend_Http_Client_Adapter_Socket',
'ssltransport' => 'tls'
);
// Instantiate a client object
$client = new Zend_Http_Client('https://www.example.com', $config);
// The following request will be sent over a TLS secure connection.
$response = $client->request();
El resultado del ejemplo anterior será similar a abrir una conexión TCP usando el siguiente comando de PHP:
fsockopen('tls://www.example.com', 443)
A partir de Zend Framework 1.9,
Zend_Http_Client_Adapter_Socket proporciona acceso directo al
contexto de flujo subyacente usado
para conectar con el servidor remoto. Esto permite al usuario pasar opciones y
parámetros específicos al flujo TCP, y al wrapper
SSL en el caso de conexiones HTTPS.
Puede acceder al contexto de flujo usando los siguientes métodos de
Zend_Http_Client_Adapter_Socket:
setStreamContext($context)Establece el contexto de flujo que usará el adaptador. Puede aceptar bien un recurso de contexto de flujo creado usando la función PHPstream_context_create(), o un array de opciones de contexto de flujo, en el mismo formato que se proporciona a esta función. Proporcionar un array creará un nuevo contexto de flujo con estas opciones, y lo establecerá.getStreamContext()Obtiene el contexto de flujo del adaptador. Si no se ha establecido ningún contexto de flujo, creará un contexto de flujo por defecto y lo devolverá. Luego puede establecer u obtener el valor de diferentes opciones de contexto usando las funciones normales de contexto de flujo de PHP.
Ejemplo 38.18. Establecer opciones de contexto de flujo para el adaptador Socket
// Array of options
$options = array(
'socket' => array(
// Bind local socket side to a specific interface
'bindto' => '10.1.2.3:50505'
),
'ssl' => array(
// Verify server side certificate,
// do not accept invalid or self-signed SSL certificates
'verify_peer' => true,
'allow_self_signed' => false,
// Capture the peer's certificate
'capture_peer_cert' => true
)
);
// Create an adapter object and attach it to the HTTP client
$adapter = new Zend_Http_Client_Adapter_Socket();
$client = new Zend_Http_Client();
$client->setAdapter($adapter);
// Method 1: pass the options array to setStreamContext()
$adapter->setStreamContext($options);
// Method 2: create a stream context and pass it to setStreamContext()
$context = stream_context_create($options);
$adapter->setStreamContext($context);
// Method 3: get the default stream context and set the options on it
$context = $adapter->getStreamContext();
stream_context_set_option($context, $options);
// Now, preform the request
$response = $client->request();
// If everything went well, you can now access the context again
$opts = stream_context_get_options($adapter->getStreamContext());
echo $opts['ssl']['peer_certificate'];
![]() |
Nota |
|---|---|
Tenga en cuenta que debe establecer cualquier opción de contexto de flujo antes de usar
el adaptador para realizar peticiones reales. Si no se establece ningún contexto antes de
realizar peticiones HTTP con el adaptador Socket, se creará un contexto
de flujo por defecto. Se puede acceder a este recurso de contexto después de realizar
cualquier petición usando el método |
El adaptador Zend_Http_Client_Adapter_Proxy es similar al
adaptador Socket por defecto - solo que la conexión se realiza a través de un servidor
proxy HTTP en lugar de una conexión directa al servidor de destino. Esto
permite el uso de Zend_Http_Client detrás de servidores proxy - lo cual
a veces es necesario por razones de seguridad o rendimiento.
Usar el adaptador Proxy requiere que se establezcan varios parámetros de configuración adicionales, además de la opción 'adapter' por defecto:
Tabla 38.3. Parámetros de configuración de Zend_Http_Client
| Parámetro | Descripción | Tipo esperado | Valor de ejemplo |
|---|---|---|---|
| proxy_host | Dirección del servidor proxy | string | 'proxy.myhost.com' o '10.1.2.3' |
| proxy_port | Puerto TCP del servidor proxy | integer | 8080 (por defecto) u 81 |
| proxy_user | Nombre de usuario del proxy, si se requiere | string | 'shahar' o '' para ninguno (por defecto) |
| proxy_pass | Contraseña del proxy, si se requiere | string | 'secret' o '' para ninguno (por defecto) |
| proxy_auth | Tipo de autenticación HTTP del proxy | string | Zend_Http_Client::AUTH_BASIC (por defecto) |
proxy_host siempre debe establecerse - si no se establece, el cliente
recurrirá a una conexión directa usando
Zend_Http_Client_Adapter_Socket. proxy_port por defecto es '8080' -
si su proxy escucha en un puerto diferente debe establecer este también.
proxy_user y proxy_pass solo son necesarios si su servidor proxy requiere que se autentique. Proporcionar estos añadirá una cabecera 'Proxy-Authentication' a la petición. Si su proxy no requiere autenticación, puede omitir estas dos opciones.
proxy_auth establece el tipo de autenticación del proxy, si su servidor proxy requiere autenticación. Los valores posibles son similares a los aceptados por el método Zend_Http_Client::setAuth(). Actualmente, solo se admite la autenticación básica (Zend_Http_Client::AUTH_BASIC).
Ejemplo 38.19. Usar Zend_Http_Client detrás de un servidor proxy
// Set the configuration parameters
$config = array(
'adapter' => 'Zend_Http_Client_Adapter_Proxy',
'proxy_host' => 'proxy.int.zend.com',
'proxy_port' => 8000,
'proxy_user' => 'shahar.e',
'proxy_pass' => 'bananashaped'
);
// Instantiate a client object
$client = new Zend_Http_Client('http://www.example.com', $config);
// Continue working...
Como se mencionó, si proxy_host no está establecido o está establecido a una cadena en blanco, la conexión recurrirá a una conexión directa normal. Esto le permite escribir fácilmente su aplicación de una manera que permita usar un proxy opcionalmente, según un parámetro de configuración.
![]() |
Nota |
|---|---|
Dado que el adaptador proxy hereda de
|
cURL es una biblioteca de cliente HTTP estándar que se distribuye con muchos sistemas operativos y puede usarse en PHP a través de la extensión cURL. Ofrece funcionalidad para muchos casos especiales que pueden darse en un cliente HTTP y la convierten en una elección perfecta para un adaptador HTTP. Admite conexiones seguras, proxy, todo tipo de mecanismos de autenticación y destaca en aplicaciones que mueven archivos grandes entre servidores.
Ejemplo 38.20. Establecer opciones de cURL
$config = array(
'adapter' => 'Zend_Http_Client_Adapter_Curl',
'curloptions' => array(CURLOPT_FOLLOWLOCATION => true),
);
$client = new Zend_Http_Client($uri, $config);
Por defecto el adaptador cURL está configurado para comportarse exactamente como
el adaptador Socket y también acepta los mismos parámetros de configuración
que los adaptadores Socket y Proxy. También puede cambiar las opciones de cURL especificando
la clave 'curloptions' en el constructor del adaptador o llamando a
setCurlOption($name, $value). La clave $name
corresponde a las constantes CURL_* de la extensión cURL. Puede
obtener acceso al handle de Curl llamando a $adapter->getHandle();
Ejemplo 38.21. Transferir archivos por handle
Puede usar cURL para transferir archivos muy grandes por HTTP mediante un manejador de archivo.
$putFileSize = filesize("filepath");
$putFileHandle = fopen("filepath", "r");
$adapter = new Zend_Http_Client_Adapter_Curl();
$client = new Zend_Http_Client();
$client->setAdapter($adapter);
$adapter->setConfig(array(
'curloptions' => array(
CURLOPT_INFILE => $putFileHandle,
CURLOPT_INFILESIZE => $putFileSize
)
));
$client->request("PUT");
A veces, es muy difícil probar código que depende de conexiones HTTP. Por ejemplo, probar una aplicación que obtiene un feed RSS de un servidor remoto requerirá una conexión de red, la cual no siempre está disponible.
Por esta razón, se proporciona el adaptador Zend_Http_Client_Adapter_Test.
Puede escribir su aplicación para usar Zend_Http_Client,
y solo para fines de prueba, por ejemplo en su conjunto de pruebas
unitarias, puede reemplazar el adaptador por defecto con un adaptador Test (un
objeto simulado, o "mock"), lo que le permite ejecutar pruebas sin realizar
realmente conexiones al servidor.
El adaptador Zend_Http_Client_Adapter_Test proporciona un método
adicional, el método setResponse(). Este método toma un parámetro,
que representa una respuesta HTTP ya sea como texto o como un
objeto Zend_Http_Response. Una vez establecido, su adaptador Test
siempre devolverá esta respuesta, sin siquiera realizar una petición
HTTP real.
Ejemplo 38.22. Probar contra un único stub de respuesta HTTP
// Instantiate a new adapter and client
$adapter = new Zend_Http_Client_Adapter_Test();
$client = new Zend_Http_Client('http://www.example.com', array(
'adapter' => $adapter
));
// Set the expected response
$adapter->setResponse(
"HTTP/1.1 200 OK" . "\r\n" .
"Content-type: text/xml" . "\r\n" .
"\r\n" .
'<?xml version="1.0" encoding="UTF-8"?>' .
'<rss version="2.0" ' .
' xmlns:content="http://purl.org/rss/1.0/modules/content/"' .
' xmlns:wfw="http://wellformedweb.org/CommentAPI/"' .
' xmlns:dc="http://purl.org/dc/elements/1.1/">' .
' <channel>' .
' <title>Premature Optimization</title>' .
// and so on...
'</rss>');
$response = $client->request('GET');
// .. continue parsing $response..
El ejemplo anterior muestra cómo puede preconfigurar su cliente HTTP para que devuelva la respuesta que necesita. Luego, puede continuar probando su propio código, sin depender de una conexión de red, la respuesta del servidor, etc. En este caso, la prueba continuaría comprobando cómo la aplicación analiza el XML en el cuerpo de la respuesta.
A veces, una única llamada a un método de un objeto puede resultar en que ese objeto realice múltiples transacciones HTTP. En este caso, no es posible usar setResponse() por sí solo porque no hay oportunidad de establecer la(s) siguiente(s) respuesta(s) que su programa pueda necesitar antes de devolver el control al llamador.
Ejemplo 38.23. Probar contra múltiples stubs de respuesta HTTP
// Instantiate a new adapter and client
$adapter = new Zend_Http_Client_Adapter_Test();
$client = new Zend_Http_Client('http://www.example.com', array(
'adapter' => $adapter
));
// Set the first expected response
$adapter->setResponse(
"HTTP/1.1 302 Found" . "\r\n" .
"Location: /" . "\r\n" .
"Content-Type: text/html" . "\r\n" .
"\r\n" .
'<html>' .
' <head><title>Moved</title></head>' .
' <body><p>This page has moved.</p></body>' .
'</html>');
// Set the next successive response
$adapter->addResponse(
"HTTP/1.1 200 OK" . "\r\n" .
"Content-Type: text/html" . "\r\n" .
"\r\n" .
'<html>' .
' <head><title>My Pet Store Home Page</title></head>' .
' <body><p>...</p></body>' .
'</html>');
// inject the http client object ($client) into your object
// being tested and then test your object's behavior below
El método setResponse() borra cualquier respuesta en el
búfer de Zend_Http_Client_Adapter_Test y establece la
primera respuesta que se devolverá. El método addResponse()
añadirá respuestas sucesivas.
Las respuestas se reproducirán en el orden en que se añadieron. Si se realizan más peticiones que el número de respuestas almacenadas, las respuestas volverán a repetirse en orden.
En el ejemplo anterior, el adaptador está configurado para probar el comportamiento de su objeto cuando encuentra una redirección 302. Dependiendo de su aplicación, seguir una redirección puede o no ser el comportamiento deseado. En nuestro ejemplo, esperamos que se siga la redirección y configuramos el adaptador de prueba para ayudarnos a probar esto. La respuesta inicial 302 se configura con el método setResponse() y la respuesta 200 que se devolverá a continuación se añade con el método addResponse(). Después de configurar el adaptador de prueba, inyecte el cliente HTTP que contiene el adaptador en su objeto bajo prueba y pruebe su comportamiento.
Si necesita que el adaptador falle bajo demanda puede usar
setNextRequestWillFail($flag). El método hará que la siguiente
llamada a connect() lance una excepción
Zend_Http_Client_Adapter_Exception. Esto puede ser útil
cuando su aplicación almacena en caché contenido de un sitio externo (en caso de que el sitio caiga)
y desea probar esta funcionalidad.
Ejemplo 38.24. Forzar el fallo del adaptador
// Instantiate a new adapter and client
$adapter = new Zend_Http_Client_Adapter_Test();
$client = new Zend_Http_Client('http://www.example.com', array(
'adapter' => $adapter
));
// Force the next request to fail with an exception
$adapter->setNextRequestWillFail(true);
try {
// This call will result in a Zend_Http_Client_Adapter_Exception
$client->request();
} catch (Zend_Http_Client_Adapter_Exception $e) {
// ...
}
// Further requests will work as expected until
// you call setNextRequestWillFail(true) again
Puede crear sus propios adaptadores de conexión y usarlos. Podría, por ejemplo, crear un adaptador de conexión que use sockets persistentes, o un adaptador de conexión con capacidades de caché, y usarlos según sea necesario en su aplicación.
Para hacerlo, debe crear su propia clase adaptadora que implemente
la interfaz Zend_Http_Client_Adapter_Interface. El siguiente
ejemplo muestra el esqueleto de una clase adaptadora implementada por el usuario. Todas las
funciones públicas definidas en este ejemplo deben definirse también en su adaptador:
Ejemplo 38.25. Crear su propio adaptador de conexión
class MyApp_Http_Client_Adapter_BananaProtocol
implements Zend_Http_Client_Adapter_Interface
{
/**
* Set the configuration array for the adapter
*
* @param array $config
*/
public function setConfig($config = array())
{
// This rarely changes - you should usually copy the
// implementation in Zend_Http_Client_Adapter_Socket.
}
/**
* Connect to the remote server
*
* @param string $host
* @param int $port
* @param boolean $secure
*/
public function connect($host, $port = 80, $secure = false)
{
// Set up the connection to the remote server
}
/**
* Send request to the remote server
*
* @param string $method
* @param Zend_Uri_Http $url
* @param string $http_ver
* @param array $headers
* @param string $body
* @return string Request as text
*/
public function write($method,
$url,
$http_ver = '1.1',
$headers = array(),
$body = '')
{
// Send request to the remote server.
// This function is expected to return the full request
// (headers and body) as a string
}
/**
* Read response from server
*
* @return string
*/
public function read()
{
// Read response from remote server and return it as a string
}
/**
* Close the connection to the server
*
*/
public function close()
{
// Close the connection to the remote server - called last.
}
}
// Then, you could use this adapter:
$client = new Zend_Http_Client(array(
'adapter' => 'MyApp_Http_Client_Adapter_BananaProtocol'
));
![[Note]](images/note.png)