function esc_url($url, $protocols = null, $_context = 'display') { $original_url = $url; if ('' == $url) { return $url; } $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\\|*\'()\\x80-\\xff]|i', '', $url); $strip = array('%0d', '%0a', '%0D', '%0A'); $url = _deep_replace($strip, $url); $url = str_replace(';//', '://', $url); if (strpos($url, ':') === false && substr($url, 0, 1) != '/' && substr($url, 0, 1) != '#' && !preg_match('/^[a-z0-9-]+?\\.php/i', $url)) { $url = 'http://' . $url; } if ('display' == $_context) { $url = preg_replace('/&([^#])(?![a-z]{2,8};)/', '&$1', $url); $url = str_replace("'", ''', $url); } if (!is_array($protocols)) { $protocols = array('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn'); } if (wp_kses_bad_protocol($url, $protocols) != $url) { return ''; } return apply_filters('clean_url', $url, $original_url, $_context); }
function nextgen_esc_url($url, $protocols = null, $_context = 'display') { $original_url = $url; if ('' == $url) { return $url; } $url = preg_replace('|[^a-z0-9 \\-~+_.?#=!&;,/:%@$\\|*\'()\\x80-\\xff]|i', '', $url); $strip = array('%0d', '%0a', '%0D', '%0A'); $url = _deep_replace($strip, $url); $url = str_replace(';//', '://', $url); /* If the URL doesn't appear to contain a scheme, we * presume it needs http:// appended (unless a relative * link starting with /, # or ? or a php file). */ if (strpos($url, ':') === false && !in_array($url[0], array('/', '#', '?')) && !preg_match('/^[a-z0-9-]+?\\.php/i', $url)) { $url = 'http://' . $url; } // Replace ampersands and single quotes only when displaying. if ('display' == $_context) { $url = wp_kses_normalize_entities($url); $url = str_replace('&', '&', $url); $url = str_replace("'", ''', $url); $url = str_replace('%', '%25', $url); $url = str_replace(' ', '%20', $url); } if ('/' === $url[0]) { $good_protocol_url = $url; } else { if (!is_array($protocols)) { $protocols = wp_allowed_protocols(); } $good_protocol_url = wp_kses_bad_protocol($url, $protocols); if (strtolower($good_protocol_url) != strtolower($url)) { return ''; } } return apply_filters('clean_url', $good_protocol_url, $original_url, $_context); }
/** * Send an HTTP request to a URI. * * Please note: The only URI that are supported in the HTTP Transport implementation * are the HTTP and HTTPS protocols. * * @access public * @since 2.7.0 * * @param string $url The request URL. * @param string|array $args { * Optional. Array or string of HTTP request arguments. * * @type string $method Request method. Accepts 'GET', 'POST', 'HEAD', or 'PUT'. * Some transports technically allow others, but should not be * assumed. Default 'GET'. * @type int $timeout How long the connection should stay open in seconds. Default 5. * @type int $redirection Number of allowed redirects. Not supported by all transports * Default 5. * @type string $httpversion Version of the HTTP protocol to use. Accepts '1.0' and '1.1'. * Default '1.0'. * @type string $user-agent User-agent value sent. * Default WordPress/' . get_bloginfo( 'version' ) . '; ' . get_bloginfo( 'url' ). * @type bool $reject_unsafe_urls Whether to pass URLs through wp_http_validate_url(). * Default false. * @type bool $blocking Whether the calling code requires the result of the request. * If set to false, the request will be sent to the remote server, * and processing returned to the calling code immediately, the caller * will know if the request succeeded or failed, but will not receive * any response from the remote server. Default true. * @type string|array $headers Array or string of headers to send with the request. * Default empty array. * @type array $cookies List of cookies to send with the request. Default empty array. * @type string|array $body Body to send with the request. Default null. * @type bool $compress Whether to compress the $body when sending the request. * Default false. * @type bool $decompress Whether to decompress a compressed response. If set to false and * compressed content is returned in the response anyway, it will * need to be separately decompressed. Default true. * @type bool $sslverify Whether to verify SSL for the request. Default true. * @type string sslcertificates Absolute path to an SSL certificate .crt file. * Default ABSPATH . WPINC . '/certificates/ca-bundle.crt'. * @type bool $stream Whether to stream to a file. If set to true and no filename was * given, it will be droped it in the WP temp dir and its name will * be set using the basename of the URL. Default false. * @type string $filename Filename of the file to write to when streaming. $stream must be * set to true. Default null. * @type int $limit_response_size Size in bytes to limit the response to. Default null. * * } * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'. * A WP_Error instance upon error. */ public function request($url, $args = array()) { $defaults = array('method' => 'GET', 'timeout' => apply_filters('http_request_timeout', 5), 'redirection' => apply_filters('http_request_redirection_count', 5), 'httpversion' => apply_filters('http_request_version', '1.0'), 'user-agent' => apply_filters('http_headers_useragent', 'WordPress/' . get_bloginfo('version') . '; ' . get_bloginfo('url')), 'reject_unsafe_urls' => apply_filters('http_request_reject_unsafe_urls', false), 'blocking' => true, 'headers' => array(), 'cookies' => array(), 'body' => null, 'compress' => false, 'decompress' => true, 'sslverify' => true, 'sslcertificates' => ABSPATH . WPINC . '/certificates/ca-bundle.crt', 'stream' => false, 'filename' => null, 'limit_response_size' => null); // Pre-parse for the HEAD checks. $args = wp_parse_args($args); // By default, Head requests do not cause redirections. if (isset($args['method']) && 'HEAD' == $args['method']) { $defaults['redirection'] = 0; } $r = wp_parse_args($args, $defaults); /** * Filters the arguments used in an HTTP request. * * @since 2.7.0 * * @param array $r An array of HTTP request arguments. * @param string $url The request URL. */ $r = apply_filters('http_request_args', $r, $url); // The transports decrement this, store a copy of the original value for loop purposes. if (!isset($r['_redirection'])) { $r['_redirection'] = $r['redirection']; } /** * Filters whether to preempt an HTTP request's return value. * * Returning a non-false value from the filter will short-circuit the HTTP request and return * early with that value. A filter should return either: * * - An array containing 'headers', 'body', 'response', 'cookies', and 'filename' elements * - A WP_Error instance * - boolean false (to avoid short-circuiting the response) * * Returning any other value may result in unexpected behaviour. * * @since 2.9.0 * * @param false|array|WP_Error $preempt Whether to preempt an HTTP request's return value. Default false. * @param array $r HTTP request arguments. * @param string $url The request URL. */ $pre = apply_filters('pre_http_request', false, $r, $url); if (false !== $pre) { return $pre; } if (function_exists('wp_kses_bad_protocol')) { if ($r['reject_unsafe_urls']) { $url = wp_http_validate_url($url); } if ($url) { $url = wp_kses_bad_protocol($url, array('http', 'https', 'ssl')); } } $arrURL = @parse_url($url); if (empty($url) || empty($arrURL['scheme'])) { return new WP_Error('http_request_failed', __('A valid URL was not provided.')); } if ($this->block_request($url)) { return new WP_Error('http_request_failed', __('User has blocked requests through HTTP.')); } // If we are streaming to a file but no filename was given drop it in the WP temp dir // and pick its name using the basename of the $url if ($r['stream']) { if (empty($r['filename'])) { $r['filename'] = get_temp_dir() . basename($url); } // Force some settings if we are streaming to a file and check for existence and perms of destination directory $r['blocking'] = true; if (!wp_is_writable(dirname($r['filename']))) { return new WP_Error('http_request_failed', __('Destination directory for file streaming does not exist or is not writable.')); } } if (is_null($r['headers'])) { $r['headers'] = array(); } // WP allows passing in headers as a string, weirdly. if (!is_array($r['headers'])) { $processedHeaders = WP_Http::processHeaders($r['headers']); $r['headers'] = $processedHeaders['headers']; } // Setup arguments $headers = $r['headers']; $data = $r['body']; $type = $r['method']; $options = array('timeout' => $r['timeout'], 'useragent' => $r['user-agent'], 'blocking' => $r['blocking'], 'hooks' => new WP_HTTP_Requests_Hooks($url, $r)); // Ensure redirects follow browser behaviour. $options['hooks']->register('requests.before_redirect', array(get_class(), 'browser_redirect_compatibility')); if ($r['stream']) { $options['filename'] = $r['filename']; } if (empty($r['redirection'])) { $options['follow_redirects'] = false; } else { $options['redirects'] = $r['redirection']; } // Use byte limit, if we can if (isset($r['limit_response_size'])) { $options['max_bytes'] = $r['limit_response_size']; } // If we've got cookies, use and convert them to Requests_Cookie. if (!empty($r['cookies'])) { $options['cookies'] = WP_Http::normalize_cookies($r['cookies']); } // SSL certificate handling if (!$r['sslverify']) { $options['verify'] = false; $options['verifyname'] = false; } else { $options['verify'] = $r['sslcertificates']; } // All non-GET/HEAD requests should put the arguments in the form body. if ('HEAD' !== $type && 'GET' !== $type) { $options['data_format'] = 'body'; } /** * Filters whether SSL should be verified for non-local requests. * * @since 2.8.0 * * @param bool $ssl_verify Whether to verify the SSL connection. Default true. */ $options['verify'] = apply_filters('https_ssl_verify', $options['verify']); // Check for proxies. $proxy = new WP_HTTP_Proxy(); if ($proxy->is_enabled() && $proxy->send_through_proxy($url)) { $options['proxy'] = new Requests_Proxy_HTTP($proxy->host() . ':' . $proxy->port()); if ($proxy->use_authentication()) { $options['proxy']->use_authentication = true; $options['proxy']->user = $proxy->username(); $options['proxy']->pass = $proxy->password(); } } // Avoid issues where mbstring.func_overload is enabled mbstring_binary_safe_encoding(); try { $requests_response = Requests::request($url, $headers, $data, $type, $options); // Convert the response into an array $http_response = new WP_HTTP_Requests_Response($requests_response, $r['filename']); $response = $http_response->to_array(); // Add the original object to the array. $response['http_response'] = $http_response; } catch (Requests_Exception $e) { $response = new WP_Error('http_request_failed', $e->getMessage()); } reset_mbstring_encoding(); /** * Fires after an HTTP API response is received and before the response is returned. * * @since 2.8.0 * * @param array|WP_Error $response HTTP response or WP_Error object. * @param string $context Context under which the hook is fired. * @param string $class HTTP transport used. * @param array $args HTTP request arguments. * @param string $url The request URL. */ do_action('http_api_debug', $response, 'response', 'Requests', $r, $url); if (is_wp_error($response)) { return $response; } if (!$r['blocking']) { return array('headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array(), 'http_response' => null); } /** * Filters the HTTP API response immediately before the response is returned. * * @since 2.9.0 * * @param array $response HTTP response. * @param array $r HTTP request arguments. * @param string $url The request URL. */ return apply_filters('http_response', $response, $r, $url); }
/** * Validate a URL for safe use in the HTTP API. * * @since 3.5.2 * * @return mixed URL or false on failure. */ function wp_http_validate_url($url) { $original_url = $url; $url = wp_kses_bad_protocol($url, array('http', 'https')); if (!$url || strtolower($url) !== strtolower($original_url)) { return false; } $parsed_url = @parse_url($url); if (!$parsed_url || empty($parsed_url['host'])) { return false; } if (isset($parsed_url['user']) || isset($parsed_url['pass'])) { return false; } if (false !== strpbrk($parsed_url['host'], ':#?[]')) { return false; } $parsed_home = @parse_url(get_option('home')); $same_host = strtolower($parsed_home['host']) === strtolower($parsed_url['host']); if (!$same_host) { $host = trim($parsed_url['host'], '.'); if (preg_match('#^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$#', $host)) { $ip = $host; } else { $ip = gethostbyname($host); if ($ip === $host) { // Error condition for gethostbyname() $ip = false; } } if ($ip) { $parts = array_map('intval', explode('.', $ip)); if (127 === $parts[0] || 10 === $parts[0] || 172 === $parts[0] && 16 <= $parts[1] && 31 >= $parts[1] || 192 === $parts[0] && 168 === $parts[1]) { // If host appears local, reject unless specifically allowed. /** * Check if HTTP request is external or not. * * Allows to change and allow external requests for the HTTP request. * * @since 3.6.0 * * @param bool false Whether HTTP request is external or not. * @param string $host IP of the requested host. * @param string $url URL of the requested host. */ if (!apply_filters('http_request_host_is_external', false, $host, $url)) { return false; } } } } if (empty($parsed_url['port'])) { return $url; } $port = $parsed_url['port']; if (80 === $port || 443 === $port || 8080 === $port) { return $url; } if ($parsed_home && $same_host && $parsed_home['port'] === $port) { return $url; } return false; }
function test_wp_kses_bad_protocol() { $bad = array('dummy:alert(1)', 'javascript:alert(1)', 'JaVaScRiPt:alert(1)', 'javascript:alert(1);', 'javascript:alert(1);', 'javascript:alert(1);', 'javascript:alert(1);', 'javascript:alert(1);', 'javascript:alert(1);', 'javascript:alert(1);', 'javascript:alert(1);', 'javascript:alert(1);', 'javascript:alert('XSS')', 'jav ascript:alert(1);', 'jav	ascript:alert(1);', 'jav
ascript:alert(1);', 'jav
ascript:alert(1);', '  javascript:alert(1);', 'javascript:javascript:alert(1);', 'javascript:javascript:alert(1);', 'javascript:javascript:alert(1);', 'javascript:javascript:alert(1);', 'javascript:javascript:alert(1);', 'javascript:alert(1)//?:', 'feed:javascript:alert(1)', 'feed:javascript:feed:javascript:feed:javascript:alert(1)'); foreach ($bad as $k => $x) { $result = wp_kses_bad_protocol(wp_kses_normalize_entities($x), wp_allowed_protocols()); if (!empty($result) && $result != 'alert(1);' && $result != 'alert(1)') { switch ($k) { case 6: $this->assertEquals('javascript&#0000058alert(1);', $result); break; case 12: $this->assertEquals(str_replace('&', '&', $x), $result); break; case 22: $this->assertEquals('javascript&#0000058alert(1);', $result); break; case 23: $this->assertEquals('javascript&#0000058alert(1)//?:', $result); break; case 24: $this->assertEquals('feed:alert(1)', $result); break; default: $this->fail("wp_kses_bad_protocol failed on {$x}. Result: {$result}"); } } } $safe = array('dummy:alert(1)', 'HTTP://example.org/', 'http://example.org/', 'http://example.org/', 'http://example.org/', 'https://example.org', 'http://example.org/wp-admin/post.php?post=2&action=edit', 'http://example.org/index.php?test='blah''); foreach ($safe as $x) { $result = wp_kses_bad_protocol(wp_kses_normalize_entities($x), array('http', 'https', 'dummy')); if ($result != $x && $result != 'http://example.org/') { $this->fail("wp_kses_bad_protocol incorrectly blocked {$x}"); } } }
/** * Checks and cleans a URL. * * A number of characters are removed from the URL. If the URL is for displaying * (the default behaviour) ampersands are also replaced. The 'clean_url' filter * is applied to the returned cleaned URL. * * @since 2.8.0 * @uses wp_kses_bad_protocol() To only permit protocols in the URL set * via $protocols or the common ones set in the function. * * @param string $url The URL to be cleaned. * @param array $protocols Optional. An array of acceptable protocols. * Defaults to 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn' if not set. * @param string $_context Private. Use esc_url_raw() for database usage. * @return string The cleaned $url after the 'clean_url' filter is applied. */ function esc_url( $url, $protocols = null, $_context = 'display' ) { $original_url = $url; if ( '' == $url ) return $url; $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url); $strip = array('%0d', '%0a', '%0D', '%0A'); $url = _deep_replace($strip, $url); $url = str_replace(';//', '://', $url); /* If the URL doesn't appear to contain a scheme, we * presume it needs http:// appended (unless a relative * link starting with /, # or ? or a php file). */ if ( strpos($url, ':') === false && ! in_array( $url[0], array( '/', '#', '?' ) ) && ! preg_match('/^[a-z0-9-]+?\.php/i', $url) ) $url = 'http://' . $url; // Replace ampersands and single quotes only when displaying. if ( 'display' == $_context ) { $url = wp_kses_normalize_entities( $url ); $url = str_replace( '&', '&', $url ); $url = str_replace( "'", ''', $url ); } if ( '/' === $url[0] ) { $good_protocol_url = $url; } else { if ( ! is_array( $protocols ) ) $protocols = wp_allowed_protocols(); $good_protocol_url = wp_kses_bad_protocol( $url, $protocols ); if ( strtolower( $good_protocol_url ) != strtolower( $url ) ) return ''; } /** * Filter a string cleaned and escaped for output as a URL. * * @since 2.3.0 * * @param string $good_protocol_url The cleaned URL to be returned. * @param string $original_url The URL prior to cleaning. * @param string $_context If 'display', replace ampersands and single quotes only. */ return apply_filters( 'clean_url', $good_protocol_url, $original_url, $_context ); }
/** * Send an HTTP request to a URI. * * Please note: The only URI that are supported in the HTTP Transport implementation * are the HTTP and HTTPS protocols. * * @access public * @since 2.7.0 * * @global string $wp_version * * @param string $url The request URL. * @param string|array $args { * Optional. Array or string of HTTP request arguments. * * @type string $method Request method. Accepts 'GET', 'POST', 'HEAD', or 'PUT'. * Some transports technically allow others, but should not be * assumed. Default 'GET'. * @type int $timeout How long the connection should stay open in seconds. Default 5. * @type int $redirection Number of allowed redirects. Not supported by all transports * Default 5. * @type string $httpversion Version of the HTTP protocol to use. Accepts '1.0' and '1.1'. * Default '1.0'. * @type string $user-agent User-agent value sent. * Default WordPress/' . $wp_version . '; ' . get_bloginfo( 'url' ). * @type bool $reject_unsafe_urls Whether to pass URLs through {@see wp_http_validate_url()}. * Default false. * @type bool $blocking Whether the calling code requires the result of the request. * If set to false, the request will be sent to the remote server, * and processing returned to the calling code immediately, the caller * will know if the request succeeded or failed, but will not receive * any response from the remote server. Default true. * @type string|array $headers Array or string of headers to send with the request. * Default empty array. * @type array $cookies List of cookies to send with the request. Default empty array. * @type string|array $body Body to send with the request. Default null. * @type bool $compress Whether to compress the $body when sending the request. * Default false. * @type bool $decompress Whether to decompress a compressed response. If set to false and * compressed content is returned in the response anyway, it will * need to be separately decompressed. Default true. * @type bool $sslverify Whether to verify SSL for the request. Default true. * @type string sslcertificates Absolute path to an SSL certificate .crt file. * Default ABSPATH . WPINC . '/certificates/ca-bundle.crt'. * @type bool $stream Whether to stream to a file. If set to true and no filename was * given, it will be droped it in the WP temp dir and its name will * be set using the basename of the URL. Default false. * @type string $filename Filename of the file to write to when streaming. $stream must be * set to true. Default null. * @type int $limit_response_size Size in bytes to limit the response to. Default null. * * } * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'. * A WP_Error instance upon error. */ public function request($url, $args = array()) { global $wp_version; $defaults = array('method' => 'GET', 'timeout' => apply_filters('http_request_timeout', 5), 'redirection' => apply_filters('http_request_redirection_count', 5), 'httpversion' => apply_filters('http_request_version', '1.0'), 'user-agent' => apply_filters('http_headers_useragent', 'WordPress/' . $wp_version . '; ' . get_bloginfo('url')), 'reject_unsafe_urls' => apply_filters('http_request_reject_unsafe_urls', false), 'blocking' => true, 'headers' => array(), 'cookies' => array(), 'body' => null, 'compress' => false, 'decompress' => true, 'sslverify' => true, 'sslcertificates' => ABSPATH . WPINC . '/certificates/ca-bundle.crt', 'stream' => false, 'filename' => null, 'limit_response_size' => null); // Pre-parse for the HEAD checks. $args = wp_parse_args($args); // By default, Head requests do not cause redirections. if (isset($args['method']) && 'HEAD' == $args['method']) { $defaults['redirection'] = 0; } $r = wp_parse_args($args, $defaults); /** * Filter the arguments used in an HTTP request. * * @since 2.7.0 * * @param array $r An array of HTTP request arguments. * @param string $url The request URL. */ $r = apply_filters('http_request_args', $r, $url); // The transports decrement this, store a copy of the original value for loop purposes. if (!isset($r['_redirection'])) { $r['_redirection'] = $r['redirection']; } /** * Filter whether to preempt an HTTP request's return value. * * Returning a non-false value from the filter will short-circuit the HTTP request and return * early with that value. A filter should return either: * * - An array containing 'headers', 'body', 'response', 'cookies', and 'filename' elements * - A WP_Error instance * - boolean false (to avoid short-circuiting the response) * * Returning any other value may result in unexpected behaviour. * * @since 2.9.0 * * @param false|array|WP_Error $preempt Whether to preempt an HTTP request's return value. Default false. * @param array $r HTTP request arguments. * @param string $url The request URL. */ $pre = apply_filters('pre_http_request', false, $r, $url); if (false !== $pre) { return $pre; } if (function_exists('wp_kses_bad_protocol')) { if ($r['reject_unsafe_urls']) { $url = wp_http_validate_url($url); } if ($url) { $url = wp_kses_bad_protocol($url, array('http', 'https', 'ssl')); } } $arrURL = @parse_url($url); if (empty($url) || empty($arrURL['scheme'])) { return new WP_Error('http_request_failed', __('A valid URL was not provided.')); } if ($this->block_request($url)) { return new WP_Error('http_request_failed', __('User has blocked requests through HTTP.')); } /* * Determine if this is a https call and pass that on to the transport functions * so that we can blacklist the transports that do not support ssl verification */ $r['ssl'] = $arrURL['scheme'] == 'https' || $arrURL['scheme'] == 'ssl'; // Determine if this request is to OUR install of WordPress. $homeURL = parse_url(get_bloginfo('url')); $r['local'] = 'localhost' == $arrURL['host'] || isset($homeURL['host']) && $homeURL['host'] == $arrURL['host']; unset($homeURL); /* * If we are streaming to a file but no filename was given drop it in the WP temp dir * and pick its name using the basename of the $url. */ if ($r['stream'] && empty($r['filename'])) { $r['filename'] = get_temp_dir() . wp_unique_filename(get_temp_dir(), basename($url)); } /* * Force some settings if we are streaming to a file and check for existence and perms * of destination directory. */ if ($r['stream']) { $r['blocking'] = true; if (!wp_is_writable(dirname($r['filename']))) { return new WP_Error('http_request_failed', __('Destination directory for file streaming does not exist or is not writable.')); } } if (is_null($r['headers'])) { $r['headers'] = array(); } if (!is_array($r['headers'])) { $processedHeaders = self::processHeaders($r['headers'], $url); $r['headers'] = $processedHeaders['headers']; } if (isset($r['headers']['User-Agent'])) { $r['user-agent'] = $r['headers']['User-Agent']; unset($r['headers']['User-Agent']); } if (isset($r['headers']['user-agent'])) { $r['user-agent'] = $r['headers']['user-agent']; unset($r['headers']['user-agent']); } if ('1.1' == $r['httpversion'] && !isset($r['headers']['connection'])) { $r['headers']['connection'] = 'close'; } // Construct Cookie: header if any cookies are set. self::buildCookieHeader($r); // Avoid issues where mbstring.func_overload is enabled. mbstring_binary_safe_encoding(); if (!isset($r['headers']['Accept-Encoding'])) { if ($encoding = WP_Http_Encoding::accept_encoding($url, $r)) { $r['headers']['Accept-Encoding'] = $encoding; } } if (!is_null($r['body']) && '' != $r['body'] || 'POST' == $r['method'] || 'PUT' == $r['method']) { if (is_array($r['body']) || is_object($r['body'])) { $r['body'] = http_build_query($r['body'], null, '&'); if (!isset($r['headers']['Content-Type'])) { $r['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=' . get_option('blog_charset'); } } if ('' === $r['body']) { $r['body'] = null; } if (!isset($r['headers']['Content-Length']) && !isset($r['headers']['content-length'])) { $r['headers']['Content-Length'] = strlen($r['body']); } } $response = $this->_dispatch_request($url, $r); reset_mbstring_encoding(); if (is_wp_error($response)) { return $response; } // Append cookies that were used in this request to the response if (!empty($r['cookies'])) { $cookies_set = wp_list_pluck($response['cookies'], 'name'); foreach ($r['cookies'] as $cookie) { if (!in_array($cookie->name, $cookies_set) && $cookie->test($url)) { $response['cookies'][] = $cookie; } } } return $response; }
function clean_url( $url, $protocols = null ) { if ('' == $url) return $url; $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%]|i', '', $url); $strip = array('%0d', '%0a'); $url = str_replace($strip, '', $url); $url = str_replace(';//', '://', $url); // Append http unless a relative link starting with / or a php file. if ( strpos($url, '://') === false && substr( $url, 0, 1 ) != '/' && !preg_match('/^[a-z0-9]+?\.php/i', $url) ) $url = 'http://' . $url; $url = preg_replace('/&([^#])(?![a-z]{2,8};)/', '&$1', $url); if ( !is_array($protocols) ) $protocols = array('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet'); if ( wp_kses_bad_protocol( $url, $protocols ) != $url ) return ''; return $url; }
function clean_url($url, $protocols = null, $context = 'display') { $original_url = $url; if ('' == $url) { return $url; } $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@()]|i', '', $url); $strip = array('%0d', '%0a'); $url = str_replace($strip, '', $url); $url = str_replace(';//', '://', $url); /* If the URL doesn't appear to contain a scheme, we * presume it needs http:// appended (unless a relative * link starting with / or a php file). */ if (strpos($url, ':') === false && substr($url, 0, 1) != '/' && !preg_match('/^[a-z0-9-]+?\\.php/i', $url)) { $url = 'http://' . $url; } // Replace ampersands ony when displaying. if ('display' == $context) { $url = preg_replace('/&([^#])(?![a-z]{2,8};)/', '&$1', $url); } if (!is_array($protocols)) { $protocols = array('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet'); } if (wp_kses_bad_protocol($url, $protocols) != $url) { return ''; } return apply_filters('clean_url', $url, $original_url, $context); }
/** * wp_kses_hair() - Builds an attribute list from string containing attributes. * * This function does a lot of work. It parses an attribute list into an array * with attribute data, and tries to do the right thing even if it gets weird * input. It will add quotes around attribute values that don't have any quotes * or apostrophes around them, to make it easier to produce HTML code that will * conform to W3C's HTML specification. It will also remove bad URL protocols * from attribute values. It also reduces duplicate attributes by using the * attribute defined first (foo='bar' foo='baz' will result in foo='bar'). * * @since 1.0.0 * * @param string $attr Attribute list from HTML element to closing HTML element tag * @param array $allowed_protocols Allowed protocols to keep * @return array List of attributes after parsing */ function wp_kses_hair($attr, $allowed_protocols) { $attrarr = array(); $mode = 0; $attrname = ''; # Loop through the whole attribute list while (strlen($attr) != 0) { $working = 0; # Was the last operation successful? switch ($mode) { case 0: # attribute name, href for instance if (preg_match('/^([-a-zA-Z]+)/', $attr, $match)) { $attrname = $match[1]; $working = $mode = 1; $attr = preg_replace('/^[-a-zA-Z]+/', '', $attr); } break; case 1: # equals sign or valueless ("selected") if (preg_match('/^\\s*=\\s*/', $attr)) { $working = 1; $mode = 2; $attr = preg_replace('/^\\s*=\\s*/', '', $attr); break; } if (preg_match('/^\\s+/', $attr)) { $working = 1; $mode = 0; if (FALSE === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y'); } $attr = preg_replace('/^\\s+/', '', $attr); } break; case 2: # attribute value, a URL after href= for instance if (preg_match('/^"([^"]*)"(\\s+|$)/', $attr, $match)) { $thisval = wp_kses_bad_protocol($match[1], $allowed_protocols); if (FALSE === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array('name' => $attrname, 'value' => $thisval, 'whole' => "{$attrname}=\"{$thisval}\"", 'vless' => 'n'); } $working = 1; $mode = 0; $attr = preg_replace('/^"[^"]*"(\\s+|$)/', '', $attr); break; } if (preg_match("/^'([^']*)'(\\s+|\$)/", $attr, $match)) { $thisval = wp_kses_bad_protocol($match[1], $allowed_protocols); if (FALSE === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array('name' => $attrname, 'value' => $thisval, 'whole' => "{$attrname}='{$thisval}'", 'vless' => 'n'); } $working = 1; $mode = 0; $attr = preg_replace("/^'[^']*'(\\s+|\$)/", '', $attr); break; } if (preg_match("%^([^\\s\"']+)(\\s+|\$)%", $attr, $match)) { $thisval = wp_kses_bad_protocol($match[1], $allowed_protocols); if (FALSE === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array('name' => $attrname, 'value' => $thisval, 'whole' => "{$attrname}=\"{$thisval}\"", 'vless' => 'n'); } # We add quotes to conform to W3C's HTML spec. $working = 1; $mode = 0; $attr = preg_replace("%^[^\\s\"']+(\\s+|\$)%", '', $attr); } break; } # switch if ($working == 0) { $attr = wp_kses_html_error($attr); $mode = 0; } } # while if ($mode == 1 && FALSE === array_key_exists($attrname, $attrarr)) { # special case, for when the attribute list ends with a valueless # attribute like "selected" $attrarr[$attrname] = array('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y'); } return $attrarr; }
/** * Checks and cleans a URL. This function is from WordPress. * * A number of characters are removed from the URL. If the URL is for displaying * (the default behaviour) ampersands are also replaced. The 'clean_url' filter * is applied to the returned cleaned URL. * * @since 2.8.0 * @uses wp_kses_bad_protocol() To only permit protocols in the URL set * via $protocols or the common ones set in the function. * * @param string $url The URL to be cleaned. * @param array $protocols Optional. An array of acceptable protocols. * Defaults to 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn' if not set. * @param string $_context Private. Use esc_url_raw() for database usage. * @return string The cleaned $url after the 'clean_url' filter is applied. */ public function esc_url($url, $protocols = null, $_context = 'display') { $original_url = $url; $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\\|*\'()\\x80-\\xff]|i', '', $url); $strip = array('%0d', '%0a', '%0D', '%0A'); $url = _deep_replace($strip, $url); $url = str_replace(';//', '://', $url); // Replace ampersands and single quotes only when displaying. if ('display' == $_context) { $url = wp_kses_normalize_entities($url); $url = str_replace('&', '&', $url); $url = str_replace('\'', ''', $url); } if (!empty($url[0]) && '/' === $url[0]) { $good_protocol_url = $url; } else { if (!is_array($protocols)) { $protocols = wp_allowed_protocols(); } $good_protocol_url = wp_kses_bad_protocol($url, $protocols); if (strtolower($good_protocol_url) != strtolower($url)) { return ''; } } /** * Filter a string cleaned and escaped for output as a URL. * * @since 2.3.0 * * @param string $good_protocol_url The cleaned URL to be returned. * @param string $original_url The URL prior to cleaning. * @param string $_context If 'display', replace ampersands and single quotes only. */ return apply_filters('clean_url', $good_protocol_url, $original_url, $_context); }
function clean_url( $url, $protocols = null ) { if ('' == $url) return $url; $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%]|i', '', $url); $strip = array('%0d', '%0a'); $url = str_replace($strip, '', $url); $url = str_replace(';//', '://', $url); $url = (!strstr($url, '://')) ? 'http://'.$url : $url; $url = preg_replace('/&([^#])(?![a-z]{2,8};)/', '&$1', $url); if ( !is_array($protocols) ) $protocols = array('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet'); if ( wp_kses_bad_protocol( $url, $protocols ) != $url ) return ''; return $url; }
function freshy_theme_page() { global $freshy_options; if ($_GET['page'] == basename(__FILE__)) { $array_themes_strings = array('lime', 'blue', 'red'); if (isset($_POST['freshy_options_update'])) { $freshy_updated_options = array(); $freshy_updated_options = $_POST; if (isset($freshy_updated_options['theme']) && $freshy_updated_options['changedtheme'] == 1) { freshy_set_theme($freshy_updated_options['theme'], $freshy_updated_options['advanced_options']); } else { $freshy_updated_options['header_bg_custom'] = wp_kses_bad_protocol($freshy_updated_options['header_bg_custom'], array('http', 'https')); update_option('freshy_options', $freshy_updated_options); $freshy_options = get_option('freshy_options'); echo '<div class="updated"><p>' . __('XTEC options updated.', 'xtec-11') . '</p></div>'; } } echo ' <div class="wrap"> <h2>' . __('XTEC Options', 'xtec-11') . '</h2> <form name="freshy_options_form" method="post"> <input type="hidden" name="freshy_options_update" value="update" /> <input type="hidden" name="changedtheme" id="changedtheme" value="0" /> <fieldset class="options"> <legend>' . __('Theme switcher', 'xtec-11') . '</legend> <table id="freshy_menu_options" width="100%" cellspacing="2" cellpadding="5" class="editform"> <col style="width:50%;"/><col/> <tr> <td> <label>' . __('Enter the label of the Homepage menu link', 'xtec-11') . ' </label> <br/> <small>' . __('info : modifying these labels should break internationalisation', 'xtec-11') . '</small> </td> <td> <input name="first_menu_label" type="text" value="' . $freshy_options['first_menu_label'] . '"/> </td> </tr>'; if (function_exists('yy_menu')) { echo ' <tr> <td> <label>' . __('Enter the label of the Blog menu link', 'xtec-11') . ' </label> <br/> <small>' . __('info : this is specially for YammYamm', 'xtec-11') . '</small> </td> <td> <input name="blog_menu_label" type="text" value="' . $freshy_options['blog_menu_label'] . '"/> </td> </tr>'; } echo ' <tr> <td> <label>' . __('Enter the label of the last menu link', 'xtec-11') . ' </label> </td> <td> <input name="last_menu_label" type="text" value="' . $freshy_options['last_menu_label'] . '"/> </td> </tr> <tr> <td> <label>' . __('Title color, ex: #006699', 'xtec-11') . ' </label> </td> <td> <input style="width:100px;" id="color_title_custom" name="color_title_custom" type="text" value="' . $freshy_options['color_title_custom'] . '"/> </td> </tr> <tr> <td> <label>' . __('Subtitle color, ex: #3af567', 'xtec-11') . ' </label> </td> <td> <input style="width:100px;" id="color_subtitle_custom" name="color_subtitle_custom" type="text" value="' . $freshy_options['color_subtitle_custom'] . '"/> </td> </tr> <tr> <td> <label>' . __('Absolute url of your own css style', 'xtec-11') . ' </label><br /> <small><a href="' . get_bloginfo('stylesheet_directory') . '/style-default.css" title="' . __('Click', 'xtec-11') . '">' . __('Download css default', 'xtec-11') . '</a></small> </td> <td> <input style="width:370px;" id="css_style_custom" name="css_style_custom" type="text" value="' . $freshy_options['css_style_custom'] . '"/> </td> </tr> <tr> <td> <label>' . __('Absolute url of your own image', 'xtec-11') . ' </label> </td> <td> <div style="border:1px solid silver;float:left;margin:2px;width:400px;height:50px;display:block;background:url('; echo $freshy_options['header_bg_custom'] . ') transparent 0 0;"> <input style="margin:10px;width:370px;" id="header_bg_custom" name="header_bg_custom" type="text" value="' . $freshy_options['header_bg_custom'] . '"/> </div> </td> </tr> '; if ($freshy_options['header_bg_custom'] != "") { echo ' <tr> <td> <label>' . __('Background vertical position', 'xtec-11') . ' </label> </td> <td> <select id="position_vertical_bg_custom" name="position_vertical_bg_custom" size="3">\\n'; $RB_var = ""; if ($freshy_options['position_vertical_bg_custom'] == "top") { $RB_var = 'selected="yes"'; } echo '<option value="top" ' . $RB_var . ' >' . __('Top', 'xtec-11') . '</option>\\n'; $RB_var = ""; if ($freshy_options['position_vertical_bg_custom'] == "middle") { $RB_var = 'selected="yes"'; } echo '<option value="middle" ' . $RB_var . ' >' . __('Middle', 'xtec-11') . '</option>\\n'; $RB_var = ""; if ($freshy_options['position_vertical_bg_custom'] == "bottom") { $RB_var = 'selected="yes"'; } echo '<option value="bottom" ' . $RB_var . ' >' . __('Bottom', 'xtec-11') . '</option>\\n'; echo ' </select> </td> </tr> <tr> <td> <label>' . __('Background horitzontal position', 'xtec-11') . ' </label> </td> <td> <select id="position_horitzontal_bg_custom" name="position_horitzontal_bg_custom" size="3">\\n'; $RB_var = ""; if ($freshy_options['position_horitzontal_bg_custom'] == "left") { $RB_var = 'selected="yes"'; } echo '<option value="left" ' . $RB_var . ' >' . __('Left', 'xtec-11') . '</option>\\n'; $RB_var = ""; if ($freshy_options['position_horitzontal_bg_custom'] == "center") { $RB_var = 'selected="yes"'; } echo '<option value="center" ' . $RB_var . ' >' . __('Center', 'xtec-11') . '</option>\\n'; $RB_var = ""; if ($freshy_options['position_horitzontal_bg_custom'] == "right") { $RB_var = 'selected="yes"'; } echo '<option value="right" ' . $RB_var . ' >' . __('Right', 'xtec-11') . '</option>\\n'; echo ' </select> </td> </tr> '; } // if $freshy_options['header_bg_custom'] != "" echo ' </table> </fieldset> <p class="submit"><input type="submit" name="Submit" value="' . __('Update Options »', 'xtec-11') . '"/></p> </form> </div> '; echo ' <div id="preview" class="wrap"> <h2 id="preview-post">' . __('Preview (updated when options are saved)', 'xtec-11') . '</h2> <iframe src="../?preview=true" width="100%" height="600" ></iframe> </div> '; } }
/** * Validate a URL for safe use in the HTTP API. * * @since 3.5.2 * * @return mixed URL or false on failure. */ function wp_http_validate_url($url) { $url = wp_kses_bad_protocol($url, array('http', 'https')); if (!$url) { return false; } $parsed_url = @parse_url($url); if (!$parsed_url || empty($parsed_url['host'])) { return false; } if (isset($parsed_url['user']) || isset($parsed_url['pass'])) { return false; } if (false !== strpos($parsed_url['host'], ':')) { return false; } $parsed_home = @parse_url(get_option('home')); $same_host = strtolower($parsed_home['host']) === strtolower($parsed_url['host']); if (!$same_host) { $host = trim($parsed_url['host'], '.'); if (preg_match('#^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$#', $host)) { $ip = $host; } else { $ip = gethostbyname($host); if ($ip === $host) { // Error condition for gethostbyname() $ip = false; } } if ($ip) { $parts = array_map('intval', explode('.', $ip)); if ('127.0.0.1' === $ip || 10 === $parts[0] || 172 === $parts[0] && 16 <= $parts[1] && 31 >= $parts[1] || 192 === $parts[0] && 168 === $parts[1]) { // If host appears local, reject unless specifically allowed. if (!apply_filters('http_request_host_is_external', false, $host, $url)) { return false; } } } } if (empty($parsed_url['port'])) { return $url; } $port = $parsed_url['port']; if (80 === $port || 443 === $port || 8080 === $port) { return $url; } if ($parsed_home && $same_host && $parsed_home['port'] === $port) { return $url; } return false; }
/** * Checks and cleans a URL. * * A number of characters are removed from the URL. If the URL is for displaying * (the default behaviour) ampersands are also replaced. The 'clean_url' filter * is applied to the returned cleaned URL. * * @since 2.8.0 * * @param string $url The URL to be cleaned. * @param array $protocols Optional. An array of acceptable protocols. * Defaults to return value of wp_allowed_protocols() * @param string $_context Private. Use esc_url_raw() for database usage. * @return string The cleaned $url after the 'clean_url' filter is applied. */ function esc_url($url, $protocols = null, $_context = 'display') { $original_url = $url; if ('' == $url) { return $url; } $url = str_replace(' ', '%20', $url); $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\\|*\'()\\[\\]\\x80-\\xff]|i', '', $url); if ('' === $url) { return $url; } if (0 !== stripos($url, 'mailto:')) { $strip = array('%0d', '%0a', '%0D', '%0A'); $url = _deep_replace($strip, $url); } $url = str_replace(';//', '://', $url); /* If the URL doesn't appear to contain a scheme, we * presume it needs http:// prepended (unless a relative * link starting with /, # or ? or a php file). */ if (strpos($url, ':') === false && !in_array($url[0], array('/', '#', '?')) && !preg_match('/^[a-z0-9-]+?\\.php/i', $url)) { $url = 'http://' . $url; } // Replace ampersands and single quotes only when displaying. if ('display' == $_context) { $url = wp_kses_normalize_entities($url); $url = str_replace('&', '&', $url); $url = str_replace("'", ''', $url); } if (false !== strpos($url, '[') || false !== strpos($url, ']')) { $parsed = wp_parse_url($url); $front = ''; if (isset($parsed['scheme'])) { $front .= $parsed['scheme'] . '://'; } elseif ('/' === $url[0]) { $front .= '//'; } if (isset($parsed['user'])) { $front .= $parsed['user']; } if (isset($parsed['pass'])) { $front .= ':' . $parsed['pass']; } if (isset($parsed['user']) || isset($parsed['pass'])) { $front .= '@'; } if (isset($parsed['host'])) { $front .= $parsed['host']; } if (isset($parsed['port'])) { $front .= ':' . $parsed['port']; } $end_dirty = str_replace($front, '', $url); $end_clean = str_replace(array('[', ']'), array('%5B', '%5D'), $end_dirty); $url = str_replace($end_dirty, $end_clean, $url); } if ('/' === $url[0]) { $good_protocol_url = $url; } else { if (!is_array($protocols)) { $protocols = wp_allowed_protocols(); } $good_protocol_url = wp_kses_bad_protocol($url, $protocols); if (strtolower($good_protocol_url) != strtolower($url)) { return ''; } } /** * Filter a string cleaned and escaped for output as a URL. * * @since 2.3.0 * * @param string $good_protocol_url The cleaned URL to be returned. * @param string $original_url The URL prior to cleaning. * @param string $_context If 'display', replace ampersands and single quotes only. */ return apply_filters('clean_url', $good_protocol_url, $original_url, $_context); }
/** * AJAX hook for the inline link editor on Tools -> Broken Links. * * @return void */ function ajax_edit() { if (!current_user_can('edit_others_posts') || !check_ajax_referer('blc_edit', false, false)) { die(json_encode(array('error' => __("You're not allowed to do that!", 'broken-link-checker')))); } if (empty($_POST['link_id']) || empty($_POST['new_url']) || !is_numeric($_POST['link_id'])) { die(json_encode(array('error' => __("Error : link_id or new_url not specified", 'broken-link-checker')))); } //Load the link $link = new blcLink(intval($_POST['link_id'])); if (!$link->valid()) { die(json_encode(array('error' => sprintf(__("Oops, I can't find the link %d", 'broken-link-checker'), intval($_POST['link_id']))))); } //Validate the new URL. $new_url = stripslashes($_POST['new_url']); $parsed = @parse_url($new_url); if (!$parsed) { die(json_encode(array('error' => __("Oops, the new URL is invalid!", 'broken-link-checker')))); } if (!current_user_can('unfiltered_html')) { //Disallow potentially dangerous URLs like "javascript:...". $protocols = wp_allowed_protocols(); $good_protocol_url = wp_kses_bad_protocol($new_url, $protocols); if ($new_url != $good_protocol_url) { die(json_encode(array('error' => __("Oops, the new URL is invalid!", 'broken-link-checker')))); } } $new_text = isset($_POST['new_text']) && is_string($_POST['new_text']) ? stripslashes($_POST['new_text']) : null; if ($new_text === '') { $new_text = null; } if (!empty($new_text) && !current_user_can('unfiltered_html')) { $new_text = stripslashes(wp_filter_post_kses(addslashes($new_text))); //wp_filter_post_kses expects slashed data. } $rez = $link->edit($new_url, $new_text); if ($rez === false) { die(json_encode(array('error' => __("An unexpected error occurred!", 'broken-link-checker')))); } else { $new_link = $rez['new_link']; /** @var blcLink $new_link */ $new_status = $new_link->analyse_status(); $ui_link_text = null; if (isset($new_text)) { $instances = $new_link->get_instances(); if (!empty($instances)) { $first_instance = reset($instances); $ui_link_text = $first_instance->ui_get_link_text(); } } $response = array('new_link_id' => $rez['new_link_id'], 'cnt_okay' => $rez['cnt_okay'], 'cnt_error' => $rez['cnt_error'], 'status_text' => $new_status['text'], 'status_code' => $new_status['code'], 'http_code' => empty($new_link->http_code) ? '' : $new_link->http_code, 'redirect_count' => $new_link->redirect_count, 'url' => $new_link->url, 'escaped_url' => esc_url_raw($new_link->url), 'final_url' => $new_link->final_url, 'link_text' => isset($new_text) ? $new_text : null, 'ui_link_text' => isset($new_text) ? $ui_link_text : null, 'errors' => array()); //url, status text, status code, link text, editable link text foreach ($rez['errors'] as $error) { /** @var $error WP_Error */ array_push($response['errors'], implode(', ', $error->get_error_messages())); } die(json_encode($response)); } }
/** * Builds an attribute list from string containing attributes. * * This function does a lot of work. It parses an attribute list into an array * with attribute data, and tries to do the right thing even if it gets weird * input. It will add quotes around attribute values that don't have any quotes * or apostrophes around them, to make it easier to produce HTML code that will * conform to W3C's HTML specification. It will also remove bad URL protocols * from attribute values. It also reduces duplicate attributes by using the * attribute defined first (foo='bar' foo='baz' will result in foo='bar'). * * @since 1.0.0 * * @param string $attr Attribute list from HTML element to closing HTML element tag * @param array $allowed_protocols Allowed protocols to keep * @return array List of attributes after parsing */ function wp_kses_hair($attr, $allowed_protocols) { $attrarr = array(); $mode = 0; $attrname = ''; $uris = array('xmlns', 'profile', 'href', 'src', 'cite', 'classid', 'codebase', 'data', 'usemap', 'longdesc', 'action'); // Loop through the whole attribute list while (strlen($attr) != 0) { $working = 0; // Was the last operation successful? switch ($mode) { case 0: // attribute name, href for instance if (preg_match('/^([-a-zA-Z:]+)/', $attr, $match)) { $attrname = $match[1]; $working = $mode = 1; $attr = preg_replace('/^[-a-zA-Z:]+/', '', $attr); } break; case 1: // equals sign or valueless ("selected") if (preg_match('/^\\s*=\\s*/', $attr)) { $working = 1; $mode = 2; $attr = preg_replace('/^\\s*=\\s*/', '', $attr); break; } if (preg_match('/^\\s+/', $attr)) { $working = 1; $mode = 0; if (false === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y'); } $attr = preg_replace('/^\\s+/', '', $attr); } break; case 2: // attribute value, a URL after href= for instance if (preg_match('%^"([^"]*)"(\\s+|/?$)%', $attr, $match)) { $thisval = $match[1]; if (in_array(strtolower($attrname), $uris)) { $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols); } if (false === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array('name' => $attrname, 'value' => $thisval, 'whole' => "{$attrname}=\"{$thisval}\"", 'vless' => 'n'); } $working = 1; $mode = 0; $attr = preg_replace('/^"[^"]*"(\\s+|$)/', '', $attr); break; } if (preg_match("%^'([^']*)'(\\s+|/?\$)%", $attr, $match)) { $thisval = $match[1]; if (in_array(strtolower($attrname), $uris)) { $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols); } if (false === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array('name' => $attrname, 'value' => $thisval, 'whole' => "{$attrname}='{$thisval}'", 'vless' => 'n'); } $working = 1; $mode = 0; $attr = preg_replace("/^'[^']*'(\\s+|\$)/", '', $attr); break; } if (preg_match("%^([^\\s\"']+)(\\s+|/?\$)%", $attr, $match)) { $thisval = $match[1]; if (in_array(strtolower($attrname), $uris)) { $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols); } if (false === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array('name' => $attrname, 'value' => $thisval, 'whole' => "{$attrname}=\"{$thisval}\"", 'vless' => 'n'); } // We add quotes to conform to W3C's HTML spec. $working = 1; $mode = 0; $attr = preg_replace("%^[^\\s\"']+(\\s+|\$)%", '', $attr); } break; } // switch if ($working == 0) { $attr = wp_kses_html_error($attr); $mode = 0; } } // while if ($mode == 1 && false === array_key_exists($attrname, $attrarr)) { // special case, for when the attribute list ends with a valueless // attribute like "selected" $attrarr[$attrname] = array('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y'); } return $attrarr; }
function wp_kses_hair($attr, $allowed_protocols) ############################################################################### # This function does a lot of work. It parses an attribute list into an array # with attribute data, and tries to do the right thing even if it gets weird # input. It will add quotes around attribute values that don't have any quotes # or apostrophes around them, to make it easier to produce HTML code that will # conform to W3C's HTML specification. It will also remove bad URL protocols # from attribute values. ############################################################################### { $attrarr = array (); $mode = 0; $attrname = ''; # Loop through the whole attribute list while (strlen($attr) != 0) { $working = 0; # Was the last operation successful? switch ($mode) { case 0 : # attribute name, href for instance if (preg_match('/^([-a-zA-Z]+)/', $attr, $match)) { $attrname = $match[1]; $working = $mode = 1; $attr = preg_replace('/^[-a-zA-Z]+/', '', $attr); } break; case 1 : # equals sign or valueless ("selected") if (preg_match('/^\s*=\s*/', $attr)) # equals sign { $working = 1; $mode = 2; $attr = preg_replace('/^\s*=\s*/', '', $attr); break; } if (preg_match('/^\s+/', $attr)) # valueless { $working = 1; $mode = 0; $attrarr[] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y'); $attr = preg_replace('/^\s+/', '', $attr); } break; case 2 : # attribute value, a URL after href= for instance if (preg_match('/^"([^"]*)"(\s+|$)/', $attr, $match)) # "value" { $thisval = wp_kses_bad_protocol($match[1], $allowed_protocols); $attrarr[] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n'); $working = 1; $mode = 0; $attr = preg_replace('/^"[^"]*"(\s+|$)/', '', $attr); break; } if (preg_match("/^'([^']*)'(\s+|$)/", $attr, $match)) # 'value' { $thisval = wp_kses_bad_protocol($match[1], $allowed_protocols); $attrarr[] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname='$thisval'", 'vless' => 'n'); $working = 1; $mode = 0; $attr = preg_replace("/^'[^']*'(\s+|$)/", '', $attr); break; } if (preg_match("%^([^\s\"']+)(\s+|$)%", $attr, $match)) # value { $thisval = wp_kses_bad_protocol($match[1], $allowed_protocols); $attrarr[] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n'); # We add quotes to conform to W3C's HTML spec. $working = 1; $mode = 0; $attr = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attr); } break; } # switch if ($working == 0) # not well formed, remove and try again { $attr = wp_kses_html_error($attr); $mode = 0; } } # while if ($mode == 1) # special case, for when the attribute list ends with a valueless # attribute like "selected" $attrarr[] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y'); return $attrarr; } # function wp_kses_hair
/** * Checks and cleans a URL. * * A number of characters are removed from the URL. If the URL is for displaying * (the default behaviour) amperstands are also replaced. The 'clean_url' filter * is applied to the returned cleaned URL. * * @since 2.8.0 * @uses wp_kses_bad_protocol() To only permit protocols in the URL set * via $protocols or the common ones set in the function. * * @param string $url The URL to be cleaned. * @param array $protocols Optional. An array of acceptable protocols. * Defaults to 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet' if not set. * @param string $_context Private. Use esc_url_raw() for database usage. * @return string The cleaned $url after the 'clean_url' filter is applied. */ function esc_url($url, $protocols = null, $_context = 'display') { $original_url = $url; if ('' == $url) { return $url; } $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\\|*\'()\\x80-\\xff]|i', '', $url); $strip = array('%0d', '%0a', '%0D', '%0A'); $url = _deep_replace($strip, $url); $url = str_replace(';//', '://', $url); /* If the URL doesn't appear to contain a scheme, we * presume it needs http:// appended (unless a relative * link starting with / or a php file). */ if (strpos($url, ':') === false && substr($url, 0, 1) != '/' && substr($url, 0, 1) != '#' && !preg_match('/^[a-z0-9-]+?\\.php/i', $url)) { $url = 'http://' . $url; } // Replace ampersands and single quotes only when displaying. if ('display' == $_context) { $url = wp_kses_normalize_entities($url); $url = str_replace('&', '&', $url); $url = str_replace("'", ''', $url); } if (!is_array($protocols)) { $protocols = array('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn'); } if (wp_kses_bad_protocol($url, $protocols) != $url) { return ''; } return apply_filters('clean_url', $url, $original_url, $_context); }
/** * Builds an attribute list from string containing attributes. * * This function does a lot of work. It parses an attribute list into an array * with attribute data, and tries to do the right thing even if it gets weird * input. It will add quotes around attribute values that don't have any quotes * or apostrophes around them, to make it easier to produce HTML code that will * conform to W3C's HTML specification. It will also remove bad URL protocols * from attribute values. It also reduces duplicate attributes by using the * attribute defined first (foo='bar' foo='baz' will result in foo='bar'). * * @since 1.0.0 * * @param string $attr Attribute list from HTML element to closing HTML element tag * @param array $allowed_protocols Allowed protocols to keep * @return array List of attributes after parsing */ function wp_kses_hair($attr, $allowed_protocols) { $attrarr = array (); $mode = 0; $attrname = ''; $uris = array('xmlns', 'profile', 'href', 'src', 'cite', 'classid', 'codebase', 'data', 'usemap', 'longdesc', 'action'); # Loop through the whole attribute list while (strlen($attr) != 0) { $working = 0; # Was the last operation successful? switch ($mode) { case 0 : # attribute name, href for instance if (preg_match('/^([-a-zA-Z]+)/', $attr, $match)) { $attrname = $match[1]; $working = $mode = 1; $attr = preg_replace('/^[-a-zA-Z]+/', '', $attr); } break; case 1 : # equals sign or valueless ("selected") if (preg_match('/^\s*=\s*/', $attr)) # equals sign { $working = 1; $mode = 2; $attr = preg_replace('/^\s*=\s*/', '', $attr); break; } if (preg_match('/^\s+/', $attr)) # valueless { $working = 1; $mode = 0; if(FALSE === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y'); } $attr = preg_replace('/^\s+/', '', $attr); } break; case 2 : # attribute value, a URL after href= for instance if (preg_match('/^"([^"]*)"(\s+|$)/', $attr, $match)) # "value" { $thisval = $match[1]; if ( in_array($attrname, $uris) ) $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols); if(FALSE === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n'); } $working = 1; $mode = 0; $attr = preg_replace('/^"[^"]*"(\s+|$)/', '', $attr); break; } if (preg_match("/^'([^']*)'(\s+|$)/", $attr, $match)) # 'value' { $thisval = $match[1]; if ( in_array($attrname, $uris) ) $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols); if(FALSE === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname='$thisval'", 'vless' => 'n'); } $working = 1; $mode = 0; $attr = preg_replace("/^'[^']*'(\s+|$)/", '', $attr); break; } if (preg_match("%^([^\s\"']+)(\s+|$)%", $attr, $match)) # value { $thisval = $match[1]; if ( in_array($attrname, $uris) ) $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols); if(FALSE === array_key_exists($attrname, $attrarr)) { $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n'); } # We add quotes to conform to W3C's HTML spec. $working = 1; $mode = 0; $attr = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attr); } break; } # switch if ($working == 0) # not well formed, remove and try again { $attr = wp_kses_html_error($attr); $mode = 0; } } # while if ($mode == 1 && FALSE === array_key_exists($attrname, $attrarr)) # special case, for when the attribute list ends with a valueless # attribute like "selected" $attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y'); return $attrarr; }