PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

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

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