16 | | * Implementation for deflate and gzip transfer encodings. |
17 | | * |
18 | | * Includes RFC 1950, RFC 1951, and RFC 1952. |
19 | | * |
20 | | * @since unknown |
21 | | * @package WordPress |
22 | | * @subpackage HTTP |
23 | | */ |
24 | | class WP_Http_Encoding { |
25 | | |
26 | | /** |
27 | | * Compress raw string using the deflate format. |
28 | | * |
29 | | * Supports the RFC 1951 standard. |
30 | | * |
31 | | * @since unknown |
32 | | * |
33 | | * @param string $raw String to compress. |
34 | | * @param int $level Optional, default is 9. Compression level, 9 is highest. |
35 | | * @param string $supports Optional, not used. When implemented it will choose the right compression based on what the server supports. |
36 | | * @return string|bool False on failure. |
37 | | */ |
38 | | function compress( $raw, $level = 9, $supports = null ) { |
39 | | return gzdeflate( $raw, $level ); |
40 | | } |
41 | | |
42 | | /** |
43 | | * Decompression of deflated string. |
44 | | * |
45 | | * Will attempt to decompress using the RFC 1950 standard, and if that fails |
46 | | * then the RFC 1951 standard deflate will be attempted. Finally, the RFC |
47 | | * 1952 standard gzip decode will be attempted. If all fail, then the |
48 | | * original compressed string will be returned. |
49 | | * |
50 | | * @since unknown |
51 | | * |
52 | | * @param string $compressed String to decompress. |
53 | | * @param int $length The optional length of the compressed data. |
54 | | * @return string|bool False on failure. |
55 | | */ |
56 | | function decompress( $compressed, $length = null ) { |
57 | | $decompressed = gzinflate( $compressed ); |
58 | | |
59 | | if( false !== $decompressed ) |
60 | | return $decompressed; |
61 | | |
62 | | $decompressed = gzuncompress( $compressed ); |
63 | | |
64 | | if( false !== $decompressed ) |
65 | | return $decompressed; |
66 | | |
67 | | $decompressed = gzdecode( $compressed ); |
68 | | |
69 | | if( false !== $decompressed ) |
70 | | return $decompressed; |
71 | | |
72 | | return $compressed; |
73 | | } |
74 | | |
75 | | /** |
76 | | * What encoding types to accept and their priority values. |
77 | | * |
78 | | * @since unknown |
79 | | * |
80 | | * @return string Types of encoding to accept. |
81 | | */ |
82 | | function accept_encoding() { |
83 | | $type = array(); |
84 | | if( function_exists( 'gzinflate' ) ) |
85 | | $type[] = 'deflate;q=1.0'; |
86 | | |
87 | | if( function_exists( 'gzuncompress' ) ) |
88 | | $type[] = 'compress;q=0.5'; |
89 | | |
90 | | if( function_exists( 'gzdecode' ) ) |
91 | | $type[] = 'gzip;q=0.5'; |
92 | | |
93 | | return implode(', ', $type); |
94 | | } |
95 | | |
96 | | /** |
97 | | * What enconding the content used when it was compressed to send in the headers. |
98 | | * |
99 | | * @since unknown |
100 | | * |
101 | | * @return string Content-Encoding string to send in the header. |
102 | | */ |
103 | | function content_encoding() { |
104 | | return 'deflate'; |
105 | | } |
106 | | |
107 | | /** |
108 | | * Whether the content be decoded based on the headers. |
109 | | * |
110 | | * @since unknown |
111 | | * |
112 | | * @param array|string $headers All of the available headers. |
113 | | * @return bool |
114 | | */ |
115 | | function should_decode($headers) { |
116 | | if( is_array( $headers ) ) { |
117 | | if( array_key_exists('content-encoding', $headers) && ! empty( $headers['content-encoding'] ) ) |
118 | | return true; |
119 | | } else if( is_string( $headers ) ) { |
120 | | return ( stripos($headers, 'content-encoding:') !== false ); |
121 | | } |
122 | | |
123 | | return false; |
124 | | } |
125 | | |
126 | | /** |
127 | | * Whether decompression and compression are supported by the PHP version. |
128 | | * |
129 | | * Each function is tested instead of checking for the zlib extension, to |
130 | | * ensure that the functions all exist in the PHP version and aren't |
131 | | * disabled. |
132 | | * |
133 | | * @since unknown |
134 | | * |
135 | | * @return bool |
136 | | */ |
137 | | function is_available() { |
138 | | return ( function_exists('gzuncompress') || function_exists('gzdeflate') || |
139 | | function_exists('gzinflate') ); |
140 | | } |
141 | | } |
142 | | |
143 | | /** |
155 | | * There are no properties, because none are needed and for performance reasons. |
156 | | * Some of the functions are static and while they do have some overhead over |
157 | | * functions in PHP4, the purpose is maintainability. When PHP5 is finally the |
158 | | * requirement, it will be easy to add the static keyword to the code. It is not |
159 | | * as easy to convert a function to a method after enough code uses the old way. |
| 25 | * There are no properties, because none are needed and for performance reasons. Some of the |
| 26 | * functions are static and while they do have some overhead over functions in PHP4, the purpose is |
| 27 | * maintainability. When PHP5 is finally the requirement, it will be easy to add the static keyword |
| 28 | * to the code. It is not as easy to convert a function to a method after enough code uses the old |
| 29 | * way. |
328 | | * Accepted 'method' values are 'GET', 'POST', and 'HEAD', some transports |
329 | | * technically allow others, but should not be assumed. The 'timeout' is |
330 | | * used to sent how long the connection should stay open before failing when |
331 | | * no response. 'redirection' is used to track how many redirects were taken |
332 | | * and used to sent the amount for other transports, but not all transports |
| 193 | * Accepted 'method' values are 'GET', 'POST', and 'HEAD', some transports technically allow |
| 194 | * others, but should not be assumed. The 'timeout' is used to sent how long the connection |
| 195 | * should stay open before failing when no response. 'redirection' is used to track how many |
| 196 | * redirects were taken and used to sent the amount for other transports, but not all transports |
341 | | * 'blocking' is the default, which is used to tell the transport, whether |
342 | | * it should halt PHP while it performs the request or continue regardless. |
343 | | * Actually, that isn't entirely correct. Blocking mode really just means |
344 | | * whether the fread should just pull what it can whenever it gets bytes or |
345 | | * if it should wait until it has enough in the buffer to read or finishes |
346 | | * reading the entire content. It doesn't actually always mean that PHP will |
347 | | * continue going after making the request. |
| 204 | * 'blocking' is the default, which is used to tell the transport, whether it should halt PHP |
| 205 | * while it performs the request or continue regardless. Actually, that isn't entirely correct. |
| 206 | * Blocking mode really just means whether the fread should just pull what it can whenever it |
| 207 | * gets bytes or if it should wait until it has enough in the buffer to read or finishes reading |
| 208 | * the entire content. It doesn't actually always mean that PHP will continue going after making |
| 209 | * the request. |
| 627 | if ( !defined('WP_DEBUG') || ( defined('WP_DEBUG') && false === WP_DEBUG ) ) { |
| 628 | if( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) |
| 629 | $handle = @fsockopen($proxy->host(), $proxy->port(), $iError, $strError, $r['timeout'] ); |
| 630 | else |
| 631 | $handle = @fsockopen($arrURL['host'], $arrURL['port'], $iError, $strError, $r['timeout'] ); |
| 632 | } |
| 633 | else { |
| 634 | if( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) |
| 635 | $handle = fsockopen($proxy->host(), $proxy->port(), $iError, $strError, $r['timeout'] ); |
| 636 | else |
| 637 | $handle = fsockopen($arrURL['host'], $arrURL['port'], $iError, $strError, $r['timeout'] ); |
| 638 | } |
| 639 | |
| 938 | $proxy = new WP_HTTP_Proxy(); |
| 939 | |
| 940 | if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) { |
| 941 | // WTF happens when the user stupidly puts http:// in the host? Bad things. Really, |
| 942 | // really bad things happen. Not exactly unleashing demons from hell, but you know. |
| 943 | // Just as bad probably. Actually, none of the other transports should work in that case |
| 944 | // so no sanitization is done. If there is, it should be done in the |
| 945 | // WP_HTTP_Proxy::host(). |
| 946 | // |
| 947 | // On second thought, why is it tcp protocol? Why not http? What if the proxy is http |
| 948 | // and not tcp? Even though, technically, http is tcp, but just a specialized form of |
| 949 | // tcp. Behavior is undefined, so it is probably good that not a lot of users will be |
| 950 | // affected by FUBAR behavior. |
| 951 | // |
| 952 | // Is it another WTF? that this multiline comment isn't using multiline comment syntax? |
| 953 | $arrContext['http']['proxy'] = 'tcp://'.$proxy->host().':'.$proxy->port(); |
| 954 | |
| 955 | // Yeah, this may or may not work. Good luck. |
| 956 | if ( $proxy->use_authentication() ) { |
| 957 | $arrContext['http']['header'] .= $proxy->authentication_header() . "\r\n"; |
| 958 | } |
| 959 | } |
| 960 | |
| 1210 | // cURL offers really easy proxy support. |
| 1211 | $proxy = new WP_HTTP_Proxy(); |
| 1212 | |
| 1213 | if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) { |
| 1214 | curl_setopt( $handle, CURLOPT_HTTPPROXYTUNNEL, true ); |
| 1215 | |
| 1216 | $isPHP5 = version_compare(PHP_VERSION, '5.0.0', '>='); |
| 1217 | |
| 1218 | if ( $isPHP5 ) { |
| 1219 | curl_setopt( $handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP ); |
| 1220 | curl_setopt( $handle, CURLOPT_PROXY, $proxy->host() ); |
| 1221 | curl_setopt( $handle, CURLOPT_PROXYPORT, $proxy->port() ); |
| 1222 | } else { |
| 1223 | curl_setopt( $handle, CURLOPT_PROXY, $proxy->host() .':'. $proxy->port() ); |
| 1224 | } |
| 1225 | |
| 1226 | if ( $proxy->use_authentication() ) { |
| 1227 | if ( $isPHP5 ) |
| 1228 | curl_setopt( $handle, CURLOPT_PROXYAUTH, CURLAUTH_BASIC ); |
| 1229 | |
| 1230 | curl_setopt( $handle, CURLOPT_PROXYUSERPWD, $proxy->authentication() ); |
| 1231 | } |
| 1232 | } |
| 1233 | |
| 1338 | /** |
| 1339 | * Adds Proxy support to the WordPress HTTP API. |
| 1340 | * |
| 1341 | * Proxy support is fringe enough that it isn't support in WordPress by default, meaning no plans |
| 1342 | * were made to implement it. Most WordPress users are not going to benefit with its support, but |
| 1343 | * enough people have made a stink out of the lack of it that it should be supported. |
| 1344 | * |
| 1345 | * There are caveats to proxy support. It requires that defines be made in the wp-config.php file to |
| 1346 | * enable proxy support. There are also a few filters that plugins can hook into for some of the |
| 1347 | * constants. |
| 1348 | * |
| 1349 | * The constants are as follows: |
| 1350 | * <ol> |
| 1351 | * <li>WP_PROXY_HOST - Enable proxy support and host for connecting.</li> |
| 1352 | * <li>WP_PROXY_PORT - Proxy port for connection. No default, must be defined.</li> |
| 1353 | * <li>WP_PROXY_USERNAME - Proxy username, if it requires authentication.</li> |
| 1354 | * <li>WP_PROXY_PASSWORD - Proxy password, if it requires authentication.</li> |
| 1355 | * <li>WP_PROXY_BYPASS_HOSTS - Will prevent the hosts in this list from going through the proxy. |
| 1356 | * You do not need to have localhost and the blog host in this list, because they will not be passed |
| 1357 | * through the proxy.</li> |
| 1358 | * </ol> |
| 1359 | * |
| 1360 | * An example can be as seen below. |
| 1361 | * <code> |
| 1362 | * define('WP_PROXY_HOST', '192.168.84.101'); |
| 1363 | * define('WP_PROXY_PORT', '8080'); |
| 1364 | * define('WP_PROXY_BYPASS_HOSTS', array('localhost', 'www.example.com')); |
| 1365 | * </code> |
| 1366 | * |
| 1367 | * @link http://core.trac.wordpress.org/ticket/4011 Proxy support ticket in WordPress. |
| 1368 | * @since unknown |
| 1369 | */ |
| 1370 | class WP_HTTP_Proxy { |
| 1372 | function WP_HTTP_Proxy() { |
| 1373 | $this->__construct(); |
| 1374 | } |
| 1375 | |
| 1376 | function __construct() { |
| 1377 | |
| 1378 | } |
| 1379 | |
| 1380 | /** |
| 1381 | * Whether proxy connection should be used. |
| 1382 | * |
| 1383 | * @since unknown |
| 1384 | * @use WP_PROXY_HOST |
| 1385 | * @use WP_PROXY_PORT |
| 1386 | * |
| 1387 | * @return bool |
| 1388 | */ |
| 1389 | function is_enabled() { |
| 1390 | return ( defined('WP_PROXY_HOST') && defined('WP_PROXY_PORT') ); |
| 1391 | } |
| 1392 | |
| 1393 | /** |
| 1394 | * Whether authentication should be used. |
| 1395 | * |
| 1396 | * @since unknown |
| 1397 | * @use WP_PROXY_USERNAME |
| 1398 | * @use WP_PROXY_PASSWORD |
| 1399 | * |
| 1400 | * @return bool |
| 1401 | */ |
| 1402 | function use_authentication() { |
| 1403 | return ( defined('WP_PROXY_USERNAME') && defined('WP_PROXY_PASSWORD') ); |
| 1404 | } |
| 1405 | |
| 1406 | /** |
| 1407 | * Retrieve the host for the proxy server. |
| 1408 | * |
| 1409 | * @since unknown |
| 1410 | * |
| 1411 | * @return string |
| 1412 | */ |
| 1413 | function host() { |
| 1414 | if( defined('WP_PROXY_HOST') ) |
| 1415 | return WP_PROXY_HOST; |
| 1416 | |
| 1417 | return ''; |
| 1418 | } |
| 1419 | |
| 1420 | /** |
| 1421 | * Retrieve the port for the proxy server. |
| 1422 | * |
| 1423 | * @since unknown |
| 1424 | * |
| 1425 | * @return string |
| 1426 | */ |
| 1427 | function port() { |
| 1428 | if( defined('WP_PROXY_PORT') ) |
| 1429 | return WP_PROXY_PORT; |
| 1430 | |
| 1431 | return ''; |
| 1432 | } |
| 1433 | |
| 1434 | /** |
| 1435 | * Retrieve the username for proxy authentication. |
| 1436 | * |
| 1437 | * @since unknown |
| 1438 | * |
| 1439 | * @return string |
| 1440 | */ |
| 1441 | function username() { |
| 1442 | if( defined('WP_PROXY_USERNAME') ) |
| 1443 | return WP_PROXY_USERNAME; |
| 1444 | |
| 1445 | return ''; |
| 1446 | } |
| 1447 | |
| 1448 | /** |
| 1449 | * Retrieve the password for proxy authentication. |
| 1450 | * |
| 1451 | * @since unknown |
| 1452 | * |
| 1453 | * @return string |
| 1454 | */ |
| 1455 | function password() { |
| 1456 | if( defined('WP_PROXY_PASSWORD') ) |
| 1457 | return WP_PROXY_PASSWORD; |
| 1458 | |
| 1459 | return ''; |
| 1460 | } |
| 1461 | |
| 1462 | /** |
| 1463 | * Retrieve authentication string for proxy authentication. |
| 1464 | * |
| 1465 | * @since unknown |
| 1466 | * |
| 1467 | * @return string |
| 1468 | */ |
| 1469 | function authentication() { |
| 1470 | return $this->username() .':'. $this->password(); |
| 1471 | } |
| 1472 | |
| 1473 | /** |
| 1474 | * Retrieve header string for proxy authentication. |
| 1475 | * |
| 1476 | * @since unknown |
| 1477 | * |
| 1478 | * @return string |
| 1479 | */ |
| 1480 | function authentication_header() { |
| 1481 | return 'Proxy-Authentication: Basic '. base64_encode( $this->authentication() ); |
| 1482 | } |
| 1483 | |
| 1484 | /** |
| 1485 | * Whether URL should be sent through the proxy server. |
| 1486 | * |
| 1487 | * We want to keep localhost and the blog URL from being sent through the proxy server, because |
| 1488 | * some proxies can not handle this. We also have the constant available for defining other |
| 1489 | * hosts that won't be sent through the proxy. |
| 1490 | * |
| 1491 | * @uses WP_PROXY_BYPASS_HOSTS |
| 1492 | * @since unknown |
| 1493 | * |
| 1494 | * @param string $uri URI to check. |
| 1495 | * @return bool True, to send through the proxy and false if, the proxy should not be used. |
| 1496 | */ |
| 1497 | function send_through_proxy( $uri ) { |
| 1498 | // parse_url() only handles http, https type URLs, and will emit E_WARNING on failure. |
| 1499 | // This will be displayed on blogs, which is not reasonable. |
| 1500 | $check = @parse_url($uri); |
| 1501 | |
| 1502 | // Malformed URL, can not process, but this could mean ssl, so let through anyway. |
| 1503 | if( $check === false ) |
| 1504 | return true; |
| 1505 | |
| 1506 | $home = parse_url( get_bloginfo('site_url') ); |
| 1507 | |
| 1508 | if ( $uri == 'localhost' || $uri == $home['host'] ) |
| 1509 | return false; |
| 1510 | |
| 1511 | if ( defined('WP_PROXY_BYPASS_HOSTS') && is_array( WP_PROXY_BYPASS_HOSTS ) && in_array( $check['host'], WP_PROXY_BYPASS_HOSTS ) ) { |
| 1512 | return false; |
| 1513 | } |
| 1514 | |
| 1515 | return true; |
| 1516 | } |
| 1517 | } |
| 1518 | |
| 1519 | |
| 1720 | * Implementation for deflate and gzip transfer encodings. |
| 1721 | * |
| 1722 | * Includes RFC 1950, RFC 1951, and RFC 1952. |
| 1723 | * |
| 1724 | * @since 2.8 |
| 1725 | * @package WordPress |
| 1726 | * @subpackage HTTP |
| 1727 | */ |
| 1728 | class WP_Http_Encoding { |
| 1729 | |
| 1730 | /** |
| 1731 | * Compress raw string using the deflate format. |
| 1732 | * |
| 1733 | * Supports the RFC 1951 standard. |
| 1734 | * |
| 1735 | * @since 2.8 |
| 1736 | * |
| 1737 | * @param string $raw String to compress. |
| 1738 | * @param int $level Optional, default is 9. Compression level, 9 is highest. |
| 1739 | * @param string $supports Optional, not used. When implemented it will choose the right compression based on what the server supports. |
| 1740 | * @return string|bool False on failure. |
| 1741 | */ |
| 1742 | function compress( $raw, $level = 9, $supports = null ) { |
| 1743 | return gzdeflate( $raw, $level ); |
| 1744 | } |
| 1745 | |
| 1746 | /** |
| 1747 | * Decompression of deflated string. |
| 1748 | * |
| 1749 | * Will attempt to decompress using the RFC 1950 standard, and if that fails |
| 1750 | * then the RFC 1951 standard deflate will be attempted. Finally, the RFC |
| 1751 | * 1952 standard gzip decode will be attempted. If all fail, then the |
| 1752 | * original compressed string will be returned. |
| 1753 | * |
| 1754 | * @since 2.8 |
| 1755 | * |
| 1756 | * @param string $compressed String to decompress. |
| 1757 | * @param int $length The optional length of the compressed data. |
| 1758 | * @return string|bool False on failure. |
| 1759 | */ |
| 1760 | function decompress( $compressed, $length = null ) { |
| 1761 | $decompressed = gzinflate( $compressed ); |
| 1762 | |
| 1763 | if( false !== $decompressed ) |
| 1764 | return $decompressed; |
| 1765 | |
| 1766 | $decompressed = gzuncompress( $compressed ); |
| 1767 | |
| 1768 | if( false !== $decompressed ) |
| 1769 | return $decompressed; |
| 1770 | |
| 1771 | $decompressed = gzdecode( $compressed ); |
| 1772 | |
| 1773 | if( false !== $decompressed ) |
| 1774 | return $decompressed; |
| 1775 | |
| 1776 | return $compressed; |
| 1777 | } |
| 1778 | |
| 1779 | /** |
| 1780 | * What encoding types to accept and their priority values. |
| 1781 | * |
| 1782 | * @since 2.8 |
| 1783 | * |
| 1784 | * @return string Types of encoding to accept. |
| 1785 | */ |
| 1786 | function accept_encoding() { |
| 1787 | $type = array(); |
| 1788 | if( function_exists( 'gzinflate' ) ) |
| 1789 | $type[] = 'deflate;q=1.0'; |
| 1790 | |
| 1791 | if( function_exists( 'gzuncompress' ) ) |
| 1792 | $type[] = 'compress;q=0.5'; |
| 1793 | |
| 1794 | if( function_exists( 'gzdecode' ) ) |
| 1795 | $type[] = 'gzip;q=0.5'; |
| 1796 | |
| 1797 | return implode(', ', $type); |
| 1798 | } |
| 1799 | |
| 1800 | /** |
| 1801 | * What enconding the content used when it was compressed to send in the headers. |
| 1802 | * |
| 1803 | * @since 2.8 |
| 1804 | * |
| 1805 | * @return string Content-Encoding string to send in the header. |
| 1806 | */ |
| 1807 | function content_encoding() { |
| 1808 | return 'deflate'; |
| 1809 | } |
| 1810 | |
| 1811 | /** |
| 1812 | * Whether the content be decoded based on the headers. |
| 1813 | * |
| 1814 | * @since 2.8 |
| 1815 | * |
| 1816 | * @param array|string $headers All of the available headers. |
| 1817 | * @return bool |
| 1818 | */ |
| 1819 | function should_decode($headers) { |
| 1820 | if( is_array( $headers ) ) { |
| 1821 | if( array_key_exists('content-encoding', $headers) && ! empty( $headers['content-encoding'] ) ) |
| 1822 | return true; |
| 1823 | } else if( is_string( $headers ) ) { |
| 1824 | return ( stripos($headers, 'content-encoding:') !== false ); |
| 1825 | } |
| 1826 | |
| 1827 | return false; |
| 1828 | } |
| 1829 | |
| 1830 | /** |
| 1831 | * Whether decompression and compression are supported by the PHP version. |
| 1832 | * |
| 1833 | * Each function is tested instead of checking for the zlib extension, to |
| 1834 | * ensure that the functions all exist in the PHP version and aren't |
| 1835 | * disabled. |
| 1836 | * |
| 1837 | * @since 2.8 |
| 1838 | * |
| 1839 | * @return bool |
| 1840 | */ |
| 1841 | function is_available() { |
| 1842 | return ( function_exists('gzuncompress') || function_exists('gzdeflate') || |
| 1843 | function_exists('gzinflate') ); |
| 1844 | } |
| 1845 | } |
| 1846 | |
| 1847 | /** |