=' ) && ! class_exists( 'idna_convert' ) ) { include BLC_DIRECTORY . '/idn/idna_convert.class.php'; if ( ! function_exists( 'encode_utf8' ) ) { include BLC_DIRECTORY . '/idn/transcode_wrapper.php'; } } if ( ! class_exists( 'blcUtility' ) ) { class blcUtility { /** * Checks if PHP is running in safe mode * blcUtility::is_safe_mode() * * @return bool */ static function is_safe_mode() { // Check php.ini safe_mode only if PHP version is lower than 5.3.0, else set to false. if ( version_compare( phpversion(), '5.3.0', '<' ) ) { $safe_mode = ini_get( 'safe_mode' ); } else { $safe_mode = false; } // Null, 0, '', '0' and so on count as false. if ( ! $safe_mode ) { return false; } // Test for some textual true/false variations. switch ( strtolower( $safe_mode ) ) { case 'on': case 'true': case 'yes': return true; case 'off': case 'false': case 'no': return false; default: // Let PHP handle anything else. return (bool) (int) $safe_mode; } } /** * blcUtility::is_open_basedir() * Checks if open_basedir is enabled * * @return bool */ static function is_open_basedir() { $open_basedir = ini_get( 'open_basedir' ); return $open_basedir && ( strtolower( $open_basedir ) != 'none' ); } /** * Truncate a string on a specified boundary character. * * @param string $text The text to truncate. * @param integer $max_characters Return no more than $max_characters * @param string $break Break on this character. Defaults to space. * @param string $pad Pad the truncated string with this string. Defaults to an HTML ellipsis. * @return string */ static function truncate( $text, $max_characters = 0, $break = ' ', $pad = '…' ) { if ( strlen( $text ) <= $max_characters ) { return $text; } $text = substr( $text, 0, $max_characters ); $break_pos = strrpos( $text, $break ); if ( false !== $break_pos ) { $text = substr( $text, 0, $break_pos ); } return $text . $pad; } /** * extract_tags() * Extract specific HTML tags and their attributes from a string. * * You can either specify one tag, an array of tag names, or a regular expression that matches the tag name(s). * If multiple tags are specified you must also set the $selfclosing parameter and it must be the same for * all specified tags (so you can't extract both normal and self-closing tags in one go). * * The function returns a numerically indexed array of extracted tags. Each entry is an associative array * with these keys : * tag_name - the name of the extracted tag, e.g. "a" or "img". * offset - the numberic offset of the first character of the tag within the HTML source. * contents - the inner HTML of the tag. This is always empty for self-closing tags. * attributes - a name -> value array of the tag's attributes, or an empty array if the tag has none. * full_tag - the entire matched tag, e.g. 'example.com'. This key * will only be present if you set $return_the_entire_tag to true. * * @param string $html The HTML code to search for tags. * @param string|array $tag The tag(s) to extract. * @param bool $selfclosing Whether the tag is self-closing or not. Setting it to null will force the script to try and make an educated guess. * @param bool $return_the_entire_tag Return the entire matched tag in 'full_tag' key of the results array. * @param string $charset The character set of the HTML code. Defaults to ISO-8859-1. * * @return array An array of extracted tags, or an empty array if no matching tags were found. */ static function extract_tags( $html, $tag, $selfclosing = null, $return_the_entire_tag = false, $charset = 'ISO-8859-1' ) { if ( is_array( $tag ) ) { $tag = implode( '|', $tag ); } //If the user didn't specify if $tag is a self-closing tag we try to auto-detect it //by checking against a list of known self-closing tags. $selfclosing_tags = array( 'area', 'base', 'basefont', 'br', 'hr', 'input', 'img', 'link', 'meta', 'col', 'param' ); if ( is_null( $selfclosing ) ) { $selfclosing = in_array( $tag, $selfclosing_tags ); } //The regexp is different for normal and self-closing tags because I can't figure out //how to make a sufficiently robust unified one. if ( $selfclosing ) { $tag_pattern = '@<(?P' . $tag . ') # \s[^>]+)? # attributes, if any \s*/?> # /> or just >, being lenient here @xsi'; } else { $tag_pattern = '@<(?P' . $tag . ') # \s[^>]+)? # attributes, if any \s*> # > (?P.*?) # tag contents # the closing @xsi'; } $attribute_pattern = '@ (?P\w+) # attribute name \s*=\s* ( (?P[\"\'])(?P.*?)(?P=quote) # a quoted value | # or (?P[^\s"\']+?)(?:\s+|$) # an unquoted value (terminated by whitespace or EOF) ) @xsi'; //Find all tags if ( ! preg_match_all( $tag_pattern, $html, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE ) ) { //Return an empty array if we didn't find anything return array(); } $tags = array(); foreach ( $matches as $match ) { // Parse tag attributes, if any. $attributes = array(); if ( ! empty( $match['attributes'][0] ) ) { if ( preg_match_all( $attribute_pattern, $match['attributes'][0], $attribute_data, PREG_SET_ORDER ) ) { //Turn the attribute data into a name->value array foreach ( $attribute_data as $attr ) { if ( ! empty( $attr['value_quoted'] ) ) { $value = $attr['value_quoted']; } elseif ( ! empty( $attr['value_unquoted'] ) ) { $value = $attr['value_unquoted']; } else { $value = ''; } // Passing the value through html_entity_decode is handy when you want // to extract link URLs or something like that. You might want to remove // or modify this call if it doesn't fit your situation. $value = html_entity_decode( $value, ENT_QUOTES, $charset ); $attributes[ $attr['name'] ] = $value; } } } $tag = array( 'tag_name' => $match['tag'][0], 'offset' => $match[0][1], 'contents' => ! empty( $match['contents'] ) ? $match['contents'][0] : '', // Empty for self-closing tags. 'attributes' => $attributes, ); if ( $return_the_entire_tag ) { $tag['full_tag'] = $match[0][0]; } $tags[] = $tag; } return $tags; } /** * Get the value of a cookie. * * @param string $cookie_name The name of the cookie to return. * @param string $default_value Optional. If the cookie is not set, this value will be returned instead. Defaults to an empty string. * @return mixed Either the value of the requested cookie, or $default_value. */ static function get_cookie( $cookie_name, $default_value = '' ) { if ( isset( $_COOKIE[ $cookie_name ] ) ) { return $_COOKIE[ $cookie_name ]; } else { return $default_value; } } /** * Format a time delta using a fuzzy format, e.g. '2 minutes ago', '2 days', etc. * * @param int $delta Time period in seconds. * @param string $type Optional. The output template to use. * @return string */ static function fuzzy_delta( $delta, $template = 'default' ) { $templates = array( 'seconds' => array( 'default' => _n_noop( '%d second', '%d seconds' ), 'ago' => _n_noop( '%d second ago', '%d seconds ago' ), ), 'minutes' => array( 'default' => _n_noop( '%d minute', '%d minutes' ), 'ago' => _n_noop( '%d minute ago', '%d minutes ago' ), ), 'hours' => array( 'default' => _n_noop( '%d hour', '%d hours' ), 'ago' => _n_noop( '%d hour ago', '%d hours ago' ), ), 'days' => array( 'default' => _n_noop( '%d day', '%d days' ), 'ago' => _n_noop( '%d day ago', '%d days ago' ), ), 'months' => array( 'default' => _n_noop( '%d month', '%d months' ), 'ago' => _n_noop( '%d month ago', '%d months ago' ), ), ); if ( $delta < 1 ) { $delta = 1; } if ( $delta < MINUTE_IN_SECONDS ) { $units = 'seconds'; } elseif ( $delta < HOUR_IN_SECONDS ) { $delta = intval( $delta / MINUTE_IN_SECONDS ); $units = 'minutes'; } elseif ( $delta < DAY_IN_SECONDS ) { $delta = intval( $delta / HOUR_IN_SECONDS ); $units = 'hours'; } elseif ( $delta < MONTH_IN_SECONDS ) { $delta = intval( $delta / DAY_IN_SECONDS ); $units = 'days'; } else { $delta = intval( $delta / MONTH_IN_SECONDS ); $units = 'months'; } return sprintf( _n( $templates[ $units ][ $template ][0], //phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralSingle $templates[ $units ][ $template ][1], //phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralPlural $delta, 'broken-link-checker' ), $delta ); } /** * Optimize the plugin's tables * * @return void */ static function optimize_database() { global $wpdb; /** @var wpdb $wpdb */ $wpdb->query( "OPTIMIZE TABLE {$wpdb->prefix}blc_links, {$wpdb->prefix}blc_instances, {$wpdb->prefix}blc_synch" ); } /** * Get the server's load averages. * * Returns an array with three samples - the 1 minute avg, the 5 minute avg, and the 15 minute avg. * * @param integer $cache How long the load averages may be cached, in seconds. Set to 0 to get maximally up-to-date data. * @return array|null Array, or NULL if retrieving load data is impossible (e.g. when running on a Windows box). */ static function get_server_load( $cache = 5 ) { static $cached_load = null; static $cached_when = 0; if ( ! empty( $cache ) && ( ( time() - $cached_when ) <= $cache ) ) { return $cached_load; } $load = null; if ( function_exists( 'sys_getloadavg' ) ) { $load = sys_getloadavg(); } else { $loadavg_file = '/proc/loadavg'; if ( @is_readable( $loadavg_file ) ) { $load = explode( ' ', file_get_contents( $loadavg_file ) ); $load = array_map( 'floatval', $load ); } } $cached_load = $load; $cached_when = time(); return $load; } /** * Convert an internationalized domain name or URL to ASCII-compatible encoding. * * @param string $url Either a domain name or a complete URL. * @param string $charset The character encoding of the $url parameter. Defaults to the encoding set in Settings -> Reading. * @return string */ static function idn_to_ascii( $url, $charset = '' ) { $idn = blcUtility::get_idna_converter(); if ( null != $idn ) { if ( empty( $charset ) ) { $charset = get_bloginfo( 'charset' ); } // Encode only the host. if ( preg_match( '@(\w+:/*)?([^/:]+)(.*$)?@s', $url, $matches ) ) { $host = $matches[2]; if ( ( strtoupper( $charset ) != 'UTF-8' ) && ( strtoupper( $charset ) != 'UTF8' ) ) { $host = encode_utf8( $host, $charset, true ); } $host = $idn->encode( $host ); $url = $matches[1] . $host . $matches[3]; } } return $url; } /** * Convert an internationalized domain name (or URL) from ASCII-compatible encoding to UTF8. * * @param string $url * @return string */ static function idn_to_utf8( $url ) { $idn = blcUtility::get_idna_converter(); if ( null !== $idn ) { $url = $idn->decode( $url ); } return $url; } /** * Get an instance of idna_converter * * @return idna_convert|null Either an instance of IDNA converter, or NULL if the converter class is not available */ static function get_idna_converter() { static $idn = null; if ( ( null === $idn ) && class_exists( 'idna_convert' ) ) { $idn = new idna_convert(); } return $idn; } /** * Generate a numeric hash from a string. The result will be constrained to the specified interval. * * @static * @param string $input * @param int $min * @param int $max * @return float */ public static function constrained_hash( $input, $min = 0, $max = 1 ) { $bytes_to_use = 3; $md5_char_count = 32; $hash = substr( md5( $input ), $md5_char_count - $bytes_to_use * 2 ); $hash = intval( hexdec( $hash ) ); return $min + ( ( $max - $min ) * ( $hash / ( pow( 2, $bytes_to_use * 8 ) - 1 ) ) ); } }//class }//class_exists