PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/broken-link-checker/includes/utility-class.php

https://bitbucket.org/awylie199/s5t
PHP | 417 lines | 248 code | 49 blank | 120 comment | 50 complexity | 8c5dc7b8523282823f5c1147832b33bc MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, Apache-2.0, LGPL-3.0, MIT, BSD-3-Clause
  1. <?php
  2. /**
  3. * @author W-Shadow
  4. * @copyright 2010
  5. */
  6. if ( ! function_exists( 'sys_get_temp_dir' ) ) {
  7. function sys_get_temp_dir() {
  8. if ( ! empty( $_ENV['TMP'] ) ) { return realpath( $_ENV['TMP'] ); }
  9. if ( ! empty( $_ENV['TMPDIR'] ) ) { return realpath( $_ENV['TMPDIR'] ); }
  10. if ( ! empty( $_ENV['TEMP'] ) ) { return realpath( $_ENV['TEMP'] ); }
  11. $tempfile = tempnam( uniqid( rand(),TRUE ),'' );
  12. if ( @file_exists( $tempfile ) ) {
  13. unlink( $tempfile );
  14. return realpath( dirname( $tempfile ) );
  15. }
  16. return '';
  17. }
  18. }
  19. //Include the internationalized domain name converter (requires PHP 5)
  20. if ( version_compare( phpversion(), '5.0.0', '>=' ) && ! class_exists( 'idna_convert' ) ) {
  21. include BLC_DIRECTORY . '/idn/idna_convert.class.php';
  22. if ( ! function_exists( 'encode_utf8' ) ) {
  23. include BLC_DIRECTORY . '/idn/transcode_wrapper.php';
  24. }
  25. }
  26. if ( ! class_exists( 'blcUtility' ) ) {
  27. class blcUtility {
  28. /**
  29. * Checks if PHP is running in safe mode
  30. * blcUtility::is_safe_mode()
  31. *
  32. * @return bool
  33. */
  34. static function is_safe_mode() {
  35. // Check php.ini safe_mode only if PHP version is lower than 5.3.0, else set to false.
  36. if ( version_compare( phpversion(), '5.3.0', '<' ) ) {
  37. $safe_mode = ini_get( 'safe_mode' );
  38. } else {
  39. $safe_mode = false;
  40. }
  41. // Null, 0, '', '0' and so on count as false.
  42. if ( ! $safe_mode ) {
  43. return false;
  44. }
  45. // Test for some textual true/false variations.
  46. switch ( strtolower( $safe_mode ) ) {
  47. case 'on':
  48. case 'true':
  49. case 'yes':
  50. return true;
  51. case 'off':
  52. case 'false':
  53. case 'no':
  54. return false;
  55. default: // Let PHP handle anything else.
  56. return (bool) (int) $safe_mode;
  57. }
  58. }
  59. /**
  60. * blcUtility::is_open_basedir()
  61. * Checks if open_basedir is enabled
  62. *
  63. * @return bool
  64. */
  65. static function is_open_basedir(){
  66. $open_basedir = ini_get( 'open_basedir' );
  67. return $open_basedir && ( strtolower( $open_basedir ) != 'none' );
  68. }
  69. /**
  70. * Truncate a string on a specified boundary character.
  71. *
  72. * @param string $text The text to truncate.
  73. * @param integer $max_characters Return no more than $max_characters
  74. * @param string $break Break on this character. Defaults to space.
  75. * @param string $pad Pad the truncated string with this string. Defaults to an HTML ellipsis.
  76. * @return string
  77. */
  78. static function truncate( $text, $max_characters = 0, $break = ' ', $pad = '&hellip;' ) {
  79. if ( strlen( $text ) <= $max_characters ) {
  80. return $text;
  81. }
  82. $text = substr( $text, 0, $max_characters );
  83. $break_pos = strrpos( $text, $break );
  84. if ( false !== $break_pos ) {
  85. $text = substr( $text, 0, $break_pos );
  86. }
  87. return $text.$pad;
  88. }
  89. /**
  90. * extract_tags()
  91. * Extract specific HTML tags and their attributes from a string.
  92. *
  93. * You can either specify one tag, an array of tag names, or a regular expression that matches the tag name(s).
  94. * If multiple tags are specified you must also set the $selfclosing parameter and it must be the same for
  95. * all specified tags (so you can't extract both normal and self-closing tags in one go).
  96. *
  97. * The function returns a numerically indexed array of extracted tags. Each entry is an associative array
  98. * with these keys :
  99. * tag_name - the name of the extracted tag, e.g. "a" or "img".
  100. * offset - the numberic offset of the first character of the tag within the HTML source.
  101. * contents - the inner HTML of the tag. This is always empty for self-closing tags.
  102. * attributes - a name -> value array of the tag's attributes, or an empty array if the tag has none.
  103. * full_tag - the entire matched tag, e.g. '<a href="http://example.com">example.com</a>'. This key
  104. * will only be present if you set $return_the_entire_tag to true.
  105. *
  106. * @param string $html The HTML code to search for tags.
  107. * @param string|array $tag The tag(s) to extract.
  108. * @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.
  109. * @param bool $return_the_entire_tag Return the entire matched tag in 'full_tag' key of the results array.
  110. * @param string $charset The character set of the HTML code. Defaults to ISO-8859-1.
  111. *
  112. * @return array An array of extracted tags, or an empty array if no matching tags were found.
  113. */
  114. static function extract_tags( $html, $tag, $selfclosing = null, $return_the_entire_tag = false, $charset = 'ISO-8859-1' ) {
  115. if ( is_array( $tag ) ) {
  116. $tag = implode( '|', $tag );
  117. }
  118. //If the user didn't specify if $tag is a self-closing tag we try to auto-detect it
  119. //by checking against a list of known self-closing tags.
  120. $selfclosing_tags = array( 'area', 'base', 'basefont', 'br', 'hr', 'input', 'img', 'link', 'meta', 'col', 'param' );
  121. if ( is_null( $selfclosing ) ) {
  122. $selfclosing = in_array( $tag, $selfclosing_tags );
  123. }
  124. //The regexp is different for normal and self-closing tags because I can't figure out
  125. //how to make a sufficiently robust unified one.
  126. if ( $selfclosing ) {
  127. $tag_pattern =
  128. '@<(?P<tag>' . $tag . ') # <tag
  129. (?P<attributes>\s[^>]+)? # attributes, if any
  130. \s*/?> # /> or just >, being lenient here
  131. @xsi';
  132. } else {
  133. $tag_pattern =
  134. '@<(?P<tag>' . $tag . ') # <tag
  135. (?P<attributes>\s[^>]+)? # attributes, if any
  136. \s*> # >
  137. (?P<contents>.*?) # tag contents
  138. </(?P=tag)> # the closing </tag>
  139. @xsi';
  140. }
  141. $attribute_pattern =
  142. '@
  143. (?P<name>\w+) # attribute name
  144. \s*=\s*
  145. (
  146. (?P<quote>[\"\'])(?P<value_quoted>.*?)(?P=quote) # a quoted value
  147. | # or
  148. (?P<value_unquoted>[^\s"\']+?)(?:\s+|$) # an unquoted value (terminated by whitespace or EOF)
  149. )
  150. @xsi';
  151. //Find all tags
  152. if ( ! preg_match_all( $tag_pattern, $html, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE ) ) {
  153. //Return an empty array if we didn't find anything
  154. return array();
  155. }
  156. $tags = array();
  157. foreach ( $matches as $match ) {
  158. // Parse tag attributes, if any.
  159. $attributes = array();
  160. if ( ! empty( $match['attributes'][0] ) ) {
  161. if ( preg_match_all( $attribute_pattern, $match['attributes'][0], $attribute_data, PREG_SET_ORDER ) ) {
  162. //Turn the attribute data into a name->value array
  163. foreach ( $attribute_data as $attr ) {
  164. if( ! empty( $attr['value_quoted'] ) ) {
  165. $value = $attr['value_quoted'];
  166. } else if( ! empty( $attr['value_unquoted'] ) ) {
  167. $value = $attr['value_unquoted'];
  168. } else {
  169. $value = '';
  170. }
  171. // Passing the value through html_entity_decode is handy when you want
  172. // to extract link URLs or something like that. You might want to remove
  173. // or modify this call if it doesn't fit your situation.
  174. $value = html_entity_decode( $value, ENT_QUOTES, $charset );
  175. $attributes[ $attr['name'] ] = $value;
  176. }
  177. }
  178. }
  179. $tag = array(
  180. 'tag_name' => $match['tag'][0],
  181. 'offset' => $match[0][1],
  182. 'contents' => ! empty( $match['contents'] ) ? $match['contents'][0] : '', // Empty for self-closing tags.
  183. 'attributes' => $attributes,
  184. );
  185. if ( $return_the_entire_tag ) {
  186. $tag['full_tag'] = $match[0][0];
  187. }
  188. $tags[] = $tag;
  189. }
  190. return $tags;
  191. }
  192. /**
  193. * Get the value of a cookie.
  194. *
  195. * @param string $cookie_name The name of the cookie to return.
  196. * @param string $default_value Optional. If the cookie is not set, this value will be returned instead. Defaults to an empty string.
  197. * @return mixed Either the value of the requested cookie, or $default_value.
  198. */
  199. static function get_cookie( $cookie_name, $default_value = '' ) {
  200. if ( isset( $_COOKIE[$cookie_name] ) ) {
  201. return $_COOKIE[$cookie_name];
  202. } else {
  203. return $default_value;
  204. }
  205. }
  206. /**
  207. * Format a time delta using a fuzzy format, e.g. '2 minutes ago', '2 days', etc.
  208. *
  209. * @param int $delta Time period in seconds.
  210. * @param string $type Optional. The output template to use.
  211. * @return string
  212. */
  213. static function fuzzy_delta( $delta, $template = 'default' ) {
  214. $templates = array(
  215. 'seconds' => array(
  216. 'default' => _n_noop('%d second', '%d seconds'),
  217. 'ago' => _n_noop('%d second ago', '%d seconds ago'),
  218. ),
  219. 'minutes' => array(
  220. 'default' => _n_noop('%d minute', '%d minutes'),
  221. 'ago' => _n_noop('%d minute ago', '%d minutes ago'),
  222. ),
  223. 'hours' => array(
  224. 'default' => _n_noop('%d hour', '%d hours'),
  225. 'ago' => _n_noop('%d hour ago', '%d hours ago'),
  226. ),
  227. 'days' => array(
  228. 'default' => _n_noop('%d day', '%d days'),
  229. 'ago' => _n_noop('%d day ago', '%d days ago'),
  230. ),
  231. 'months' => array(
  232. 'default' => _n_noop('%d month', '%d months'),
  233. 'ago' => _n_noop('%d month ago', '%d months ago'),
  234. ),
  235. );
  236. if ( $delta < 1 ) {
  237. $delta = 1;
  238. }
  239. if ( $delta < MINUTE_IN_SECONDS ) {
  240. $units = 'seconds';
  241. } elseif ( $delta < HOUR_IN_SECONDS ) {
  242. $delta = intval( $delta / MINUTE_IN_SECONDS );
  243. $units = 'minutes';
  244. } elseif ( $delta < DAY_IN_SECONDS ) {
  245. $delta = intval( $delta / HOUR_IN_SECONDS );
  246. $units = 'hours';
  247. } elseif ( $delta < MONTH_IN_SECONDS ) {
  248. $delta = intval( $delta / DAY_IN_SECONDS );
  249. $units = 'days';
  250. } else {
  251. $delta = intval( $delta / MONTH_IN_SECONDS );
  252. $units = 'months';
  253. }
  254. return sprintf(
  255. _n(
  256. $templates[$units][$template][0],
  257. $templates[$units][$template][1],
  258. $delta,
  259. 'broken-link-checker'
  260. ),
  261. $delta
  262. );
  263. }
  264. /**
  265. * Optimize the plugin's tables
  266. *
  267. * @return void
  268. */
  269. static function optimize_database(){
  270. global $wpdb; /** @var wpdb $wpdb */
  271. $wpdb->query( "OPTIMIZE TABLE {$wpdb->prefix}blc_links, {$wpdb->prefix}blc_instances, {$wpdb->prefix}blc_synch" );
  272. }
  273. /**
  274. * Get the server's load averages.
  275. *
  276. * Returns an array with three samples - the 1 minute avg, the 5 minute avg, and the 15 minute avg.
  277. *
  278. * @param integer $cache How long the load averages may be cached, in seconds. Set to 0 to get maximally up-to-date data.
  279. * @return array|null Array, or NULL if retrieving load data is impossible (e.g. when running on a Windows box).
  280. */
  281. static function get_server_load( $cache = 5 ) {
  282. static $cached_load = null;
  283. static $cached_when = 0;
  284. if ( ! empty( $cache ) && ((time() - $cached_when) <= $cache) ) {
  285. return $cached_load;
  286. }
  287. $load = null;
  288. if ( function_exists( 'sys_getloadavg' ) ) {
  289. $load = sys_getloadavg();
  290. } else {
  291. $loadavg_file = '/proc/loadavg';
  292. if ( @is_readable( $loadavg_file ) ) {
  293. $load = explode( ' ', file_get_contents( $loadavg_file ) );
  294. $load = array_map( 'floatval', $load );
  295. }
  296. }
  297. $cached_load = $load;
  298. $cached_when = time();
  299. return $load;
  300. }
  301. /**
  302. * Convert an internationalized domain name or URL to ASCII-compatible encoding.
  303. *
  304. * @param string $url Either a domain name or a complete URL.
  305. * @param string $charset The character encoding of the $url parameter. Defaults to the encoding set in Settings -> Reading.
  306. * @return string
  307. */
  308. static function idn_to_ascii( $url, $charset = '' ) {
  309. $idn = blcUtility::get_idna_converter();
  310. if ( $idn != null ) {
  311. if ( empty( $charset ) ) {
  312. $charset = get_bloginfo( 'charset' );
  313. }
  314. // Encode only the host.
  315. if ( preg_match( '@(\w+:/*)?([^/:]+)(.*$)?@s', $url, $matches ) ) {
  316. $host = $matches[2];
  317. if ( ( strtoupper( $charset ) != 'UTF-8') && ( strtoupper( $charset ) != 'UTF8') ) {
  318. $host = encode_utf8( $host, $charset, true );
  319. }
  320. $host = $idn->encode( $host );
  321. $url = $matches[1] . $host . $matches[3];
  322. }
  323. }
  324. return $url;
  325. }
  326. /**
  327. * Convert an internationalized domain name (or URL) from ASCII-compatible encoding to UTF8.
  328. *
  329. * @param string $url
  330. * @return string
  331. */
  332. static function idn_to_utf8( $url ) {
  333. $idn = blcUtility::get_idna_converter();
  334. if ( null !== $idn ) {
  335. $url = $idn->decode( $url );
  336. }
  337. return $url;
  338. }
  339. /**
  340. * Get an instance of idna_converter
  341. *
  342. * @return idna_convert|null Either an instance of IDNA converter, or NULL if the converter class is not available
  343. */
  344. static function get_idna_converter() {
  345. static $idn = null;
  346. if ( ( null === $idn ) && class_exists( 'idna_convert' ) ) {
  347. $idn = new idna_convert();
  348. }
  349. return $idn;
  350. }
  351. /**
  352. * Generate a numeric hash from a string. The result will be constrained to the specified interval.
  353. *
  354. * @static
  355. * @param string $input
  356. * @param int $min
  357. * @param int $max
  358. * @return float
  359. */
  360. public static function constrained_hash( $input, $min = 0, $max = 1 ) {
  361. $bytes_to_use = 3;
  362. $md5_char_count = 32;
  363. $hash = substr( md5( $input ), $md5_char_count - $bytes_to_use * 2 );
  364. $hash = intval( hexdec( $hash ) );
  365. return $min + ( ( $max - $min ) * ( $hash / ( pow( 2, $bytes_to_use * 8 ) - 1) ) );
  366. }
  367. }//class
  368. }//class_exists