* @copyright Meritoo */ class Miscellaneous { /** * Returns directory's content (names of directories and files) * * @param string $directoryPath Path of directory who content should be returned * @param bool $recursive (optional) If is set to true, sub-directories are also searched for content. * Otherwise - only content of given directory is returned. * @param int $maxFilesCount (optional) Maximum files that will be returned. If it's null, all files are * returned. * @return array|null */ public static function getDirectoryContent($directoryPath, $recursive = false, $maxFilesCount = null) { /* * Path of directory is unknown or does not exist and is not readable? * Nothing to do */ if (empty($directoryPath) || !is_readable($directoryPath)) { return null; } $files = []; $startFileName = ''; if (self::isFilePath($directoryPath)) { $startDirectoryPath = dirname($directoryPath); $startFileName = str_replace($startDirectoryPath, '', $directoryPath); $directoryPath = $startDirectoryPath; } $count = 0; $startFileFound = false; if (!Regex::endsWith($directoryPath, '/')) { $directoryPath .= '/'; } if (Regex::startsWith($startFileName, '/')) { $startFileName = mb_substr($startFileName, 1); } $directoryContent = scandir($directoryPath, SCANDIR_SORT_ASCENDING); if (!empty($directoryContent)) { foreach ($directoryContent as $fileName) { if ('.' !== $fileName && '..' !== $fileName) { $content = null; if (!empty($startFileName) && !$startFileFound) { if ($fileName === $startFileName) { $startFileFound = true; } continue; } if ($recursive && is_dir($directoryPath . $fileName)) { $content = self::getDirectoryContent($directoryPath . $fileName, true, $maxFilesCount - $count); } if (null !== $content) { $files[$fileName] = $content; if (null !== $maxFilesCount) { $count += Arrays::getNonArrayElementsCount($content); } } else { $files[] = $fileName; if (null !== $maxFilesCount) { ++$count; } } if (null !== $maxFilesCount && $count >= $maxFilesCount) { break; } } } } return $files; } /** * Returns information if given path it's a file's path, if the path contains file name * * @param string $path The path to check * @return bool */ public static function isFilePath($path) { $info = pathinfo($path); return isset($info['extension']) && !empty($info['extension']); } /** * Converts checkbox value to boolean * * @param string $checkboxValue Checkbox value * @return bool */ public static function checkboxValue2Boolean($checkboxValue) { $mapping = [ 'on' => true, 'off' => false, ]; $clearValue = strtolower(trim($checkboxValue)); if (isset($mapping[$clearValue])) { return $mapping[$clearValue]; } return false; } /** * Converts checkbox value to integer * * @param string $checkboxValue Checkbox value * @return int */ public static function checkboxValue2Integer($checkboxValue) { return (int)self::checkboxValue2Boolean($checkboxValue); } /** * Returns name of file with given extension after verification if it contains the extension * * @param string $fileName The file name to verify * @param string $extension The extension to verify and include * @return string */ public static function includeFileExtension($fileName, $extension) { $fileExtension = self::getFileExtension($fileName, true); /* * File has given extension? * Nothing to do */ if ($fileExtension === strtolower($extension)) { return $fileName; } return sprintf('%s.%s', $fileName, $extension); } /** * Returns file extension * * @param string $fileName File name * @param bool $asLowerCase (optional) if true extension is returned as lowercase string * @return string */ public static function getFileExtension($fileName, $asLowerCase = false) { $extension = ''; $matches = []; if (preg_match('|(.+)\.(.+)|', $fileName, $matches)) { $extension = end($matches); } if ($asLowerCase) { return strtolower($extension); } return $extension; } /** * Returns file name from given path * * @param string $path A path that contains file name * @return string */ public static function getFileNameFromPath($path) { $matches = []; $pattern = sprintf('|([^\%s.]+\.[A-Za-z0-9.]+)$|', DIRECTORY_SEPARATOR); if ((bool)preg_match($pattern, $path, $matches)) { return $matches[1]; } return ''; } /** * Returns unique name for file based on given original name * * @param string $originalFileName Original name of the file * @param int $objectId (optional) Object ID, the ID of database's row. May be included into the * generated / unique name. * @return string */ public static function getUniqueFileName($originalFileName, $objectId = 0) { /* * Get parts of the file name: * - without extension * - and... the extension */ $withoutExtension = self::getFileNameWithoutExtension($originalFileName); $extension = self::getFileExtension($originalFileName, true); /* * Let's clear name of file * * Attention. * The name without extension may be cleared / urlized only to avoid incorrect name by replacing "." with "-". */ $withoutExtension = Urlizer::urlize($withoutExtension); /* * Now I have to complete the template used to build / generate unique name */ $template = '%s-%s.%s'; // [file's name]-[unique key].[file's extension] /* * Add some uniqueness */ $unique = self::getUniqueString(mt_rand()); /* * Finally build and return the unique name */ if ($objectId > 0) { $template = '%s-%s-%s.%s'; // [file's name]-[unique key]-[object ID].[file's extension] return sprintf($template, $withoutExtension, $unique, $objectId, $extension); } return sprintf($template, $withoutExtension, $unique, $extension); } /** * Returns file name without extension * * @param string $fileName The file name * @return string */ public static function getFileNameWithoutExtension($fileName) { $matches = []; if (is_string($fileName) && (bool)preg_match('|(.+)\.(.+)|', $fileName, $matches)) { return $matches[1]; } return ''; } /** * Converts value to non-negative integer (element of the set {0, 1, 2, 3, ...}) * * @param mixed $value Value to convert * @param int $negativeReplacement (optional) Replacement for negative value * @return int */ public static function value2NonNegativeInteger($value, $negativeReplacement = 0) { $effect = (int)$value; if ($effect < 0) { return $negativeReplacement; } return $effect; } /** * Returns information if given PHP module is compiled and loaded * * @param string $phpModuleName PHP module name * @return bool */ public static function isPhpModuleLoaded($phpModuleName) { $phpModulesArray = get_loaded_extensions(); return in_array($phpModuleName, $phpModulesArray, false); } /** * Converts given string characters to latin characters * * @param string $string String to convert * @param bool $lowerCaseHuman (optional) If is set to true, converted string is returned as lowercase and * human-readable. Otherwise - as original. * @param string $replacementChar (optional) Replacement character for all non-latin characters and uppercase * letters, if 2nd argument is set to true * @return string */ public static function toLatin($string, $lowerCaseHuman = true, $replacementChar = '-') { if (is_string($string)) { $string = trim($string); } /* * Empty value? * Nothing to do */ if (empty($string)) { return ''; } $converter = Transliterator::create('Latin-ASCII;'); /* * Oops, cannot instantiate converter * Nothing to do */ if (null === $converter) { return ''; } $converted = $converter->transliterate($string); /* * Make the string lowercase and human-readable */ if ($lowerCaseHuman) { $matches = []; $matchCount = preg_match_all('|[A-Z]{1}[^A-Z]*|', $converted, $matches); if ($matchCount > 0) { $parts = $matches[0]; $converted = mb_strtolower(implode($replacementChar, $parts)); } } /* * Let's replace special characters to spaces * ...and finally spaces to $replacementChar */ $replaced = preg_replace('|[^a-zA-Z0-9]|', ' ', $converted); return preg_replace('| +|', $replacementChar, trim($replaced)); } /** * Returns unique string * * @param string $prefix (optional) Prefix of the unique string. May be used while generating the unique * string simultaneously on several hosts at the same microsecond. * @param bool $hashed (optional) If is set to true, the unique string is hashed additionally. Otherwise - not. * @return string */ public static function getUniqueString($prefix = '', $hashed = false) { $unique = uniqid($prefix, true); if ($hashed) { return sha1($unique); } return $unique; } /** * Replaces part of string with other string or strings. * There is a few combination of what should be searched and with what it should be replaced. * * @param string|array $subject The string or an array of strings to search and replace * @param string|array $search String or pattern or array of patterns to find. It may be: string, an array * of strings or an array of patterns. * @param string|array $replacement The string or an array of strings to replace. It may be: string or an array * of strings. * @param bool $quoteStrings (optional) If is set to true, strings are surrounded with single quote sign * @return string * * Example: * a) an array of strings to search * $subject = [ * 'Lorem ipsum dolor sit amet.', * 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis.', * ]; * * b) an array of patterns * $search = [ * '|ipsum|', * '|pellentesque|', * ]; * * c) an array of strings to replace * $replacement = [ * 'commodo', * 'interdum', * ]; * * The result: * [ * 'Lorem commodo dolor sit amet.', * 'Etiam ullamcorper. Suspendisse a interdum dui, non felis.', * ]; */ public static function replace($subject, $search, $replacement, $quoteStrings = false) { /* * Unknown source or item to find or replacement is an empty array? * Nothing to do */ if (empty($subject) || empty($search) || [] === $replacement) { return $subject; } $effect = $subject; $searchIsString = is_string($search); $searchIsArray = is_array($search); /* * Value to find is neither a string nor an array OR it's an empty string? * Nothing to do */ if ((!$searchIsString && !$searchIsArray) || ($searchIsString && '' === $search)) { return $effect; } $replacementIsString = is_string($replacement); $replacementIsArray = is_array($replacement); $bothAreStrings = $searchIsString && $replacementIsString; $bothAreArrays = $searchIsArray && $replacementIsArray; if ($quoteStrings) { if ($replacementIsString) { $replacement = '\'' . $replacement . '\''; } elseif ($replacementIsArray) { foreach ($replacement as &$item) { if (is_string($item)) { $item = '\'' . $item . '\''; } } unset($item); } } /* * 1st step: replace strings, simple operation with strings */ if ($bothAreStrings) { $effect = str_replace($search, $replacement, $subject); } /* * 2nd step: replace with regular expressions. * Attention. Searched and replacement value should be the same type: strings or arrays. */ if ($effect === $subject && ($bothAreStrings || $bothAreArrays)) { /* * I have to avoid string that contains spaces only, e.g. " ". * It's required to avoid bug: preg_replace(): Empty regular expression. */ if ($searchIsArray || ($searchIsString && !empty(trim($search)))) { $replaced = @preg_replace($search, $replacement, $subject); if (null !== $replaced && [] !== $replaced) { $effect = $replaced; } } } /* * 3rd step: complex replace of the replacement defined as an array. * It may be useful when you want to search for a one string and replace the string with multiple values. */ if ($effect === $subject && $searchIsString && $replacementIsArray) { $subjectIsArray = is_array($subject); $effect = ''; if ($subjectIsArray) { $effect = []; } /* * I have to make the subject an array... */ $subject = Arrays::makeArray($subject); /* * ...and use iterate through the subjects, * because explode() function expects strings as both arguments (1st and 2nd) */ foreach ($subject as $subSubject) { $subEffect = ''; $exploded = explode($search, $subSubject); $explodedCount = count($exploded); foreach ($exploded as $key => $item) { $subEffect .= $item; /* * The replacement shouldn't be included when the searched string was not found */ if ($explodedCount > 1 && $key < $explodedCount - 1 && isset($replacement[$key])) { $subEffect .= $replacement[$key]; } } if ($subjectIsArray) { $effect[] = $subEffect; continue; } $effect .= $subEffect; } } return $effect; } /** * Returns new file name after adding prefix or suffix (or both of them) to the name * * @param string $fileName The file name * @param string $prefix File name prefix * @param string $suffix File name suffix * @return string */ public static function getNewFileName($fileName, $prefix, $suffix) { $effect = $fileName; if (!empty($fileName) && (!empty($prefix) || !empty($suffix))) { $name = self::getFileNameWithoutExtension($fileName); $extension = self::getFileExtension($fileName); $effect = sprintf('%s%s%s.%s', $prefix, $name, $suffix, $extension); } return $effect; } /** * Returns operating system name PHP is running on * * @return string */ public static function getOperatingSystemNameServer() { return PHP_OS; /* * Previous version: * return php_uname('s'); */ } /** * Returns part of string preserving words * * @param string $text The string / text * @param int $maxLength Maximum length of given string * @param string $suffix (optional) The suffix to add at the end of string * @return string */ public static function substringToWord($text, $maxLength, $suffix = '...') { $effect = $text; $textLength = mb_strlen($text, 'utf-8'); $suffixLength = mb_strlen($suffix, 'utf-8'); $maxLength -= $suffixLength; if ($textLength > $maxLength) { $effect = mb_substr($text, 0, $maxLength, 'utf-8'); $lastSpacePosition = mb_strrpos($effect, ' ', 'utf-8'); if (false !== $lastSpacePosition) { $effect = mb_substr($effect, 0, $lastSpacePosition, 'utf-8'); } $effect .= $suffix; } return $effect; } /** * Breaks long text * * @param string $text The text to check and break * @param int $perLine (optional) Characters count per line. Default: 100. * @param string $separator (optional) Separator that is placed between lines. Default: "
". * @param string $encoding (optional) Character encoding. Used by mb_substr(). Default: "UTF-8". * @param int $proportionalAberration (optional) Proportional aberration for chars (percent value). Default: 20. * @return string */ public static function breakLongText( $text, $perLine = 100, $separator = '
', $encoding = 'utf-8', $proportionalAberration = 20 ) { $effect = $text; $textLength = mb_strlen($text); if (!empty($text) && $textLength > $perLine) { /* * The html_entity_decode() function is used here, because while operating * on string that contains only special characters the string is divided * incorrectly, e.g. "<<<<<" -> "<<<<&
lt;". */ //$text = htmlspecialchars_decode($text); $text = html_entity_decode($text, ENT_QUOTES); $effect = ''; $currentPosition = 0; $charsAberration = ceil($perLine * ($proportionalAberration / 100)); $charsPerLineDefault = $perLine; while ($currentPosition <= $textLength) { $insertSeparator = false; /* * Looking for spaces before and after current position. It was done, because text wasn't * broken properly and some words were breaked and placed into two lines. */ if ($charsAberration > 0) { $length = $perLine + $charsAberration; $lineWithAberration = mb_substr($text, $currentPosition, $length, $encoding); if (!Regex::contains($lineWithAberration, ' ')) { $length = $perLine - $charsAberration; $lineWithAberration = mb_substr($text, $currentPosition, $length, $encoding); } if (Regex::startsWith($lineWithAberration, ' ')) { ++$currentPosition; $lineWithAberration = ltrim($lineWithAberration); } $spacePosition = mb_strrpos($lineWithAberration, ' ', 0, $encoding); if (false !== $spacePosition && 0 < $spacePosition) { /* @var int $spacePosition */ $perLine = $spacePosition; $insertSeparator = true; } } $charsOneLine = mb_substr($text, $currentPosition, $perLine, $encoding); /* * The htmlspecialchars() function is used here, because... * Reason and comment the same as above for html_entity_decode() function. */ $effect .= htmlspecialchars($charsOneLine); //$effect .= $charsOneLine; $currentPosition += $perLine; $oneLineContainsSpace = Regex::contains($charsOneLine, ' '); if (($insertSeparator || !$oneLineContainsSpace) && $currentPosition <= $textLength) { $effect .= $separator; } $perLine = $charsPerLineDefault; } } return $effect; } /** * Removes the directory. * If not empty, removes also contents. * * @param string $directoryPath Directory path * @param bool $contentOnly (optional) If is set to true, only content of the directory is removed, not * directory itself. Otherwise - directory is removed too (default behaviour). * @return bool|null */ public static function removeDirectory($directoryPath, $contentOnly = false) { /* * Directory does not exist? * Nothing to do */ if (!file_exists($directoryPath)) { return null; } /* * It's not a directory? * Let's treat it like file */ if (!is_dir($directoryPath)) { return unlink($directoryPath); } foreach (scandir($directoryPath, SCANDIR_SORT_ASCENDING) as $item) { if ('.' === $item || '..' === $item) { continue; } if (!self::removeDirectory($directoryPath . DIRECTORY_SEPARATOR . $item)) { return false; } } /* * Directory should be removed too? */ if (!$contentOnly) { return rmdir($directoryPath); } return true; } /** * Returns information if value is decimal * * @param mixed $value The value to check * @return bool */ public static function isDecimal($value) { return is_scalar($value) && floor($value) !== (float)$value; } /** * Returns the string in camel case * * @param string $string The string to convert e.g. this-is-eXamplE (return: thisIsExample) * @param string $separator (optional) Separator used to find parts of the string, e.g. '-' or ',' * @return string */ public static function getCamelCase($string, $separator = ' ') { if (empty($string)) { return ''; } $effect = ''; $members = explode($separator, $string); foreach ($members as $key => $value) { $value = mb_strtolower($value); if (0 === $key) { $effect .= self::lowercaseFirst($value); } else { $effect .= self::uppercaseFirst($value); } } return $effect; } /** * Make a string's first character lowercase * * @param string $text The text to get first character lowercase * @param bool|null $restLowercase (optional) Information that to do with rest of given string * @return string * * Values of the $restLowercase argument: * - null (default): nothing is done with the string * - true: the rest of string is lowercased * - false: the rest of string is uppercased */ public static function lowercaseFirst($text, $restLowercase = null) { if (empty($text)) { return ''; } $effect = $text; if ($restLowercase) { $effect = mb_strtolower($effect); } elseif (false === $restLowercase) { $effect = mb_strtoupper($effect); } return lcfirst($effect); } /** * Make a string's first character uppercase * * @param string $text The text to get uppercase * @param bool|null $restLowercase (optional) Information that to do with rest of given string * @return string * * Values of the $restLowercase argument: * - null (default): nothing is done with the string * - true: the rest of string is lowercased * - false: the rest of string is uppercased */ public static function uppercaseFirst($text, $restLowercase = null) { if (empty($text)) { return ''; } $effect = $text; if ($restLowercase) { $effect = mb_strtolower($effect); } elseif (false === $restLowercase) { $effect = mb_strtoupper($effect); } return ucfirst($effect); } /** * Quotes given value with apostrophes or quotation marks * * @param mixed $value The value to quote * @param bool $useApostrophe (optional) If is set to true, apostrophes are used. Otherwise - quotation marks. * @return string */ public static function quoteValue($value, $useApostrophe = true) { if (is_string($value)) { $quotes = '"'; if ($useApostrophe) { $quotes = '\''; } $value = sprintf('%s%s%s', $quotes, $value, $quotes); } return $value; } /** * Returns size (of file or directory) in human readable format * * @param int $sizeInBytes The size in bytes * @return string */ public static function getHumanReadableSize($sizeInBytes) { $units = [ 'B', 'KB', 'MB', 'GB', 'TB', 'PB', ]; $index = floor(log($sizeInBytes, 1024)); $size = round($sizeInBytes / (1024 ** $index), 2); $unit = $units[(int)$index]; return sprintf('%s %s', $size, $unit); } /** * Returns string without the last element. * The string should contain given separator. * * @param string $string The string to check * @param string $separator The separator which divides elements of string * @return string */ public static function getStringWithoutLastElement($string, $separator) { $elements = self::getStringElements($string, $separator); $lastKey = Arrays::getLastKey($elements); unset($elements[$lastKey]); return implode($separator, $elements); } /** * Returns elements of given string divided by given separator * * @param string $string The string to check * @param string $separator The separator which divides elements of string * @return array */ public static function getStringElements($string, $separator) { $matches = []; $pattern = sprintf('|[^\%s]+|', $separator); $matchCount = preg_match_all($pattern, $string, $matches); if ($matchCount > 1) { return $matches[0]; } return []; } /** * Returns the last element of given string divided by given separator * * @param string $string The string to check * @param string $separator The separator which divides elements of string * @return string|null */ public static function getLastElementOfString($string, $separator) { $elements = self::getStringElements($string, $separator); /* * No elements? * Nothing to do */ if (empty($elements)) { return null; } $element = Arrays::getLastElement($elements); return trim($element); } /** * Returns smartly trimmed string. * If the string is empty, contains only spaces, e.g. " ", nothing is done and the original string is returned. * * @param string $string The string to trim * @return string */ public static function trimSmart($string) { $trimmed = trim($string); if (empty($trimmed)) { return $string; } return $trimmed; } /** * Returns concatenated given paths * * The paths may be passed as: * - an array of paths / strings * - strings passed as following arguments * * Examples: * - concatenatePaths(['path/first', 'path/second', 'path/third']); * - concatenatePaths('path/first', 'path/second', 'path/third'); * * @param string|array $paths Paths co concatenate. As described above: an array of paths / strings or strings * passed as following arguments. * @return string */ public static function concatenatePaths($paths) { /* * If paths are not provided as array, get the paths from methods' arguments */ if (!is_array($paths)) { $paths = func_get_args(); } /* * No paths provided? * Nothing to do */ if (empty($paths)) { return ''; } /* * Some useful variables */ $concatenated = ''; $firstWindowsBased = false; $separator = DIRECTORY_SEPARATOR; foreach ($paths as $path) { $path = trim($path); /* * Empty paths are useless */ if (empty($path)) { continue; } /* * Does the first path is a Windows-based path? */ if (Arrays::isFirstElement($paths, $path)) { $firstWindowsBased = Regex::isWindowsBasedPath($path); if ($firstWindowsBased) { $separator = '\\'; } } /* * Remove the starting / beginning directory's separator */ $path = self::removeStartingDirectorySeparator($path, $separator); /* * Removes the ending directory's separator */ $path = self::removeEndingDirectorySeparator($path, $separator); /* * If OS is Windows, first part of the concatenated path should be the first passed path, * because in Windows paths starts with drive letter, e.g. "C:", and the directory separator is not * necessary at the beginning. */ if ($firstWindowsBased && empty($concatenated)) { $concatenated = $path; continue; } /* * Concatenate the paths / strings with OS-related directory separator between them (slash or backslash) */ $concatenated = sprintf('%s%s%s', $concatenated, $separator, $path); } return $concatenated; } /** * Removes the starting / beginning directory's separator * * @param string $text Text that may contain a directory's separator at the start / beginning * @param string $separator (optional) The directory's separator, e.g. "/". If is empty (not provided), separator * provided by operating system will be used. * @return string */ public static function removeStartingDirectorySeparator($text, $separator = '') { /* * Not a string? * Nothing to do */ if (!is_string($text)) { return ''; } if (empty($separator)) { $separator = DIRECTORY_SEPARATOR; } $effect = trim($text); if (Regex::startsWithDirectorySeparator($effect, $separator)) { $effect = mb_substr($effect, mb_strlen($separator)); } return $effect; } /** * Removes the ending directory's separator * * @param string $text Text that may contain a directory's separator at the end * @param string $separator (optional) The directory's separator, e.g. "/". If is empty (not provided), system's * separator is used. * @return string */ public static function removeEndingDirectorySeparator($text, $separator = '') { /* * Not a string? * Nothing to do */ if (!is_string($text)) { return ''; } if (empty($separator)) { $separator = DIRECTORY_SEPARATOR; } $effect = trim($text); if (Regex::endsWithDirectorySeparator($effect, $separator)) { $effect = mb_substr($effect, 0, mb_strlen($effect) - mb_strlen($separator)); } return $effect; } /** * Returns safely value of global variable, found in one of the global arrays / variables, e.g. $_GET * * @param int $globalSourceType Represents the global array / variable. One of constants: INPUT_GET, INPUT_POST, * INPUT_COOKIE, INPUT_SERVER, or INPUT_ENV. * @param string $variableName Name of the variable to return value * @return mixed */ public static function getSafelyGlobalVariable($globalSourceType, $variableName) { $value = filter_input($globalSourceType, $variableName); if (null === $value) { $globalSource = null; switch ($globalSourceType) { case INPUT_GET: $globalSource = $_GET; break; case INPUT_POST: $globalSource = $_POST; break; case INPUT_COOKIE: $globalSource = $_COOKIE; break; case INPUT_SERVER: $globalSource = $_SERVER; break; case INPUT_ENV: $globalSource = $_ENV; break; } if (null !== $globalSource && isset($globalSource[$variableName])) { $value = $globalSource[$variableName]; } } return $value; } /** * Adds missing the "0" characters to given number until given length is reached * * Example: * - number: 201 * - length: 6 * - will be returned: 000201 * * If "before" parameter is false, zeros will be inserted after given number. If given number is longer than * given length the number will be returned as it was given to the method. * * @param mixed $number Number for who the "0" characters should be inserted * @param int $length Wanted length of final number * @param bool $before (optional) If false, 0 characters will be inserted after given number * @return string */ public static function fillMissingZeros($number, $length, $before = true) { /* * It's not a number? Empty string is not a number too. * Nothing to do */ if (!is_numeric($number)) { return ''; } $text = trim($number); $textLength = mb_strlen($text); if ($length <= $textLength) { return $text; } for ($i = ($length - $textLength); 0 < $i; --$i) { if ($before) { $text = '0' . $text; continue; } $text .= '0'; } return $text; } /** * Returns information if given value is located in interval between given utmost left and right values * * @param int|float $value Value to verify * @param int|float $left Left utmost value of interval * @param int|float $right Right utmost value of interval * @return bool */ public static function isBetween($value, $left, $right) { return $value > $left && $value < $right; } /** * Returns type of given variable. * If it's an object, full class name is returned. * * @param mixed $variable Variable who type should be returned * @return string */ public static function getType($variable) { if (is_object($variable)) { return Reflection::getClassName($variable); } return gettype($variable); } /** * Returns valid value of color's component (e.g. red). * If given value is greater than 0, returns the value. Otherwise - 0. * * @param int $colorComponent Color's component to verify. Decimal value, e.g. 255. * @param bool $asHexadecimal (optional) If is set to true, hexadecimal value is returned (default behaviour). * Otherwise - decimal. * @return int|string */ public static function getValidColorComponent($colorComponent, $asHexadecimal = true) { $colorComponent = (int)$colorComponent; if ($colorComponent < 0 || $colorComponent > 255) { $colorComponent = 0; } if ($asHexadecimal) { $hexadecimal = dechex($colorComponent); if (1 === strlen($hexadecimal)) { return sprintf('0%s', $hexadecimal); } return $hexadecimal; } return $colorComponent; } /** * Returns inverted value of color for given color * * @param string $color Hexadecimal value of color to invert (with or without hash), e.g. "dd244c" or "#22a5fe" * @return string */ public static function getInvertedColor($color) { /* * Prepare the color for later usage */ $color = trim($color); $withHash = Regex::startsWith($color, '#'); /* * Verify and get valid value of color. * An exception will be thrown if the value is not a color. */ $validColor = Regex::getValidColorHexValue($color); /* * Grab color's components */ $red = hexdec(substr($validColor, 0, 2)); $green = hexdec(substr($validColor, 2, 2)); $blue = hexdec(substr($validColor, 4, 2)); /* * Calculate inverted color's components */ $redInverted = self::getValidColorComponent(255 - $red); $greenInverted = self::getValidColorComponent(255 - $green); $blueInverted = self::getValidColorComponent(255 - $blue); /* * Voila, here is the inverted color */ $invertedColor = sprintf('%s%s%s', $redInverted, $greenInverted, $blueInverted); if ($withHash) { return sprintf('#%s', $invertedColor); } return $invertedColor; } /** * Returns project's root path. * Looks for directory that contains composer.json. * * @return string */ public static function getProjectRootPath() { $projectRootPath = ''; $fileName = 'composer.json'; $directoryPath = __DIR__; /* * Path of directory it's not the path of last directory? */ while (DIRECTORY_SEPARATOR !== $directoryPath) { $filePath = static::concatenatePaths($directoryPath, $fileName); /* * Is here file we are looking for? * Maybe it's a project's root path */ if (file_exists($filePath)) { $projectRootPath = $directoryPath; } $directoryPath = dirname($directoryPath); } return $projectRootPath; } }