PageRenderTime 25ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/wcfsetup/install/files/lib/util/StringUtil.class.php

https://github.com/KomHunter2/WCF
PHP | 564 lines | 284 code | 58 blank | 222 comment | 50 complexity | a856491c3576d089be8b28eb90793aa2 MD5 | raw file
  1. <?php
  2. namespace wcf\util;
  3. use wcf\system\WCF;
  4. /**
  5. * Contains string-related functions.
  6. *
  7. * @author Marcel Werk
  8. * @copyright 2001-2009 WoltLab GmbH
  9. * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  10. * @package com.woltlab.wcf
  11. * @subpackage util
  12. * @category Community Framework
  13. */
  14. class StringUtil {
  15. const HTML_PATTERN = '~</?[a-z]+[1-6]?
  16. (?:\s*[a-z]+\s*=\s*(?:
  17. "[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'|[^\s>]
  18. ))*\s*/?>~ix';
  19. /**
  20. * Returns a salted hash of the given value.
  21. *
  22. * @param string $value
  23. * @param string $salt
  24. * @return string $hash
  25. */
  26. public static function getSaltedHash($value, $salt) {
  27. if (!defined('ENCRYPTION_ENABLE_SALTING') || ENCRYPTION_ENABLE_SALTING) {
  28. $hash = '';
  29. // salt
  30. if (!defined('ENCRYPTION_SALT_POSITION') || ENCRYPTION_SALT_POSITION == 'before') {
  31. $hash .= $salt;
  32. }
  33. // value
  34. if (!defined('ENCRYPTION_ENCRYPT_BEFORE_SALTING') || ENCRYPTION_ENCRYPT_BEFORE_SALTING) {
  35. $hash .= self::encrypt($value);
  36. }
  37. else {
  38. $hash .= $value;
  39. }
  40. // salt
  41. if (defined('ENCRYPTION_SALT_POSITION') && ENCRYPTION_SALT_POSITION == 'after') {
  42. $hash .= $salt;
  43. }
  44. return self::encrypt($hash);
  45. }
  46. else {
  47. return self::encrypt($value);
  48. }
  49. }
  50. /**
  51. * Returns a double salted hash of the given value.
  52. *
  53. * @param string $value
  54. * @param string $salt
  55. * @return string $hash
  56. */
  57. public static function getDoubleSaltedHash($value, $salt) {
  58. return self::encrypt($salt . self::getSaltedHash($value, $salt));
  59. }
  60. /**
  61. * encrypts the given value.
  62. *
  63. * @param string $value
  64. * @return string $hash
  65. */
  66. public static function encrypt($value) {
  67. if (defined('ENCRYPTION_METHOD')) {
  68. switch (ENCRYPTION_METHOD) {
  69. case 'sha1': return sha1($value);
  70. case 'md5': return md5($value);
  71. case 'crc32': return crc32($value);
  72. case 'crypt': return crypt($value);
  73. }
  74. }
  75. return sha1($value);
  76. }
  77. /**
  78. * alias to php sha1() function.
  79. *
  80. * @param string $value
  81. * @return string $hash
  82. */
  83. public static function getHash($value) {
  84. return sha1($value);
  85. }
  86. /**
  87. * Creates a random hash.
  88. *
  89. * @return string a random hash
  90. */
  91. public static function getRandomID() {
  92. return self::getHash(microtime() . uniqid(mt_rand(), true));
  93. }
  94. /**
  95. * Converts dos to unix newlines.
  96. *
  97. * @param string $string
  98. * @return string $string
  99. */
  100. public static function unifyNewlines($string) {
  101. return preg_replace("%(\r\n)|(\r)%", "\n", $string);
  102. }
  103. /**
  104. * alias to php trim() function
  105. *
  106. * @param string $string
  107. * @return string $string
  108. */
  109. public static function trim($text) {
  110. return trim($text);
  111. }
  112. /**
  113. * Converts html special characters.
  114. *
  115. * @param string $string
  116. * @return string $string
  117. */
  118. public static function encodeHTML($string) {
  119. if (is_object($string))
  120. $string = $string->__toString();
  121. return @htmlspecialchars($string, ENT_COMPAT, 'UTF-8');
  122. }
  123. /**
  124. * Decodes html entities.
  125. *
  126. * @param string $string
  127. * @return string $string
  128. */
  129. public static function decodeHTML($string) {
  130. if (is_object($string))
  131. $string = $string->__toString();
  132. $string = str_ireplace('&nbsp;', ' ', $string); // convert non-breaking spaces to ascii 32; not ascii 160
  133. return @html_entity_decode($string, ENT_COMPAT, 'UTF-8');
  134. }
  135. /**
  136. * Formats a numeric.
  137. *
  138. * @param numeric $numeric
  139. * @return string
  140. */
  141. public static function formatNumeric($numeric) {
  142. if (is_int($numeric))
  143. return self::formatInteger($numeric);
  144. else if (is_float($numeric))
  145. return self::formatDouble($numeric);
  146. else {
  147. if (floatval($numeric) - (float) intval($numeric))
  148. return self::formatDouble($numeric);
  149. else
  150. return self::formatInteger(intval($numeric));
  151. }
  152. }
  153. /**
  154. * Formats an integer.
  155. *
  156. * @param integer $integer
  157. * @return string
  158. */
  159. public static function formatInteger($integer) {
  160. $integer = self::addThousandsSeparator($integer);
  161. return $integer;
  162. }
  163. /**
  164. * Formats a double.
  165. *
  166. * @param double $double
  167. * @param integer $minDecimals
  168. * @return string
  169. */
  170. public static function formatDouble($double, $minDecimals = 0) {
  171. // consider as integer, if no decimal places found
  172. if (!$minDecimals && preg_match('~^(-?\d+)(?:\.(?:0*|00[0-4]\d*))?$~', $double, $match)) {
  173. return self::formatInteger($match[1]);
  174. }
  175. // round
  176. $double = round($double, ($minDecimals > 2 ? $minDecimals : 2));
  177. // remove last 0
  178. if ($minDecimals < 2 && substr($double, -1) == '0') $double = substr($double, 0, -1);
  179. // replace decimal point
  180. $double = str_replace('.', WCF::getLanguage()->get('wcf.global.decimalPoint'), $double);
  181. // add thousands separator
  182. $double = self::addThousandsSeparator($double);
  183. return $double;
  184. }
  185. /**
  186. * Adds thousands separators to a given number.
  187. *
  188. * @param mixed $number
  189. * @return string
  190. */
  191. public static function addThousandsSeparator($number) {
  192. if ($number >= 1000 || $number <= -1000) {
  193. $number = preg_replace('~(?<=\d)(?=(\d{3})+(?!\d))~', WCF::getLanguage()->get('wcf.global.thousandsSeparator'), $number);
  194. }
  195. return $number;
  196. }
  197. /**
  198. * Sorts an array of strings and maintain index association.
  199. *
  200. * @param array $strings
  201. * @return boolean
  202. */
  203. public static function sort(&$strings) {
  204. return asort($strings, SORT_LOCALE_STRING);
  205. }
  206. /**
  207. * alias to php strlen() function.
  208. */
  209. public static function length($string) {
  210. return mb_strlen($string);
  211. }
  212. /**
  213. * alias to php strpos() function.
  214. */
  215. public static function indexOf($hayStack, $needle, $offset = 0) {
  216. return mb_strpos($hayStack, $needle, $offset);
  217. }
  218. /**
  219. * alias to php stripos() function.
  220. */
  221. public static function indexOfIgnoreCase($hayStack, $needle, $offset = 0) {
  222. return mb_strpos(self::toLowerCase($hayStack), self::toLowerCase($needle), $offset);
  223. }
  224. /**
  225. * alias to php strrpos() function.
  226. */
  227. public static function lastIndexOf($hayStack, $needle) {
  228. return mb_strrpos($hayStack, $needle);
  229. }
  230. /**
  231. * alias to php substr() function.
  232. */
  233. public static function substring($string, $start, $length = null) {
  234. if ($length !== null) return mb_substr($string, $start, $length);
  235. return mb_substr($string, $start);
  236. }
  237. /**
  238. * alias to php strtolower() function.
  239. */
  240. public static function toLowerCase($string) {
  241. return mb_strtolower($string);
  242. }
  243. /**
  244. * alias to php strtoupper() function.
  245. */
  246. public static function toUpperCase($string) {
  247. return mb_strtoupper($string);
  248. }
  249. /**
  250. * alias to php substr_count() function.
  251. */
  252. public static function countSubstring($hayStack, $needle) {
  253. return mb_substr_count($hayStack, $needle);
  254. }
  255. /**
  256. * alias to php ucfirst() function.
  257. */
  258. public static function firstCharToUpperCase($string) {
  259. return self::toUpperCase(self::substring($string, 0, 1)).self::substring($string, 1);
  260. }
  261. /**
  262. * alias to php lcfirst() function.
  263. */
  264. public static function firstCharToLowerCase($string) {
  265. return self::toLowerCase(self::substring($string, 0, 1)).self::substring($string, 1);
  266. }
  267. /**
  268. * alias to php ucwords() function.
  269. */
  270. public static function wordsToUpperCase($string) {
  271. return mb_convert_case($string, MB_CASE_TITLE);
  272. }
  273. /**
  274. * alias to php str_replace() function.
  275. */
  276. public static function replace($search, $replace, $subject, &$count = null) {
  277. return str_replace($search, $replace, $subject, $count);
  278. }
  279. /**
  280. * alias to php str_ireplace() function.
  281. */
  282. public static function replaceIgnoreCase($search, $replace, $subject, &$count = 0) {
  283. $startPos = self::indexOf(self::toLowerCase($subject), self::toLowerCase($search));
  284. if ($startPos === false) return $subject;
  285. else {
  286. $endPos = $startPos + self::length($search);
  287. $count++;
  288. return self::substring($subject, 0, $startPos) . $replace . self::replaceIgnoreCase($search, $replace, self::substring($subject, $endPos), $count);
  289. }
  290. }
  291. /**
  292. * Unescapes escaped characters in a string.
  293. *
  294. * @param string $string
  295. * @param string $chars
  296. * @return string
  297. */
  298. public static function unescape($string, $chars = '"') {
  299. for ($i = 0, $j = strlen($chars); $i < $j; $i++) {
  300. $string = self::replace('\\'.$chars[$i], $chars[$i], $string);
  301. }
  302. return $string;
  303. }
  304. /**
  305. * Takes a numeric HTML entity value and returns the appropriate UTF-8 bytes.
  306. *
  307. * @param integer $dec html entity value
  308. * @return string utf-8 bytes
  309. */
  310. public static function getCharacter($dec) {
  311. if ($dec < 128) {
  312. $utf = chr($dec);
  313. }
  314. else if ($dec < 2048) {
  315. $utf = chr(192 + (($dec - ($dec % 64)) / 64));
  316. $utf .= chr(128 + ($dec % 64));
  317. }
  318. else {
  319. $utf = chr(224 + (($dec - ($dec % 4096)) / 4096));
  320. $utf .= chr(128 + ((($dec % 4096) - ($dec % 64)) / 64));
  321. $utf .= chr(128 + ($dec % 64));
  322. }
  323. return $utf;
  324. }
  325. /**
  326. * Converts UTF-8 to Unicode
  327. * @see http://www1.tip.nl/~t876506/utf8tbl.html
  328. *
  329. * @param string $c
  330. * @return integer unicode value of $c
  331. */
  332. public static function getCharValue($c) {
  333. $ud = 0;
  334. if (ord($c{0}) >= 0 && ord($c{0}) <= 127)
  335. $ud = ord($c{0});
  336. if (ord($c{0}) >= 192 && ord($c{0}) <= 223)
  337. $ud = (ord($c{0}) - 192) * 64 + (ord($c{1}) - 128);
  338. if (ord($c{0}) >= 224 && ord($c{0}) <= 239)
  339. $ud = (ord($c{0}) - 224) * 4096 + (ord($c{1}) - 128) * 64 + (ord($c{2}) - 128);
  340. if (ord($c{0}) >= 240 && ord($c{0}) <= 247)
  341. $ud = (ord($c{0}) - 240) * 262144 + (ord($c{1}) - 128) * 4096 + (ord($c{2}) - 128) * 64 + (ord($c{3}) - 128);
  342. if (ord($c{0}) >= 248 && ord($c{0}) <= 251)
  343. $ud = (ord($c{0}) - 248) * 16777216 + (ord($c{1}) - 128) * 262144 + (ord($c{2}) - 128) * 4096 + (ord($c{3}) - 128) * 64 + (ord($c{4}) - 128);
  344. if (ord($c{0}) >= 252 && ord($c{0}) <= 253)
  345. $ud = (ord($c{0}) - 252) * 1073741824 + (ord($c{1}) - 128) * 16777216 + (ord($c{2}) - 128) * 262144 + (ord($c{3}) - 128) * 4096 + (ord($c{4}) - 128) * 64 + (ord($c{5}) - 128);
  346. if (ord($c{0}) >= 254 && ord($c{0}) <= 255)
  347. $ud = false; // error
  348. return $ud;
  349. }
  350. /**
  351. * Returns html entities of all characters in the given string.
  352. *
  353. * @param string $string
  354. * @return string
  355. */
  356. public static function encodeAllChars($string) {
  357. $result = '';
  358. for ($i = 0, $j = StringUtil::length($string); $i < $j; $i++) {
  359. $char = StringUtil::substring($string, $i, 1);
  360. $result .= '&#'.StringUtil::getCharValue($char).';';
  361. }
  362. return $result;
  363. }
  364. /**
  365. * Returns true, if the given string contains only ASCII characters.
  366. *
  367. * @param string $string
  368. * @return boolean
  369. */
  370. public static function isASCII($string) {
  371. return preg_match('/^[\x00-\x7F]*$/', $string);
  372. }
  373. /**
  374. * Returns true, if the given string is utf-8 encoded.
  375. * @see http://www.w3.org/International/questions/qa-forms-utf-8
  376. *
  377. * @param string $string
  378. * @return boolean
  379. */
  380. public static function isUTF8($string) {
  381. /*return preg_match('/^(
  382. [\x09\x0A\x0D\x20-\x7E]* # ASCII
  383. | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
  384. | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
  385. | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
  386. | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
  387. | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
  388. | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
  389. | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
  390. )*$/x', $string);
  391. */
  392. return preg_match('/(
  393. [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
  394. | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
  395. | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
  396. | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
  397. | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
  398. | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
  399. | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
  400. )/x', $string);
  401. }
  402. /**
  403. * Extracts the class name from a standardised class path.
  404. *
  405. * @param string $classPath
  406. * @return string class name
  407. */
  408. public static function getClassName($classPath) {
  409. return preg_replace('~(?:.*/)?([^/]+).class.php~i', '\\1', $classPath);
  410. }
  411. /**
  412. * Escapes the closing cdata tag.
  413. *
  414. * @param string $string
  415. * @return string
  416. */
  417. public static function escapeCDATA($string) {
  418. return str_replace(']]>', ']]]]><![CDATA[>', $string);
  419. }
  420. /**
  421. * Converts a string to requested character encoding.
  422. * @see mb_convert_encoding()
  423. *
  424. * @param string $inCharset
  425. * @param string $outCharset
  426. * @param string $string
  427. * @return string converted string
  428. */
  429. public static function convertEncoding($inCharset, $outCharset, $string) {
  430. if ($inCharset == 'ISO-8859-1' && $outCharset == 'UTF-8') return utf8_encode($string);
  431. if ($inCharset == 'UTF-8' && $outCharset == 'ISO-8859-1') return utf8_decode($string);
  432. return mb_convert_encoding($string, $outCharset, $inCharset);
  433. }
  434. /**
  435. * Strips HTML tags from a string.
  436. *
  437. * @param string $string
  438. * @return string
  439. */
  440. public static function stripHTML($string) {
  441. return preg_replace(self::HTML_PATTERN, '', $string);
  442. }
  443. /**
  444. * Returns false, if the given word is forbidden by given word filter.
  445. *
  446. * @param string $word
  447. * @param string $filter
  448. * @return boolean
  449. */
  450. public static function executeWordFilter($word, $filter) {
  451. $word = self::toLowerCase($word);
  452. if ($filter != '') {
  453. $forbiddenNames = explode("\n", self::toLowerCase(self::unifyNewlines($filter)));
  454. foreach ($forbiddenNames as $forbiddenName) {
  455. if (self::indexOf($forbiddenName, '*') !== false) {
  456. $forbiddenName = self::replace('\*', '.*', preg_quote($forbiddenName, '/'));
  457. if (preg_match('/^'.$forbiddenName.'$/s', $word)) {
  458. return false;
  459. }
  460. }
  461. else {
  462. if ($word == $forbiddenName) {
  463. return false;
  464. }
  465. }
  466. }
  467. }
  468. return true;
  469. }
  470. /**
  471. * Splits given string into smaller chunks.
  472. *
  473. * @param string $string
  474. * @param integer $length
  475. * @param string $break
  476. * @return string
  477. */
  478. public static function splitIntoChunks($string, $length = 75, $break = "\r\n") {
  479. return mb_ereg_replace('.{'.$length.'}', "\\0".$break, $string);
  480. }
  481. /**
  482. * Generates a random user password with the given character length.
  483. *
  484. * @param integer $length
  485. * @return string new password
  486. */
  487. public static function getRandomPassword($length = 8) {
  488. $availableCharacters = array(
  489. 0 => 'abcdefghijklmnopqrstuvwxyz',
  490. 1 => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
  491. 2 => '0123456789',
  492. 3 => '+#-.,;:?!'
  493. );
  494. $password = '';
  495. $type = 0;
  496. for ($i = 0; $i < $length; $i++) {
  497. $type = ($i % 4 == 0) ? 0 : ($type + 1);
  498. $password .= substr($availableCharacters[$type], MathUtil::getRandomValue(0, strlen($availableCharacters[$type]) - 1), 1);
  499. }
  500. return str_shuffle($password);
  501. }
  502. }