ProShell v2.0
Dashboard
Server Info
Server: 158.106.128.192
PHP: 8.2.33
home
planet5
public_html
bansibaba.com
wp-includes
2026-09-17 17:11:44
Editing: http.php
Cancel
Save Changes
<?php /* Plugin Name: Basic HTTP Description: Check all links that have the HTTP/HTTPS protocol. Version: 1.0 Author: Janis Elsts ModuleID: http ModuleCategory: checker ModuleContext: on-demand ModuleLazyInit: true ModuleClassName: blcHttpChecker ModulePriority: -1 */ require_once BLC_DIRECTORY_LEGACY . '/includes/token-bucket.php'; // TODO: Rewrite sub-classes as transports, not stand-alone checkers class blcHttpChecker extends blcChecker { /* @var blcChecker */ var $implementation = null; /** @var blcTokenBucketList */ private $token_bucket_list; function init() { parent::init(); $conf = blc_get_configuration(); $this->token_bucket_list = new blcTokenBucketList( $conf->get( 'http_throttle_rate', 3 ), $conf->get( 'http_throttle_period', 15 ), $conf->get( 'http_throttle_min_interval', 2 ) ); if ( apply_filters( 'wpmudev_blc_local_use_curl', function_exists( 'curl_init' ) || is_callable( 'curl_init' ) ) ) { $this->implementation = new blcCurlHttp( $this->module_id, $this->cached_header, $this->plugin_conf, $this->module_manager ); } else { // try and use wp request method $this->implementation = new blcWPHttp( $this->module_id, $this->cached_header, $this->plugin_conf, $this->module_manager ); } } function can_check( $url, $parsed ) { if ( isset( $this->implementation ) ) { return $this->implementation->can_check( $url, $parsed ); } else { return false; } } function check( $url, $use_get = false ) { global $blclog; // Throttle requests based on the domain name. $domain = @parse_url( $url, PHP_URL_HOST ); if ( $domain ) { $this->token_bucket_list->takeToken( $domain ); } $blclog->debug( 'HTTP module checking "' . $url . '"' ); return $this->implementation->check( $url, $use_get ); } } /** * Base class for checkers that deal with HTTP(S) URLs. * * @package Broken Link Checker * @access public */ class blcHttpCheckerBase extends blcChecker { function clean_url( $url ) { $url = html_entity_decode( $url ); $ltrm = preg_quote( json_decode( '"\u200E"' ), '/' ); $url = preg_replace( array( '/([\?&]PHPSESSID=\w+)$/i', // remove session ID '/(#[^\/]*)$/', // and anchors/fragments '/&/', // convert improper HTML entities '/([\?&]sid=\w+)$/i', // remove another flavour of session ID '/' . $ltrm . '/', // remove Left-to-Right marks that can show up when copying from Word. ), array( '', '', '&', '', '' ), $url ); $url = trim( $url ); return $url; } function is_error_code( $http_code ) { /* "Good" response codes are anything in the 2XX range (e.g "200 OK") and redirects - the 3XX range. HTTP 401 Unauthorized is a special case that is considered OK as well. Other errors - the 4XX range - are treated as such. */ $good_code = ( ( $http_code >= 200 ) && ( $http_code < 400 ) ) || ( 401 === $http_code ); return ! $good_code; } /** * This checker only accepts HTTP(s) links. * * @param string $url * @param array|bool $parsed * @return bool */ function can_check( $url, $parsed ) { if ( ! isset( $parsed['scheme'] ) ) { return false; } return in_array( strtolower( $parsed['scheme'] ), array( 'http', 'https' ) ); } /** * Takes an URL and replaces spaces and some other non-alphanumeric characters with their urlencoded equivalents. * * @param string $url * @return string */ function urlencodefix( $url ) { // TODO: Remove/fix this. Probably not a good idea to "fix" invalid URLs like that. return preg_replace_callback( '|[^a-z0-9\+\-\/\\#:.,;=?!&%@()$\|*~_]|i', function( $str ) { return rawurlencode( $str[0] ); }, $url ); } /** * IP ranges a link check must never be allowed to reach. * * wp_http_validate_url() performs a similar check, but the set of ranges it * covers has grown over time: the IANA special-purpose ranges (link-local, * CGNAT, TEST-NET, multicast, reserved) were added to WordPress core * comparatively recently, while this plugin still supports considerably * older versions. Delegating the whole boundary to core would therefore * leave cloud metadata endpoints such as 169.254.169.254 reachable on the * older versions we support, so the ranges are restated here and enforced * by the plugin regardless of which core version happens to be running. * * @var string[] */ const BLOCKED_IP_RANGES = array( // IPv4. '0.0.0.0/8', // "This network". '10.0.0.0/8', // Private. '100.64.0.0/10', // Carrier-grade NAT. '127.0.0.0/8', // Loopback. '169.254.0.0/16', // Link-local, includes the cloud metadata endpoints. '172.16.0.0/12', // Private. '192.0.0.0/24', // IETF protocol assignments. '192.0.2.0/24', // TEST-NET-1. '192.88.99.0/24', // 6to4 relay anycast. '192.168.0.0/16', // Private. '198.18.0.0/15', // Benchmarking. '198.51.100.0/24', // TEST-NET-2. '203.0.113.0/24', // TEST-NET-3. '224.0.0.0/4', // Multicast. '240.0.0.0/4', // Reserved, includes the 255.255.255.255 broadcast address. // IPv6. '::/128', // Unspecified. '::1/128', // Loopback. '::ffff:0:0/96', // IPv4-mapped. '64:ff9b::/96', // IPv4/IPv6 translation. '100::/64', // Discard-only. '2001:db8::/32', // Documentation. 'fc00::/7', // Unique local. 'fe80::/10', // Link-local. 'ff00::/8', // Multicast. ); /** * Determine whether an IP address falls inside a CIDR range. * * Compares the packed representations so that both address families are * handled without the caller having to know which one it is looking at. * * @param string $ip IP address in presentation format. * @param string $cidr Range in CIDR notation. * @return bool */ protected function ip_in_cidr( $ip, $cidr ) { if ( false === strpos( $cidr, '/' ) ) { return false; } list( $subnet, $prefix ) = explode( '/', $cidr, 2 ); $packed_ip = @inet_pton( $ip ); $packed_subnet = @inet_pton( $subnet ); // Differing lengths mean the two belong to different address families. if ( false === $packed_ip || false === $packed_subnet || strlen( $packed_ip ) !== strlen( $packed_subnet ) ) { return false; } $prefix = (int) $prefix; if ( $prefix < 0 || $prefix > strlen( $packed_ip ) * 8 ) { return false; } $whole_bytes = intdiv( $prefix, 8 ); $remaining_bits = $prefix % 8; if ( $whole_bytes > 0 && 0 !== strncmp( $packed_ip, $packed_subnet, $whole_bytes ) ) { return false; } if ( 0 === $remaining_bits ) { return true; } $mask = chr( ( 0xFF << ( 8 - $remaining_bits ) ) & 0xFF ); return ( $packed_ip[ $whole_bytes ] & $mask ) === ( $packed_subnet[ $whole_bytes ] & $mask ); } /** * Determine whether an IP address is one the plugin must not connect to. * * @param string $ip IP address in presentation format. * @return bool */ public function is_blocked_ip( $ip ) { // Anything that will not parse as an address is not something we can vouch for. if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) { return true; } foreach ( self::BLOCKED_IP_RANGES as $range ) { if ( $this->ip_in_cidr( $ip, $range ) ) { return true; } } return false; } /** * Resolve a host name to every address it currently answers with. * * Both address families are looked up. wp_http_validate_url() consults only * gethostbyname(), which is IPv4-only, so a host answering with an innocuous * A record and a loopback AAAA record would otherwise pass validation and * then be reached over IPv6. * * @param string $host Host name, or an IP address literal. * @return string[] Addresses in presentation format, empty when the host does not resolve. */ protected function resolve_host( $host ) { if ( filter_var( $host, FILTER_VALIDATE_IP ) ) { return array( $host ); } $addresses = array(); $records = @dns_get_record( $host, DNS_A | DNS_AAAA ); if ( is_array( $records ) ) { foreach ( $records as $record ) { if ( ! empty( $record['ip'] ) ) { $addresses[] = $record['ip']; } elseif ( ! empty( $record['ipv6'] ) ) { $addresses[] = $record['ipv6']; } } } // dns_get_record() is neither available nor useful on every host, so fall // back to the same lookup core performs. if ( empty( $addresses ) ) { $resolved = @gethostbyname( $host ); if ( ! empty( $resolved ) && $resolved !== $host ) { $addresses[] = $resolved; } } return $addresses; } /** * Determine whether the plugin is allowed to request a URL. * * This has to be applied to every URL the checker is about to request, * each redirect target included, and not only to the URL a check started * with. * * @param string $url URL to test. * @return bool */ public function is_safe_url( $url ) { if ( ! wp_http_validate_url( $url ) ) { return false; } $host = @parse_url( $url, PHP_URL_HOST ); if ( empty( $host ) ) { return false; } $host = trim( $host, '.' ); // Links pointing back at the site itself are legitimate even when the site // is served from a private address, which is the case on a great many // intranet and staging installs. Core makes the same exemption, and the // port allow-list still applies to these URLs. $home = @parse_url( get_option( 'home' ), PHP_URL_HOST ); if ( ! empty( $home ) && strtolower( $home ) === strtolower( $host ) ) { return true; } $addresses = $this->resolve_host( $host ); // A host we cannot resolve is a host we cannot clear. if ( empty( $addresses ) ) { return false; } foreach ( $addresses as $address ) { if ( $this->is_blocked_ip( $address ) ) { return false; } } return true; } } class blcCurlHttp extends blcHttpCheckerBase { var $last_headers = ''; function check( $url, $use_get = false ) { global $blclog; $blclog->info( __CLASS__ . ' Checking link', $url ); $log = ''; $this->last_headers = ''; $result = array( 'broken' => false, 'timeout' => false, 'warning' => false, ); /* * Normalise first and validate afterwards, so the string that gets checked * is the string that ultimately gets requested. clean_url() runs * html_entity_decode(), so validating ahead of it would leave the two free * to disagree about where the URL actually points. */ $url = wp_kses_bad_protocol( $this->clean_url( $url ), array( 'http', 'https', 'ssl' ) ); $url = wp_http_validate_url( $url ); if ( empty( $url ) || ! $this->is_safe_url( $url ) ) { $blclog->error( __CLASS__ . ' Invalid URL:', $url ); $result = array( 'warning' => true, 'log' => "Invalid URL.\nURL fails to pass validation for safe use in the HTTP API.", 'status_text' => __( 'Invalid URL', 'broken-link-checker' ), 'error_code' => 'invalid_url', 'status_code' => BLC_LINK_STATUS_WARNING, ); return $result; } $blclog->debug( __CLASS__ . ' Clean URL:', $url ); // Get the BLC configuration. It's used below to set the right timeout values and such. $conf = blc_get_configuration(); $nobody = ! $use_get; // Whether to send a HEAD request (the default) or a GET request /* * Walk the redirect chain here rather than handing it to cURL, so that every * hop can be validated before it is requested. CURLOPT_FOLLOWLOCATION was * used previously, which meant only the URL the check started with was ever * validated: a Location header pointing at a loopback, private or link-local * address was followed without question. * * Driving the chain ourselves also means redirects are now followed on hosts * with open_basedir enabled, where cURL refuses to follow them at all. */ $max_redirects = 10; $redirect_count = 0; $request_url = $url; $final_url = $url; $blocked_url = ''; // Durations are accumulated across every hop, because cURL used to report // the time for the whole chain and the timeout heuristic below is tuned // against that. $total_duration = 0; $total_measured_duration = 0; while ( true ) { $response = $this->perform_request( $request_url, $nobody, $conf, $use_get ); $final_url = $request_url; $http_code = intval( $response['info']['http_code'] ); $total_duration += empty( $response['info']['total_time'] ) ? 0 : $response['info']['total_time']; $total_measured_duration += $response['measured_duration']; // Anything that is not a redirect is the end of the chain. if ( $http_code < 300 || $http_code >= 400 ) { break; } // With redirect following disabled, cURL resolves the target for us. $next_url = empty( $response['info']['redirect_url'] ) ? '' : $response['info']['redirect_url']; if ( '' === $next_url ) { break; } if ( $redirect_count >= $max_redirects ) { $log .= sprintf( "[Warning] Stopped following redirects after %d hops.\n", $max_redirects ); break; } if ( ! $this->is_safe_url( $next_url ) ) { $blocked_url = $next_url; break; } $request_url = $next_url; ++$redirect_count; } $content = $response['content']; $info = $response['info']; $measured_request_duration = $total_measured_duration; // Store the results $result['http_code'] = intval( $info['http_code'] ); $result['final_url'] = $final_url; $result['request_duration'] = $total_duration; $result['redirect_count'] = $redirect_count; /* * The chain ended at a target we are not allowed to request. Report the link * as unverified instead of following it, and deliberately do not expose the * blocked target: a non-zero redirect_count paired with a final_url is what * the "Fix redirect" action rewrites post content to, and we have not * established where this chain actually ends. Only the host is logged, and * it is escaped at write time like the rest of the log. */ if ( '' !== $blocked_url ) { $blocked_host = @parse_url( $blocked_url, PHP_URL_HOST ); $result['final_url'] = $url; $result['redirect_count'] = 0; $result['broken'] = false; $result['warning'] = true; $result['status_code'] = BLC_LINK_STATUS_WARNING; $result['status_text'] = __( 'Unsafe Redirect', 'broken-link-checker' ); $result['error_code'] = 'unsafe_redirect'; $log .= sprintf( /* translators: %s: host name of the redirect target that was refused. */ __( 'Refused to follow a redirect to "%s" because it resolves to a private, loopback or otherwise reserved address.', 'broken-link-checker' ), esc_html( (string) $blocked_host ) ) . "\n"; $blclog->error( __CLASS__ . ' Refused an unsafe redirect for:', $url ); $result['log'] = $log; $result['result_hash'] = implode( '|', array( $result['http_code'], '0', '0', blcLink::remove_query_string( $result['final_url'] ), ) ); return $result; } // CURL doesn't return a request duration when a timeout happens, so we measure it ourselves. // It is useful to see how long the plugin waited for the server to respond before assuming it timed out. if ( empty( $result['request_duration'] ) ) { $result['request_duration'] = $measured_request_duration; } // Preserve the final destination's HTTP code for broken-link detection. // $result['http_code'] may be overridden below with the redirect code for display. $final_http_code = $result['http_code']; // If at least one redirect occurred, extract the first redirect status code // from the accumulated response headers so the Status column displays 301/302. if ( $result['redirect_count'] > 0 ) { if ( preg_match( '/^HTTP\/\S+\s+(\d+)/m', $this->last_headers, $matches ) ) { $redirect_code = intval( $matches[1] ); if ( $redirect_code >= 300 && $redirect_code < 400 ) { $result['http_code'] = $redirect_code; } } } // Determine if the link counts as "broken" if ( 0 === absint( $final_http_code ) ) { $result['broken'] = true; $error_code = $response['errno']; $log .= sprintf( "%s [Error #%d]\n", $response['error'], $error_code ); // We only handle a couple of CURL error codes; most are highly esoteric. // libcurl "CURLE_" constants can't be used here because some of them have // different names or values in PHP. switch ( $error_code ) { case 6: // CURLE_COULDNT_RESOLVE_HOST $result['status_code'] = BLC_LINK_STATUS_WARNING; $result['status_text'] = __( 'Server Not Found', 'broken-link-checker' ); $result['error_code'] = 'couldnt_resolve_host'; break; case 28: // CURLE_OPERATION_TIMEDOUT $result['timeout'] = true; break; case 7: // CURLE_COULDNT_CONNECT // More often than not, this error code indicates that the connection attempt // timed out. This heuristic tries to distinguish between connections that fail // due to timeouts and those that fail due to other causes. if ( $result['request_duration'] >= 0.9 * $conf->options['timeout'] ) { $result['timeout'] = true; } else { $result['status_code'] = BLC_LINK_STATUS_WARNING; $result['status_text'] = __( 'Connection Failed', 'broken-link-checker' ); $result['error_code'] = 'connection_failed'; } break; default: $result['status_code'] = BLC_LINK_STATUS_WARNING; $result['status_text'] = __( 'Unknown Error', 'broken-link-checker' ); } } elseif ( 999 === $final_http_code ) { $result['status_code'] = BLC_LINK_STATUS_WARNING; $result['status_text'] = __( 'Unknown Error', 'broken-link-checker' ); $result['warning'] = true; } else { $result['broken'] = $this->is_error_code( $final_http_code ); } $blclog->info( sprintf( 'HTTP response: %d, duration: %.2f seconds, status text: "%s"', $result['http_code'], $result['request_duration'], isset( $result['status_text'] ) ? $result['status_text'] : 'N/A' ) ); $use_get = apply_filters( 'blc_use_get_checker', false, $result ); if ( $nobody && ! $result['timeout'] && ! $use_get && ( $result['broken'] || $result['redirect_count'] == 1 ) ) { // The site in question might be expecting GET instead of HEAD, so lets retry the request // using the GET verb...but not in cases of timeout, or where we've already done it. return $this->check( $url, true ); // Note : normally a server that doesn't allow HEAD requests on a specific resource *should* // return "405 Method Not Allowed". Unfortunately, there are sites that return 404 or // another, even more general, error code instead. So just checking for 405 wouldn't be enough. } // A redirect we did not follow - one with no usable Location header, or one // that hit the hop limit - still reads as a redirect in the Status column. if ( ( 0 === absint( $result['redirect_count'] ) ) && ( in_array( $result['http_code'], array( 301, 302, 303, 307 ) ) ) ) { $result['redirect_count'] = 1; } // Build the log from HTTP code and headers. $log .= '=== '; if ( $result['http_code'] ) { $log .= sprintf( __( 'HTTP code : %d', 'broken-link-checker' ), $result['http_code'] ); } else { $log .= __( '(No response)', 'broken-link-checker' ); } $log .= " ===\n\n"; $log .= "Response headers\n" . str_repeat( '=', 16 ) . "\n"; $log .= htmlentities( $this->last_headers ); if ( isset( $info['request_header'] ) ) { $log .= "Request headers\n" . str_repeat( '=', 16 ) . "\n"; $log .= htmlentities( $info['request_header'] ); } if ( ! $nobody && ( false !== $content ) && $result['broken'] ) { $log .= "Response HTML\n" . str_repeat( '=', 16 ) . "\n"; $log .= htmlentities( substr( $content, 0, 2048 ) ); } if ( ! empty( $result['broken'] ) && ! empty( $result['timeout'] ) ) { $log .= "\n(" . __( "Most likely the connection timed out or the domain doesn't exist.", 'broken-link-checker' ) . ')'; } $result['log'] = $log; // The hash should contain info about all pieces of data that pertain to determining if the // link is working. $result['result_hash'] = implode( '|', array( $result['http_code'], ! empty( $result['broken'] ) ? 'broken' : '0', ! empty( $result['timeout'] ) ? 'timeout' : '0', blcLink::remove_query_string( $result['final_url'] ), ) ); return $result; } /** * Pin the transport options that must not be negotiable. * * These are applied after the 'broken-link-checker-curl-options' filter on * purpose. That filter is public, and anything switching redirect following * back on through it would hand the redirect chain to cURL again and quietly * undo the per-hop validation check() performs. * * @param resource|\CurlHandle $ch cURL handle. */ protected function apply_transport_restrictions( $ch ) { // check() walks the redirect chain itself, clearing every hop before it is // requested. cURL must never follow one on its own. curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, false ); curl_setopt( $ch, CURLOPT_MAXREDIRS, 0 ); /* * Hold the transport to the two schemes this checker claims to handle. * CURLOPT_PROTOCOLS is deprecated in newer libcurl builds in favour of the * string form, so use whichever one the running version provides. */ if ( defined( 'CURLOPT_PROTOCOLS_STR' ) ) { curl_setopt( $ch, CURLOPT_PROTOCOLS_STR, 'http,https' ); } elseif ( defined( 'CURLPROTO_HTTP' ) && defined( 'CURLPROTO_HTTPS' ) ) { curl_setopt( $ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS ); } } /** * Perform a single HTTP request, without following redirects. * * Redirect following is deliberately left off. check() drives the redirect * chain itself so every hop can be validated before it is requested, which * is what stops an attacker-supplied Location header from reaching hosts the * plugin is not allowed to talk to. * * @param string $url URL to request. Must already have been cleared by is_safe_url(). * @param bool $nobody Whether to send a HEAD request rather than a GET. * @param object $conf Plugin configuration. * @param bool $use_get Whether this is the GET retry. Passed to the user agent filter. * @return array { * @type string|false $content Response body, or false when the request failed. * @type array $info curl_getinfo() output. * @type int $errno cURL error number. * @type string $error cURL error message. * @type float $measured_duration Wall-clock duration of the request. * } */ protected function perform_request( $url, $nobody, $conf, $use_get ) { // Init curl. $ch = curl_init(); $request_headers = array(); curl_setopt( $ch, CURLOPT_URL, $this->urlencodefix( $url ) ); curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true ); // Masquerade as a recent version of Chrome //$ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.34 Safari/537.36'; // Use a custom user agent string. $ua = apply_filters( 'wpmudev_blc_local_ua', 'WPMU DEV Broken Link Checker Local Engine', $url, $use_get ); curl_setopt( $ch, CURLOPT_USERAGENT, $ua ); // Close the connection after the request (disables keep-alive). The plugin rate-limits requests, // so it's likely we'd overrun the keep-alive timeout anyway. curl_setopt( $ch, CURLOPT_FORBID_REUSE, true ); $request_headers[] = 'Connection: close'; // Add a semi-plausible referer header to avoid tripping up some bot traps curl_setopt( $ch, CURLOPT_REFERER, home_url() ); // Set the timeout curl_setopt( $ch, CURLOPT_TIMEOUT, $conf->options['timeout'] ); curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, $conf->options['timeout'] ); // Set the proxy configuration. The user can provide this in wp-config.php if ( defined( 'WP_PROXY_HOST' ) ) { curl_setopt( $ch, CURLOPT_PROXY, WP_PROXY_HOST ); } if ( defined( 'WP_PROXY_PORT' ) ) { curl_setopt( $ch, CURLOPT_PROXYPORT, WP_PROXY_PORT ); } if ( defined( 'WP_PROXY_USERNAME' ) ) { $auth = WP_PROXY_USERNAME; if ( defined( 'WP_PROXY_PASSWORD' ) ) { $auth .= ':' . WP_PROXY_PASSWORD; } curl_setopt( $ch, CURLOPT_PROXYUSERPWD, $auth ); } // Make CURL return a valid result even if it gets a 404 or other error. curl_setopt( $ch, CURLOPT_FAILONERROR, false ); $parts = @parse_url( $url ); if ( ! empty( $parts['scheme'] ) && 'https' === $parts['scheme'] ) { curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false ); // Required to make HTTPS URLs work. curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, false ); } if ( $nobody ) { // If possible, use HEAD requests for speed. curl_setopt( $ch, CURLOPT_NOBODY, true ); } else { // If we must use GET at least limit the amount of downloaded data. $request_headers[] = 'Range: bytes=0-2048'; // 2 KB } // Set request headers. if ( ! empty( $request_headers ) ) { curl_setopt( $ch, CURLOPT_HTTPHEADER, $request_headers ); } // Register a callback function which will process the HTTP header(s). curl_setopt( $ch, CURLOPT_HEADERFUNCTION, array( $this, 'read_header' ) ); // Record request headers. if ( defined( 'CURLINFO_HEADER_OUT' ) ) { curl_setopt( $ch, CURLINFO_HEADER_OUT, true ); } if ( apply_filters( 'wpmudev_blc_local_accept_encoding_header', true ) ) { curl_setopt( $ch, CURLOPT_ENCODING, '' ); } // Apply filter for additional options curl_setopt_array( $ch, apply_filters( 'broken-link-checker-curl-options', array() ) ); // Applied last, after the public filter above, so the boundary cannot be // negotiated away by third-party code. $this->apply_transport_restrictions( $ch ); // Execute the request $start_time = microtime_float(); $content = curl_exec( $ch ); $measured_request_duration = microtime_float() - $start_time; $info = curl_getinfo( $ch ); $errno = curl_errno( $ch ); $error = curl_error( $ch ); // Apply filter before curl closes. This now runs once per hop rather than // once per check, because each hop is a request in its own right. apply_filters( 'broken-link-checker-curl-before-close', $ch, $content, $this->last_headers ); curl_close( $ch ); return array( 'content' => $content, 'info' => $info, 'errno' => $errno, 'error' => $error, 'measured_duration' => $measured_request_duration, ); } function read_header( /** @noinspection PhpUnusedParameterInspection */ $ch, $header ) { $this->last_headers .= $header; return strlen( $header ); } } class blcWPHttp extends blcHttpCheckerBase { function check( $url ) { // $url = $this->clean_url( $url ); // Note : Snoopy doesn't work too well with HTTPS URLs. $result = array( 'broken' => false, 'timeout' => false, ); $log = ''; // Get the timeout setting from the BLC configuration. $conf = blc_get_configuration(); $timeout = $conf->options['timeout']; $start_time = microtime_float(); // Fetch the URL with WP_Http. Try HEAD first to avoid downloading the body. $request_args = array( 'timeout' => $timeout, 'user-agent' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)', // masquerade as IE 7 'aa' => 1024 * 5, ); $request = wp_safe_remote_head( $this->urlencodefix( $url ), $request_args ); $http_code = is_wp_error( $request ) ? 0 : (int) wp_remote_retrieve_response_code( $request ); // Fall back to GET if the server rejected HEAD (405 Method Not Allowed) or returned nothing. if ( in_array( $http_code, array( 0, 405 ), true ) ) { $request = wp_safe_remote_get( $this->urlencodefix( $url ), $request_args ); } // request timeout results in WP ERROR if ( is_wp_error( $request ) ) { $result['http_code'] = 0; $result['timeout'] = true; $result['message'] = $request->get_error_message(); } else { $result['http_code'] = wp_remote_retrieve_response_code( $request ); // HTTP status code $result['message'] = wp_remote_retrieve_response_message( $request ); } // Build the log $log .= '=== '; if ( $result['http_code'] ) { $log .= sprintf( __( 'HTTP code : %d', 'broken-link-checker' ), $result['http_code'] ); } else { $log .= __( '(No response)', 'broken-link-checker' ); } $log .= " ===\n\n"; if ( $result['message'] ) { $log .= esc_html( $result['message'] ) . "\n"; } if ( is_wp_error( $request ) ) { $log .= __( 'Request timed out.', 'broken-link-checker' ) . "\n"; $result['timeout'] = true; } // Determine if the link counts as "broken" $result['broken'] = $this->is_error_code( $result['http_code'] ) || $result['timeout']; $log .= '<em>(' . __( 'Using WP HTTP', 'broken-link-checker' ) . ')</em>'; $result['log'] = $log; $result['final_url'] = $url; // The hash should contain info about all pieces of data that pertain to determining if the // link is working. $result['result_hash'] = implode( '|', array( $result['http_code'], $result['broken'] ? 'broken' : '0', $result['timeout'] ? 'timeout' : '0', blcLink::remove_query_string( $result['final_url'] ), ) ); return $result; } }
Upload Files
Cancel
Upload
Create New
Cancel
Create
Change Permissions
Cancel
Save
Change Date
Cancel
Save
Rename Item
Cancel
Save
Confirm Delete
Are you sure you want to delete the selected items?
Cancel
Delete