Complex classes like HTTPClient often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use HTTPClient, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 100 | class HTTPClient { |
||
| 101 | //set these if you like |
||
| 102 | var $agent; // User agent |
||
| 103 | var $http; // HTTP version defaults to 1.0 |
||
| 104 | var $timeout; // read timeout (seconds) |
||
| 105 | var $cookies; |
||
| 106 | var $referer; |
||
| 107 | var $max_redirect; |
||
| 108 | var $max_bodysize; |
||
| 109 | var $max_bodysize_abort = true; // if set, abort if the response body is bigger than max_bodysize |
||
| 110 | var $header_regexp; // if set this RE must match against the headers, else abort |
||
| 111 | var $headers; |
||
| 112 | var $debug; |
||
| 113 | var $start = 0.0; // for timings |
||
| 114 | var $keep_alive = true; // keep alive rocks |
||
| 115 | |||
| 116 | // don't set these, read on error |
||
| 117 | var $error; |
||
| 118 | var $redirect_count; |
||
| 119 | |||
| 120 | // read these after a successful request |
||
| 121 | var $status; |
||
| 122 | var $resp_body; |
||
| 123 | var $resp_headers; |
||
| 124 | |||
| 125 | // set these to do basic authentication |
||
| 126 | var $user; |
||
| 127 | var $pass; |
||
| 128 | |||
| 129 | // set these if you need to use a proxy |
||
| 130 | var $proxy_host; |
||
| 131 | var $proxy_port; |
||
| 132 | var $proxy_user; |
||
| 133 | var $proxy_pass; |
||
| 134 | var $proxy_ssl; //boolean set to true if your proxy needs SSL |
||
| 135 | var $proxy_except; // regexp of URLs to exclude from proxy |
||
| 136 | |||
| 137 | // list of kept alive connections |
||
| 138 | static $connections = array(); |
||
| 139 | |||
| 140 | // what we use as boundary on multipart/form-data posts |
||
| 141 | var $boundary = '---DokuWikiHTTPClient--4523452351'; |
||
| 142 | |||
| 143 | /** |
||
| 144 | * Constructor. |
||
| 145 | * |
||
| 146 | * @author Andreas Gohr <[email protected]> |
||
| 147 | */ |
||
| 148 | function __construct(){ |
||
| 149 | $this->agent = 'Mozilla/4.0 (compatible; DokuWiki HTTP Client; '.PHP_OS.')'; |
||
| 150 | $this->timeout = 15; |
||
| 151 | $this->cookies = array(); |
||
| 152 | $this->referer = ''; |
||
| 153 | $this->max_redirect = 3; |
||
| 154 | $this->redirect_count = 0; |
||
| 155 | $this->status = 0; |
||
| 156 | $this->headers = array(); |
||
| 157 | $this->http = '1.0'; |
||
| 158 | $this->debug = false; |
||
| 159 | $this->max_bodysize = 0; |
||
| 160 | $this->header_regexp= ''; |
||
| 161 | if(extension_loaded('zlib')) $this->headers['Accept-encoding'] = 'gzip'; |
||
| 162 | $this->headers['Accept'] = 'text/xml,application/xml,application/xhtml+xml,'. |
||
| 163 | 'text/html,text/plain,image/png,image/jpeg,image/gif,*/*'; |
||
| 164 | $this->headers['Accept-Language'] = 'en-us'; |
||
| 165 | } |
||
| 166 | |||
| 167 | |||
| 168 | /** |
||
| 169 | * Simple function to do a GET request |
||
| 170 | * |
||
| 171 | * Returns the wanted page or false on an error; |
||
| 172 | * |
||
| 173 | * @param string $url The URL to fetch |
||
| 174 | * @param bool $sloppy304 Return body on 304 not modified |
||
| 175 | * @return false|string response body, false on error |
||
| 176 | * |
||
| 177 | * @author Andreas Gohr <[email protected]> |
||
| 178 | */ |
||
| 179 | function get($url,$sloppy304=false){ |
||
| 180 | if(!$this->sendRequest($url)) return false; |
||
| 181 | if($this->status == 304 && $sloppy304) return $this->resp_body; |
||
| 182 | if($this->status < 200 || $this->status > 206) return false; |
||
| 183 | return $this->resp_body; |
||
| 184 | } |
||
| 185 | |||
| 186 | /** |
||
| 187 | * Simple function to do a GET request with given parameters |
||
| 188 | * |
||
| 189 | * Returns the wanted page or false on an error. |
||
| 190 | * |
||
| 191 | * This is a convenience wrapper around get(). The given parameters |
||
| 192 | * will be correctly encoded and added to the given base URL. |
||
| 193 | * |
||
| 194 | * @param string $url The URL to fetch |
||
| 195 | * @param array $data Associative array of parameters |
||
| 196 | * @param bool $sloppy304 Return body on 304 not modified |
||
| 197 | * @return false|string response body, false on error |
||
| 198 | * |
||
| 199 | * @author Andreas Gohr <[email protected]> |
||
| 200 | */ |
||
| 201 | function dget($url,$data,$sloppy304=false){ |
||
| 202 | if(strpos($url,'?')){ |
||
| 203 | $url .= '&'; |
||
| 204 | }else{ |
||
| 205 | $url .= '?'; |
||
| 206 | } |
||
| 207 | $url .= $this->_postEncode($data); |
||
| 208 | return $this->get($url,$sloppy304); |
||
| 209 | } |
||
| 210 | |||
| 211 | /** |
||
| 212 | * Simple function to do a POST request |
||
| 213 | * |
||
| 214 | * Returns the resulting page or false on an error; |
||
| 215 | * |
||
| 216 | * @param string $url The URL to fetch |
||
| 217 | * @param array $data Associative array of parameters |
||
| 218 | * @return false|string response body, false on error |
||
| 219 | * @author Andreas Gohr <[email protected]> |
||
| 220 | */ |
||
| 221 | function post($url,$data){ |
||
| 226 | |||
| 227 | /** |
||
| 228 | * Send an HTTP request |
||
| 229 | * |
||
| 230 | * This method handles the whole HTTP communication. It respects set proxy settings, |
||
| 231 | * builds the request headers, follows redirects and parses the response. |
||
| 232 | * |
||
| 233 | * Post data should be passed as associative array. When passed as string it will be |
||
| 234 | * sent as is. You will need to setup your own Content-Type header then. |
||
| 235 | * |
||
| 236 | * @param string $url - the complete URL |
||
| 237 | * @param mixed $data - the post data either as array or raw data |
||
| 238 | * @param string $method - HTTP Method usually GET or POST. |
||
| 239 | * @return bool - true on success |
||
| 240 | * |
||
| 241 | * @author Andreas Goetz <[email protected]> |
||
| 242 | * @author Andreas Gohr <[email protected]> |
||
| 243 | */ |
||
| 244 | function sendRequest($url,$data='',$method='GET'){ |
||
| 557 | |||
| 558 | /** |
||
| 559 | * Tries to establish a CONNECT tunnel via Proxy |
||
| 560 | * |
||
| 561 | * Protocol, Servername and Port will be stripped from the request URL when a successful CONNECT happened |
||
| 562 | * |
||
| 563 | * @param resource &$socket |
||
| 564 | * @param string &$requesturl |
||
| 565 | * @throws HTTPClientException when a tunnel is needed but could not be established |
||
| 566 | * @return bool true if a tunnel was established |
||
| 567 | */ |
||
| 568 | function _ssltunnel(&$socket, &$requesturl){ |
||
| 569 | if(!$this->proxy_host) return false; |
||
| 570 | $requestinfo = parse_url($requesturl); |
||
| 571 | if($requestinfo['scheme'] != 'https') return false; |
||
| 572 | if(!$requestinfo['port']) $requestinfo['port'] = 443; |
||
| 573 | |||
| 574 | // build request |
||
| 575 | $request = "CONNECT {$requestinfo['host']}:{$requestinfo['port']} HTTP/1.0".HTTP_NL; |
||
| 576 | $request .= "Host: {$requestinfo['host']}".HTTP_NL; |
||
| 577 | if($this->proxy_user) { |
||
| 578 | $request .= 'Proxy-Authorization: Basic '.base64_encode($this->proxy_user.':'.$this->proxy_pass).HTTP_NL; |
||
| 579 | } |
||
| 580 | $request .= HTTP_NL; |
||
| 581 | |||
| 582 | $this->_debug('SSL Tunnel CONNECT',$request); |
||
| 583 | $this->_sendData($socket, $request, 'SSL Tunnel CONNECT'); |
||
| 584 | |||
| 585 | // read headers from socket |
||
| 586 | $r_headers = ''; |
||
| 587 | do{ |
||
| 588 | $r_line = $this->_readLine($socket, 'headers'); |
||
| 589 | $r_headers .= $r_line; |
||
| 590 | }while($r_line != "\r\n" && $r_line != "\n"); |
||
| 591 | |||
| 592 | $this->_debug('SSL Tunnel Response',$r_headers); |
||
| 593 | if(preg_match('/^HTTP\/1\.[01] 200/i',$r_headers)){ |
||
| 594 | // set correct peer name for verification (enabled since PHP 5.6) |
||
| 595 | stream_context_set_option($socket, 'ssl', 'peer_name', $requestinfo['host']); |
||
| 596 | |||
| 597 | // because SSLv3 is mostly broken, we try TLS connections here first. |
||
| 598 | // according to https://github.com/splitbrain/dokuwiki/commit/c05ef534 we had problems with certain |
||
| 599 | // setups with this solution before, but we have no usable test for that and TLS should be the more |
||
| 600 | // common crypto by now |
||
| 601 | if (@stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { |
||
| 602 | $requesturl = $requestinfo['path']. |
||
| 603 | (!empty($requestinfo['query'])?'?'.$requestinfo['query']:''); |
||
| 604 | return true; |
||
| 605 | } |
||
| 606 | |||
| 607 | // if the above failed, this will most probably not work either, but we can try |
||
| 608 | if (@stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv3_CLIENT)) { |
||
| 609 | $requesturl = $requestinfo['path']. |
||
| 610 | (!empty($requestinfo['query'])?'?'.$requestinfo['query']:''); |
||
| 611 | return true; |
||
| 612 | } |
||
| 613 | |||
| 614 | throw new HTTPClientException('Failed to set up crypto for secure connection to '.$requestinfo['host'], -151); |
||
| 615 | } |
||
| 616 | |||
| 617 | throw new HTTPClientException('Failed to establish secure proxy connection', -150); |
||
| 618 | } |
||
| 619 | |||
| 620 | /** |
||
| 621 | * Safely write data to a socket |
||
| 622 | * |
||
| 623 | * @param resource $socket An open socket handle |
||
| 624 | * @param string $data The data to write |
||
| 625 | * @param string $message Description of what is being read |
||
| 626 | * @throws HTTPClientException |
||
| 627 | * |
||
| 628 | * @author Tom N Harris <[email protected]> |
||
| 629 | */ |
||
| 630 | function _sendData($socket, $data, $message) { |
||
| 659 | |||
| 660 | /** |
||
| 661 | * Safely read data from a socket |
||
| 662 | * |
||
| 663 | * Reads up to a given number of bytes or throws an exception if the |
||
| 664 | * response times out or ends prematurely. |
||
| 665 | * |
||
| 666 | * @param resource $socket An open socket handle in non-blocking mode |
||
| 667 | * @param int $nbytes Number of bytes to read |
||
| 668 | * @param string $message Description of what is being read |
||
| 669 | * @param bool $ignore_eof End-of-file is not an error if this is set |
||
| 670 | * @throws HTTPClientException |
||
| 671 | * @return string |
||
| 672 | * |
||
| 673 | * @author Tom N Harris <[email protected]> |
||
| 674 | */ |
||
| 675 | function _readData($socket, $nbytes, $message, $ignore_eof = false) { |
||
| 712 | |||
| 713 | /** |
||
| 714 | * Safely read a \n-terminated line from a socket |
||
| 715 | * |
||
| 716 | * Always returns a complete line, including the terminating \n. |
||
| 717 | * |
||
| 718 | * @param resource $socket An open socket handle in non-blocking mode |
||
| 719 | * @param string $message Description of what is being read |
||
| 720 | * @throws HTTPClientException |
||
| 721 | * @return string |
||
| 722 | * |
||
| 723 | * @author Tom N Harris <[email protected]> |
||
| 724 | */ |
||
| 725 | function _readLine($socket, $message) { |
||
| 750 | |||
| 751 | /** |
||
| 752 | * print debug info |
||
| 753 | * |
||
| 754 | * Uses _debug_text or _debug_html depending on the SAPI name |
||
| 755 | * |
||
| 756 | * @author Andreas Gohr <[email protected]> |
||
| 757 | * |
||
| 758 | * @param string $info |
||
| 759 | * @param mixed $var |
||
| 760 | */ |
||
| 761 | function _debug($info,$var=null){ |
||
| 769 | |||
| 770 | /** |
||
| 771 | * print debug info as HTML |
||
| 772 | * |
||
| 773 | * @param string $info |
||
| 774 | * @param mixed $var |
||
| 775 | */ |
||
| 776 | function _debug_html($info, $var=null){ |
||
| 786 | |||
| 787 | /** |
||
| 788 | * prints debug info as plain text |
||
| 789 | * |
||
| 790 | * @param string $info |
||
| 791 | * @param mixed $var |
||
| 792 | */ |
||
| 793 | function _debug_text($info, $var=null){ |
||
| 798 | |||
| 799 | /** |
||
| 800 | * Return current timestamp in microsecond resolution |
||
| 801 | * |
||
| 802 | * @return float |
||
| 803 | */ |
||
| 804 | static function _time(){ |
||
| 808 | |||
| 809 | /** |
||
| 810 | * convert given header string to Header array |
||
| 811 | * |
||
| 812 | * All Keys are lowercased. |
||
| 813 | * |
||
| 814 | * @author Andreas Gohr <[email protected]> |
||
| 815 | * |
||
| 816 | * @param string $string |
||
| 817 | * @return array |
||
| 818 | */ |
||
| 819 | function _parseHeaders($string){ |
||
| 841 | |||
| 842 | /** |
||
| 843 | * convert given header array to header string |
||
| 844 | * |
||
| 845 | * @author Andreas Gohr <[email protected]> |
||
| 846 | * |
||
| 847 | * @param array $headers |
||
| 848 | * @return string |
||
| 849 | */ |
||
| 850 | function _buildHeaders($headers){ |
||
| 858 | |||
| 859 | /** |
||
| 860 | * get cookies as http header string |
||
| 861 | * |
||
| 862 | * @author Andreas Goetz <[email protected]> |
||
| 863 | * |
||
| 864 | * @return string |
||
| 865 | */ |
||
| 866 | function _getCookies(){ |
||
| 875 | |||
| 876 | /** |
||
| 877 | * Encode data for posting |
||
| 878 | * |
||
| 879 | * @author Andreas Gohr <[email protected]> |
||
| 880 | * |
||
| 881 | * @param array $data |
||
| 882 | * @return string |
||
| 883 | */ |
||
| 884 | function _postEncode($data){ |
||
| 887 | |||
| 888 | /** |
||
| 889 | * Encode data for posting using multipart encoding |
||
| 890 | * |
||
| 891 | * @fixme use of urlencode might be wrong here |
||
| 892 | * @author Andreas Gohr <[email protected]> |
||
| 893 | * |
||
| 894 | * @param array $data |
||
| 895 | * @return string |
||
| 896 | */ |
||
| 897 | function _postMultipartEncode($data){ |
||
| 920 | |||
| 921 | /** |
||
| 922 | * Generates a unique identifier for a connection. |
||
| 923 | * |
||
| 924 | * @param string $server |
||
| 925 | * @param string $port |
||
| 926 | * @return string unique identifier |
||
| 927 | */ |
||
| 928 | function _uniqueConnectionId($server, $port) { |
||
| 931 | } |
||
| 932 | |||
| 934 |
Adding explicit visibility (
private,protected, orpublic) is generally recommend to communicate to other developers how, and from where this method is intended to be used.