Added the zend framework 2 library, the path is specified in line no.26 in zend_modul...
[openemr.git] / interface / modules / zend_modules / library / Zend / Http / Client / Adapter / Proxy.php
blob413f2c7b2f83aad29f8ca805a7cf69df7c291953
1 <?php
2 /**
3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
8 */
10 namespace Zend\Http\Client\Adapter;
12 use Zend\Http\Client;
13 use Zend\Http\Client\Adapter\Exception as AdapterException;
14 use Zend\Http\Response;
15 use Zend\Stdlib\ErrorHandler;
17 /**
18 * HTTP Proxy-supporting Zend\Http\Client adapter class, based on the default
19 * socket based adapter.
21 * Should be used if proxy HTTP access is required. If no proxy is set, will
22 * fall back to Zend\Http\Client\Adapter\Socket behavior. Just like the
23 * default Socket adapter, this adapter does not require any special extensions
24 * installed.
26 class Proxy extends Socket
28 /**
29 * Parameters array
31 * @var array
33 protected $config = array(
34 'ssltransport' => 'ssl',
35 'sslcert' => null,
36 'sslpassphrase' => null,
37 'sslverifypeer' => true,
38 'sslcapath' => null,
39 'sslallowselfsigned' => false,
40 'sslusecontext' => false,
41 'proxy_host' => '',
42 'proxy_port' => 8080,
43 'proxy_user' => '',
44 'proxy_pass' => '',
45 'proxy_auth' => Client::AUTH_BASIC,
46 'persistent' => false
49 /**
50 * Whether HTTPS CONNECT was already negotiated with the proxy or not
52 * @var bool
54 protected $negotiated = false;
56 /**
57 * Set the configuration array for the adapter
59 * @param array $options
61 public function setOptions($options = array())
63 //enforcing that the proxy keys are set in the form proxy_*
64 foreach ($options as $k => $v) {
65 if (preg_match("/^proxy[a-z]+/", $k)) {
66 $options['proxy_' . substr($k, 5, strlen($k))] = $v;
67 unset($options[$k]);
71 parent::setOptions($options);
74 /**
75 * Connect to the remote server
77 * Will try to connect to the proxy server. If no proxy was set, will
78 * fall back to the target server (behave like regular Socket adapter)
80 * @param string $host
81 * @param int $port
82 * @param bool $secure
83 * @throws AdapterException\RuntimeException
85 public function connect($host, $port = 80, $secure = false)
87 // If no proxy is set, fall back to Socket adapter
88 if (! $this->config['proxy_host']) {
89 parent::connect($host, $port, $secure);
90 return;
93 /* Url might require stream context even if proxy connection doesn't */
94 if ($secure) {
95 $this->config['sslusecontext'] = true;
98 // Connect (a non-secure connection) to the proxy server
99 parent::connect(
100 $this->config['proxy_host'],
101 $this->config['proxy_port'],
102 false
107 * Send request to the proxy server
109 * @param string $method
110 * @param \Zend\Uri\Uri $uri
111 * @param string $httpVer
112 * @param array $headers
113 * @param string $body
114 * @throws AdapterException\RuntimeException
115 * @return string Request as string
117 public function write($method, $uri, $httpVer = '1.1', $headers = array(), $body = '')
119 // If no proxy is set, fall back to default Socket adapter
120 if (! $this->config['proxy_host']) return parent::write($method, $uri, $httpVer, $headers, $body);
122 // Make sure we're properly connected
123 if (! $this->socket) {
124 throw new AdapterException\RuntimeException("Trying to write but we are not connected");
127 $host = $this->config['proxy_host'];
128 $port = $this->config['proxy_port'];
130 if ($this->connectedTo[0] != "tcp://$host" || $this->connectedTo[1] != $port) {
131 throw new AdapterException\RuntimeException("Trying to write but we are connected to the wrong proxy server");
134 // Add Proxy-Authorization header
135 if ($this->config['proxy_user'] && ! isset($headers['proxy-authorization'])) {
136 $headers['proxy-authorization'] = Client::encodeAuthHeader(
137 $this->config['proxy_user'], $this->config['proxy_pass'], $this->config['proxy_auth']
141 // if we are proxying HTTPS, preform CONNECT handshake with the proxy
142 if ($uri->getScheme() == 'https' && (! $this->negotiated)) {
143 $this->connectHandshake($uri->getHost(), $uri->getPort(), $httpVer, $headers);
144 $this->negotiated = true;
147 // Save request method for later
148 $this->method = $method;
150 // Build request headers
151 if ($this->negotiated) {
152 $path = $uri->getPath();
153 if ($uri->getQuery()) {
154 $path .= '?' . $uri->getQuery();
156 $request = "$method $path HTTP/$httpVer\r\n";
157 } else {
158 $request = "$method $uri HTTP/$httpVer\r\n";
161 // Add all headers to the request string
162 foreach ($headers as $k => $v) {
163 if (is_string($k)) $v = "$k: $v";
164 $request .= "$v\r\n";
167 if (is_resource($body)) {
168 $request .= "\r\n";
169 } else {
170 // Add the request body
171 $request .= "\r\n" . $body;
174 // Send the request
175 ErrorHandler::start();
176 $test = fwrite($this->socket, $request);
177 $error = ErrorHandler::stop();
178 if (!$test) {
179 throw new AdapterException\RuntimeException("Error writing request to proxy server", 0, $error);
182 if (is_resource($body)) {
183 if (stream_copy_to_stream($body, $this->socket) == 0) {
184 throw new AdapterException\RuntimeException('Error writing request to server');
188 return $request;
192 * Preform handshaking with HTTPS proxy using CONNECT method
194 * @param string $host
195 * @param int $port
196 * @param string $httpVer
197 * @param array $headers
198 * @throws AdapterException\RuntimeException
200 protected function connectHandshake($host, $port = 443, $httpVer = '1.1', array &$headers = array())
202 $request = "CONNECT $host:$port HTTP/$httpVer\r\n" .
203 "Host: " . $this->config['proxy_host'] . "\r\n";
205 // Add the user-agent header
206 if (isset($this->config['useragent'])) {
207 $request .= "User-agent: " . $this->config['useragent'] . "\r\n";
210 // If the proxy-authorization header is set, send it to proxy but remove
211 // it from headers sent to target host
212 if (isset($headers['proxy-authorization'])) {
213 $request .= "Proxy-authorization: " . $headers['proxy-authorization'] . "\r\n";
214 unset($headers['proxy-authorization']);
217 $request .= "\r\n";
219 // Send the request
220 ErrorHandler::start();
221 $test = fwrite($this->socket, $request);
222 $error = ErrorHandler::stop();
223 if (!$test) {
224 throw new AdapterException\RuntimeException("Error writing request to proxy server", 0, $error);
227 // Read response headers only
228 $response = '';
229 $gotStatus = false;
230 ErrorHandler::start();
231 while ($line = fgets($this->socket)) {
232 $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false);
233 if ($gotStatus) {
234 $response .= $line;
235 if (!rtrim($line)) break;
238 ErrorHandler::stop();
240 // Check that the response from the proxy is 200
241 if (Response::extractCode($response) != 200) {
242 throw new AdapterException\RuntimeException("Unable to connect to HTTPS proxy. Server response: " . $response);
245 // If all is good, switch socket to secure mode. We have to fall back
246 // through the different modes
247 $modes = array(
248 STREAM_CRYPTO_METHOD_TLS_CLIENT,
249 STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
250 STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
251 STREAM_CRYPTO_METHOD_SSLv2_CLIENT
254 $success = false;
255 foreach ($modes as $mode) {
256 $success = stream_socket_enable_crypto($this->socket, true, $mode);
257 if ($success) break;
260 if (! $success) {
261 throw new AdapterException\RuntimeException("Unable to connect to" .
262 " HTTPS server through proxy: could not negotiate secure connection.");
267 * Close the connection to the server
270 public function close()
272 parent::close();
273 $this->negotiated = false;
277 * Destructor: make sure the socket is disconnected
280 public function __destruct()
282 if ($this->socket) $this->close();