Proxy.php 5.5 KB

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