=' ) && ! 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
(?P=tag)> # 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