1<?php 2/** 3 * PEAR_Proxy 4 * 5 * HTTP Proxy handling 6 * 7 * @category pear 8 * @package PEAR 9 * @author Nico Boehr 10 * @copyright 1997-2009 The Authors 11 * @license http://opensource.org/licenses/bsd-license.php New BSD License 12 * @link http://pear.php.net/package/PEAR 13 */ 14 15class PEAR_Proxy 16{ 17 var $config = null; 18 19 /** 20 * @access private 21 */ 22 var $proxy_host; 23 /** 24 * @access private 25 */ 26 var $proxy_port; 27 /** 28 * @access private 29 */ 30 var $proxy_user; 31 /** 32 * @access private 33 */ 34 var $proxy_pass; 35 /** 36 * @access private 37 */ 38 var $proxy_schema; 39 40 function __construct($config = null) 41 { 42 $this->config = $config; 43 $this->_parseProxyInfo(); 44 } 45 46 /** 47 * @access private 48 */ 49 function _parseProxyInfo() 50 { 51 $this->proxy_host = $this->proxy_port = $this->proxy_user = $this->proxy_pass = ''; 52 if ($this->config->get('http_proxy')&& 53 $proxy = parse_url($this->config->get('http_proxy')) 54 ) { 55 $this->proxy_host = isset($proxy['host']) ? $proxy['host'] : null; 56 57 $this->proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; 58 $this->proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; 59 $this->proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; 60 $this->proxy_schema = (isset($proxy['scheme']) && $proxy['scheme'] == 'https') ? 'https' : 'http'; 61 } 62 } 63 64 /** 65 * @access private 66 */ 67 function _httpConnect($fp, $host, $port) 68 { 69 fwrite($fp, "CONNECT $host:$port HTTP/1.1\r\n"); 70 fwrite($fp, "Host: $host:$port\r\n"); 71 if ($this->getProxyAuth()) { 72 fwrite($fp, 'Proxy-Authorization: Basic ' . $this->getProxyAuth() . "\r\n"); 73 } 74 fwrite($fp, "\r\n"); 75 76 while ($line = trim(fgets($fp, 1024))) { 77 if (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { 78 $code = (int)$matches[1]; 79 80 /* as per RFC 2817 */ 81 if ($code < 200 || $code >= 300) { 82 return PEAR::raiseError("Establishing a CONNECT tunnel through proxy failed with response code $code"); 83 } 84 } 85 } 86 87 // connection was successful -- establish SSL through 88 // the tunnel 89 $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT; 90 91 if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) { 92 $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; 93 $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; 94 } 95 96 // set the correct hostname for working hostname 97 // verification 98 stream_context_set_option($fp, 'ssl', 'peer_name', $host); 99 100 // blocking socket needed for 101 // stream_socket_enable_crypto() 102 // see 103 // <http://php.net/manual/en/function.stream-socket-enable-crypto.php> 104 stream_set_blocking ($fp, true); 105 $crypto_res = stream_socket_enable_crypto($fp, true, $crypto_method); 106 if (!$crypto_res) { 107 return PEAR::raiseError("Could not establish SSL connection through proxy $proxy_host:$proxy_port: $crypto_res"); 108 } 109 110 return true; 111 } 112 113 /** 114 * get the authorization information for the proxy, encoded to be 115 * passed in the Proxy-Authentication HTTP header. 116 * @return null|string the encoded authentication information if a 117 * proxy and authentication is configured, null 118 * otherwise. 119 */ 120 function getProxyAuth() 121 { 122 if ($this->isProxyConfigured() && $this->proxy_user != '') { 123 return base64_encode($this->proxy_user . ':' . $this->proxy_pass); 124 } 125 return null; 126 } 127 128 function getProxyUser() 129 { 130 return $this->proxy_user; 131 } 132 133 /** 134 * Check if we are configured to use a proxy. 135 * 136 * @return boolean true if we are configured to use a proxy, false 137 * otherwise. 138 * @access public 139 */ 140 function isProxyConfigured() 141 { 142 return $this->proxy_host != ''; 143 } 144 145 /** 146 * Open a socket to a remote server, possibly involving a HTTP 147 * proxy. 148 * 149 * If an HTTP proxy has been configured (http_proxy PEAR_Config 150 * setting), the proxy will be used. 151 * 152 * @param string $host the host to connect to 153 * @param string $port the port to connect to 154 * @param boolean $secure if true, establish a secure connection 155 * using TLS. 156 * @access public 157 */ 158 function openSocket($host, $port, $secure = false) 159 { 160 if ($this->isProxyConfigured()) { 161 $fp = @fsockopen( 162 $this->proxy_host, $this->proxy_port, 163 $errno, $errstr, 15 164 ); 165 166 if (!$fp) { 167 return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", -9276); 168 } 169 170 /* HTTPS is to be used and we have a proxy, use CONNECT verb */ 171 if ($secure) { 172 $res = $this->_httpConnect($fp, $host, $port); 173 174 if (PEAR::isError($res)) { 175 return $res; 176 } 177 } 178 } else { 179 if ($secure) { 180 $host = 'ssl://' . $host; 181 } 182 183 $fp = @fsockopen($host, $port, $errno, $errstr); 184 if (!$fp) { 185 return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); 186 } 187 } 188 189 return $fp; 190 } 191} 192