* @link http://getkirby.com * @copyright Bastian Allgeier * @license http://www.opensource.org/licenses/mit-license.php MIT License */ class Str { public static $ascii = array( '/Ä/' => 'Ae', '/æ|ǽ|ä/' => 'ae', '/œ|ö/' => 'oe', '/À|Á|Â|Ã|Å|Ǻ|Ā|Ă|Ą|Ǎ|А/' => 'A', '/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª|а/' => 'a', '/Б/' => 'B', '/б/' => 'b', '/Ç|Ć|Ĉ|Ċ|Č|Ц/' => 'C', '/ç|ć|ĉ|ċ|č|ц/' => 'c', '/Ð|Ď|Đ/' => 'Dj', '/ð|ď|đ/' => 'dj', '/Д/' => 'D', '/д/' => 'd', '/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě|Е|Ё|Э/' => 'E', '/è|é|ê|ë|ē|ĕ|ė|ę|ě|е|ё|э/' => 'e', '/Ф/' => 'F', '/ƒ|ф/' => 'f', '/Ĝ|Ğ|Ġ|Ģ|Г/' => 'G', '/ĝ|ğ|ġ|ģ|г/' => 'g', '/Ĥ|Ħ|Х/' => 'H', '/ĥ|ħ|х/' => 'h', '/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ|И/' => 'I', '/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı|и/' => 'i', '/Ĵ|Й/' => 'J', '/ĵ|й/' => 'j', '/Ķ|К/' => 'K', '/ķ|к/' => 'k', '/Ĺ|Ļ|Ľ|Ŀ|Ł|Л/' => 'L', '/ĺ|ļ|ľ|ŀ|ł|л/' => 'l', '/М/' => 'M', '/м/' => 'm', '/Ñ|Ń|Ņ|Ň|Н/' => 'N', '/ñ|ń|ņ|ň|ʼn|н/' => 'n', '/Ö/' => 'Oe', '/ö/' => 'oe', '/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ|О/' => 'O', '/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º|о/' => 'o', '/П/' => 'P', '/п/' => 'p', '/Ŕ|Ŗ|Ř|Р/' => 'R', '/ŕ|ŗ|ř|р/' => 'r', '/Ś|Ŝ|Ş|Ș|Š|С/' => 'S', '/ś|ŝ|ş|ș|š|ſ|с/' => 's', '/Ţ|Ț|Ť|Ŧ|Т/' => 'T', '/ţ|ț|ť|ŧ|т/' => 't', '/Ü/' => 'Ue', '/ü/' => 'ue', '/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ|У/' => 'U', '/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ|у/' => 'u', '/В/' => 'V', '/в/' => 'v', '/Ý|Ÿ|Ŷ|Ы/' => 'Y', '/ý|ÿ|ŷ|ы/' => 'y', '/Ŵ/' => 'W', '/ŵ/' => 'w', '/Ź|Ż|Ž|З/' => 'Z', '/ź|ż|ž|з/' => 'z', '/Æ|Ǽ/' => 'AE', '/ß/'=> 'ss', '/IJ/' => 'IJ', '/ij/' => 'ij', '/Œ/' => 'OE', '/Ч/' => 'Ch', '/ч/' => 'ch', '/Ю/' => 'Ju', '/ю/' => 'ju', '/Я/' => 'Ja', '/я/' => 'ja', '/Ш/' => 'Sh', '/ш/' => 'sh', '/Щ/' => 'Shch', '/щ/' => 'shch', '/Ж/' => 'Zh', '/ж/' => 'zh', ); /** * Default options for string methods * * @var array */ public static $defaults = array( 'slug' => array( 'separator' => '-', 'allowed' => 'a-z0-9' ) ); /** * Converts a string to a html-safe string * * * * echo str::html('some über crazy stuff'); * // output: some über crazy stuff * * echo str::html('some über crazy stuff', false); * // output: some <em>über crazy</em> stuff * * * * @param string $string * @param boolean $keepTags True: lets stuff inside html tags untouched. * @return string The html string */ public static function html($string, $keepTags = true) { return html::encode($string, $keepTags); } /** * Removes all html tags and encoded chars from a string * * * * echo str::unhtml('some crazy stuff'); * // output: some uber crazy stuff * * * * @param string $string * @return string The html string */ public static function unhtml($string) { return html::decode($string); } /** * Converts a string to a xml-safe string * Converts it to html-safe first and then it * will replace html entities to xml entities * * * * echo str::xml('some über crazy stuff'); * // output: some über crazy stuff * * * * @param string $text * @param boolean $html True: convert to html first * @return string */ public static function xml($text, $html = true) { return xml::encode($text, $html); } /** * Removes all xml entities from a string * and convert them to html entities first * and remove all html entities afterwards. * * * * echo str::unxml('some über crazy stuff'); * // output: some über crazy stuff * * * * @param string $string * @return string */ public static function unxml($string) { return xml::decode($string); } /** * Parses a string by a set of available methods * * Available methods: * - json * - xml * - url * - query * - php * * * * str::parse('{"test":"cool","super":"genious"}'); * // output: array( * // 'test' => 'cool', * // 'super' => 'genious' * // ); * * str::parse('nice', 'xml'); * // output: array( * // 'entries' => array( * // 'cool' => 'nice' * // ) * // ); * * * * @param string $string * @param string $mode * @return mixed */ public static function parse($string, $mode = 'json') { if(is_array($string) || is_object($string)) return $string; switch($mode) { case 'json': return (array)@json_decode($string, true); case 'xml': return xml::parse($string); case 'url': return (array)@parse_url($string); case 'php': return @unserialize($string); default: return $string; } } /** * Encode a string (used for email addresses) * * @param string $string * @return string */ public static function encode($string) { $string = (string)$string; $encoded = ''; for($i = 0; $i < static::length($string); $i++) { $char = static::substr($string, $i, 1); if(MB) { list(, $code) = unpack('N', mb_convert_encoding($char, 'UCS-4BE', 'UTF-8')); } else { $code = ord($char); } $encoded .= rand(1, 2) == 1 ? '&#' . $code . ';' : '&#x' . dechex($code) . ';'; } return $encoded; } /** * Generates an "a mailto" tag * * * * echo str::email('bastian@getkirby.com'); * echo str::email('bastian@getkirby.com', 'mail me'); * * * * @param string $email The url for the a tag * @param mixed $text The optional text. If null, the url will be used as text * @param array $attr Additional attributes for the tag * @return string the generated html */ public static function email($email, $text = false, $attr = array()) { return html::email($email, $text, $attr); } /** * Generates an a tag * * @param string $href The url for the a tag * @param mixed $text The optional text. If null, the url will be used as text * @param array $attr Additional attributes for the tag * @return string the generated html */ public static function link($href, $text = null, $attr = array()) { return html::a($href, $text, $attr); } /** * Returns an array with all words in a string * * @param string $string */ public static function words($string) { preg_match_all('/(\pL{4,})/iu', $string, $m); return array_shift($m); } /** * Returns an array with all sentences in a string * * @param string $string * @return string */ public static function sentences($string) { return preg_split('/(?<=[.?!])\s+/', $string, -1, PREG_SPLIT_NO_EMPTY); } /** * Returns an array with all lines in a string * * @param string $string * @return array */ public static function lines($string) { return str::split($string, PHP_EOL); } /** * Checks if the given string is a URL * * @param string $string * @return boolean */ public static function isURL($string) { return filter_var($string, FILTER_VALIDATE_URL); } /** * Shortens a string and adds an ellipsis if the string is too long * * * * echo str::short('This is a very, very, very long string', 10); * // output: This is a… * * echo str::short('This is a very, very, very long string', 10, '####'); * // output: This i#### * * * * @param string $string The string to be shortened * @param int $length The final number of characters the string should have * @param string $rep The element, which should be added if the string is too long. Ellipsis is the default. * @return string The shortened string */ public static function short($string, $length, $rep = '…') { if(!$length) return $string; if(static::length($string) <= $length) return $string; $string = static::substr($string, 0, $length); return $string . $rep; } /** * Creates an excerpt of a string * It removes all html tags first and then uses str::short * * @param string $string The string to be shortened * @param int $chars The final number of characters the string should have * @param boolean $removehtml True: remove the HTML tags from the string first * @param string $rep The element, which should be added if the string is too long. Ellipsis is the default. * @return string The shortened string */ public static function excerpt($string, $chars = 140, $removehtml = true, $rep='…') { if($removehtml) $string = strip_tags($string); $string = str_replace(PHP_EOL, ' ', trim($string)); if(static::length($string) <= $chars) return $string; return $chars == 0 ? $string : static::substr($string, 0, strrpos(static::substr($string, 0, $chars), ' ')) . $rep; } /** * The widont function makes sure that there are no * typographical widows at the end of a paragraph – * that's a single word in the last line * * @param string $string * @return string */ public static function widont($string = '') { return preg_replace_callback('|([^\s])\s+([^\s]+)\s*$|', function($matches) { if(str::contains($matches[2], '-')) { return $matches[1] . ' ' . str_replace('-', '‑', $matches[2]); } else { return $matches[1] . ' ' . $matches[2]; } }, $string); } /** * An UTF-8 safe version of substr() * * @param string $str * @param int $start * @param int $length * @return string */ public static function substr($str, $start, $length = null) { $length = $length === null ? static::length($str) : $length; return MB ? mb_substr($str, $start, $length, 'UTF-8') : substr($str, $start, $length); } /** * An UTF-8 safe version of strtolower() * * @param string $str * @return string */ public static function lower($str) { return MB ? mb_strtolower($str, 'UTF-8') : strtolower($str); } /** * An UTF-8 safe version of strotoupper() * * @param string $str * @return string */ public static function upper($str) { return MB ? mb_strtoupper($str, 'UTF-8') : strtoupper($str); } /** * An UTF-8 safe version of strlen() * * @param string $str * @return string */ public static function length($str) { return MB ? mb_strlen($str, 'UTF-8') : strlen($str); } /** * Checks if a str contains another string * * @param string $str * @param string $needle * @param boolean $i ignore upper/lowercase * @return string */ public static function contains($str, $needle, $i = true) { if($i) { $str = static::lower($str); $needle = static::lower($needle); } return strstr($str, $needle) ? true : false; } /** * Generates a random string * * @param int $length The length of the random string * @return string */ public static function random($length = false, $type = 'alphaNum') { $length = $length ? $length : rand(5,10); $pool = static::pool($type); shuffle($pool); $size = count($pool) - 1; $hash = ''; for($x = 0; $x < $length; $x++) { $hash .= $pool[rand(0, $size)]; } return $hash; } /** * Convert a string to a safe version to be used in a URL * * @param string $string The unsafe string * @param string $separator To be used instead of space and other non-word characters. * @return string The safe string */ public static function slug($string, $separator = null, $allowed = null) { $separator = $separator ?: static::$defaults['slug']['separator']; $allowed = $allowed ?: static::$defaults['slug']['allowed']; $string = trim($string); $string = static::lower($string); $string = static::ascii($string); // replace spaces with simple dashes $string = preg_replace('![^' . $allowed . ']!i', $separator, $string); // remove double dashes $string = preg_replace('![' . preg_quote($separator) . ']{2,}!', $separator, $string); // trim trailing and leading dashes $string = trim($string, $separator); // replace slashes with dashes $string = str_replace('/', $separator, $string); return $string; } /** * Better alternative for explode() * It takes care of removing empty values * and it has a built-in way to skip values * which are too short. * * @param string $string The string to split * @param string $separator The string to split by * @param int $length The min length of values. * @return array An array of found values */ public static function split($string, $separator = ',', $length = 1) { if(is_array($string)) return $string; $string = trim($string, $separator); $parts = explode($separator, $string); $out = array(); foreach($parts AS $p) { $p = trim($p); if(static::length($p) > 0 && static::length($p) >= $length) $out[] = $p; } return $out; } /** * An UTF-8 safe version of ucwords() * * @param string $string * @return string */ public static function ucwords($string) { return MB ? mb_convert_case($string, MB_CASE_TITLE, 'UTF-8') : ucwords(strtolower($string)); } /** * An UTF-8 safe version of ucfirst() * * @param string $string * @return string */ public static function ucfirst($string) { return static::upper(static::substr($string, 0, 1)) . static::lower(static::substr($string, 1)); } /** * Tries to detect the string encoding * * @param string $string * @return string */ public static function encoding($string) { if(MB) { return mb_detect_encoding($string, 'UTF-8, ISO-8859-1, windows-1251'); } else { foreach(array('utf-8', 'iso-8859-1', 'windows-1251') as $item) { if(md5(iconv($item, $item, $string)) == md5($string)) return $item; } return false; } } /** * Converts a string to a different encoding * * @param string $string * @param string $targetEncoding * @param string $sourceEncoding (optional) * @return string */ public static function convert($string, $targetEncoding, $sourceEncoding = null) { // detect the source encoding if not passed as third argument if(is_null($sourceEncoding)) $sourceEncoding = static::encoding($string); return iconv($sourceEncoding, $targetEncoding, $string); } /** * Converts a string to UTF-8 * * @param string $string * @return string */ public static function utf8($string) { return static::convert($string, 'utf-8'); } /** * A better way to strip slashes * * @param string $string * @return string */ public static function stripslashes($string) { if(is_array($string)) return $string; return get_magic_quotes_gpc() ? stripslashes($string) : $string; } /** * A super simple string template engine, * which replaces tags like {mytag} with any other string * * @param string $string * @param array $data An associative array with keys, which should be replaced and values. * @return string */ public static function template($string, $data = array()) { $replace = array(); foreach($data as $key => $value) $replace['{' . $key . '}'] = $value; return str_replace(array_keys($replace), array_values($replace), $string); } /** * Convert a string to 7-bit ASCII. * * @param string $string * @return string */ public static function ascii($string) { $foreign = static::$ascii; $string = preg_replace(array_keys($foreign), array_values($foreign), $string); return preg_replace('/[^\x09\x0A\x0D\x20-\x7E]/', '', $string); } /** * Forces a download of the string as text file * * @param string $string * @param string $name Optional name for the downloaded file */ public static function download($string, $name = null) { header::download(array( 'name' => $name ? $name : 'text.txt', 'size' => static::length($string), 'mime' => 'text/plain', )); die($string); } /** * Checks if a string starts with the passed needle * * @param string $string * @param string $needle * @return boolean */ public static function startsWith($string, $needle) { return $needle === '' || strpos($string, $needle) === 0; } /** * Checks if a string ends with the passed needle * * @param string $string * @param string $needle * @return boolean */ public static function endsWith($string, $needle) { return $needle === '' || static::substr($string, -static::length($needle)) === $needle; } /** * Get a character pool with various possible combinations * * @param string $type * @param boolean $array * @return string */ public static function pool($type, $array = true) { $pool = array(); if(is_array($type)) { foreach($type as $t) { $pool = array_merge($pool, static::pool($t)); } } else { switch($type) { case 'alphaLower': $pool = range('a','z'); break; case 'alphaUpper': $pool = range('A', 'Z'); break; case 'alpha': $pool = static::pool(array('alphaLower', 'alphaUpper')); break; case 'num': $pool = range(0, 9); break; case 'alphaNum': $pool = static::pool(array('alpha', 'num')); break; } } return $array ? $pool : implode('', $pool); } }