=') && !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 { /** * blcUtility::is_safe_mode() * Checks if PHP is running in safe mode * * @return bool */ static function is_safe_mode(){ $safe_mode = ini_get('safe_mode'); //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 ( $break_pos !== false ){ $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']; } else if( !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'){ $ONE_MINUTE = 60; $ONE_HOUR = 60 * $ONE_MINUTE; $ONE_DAY = 24 * $ONE_HOUR; $ONE_MONTH = $ONE_DAY * 3652425 / 120000; $ONE_YEAR = $ONE_DAY * 3652425 / 10000; $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 < $ONE_MINUTE ){ $units = 'seconds'; } elseif ( $delta < $ONE_HOUR ){ $delta = intval($delta / $ONE_MINUTE); $units = 'minutes'; } elseif ( $delta < $ONE_DAY ){ $delta = intval($delta / $ONE_HOUR); $units = 'hours'; } elseif ( $delta < $ONE_MONTH ){ $delta = intval($delta / $ONE_DAY); $units = 'days'; } else { $delta = intval( $delta / $ONE_MONTH ); $units = 'months'; } return sprintf( _n( $templates[$units][$template][0], $templates[$units][$template][1], $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 ( $idn != null ){ 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 ( $idn != null ){ $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 ( ($idn == null) && 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