| 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 | /** |