Initial
This commit is contained in:
219
system/Helpers/array_helper.php
Normal file
219
system/Helpers/array_helper.php
Normal file
@@ -0,0 +1,219 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
// CodeIgniter Array Helpers
|
||||
|
||||
if (! function_exists('dot_array_search')) {
|
||||
/**
|
||||
* Searches an array through dot syntax. Supports
|
||||
* wildcard searches, like foo.*.bar
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function dot_array_search(string $index, array $array)
|
||||
{
|
||||
// See https://regex101.com/r/44Ipql/1
|
||||
$segments = preg_split(
|
||||
'/(?<!\\\\)\./',
|
||||
rtrim($index, '* '),
|
||||
0,
|
||||
PREG_SPLIT_NO_EMPTY
|
||||
);
|
||||
|
||||
$segments = array_map(static function ($key) {
|
||||
return str_replace('\.', '.', $key);
|
||||
}, $segments);
|
||||
|
||||
return _array_search_dot($segments, $array);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('_array_search_dot')) {
|
||||
/**
|
||||
* Used by `dot_array_search` to recursively search the
|
||||
* array with wildcards.
|
||||
*
|
||||
* @internal This should not be used on its own.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function _array_search_dot(array $indexes, array $array)
|
||||
{
|
||||
// Grab the current index
|
||||
$currentIndex = $indexes ? array_shift($indexes) : null;
|
||||
|
||||
if ((empty($currentIndex) && (int) $currentIndex !== 0) || (! isset($array[$currentIndex]) && $currentIndex !== '*')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Handle Wildcard (*)
|
||||
if ($currentIndex === '*') {
|
||||
$answer = [];
|
||||
|
||||
foreach ($array as $value) {
|
||||
if (! is_array($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$answer[] = _array_search_dot($indexes, $value);
|
||||
}
|
||||
|
||||
$answer = array_filter($answer, static function ($value) {
|
||||
return $value !== null;
|
||||
});
|
||||
|
||||
if ($answer !== []) {
|
||||
if (count($answer) === 1) {
|
||||
// If array only has one element, we return that element for BC.
|
||||
return current($answer);
|
||||
}
|
||||
|
||||
return $answer;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// If this is the last index, make sure to return it now,
|
||||
// and not try to recurse through things.
|
||||
if (empty($indexes)) {
|
||||
return $array[$currentIndex];
|
||||
}
|
||||
|
||||
// Do we need to recursively search this value?
|
||||
if (is_array($array[$currentIndex]) && $array[$currentIndex] !== []) {
|
||||
return _array_search_dot($indexes, $array[$currentIndex]);
|
||||
}
|
||||
|
||||
// Otherwise we've found our match!
|
||||
return $array[$currentIndex];
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('array_deep_search')) {
|
||||
/**
|
||||
* Returns the value of an element at a key in an array of uncertain depth.
|
||||
*
|
||||
* @param mixed $key
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
function array_deep_search($key, array $array)
|
||||
{
|
||||
if (isset($array[$key])) {
|
||||
return $array[$key];
|
||||
}
|
||||
|
||||
foreach ($array as $value) {
|
||||
if (is_array($value) && ($result = array_deep_search($key, $value))) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('array_sort_by_multiple_keys')) {
|
||||
/**
|
||||
* Sorts a multidimensional array by its elements values. The array
|
||||
* columns to be used for sorting are passed as an associative
|
||||
* array of key names and sorting flags.
|
||||
*
|
||||
* Both arrays of objects and arrays of array can be sorted.
|
||||
*
|
||||
* Example:
|
||||
* array_sort_by_multiple_keys($players, [
|
||||
* 'team.hierarchy' => SORT_ASC,
|
||||
* 'position' => SORT_ASC,
|
||||
* 'name' => SORT_STRING,
|
||||
* ]);
|
||||
*
|
||||
* The '.' dot operator in the column name indicates a deeper array or
|
||||
* object level. In principle, any number of sublevels could be used,
|
||||
* as long as the level and column exist in every array element.
|
||||
*
|
||||
* For information on multi-level array sorting, refer to Example #3 here:
|
||||
* https://www.php.net/manual/de/function.array-multisort.php
|
||||
*
|
||||
* @param array $array the reference of the array to be sorted
|
||||
* @param array $sortColumns an associative array of columns to sort
|
||||
* after and their sorting flags
|
||||
*/
|
||||
function array_sort_by_multiple_keys(array &$array, array $sortColumns): bool
|
||||
{
|
||||
// Check if there really are columns to sort after
|
||||
if (empty($sortColumns) || empty($array)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Group sorting indexes and data
|
||||
$tempArray = [];
|
||||
|
||||
foreach ($sortColumns as $key => $sortFlag) {
|
||||
// Get sorting values
|
||||
$carry = $array;
|
||||
|
||||
// The '.' operator separates nested elements
|
||||
foreach (explode('.', $key) as $keySegment) {
|
||||
// Loop elements if they are objects
|
||||
if (is_object(reset($carry))) {
|
||||
// Extract the object attribute
|
||||
foreach ($carry as $index => $object) {
|
||||
$carry[$index] = $object->{$keySegment};
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extract the target column if elements are arrays
|
||||
$carry = array_column($carry, $keySegment);
|
||||
}
|
||||
|
||||
// Store the collected sorting parameters
|
||||
$tempArray[] = $carry;
|
||||
$tempArray[] = $sortFlag;
|
||||
}
|
||||
|
||||
// Append the array as reference
|
||||
$tempArray[] = &$array;
|
||||
|
||||
// Pass sorting arrays and flags as an argument list.
|
||||
return array_multisort(...$tempArray);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('array_flatten_with_dots')) {
|
||||
/**
|
||||
* Flatten a multidimensional array using dots as separators.
|
||||
*
|
||||
* @param iterable $array The multi-dimensional array
|
||||
* @param string $id Something to initially prepend to the flattened keys
|
||||
*
|
||||
* @return array The flattened array
|
||||
*/
|
||||
function array_flatten_with_dots(iterable $array, string $id = ''): array
|
||||
{
|
||||
$flattened = [];
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
$newKey = $id . $key;
|
||||
|
||||
if (is_array($value)) {
|
||||
$flattened = array_merge($flattened, array_flatten_with_dots($value, $newKey . '.'));
|
||||
} else {
|
||||
$flattened[$newKey] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $flattened;
|
||||
}
|
||||
}
|
||||
99
system/Helpers/cookie_helper.php
Normal file
99
system/Helpers/cookie_helper.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Config\App;
|
||||
use Config\Services;
|
||||
|
||||
//=============================================================================
|
||||
// CodeIgniter Cookie Helpers
|
||||
//=============================================================================
|
||||
|
||||
if (! function_exists('set_cookie')) {
|
||||
/**
|
||||
* Set cookie
|
||||
*
|
||||
* Accepts seven parameters, or you can submit an associative
|
||||
* array in the first parameter containing all the values.
|
||||
*
|
||||
* @param array|string $name Cookie name or array containing binds
|
||||
* @param string $value The value of the cookie
|
||||
* @param string $expire The number of seconds until expiration
|
||||
* @param string $domain For site-wide cookie. Usually: .yourdomain.com
|
||||
* @param string $path The cookie path
|
||||
* @param string $prefix The cookie prefix
|
||||
* @param bool $secure True makes the cookie secure
|
||||
* @param bool $httpOnly True makes the cookie accessible via http(s) only (no javascript)
|
||||
* @param string|null $sameSite The cookie SameSite value
|
||||
*
|
||||
* @see \CodeIgniter\HTTP\Response::setCookie()
|
||||
*/
|
||||
function set_cookie(
|
||||
$name,
|
||||
string $value = '',
|
||||
string $expire = '',
|
||||
string $domain = '',
|
||||
string $path = '/',
|
||||
string $prefix = '',
|
||||
bool $secure = false,
|
||||
bool $httpOnly = false,
|
||||
?string $sameSite = null
|
||||
) {
|
||||
$response = Services::response();
|
||||
$response->setCookie($name, $value, $expire, $domain, $path, $prefix, $secure, $httpOnly, $sameSite);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('get_cookie')) {
|
||||
/**
|
||||
* Fetch an item from the $_COOKIE array
|
||||
*
|
||||
* @param string $index
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @see \CodeIgniter\HTTP\IncomingRequest::getCookie()
|
||||
*/
|
||||
function get_cookie($index, bool $xssClean = false)
|
||||
{
|
||||
$prefix = isset($_COOKIE[$index]) ? '' : config(App::class)->cookiePrefix;
|
||||
$request = Services::request();
|
||||
$filter = $xssClean ? FILTER_SANITIZE_FULL_SPECIAL_CHARS : FILTER_DEFAULT;
|
||||
|
||||
return $request->getCookie($prefix . $index, $filter);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('delete_cookie')) {
|
||||
/**
|
||||
* Delete a cookie
|
||||
*
|
||||
* @param mixed $name
|
||||
* @param string $domain the cookie domain. Usually: .yourdomain.com
|
||||
* @param string $path the cookie path
|
||||
* @param string $prefix the cookie prefix
|
||||
*
|
||||
* @see \CodeIgniter\HTTP\Response::deleteCookie()
|
||||
*/
|
||||
function delete_cookie($name, string $domain = '', string $path = '/', string $prefix = '')
|
||||
{
|
||||
Services::response()->deleteCookie($name, $domain, $path, $prefix);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('has_cookie')) {
|
||||
/**
|
||||
* Checks if a cookie exists by name.
|
||||
*/
|
||||
function has_cookie(string $name, ?string $value = null, string $prefix = ''): bool
|
||||
{
|
||||
return Services::response()->hasCookie($name, $value, $prefix);
|
||||
}
|
||||
}
|
||||
66
system/Helpers/date_helper.php
Normal file
66
system/Helpers/date_helper.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
// CodeIgniter Date Helpers
|
||||
|
||||
if (! function_exists('now')) {
|
||||
/**
|
||||
* Get "now" time
|
||||
*
|
||||
* Returns time() based on the timezone parameter or on the
|
||||
* app_timezone() setting
|
||||
*
|
||||
* @param string $timezone
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
function now(?string $timezone = null): int
|
||||
{
|
||||
$timezone = empty($timezone) ? app_timezone() : $timezone;
|
||||
|
||||
if ($timezone === 'local' || $timezone === date_default_timezone_get()) {
|
||||
return time();
|
||||
}
|
||||
|
||||
$datetime = new DateTime('now', new DateTimeZone($timezone));
|
||||
sscanf($datetime->format('j-n-Y G:i:s'), '%d-%d-%d %d:%d:%d', $day, $month, $year, $hour, $minute, $second);
|
||||
|
||||
return mktime($hour, $minute, $second, $month, $day, $year);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('timezone_select')) {
|
||||
/**
|
||||
* Generates a select field of all available timezones
|
||||
*
|
||||
* Returns a string with the formatted HTML
|
||||
*
|
||||
* @param string $class Optional class to apply to the select field
|
||||
* @param string $default Default value for initial selection
|
||||
* @param int $what One of the DateTimeZone class constants (for listIdentifiers)
|
||||
* @param string $country A two-letter ISO 3166-1 compatible country code (for listIdentifiers)
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
function timezone_select(string $class = '', string $default = '', int $what = DateTimeZone::ALL, ?string $country = null): string
|
||||
{
|
||||
$timezones = DateTimeZone::listIdentifiers($what, $country);
|
||||
|
||||
$buffer = "<select name='timezone' class='{$class}'>" . PHP_EOL;
|
||||
|
||||
foreach ($timezones as $timezone) {
|
||||
$selected = ($timezone === $default) ? 'selected' : '';
|
||||
$buffer .= "<option value='{$timezone}' {$selected}>{$timezone}</option>" . PHP_EOL;
|
||||
}
|
||||
|
||||
return $buffer . ('</select>' . PHP_EOL);
|
||||
}
|
||||
}
|
||||
443
system/Helpers/filesystem_helper.php
Normal file
443
system/Helpers/filesystem_helper.php
Normal file
@@ -0,0 +1,443 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
// CodeIgniter File System Helpers
|
||||
|
||||
if (! function_exists('directory_map')) {
|
||||
/**
|
||||
* Create a Directory Map
|
||||
*
|
||||
* Reads the specified directory and builds an array
|
||||
* representation of it. Sub-folders contained with the
|
||||
* directory will be mapped as well.
|
||||
*
|
||||
* @param string $sourceDir Path to source
|
||||
* @param int $directoryDepth Depth of directories to traverse
|
||||
* (0 = fully recursive, 1 = current dir, etc)
|
||||
* @param bool $hidden Whether to show hidden files
|
||||
*/
|
||||
function directory_map(string $sourceDir, int $directoryDepth = 0, bool $hidden = false): array
|
||||
{
|
||||
try {
|
||||
$fp = opendir($sourceDir);
|
||||
|
||||
$fileData = [];
|
||||
$newDepth = $directoryDepth - 1;
|
||||
$sourceDir = rtrim($sourceDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
|
||||
while (false !== ($file = readdir($fp))) {
|
||||
// Remove '.', '..', and hidden files [optional]
|
||||
if ($file === '.' || $file === '..' || ($hidden === false && $file[0] === '.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_dir($sourceDir . $file)) {
|
||||
$file .= DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
if (($directoryDepth < 1 || $newDepth > 0) && is_dir($sourceDir . $file)) {
|
||||
$fileData[$file] = directory_map($sourceDir . $file, $newDepth, $hidden);
|
||||
} else {
|
||||
$fileData[] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
closedir($fp);
|
||||
|
||||
return $fileData;
|
||||
} catch (Throwable $e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('directory_mirror')) {
|
||||
/**
|
||||
* Recursively copies the files and directories of the origin directory
|
||||
* into the target directory, i.e. "mirror" its contents.
|
||||
*
|
||||
* @param bool $overwrite Whether individual files overwrite on collision
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
function directory_mirror(string $originDir, string $targetDir, bool $overwrite = true): void
|
||||
{
|
||||
if (! is_dir($originDir = rtrim($originDir, '\\/'))) {
|
||||
throw new InvalidArgumentException(sprintf('The origin directory "%s" was not found.', $originDir));
|
||||
}
|
||||
|
||||
if (! is_dir($targetDir = rtrim($targetDir, '\\/'))) {
|
||||
@mkdir($targetDir, 0755, true);
|
||||
}
|
||||
|
||||
$dirLen = strlen($originDir);
|
||||
|
||||
/**
|
||||
* @var SplFileInfo $file
|
||||
*/
|
||||
foreach (new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($originDir, FilesystemIterator::SKIP_DOTS),
|
||||
RecursiveIteratorIterator::SELF_FIRST
|
||||
) as $file) {
|
||||
$origin = $file->getPathname();
|
||||
$target = $targetDir . substr($origin, $dirLen);
|
||||
|
||||
if ($file->isDir()) {
|
||||
if (! is_dir($target)) {
|
||||
mkdir($target, 0755);
|
||||
}
|
||||
} elseif (! is_file($target) || ($overwrite && is_file($target))) {
|
||||
copy($origin, $target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('write_file')) {
|
||||
/**
|
||||
* Write File
|
||||
*
|
||||
* Writes data to the file specified in the path.
|
||||
* Creates a new file if non-existent.
|
||||
*
|
||||
* @param string $path File path
|
||||
* @param string $data Data to write
|
||||
* @param string $mode fopen() mode (default: 'wb')
|
||||
*/
|
||||
function write_file(string $path, string $data, string $mode = 'wb'): bool
|
||||
{
|
||||
try {
|
||||
$fp = fopen($path, $mode);
|
||||
|
||||
flock($fp, LOCK_EX);
|
||||
|
||||
for ($result = $written = 0, $length = strlen($data); $written < $length; $written += $result) {
|
||||
if (($result = fwrite($fp, substr($data, $written))) === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
flock($fp, LOCK_UN);
|
||||
fclose($fp);
|
||||
|
||||
return is_int($result);
|
||||
} catch (Throwable $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('delete_files')) {
|
||||
/**
|
||||
* Delete Files
|
||||
*
|
||||
* Deletes all files contained in the supplied directory path.
|
||||
* Files must be writable or owned by the system in order to be deleted.
|
||||
* If the second parameter is set to true, any directories contained
|
||||
* within the supplied base directory will be nuked as well.
|
||||
*
|
||||
* @param string $path File path
|
||||
* @param bool $delDir Whether to delete any directories found in the path
|
||||
* @param bool $htdocs Whether to skip deleting .htaccess and index page files
|
||||
* @param bool $hidden Whether to include hidden files (files beginning with a period)
|
||||
*/
|
||||
function delete_files(string $path, bool $delDir = false, bool $htdocs = false, bool $hidden = false): bool
|
||||
{
|
||||
$path = realpath($path) ?: $path;
|
||||
$path = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
|
||||
try {
|
||||
foreach (new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
|
||||
RecursiveIteratorIterator::CHILD_FIRST
|
||||
) as $object) {
|
||||
$filename = $object->getFilename();
|
||||
if (! $hidden && $filename[0] === '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $htdocs || ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename)) {
|
||||
$isDir = $object->isDir();
|
||||
if ($isDir && $delDir) {
|
||||
rmdir($object->getPathname());
|
||||
|
||||
continue;
|
||||
}
|
||||
if (! $isDir) {
|
||||
unlink($object->getPathname());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (Throwable $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('get_filenames')) {
|
||||
/**
|
||||
* Get Filenames
|
||||
*
|
||||
* Reads the specified directory and builds an array containing the filenames.
|
||||
* Any sub-folders contained within the specified path are read as well.
|
||||
*
|
||||
* @param string $sourceDir Path to source
|
||||
* @param bool|null $includePath Whether to include the path as part of the filename; false for no path, null for a relative path, true for full path
|
||||
* @param bool $hidden Whether to include hidden files (files beginning with a period)
|
||||
*/
|
||||
function get_filenames(string $sourceDir, ?bool $includePath = false, bool $hidden = false): array
|
||||
{
|
||||
$files = [];
|
||||
|
||||
$sourceDir = realpath($sourceDir) ?: $sourceDir;
|
||||
$sourceDir = rtrim($sourceDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
|
||||
try {
|
||||
foreach (new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($sourceDir, RecursiveDirectoryIterator::SKIP_DOTS),
|
||||
RecursiveIteratorIterator::SELF_FIRST
|
||||
) as $name => $object) {
|
||||
$basename = pathinfo($name, PATHINFO_BASENAME);
|
||||
if (! $hidden && $basename[0] === '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($includePath === false) {
|
||||
$files[] = $basename;
|
||||
} elseif ($includePath === null) {
|
||||
$files[] = str_replace($sourceDir, '', $name);
|
||||
} else {
|
||||
$files[] = $name;
|
||||
}
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
return [];
|
||||
}
|
||||
|
||||
sort($files);
|
||||
|
||||
return $files;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('get_dir_file_info')) {
|
||||
/**
|
||||
* Get Directory File Information
|
||||
*
|
||||
* Reads the specified directory and builds an array containing the filenames,
|
||||
* filesize, dates, and permissions
|
||||
*
|
||||
* Any sub-folders contained within the specified path are read as well.
|
||||
*
|
||||
* @param string $sourceDir Path to source
|
||||
* @param bool $topLevelOnly Look only at the top level directory specified?
|
||||
* @param bool $recursion Internal variable to determine recursion status - do not use in calls
|
||||
*/
|
||||
function get_dir_file_info(string $sourceDir, bool $topLevelOnly = true, bool $recursion = false): array
|
||||
{
|
||||
static $fileData = [];
|
||||
$relativePath = $sourceDir;
|
||||
|
||||
try {
|
||||
$fp = opendir($sourceDir);
|
||||
|
||||
// reset the array and make sure $source_dir has a trailing slash on the initial call
|
||||
if ($recursion === false) {
|
||||
$fileData = [];
|
||||
$sourceDir = rtrim(realpath($sourceDir), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
// Used to be foreach (scandir($source_dir, 1) as $file), but scandir() is simply not as fast
|
||||
while (false !== ($file = readdir($fp))) {
|
||||
if (is_dir($sourceDir . $file) && $file[0] !== '.' && $topLevelOnly === false) {
|
||||
get_dir_file_info($sourceDir . $file . DIRECTORY_SEPARATOR, $topLevelOnly, true);
|
||||
} elseif ($file[0] !== '.') {
|
||||
$fileData[$file] = get_file_info($sourceDir . $file);
|
||||
$fileData[$file]['relative_path'] = $relativePath;
|
||||
}
|
||||
}
|
||||
|
||||
closedir($fp);
|
||||
|
||||
return $fileData;
|
||||
} catch (Throwable $fe) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('get_file_info')) {
|
||||
/**
|
||||
* Get File Info
|
||||
*
|
||||
* Given a file and path, returns the name, path, size, date modified
|
||||
* Second parameter allows you to explicitly declare what information you want returned
|
||||
* Options are: name, server_path, size, date, readable, writable, executable, fileperms
|
||||
* Returns false if the file cannot be found.
|
||||
*
|
||||
* @param string $file Path to file
|
||||
* @param mixed $returnedValues Array or comma separated string of information returned
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
function get_file_info(string $file, $returnedValues = ['name', 'server_path', 'size', 'date'])
|
||||
{
|
||||
if (! is_file($file)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$fileInfo = [];
|
||||
|
||||
if (is_string($returnedValues)) {
|
||||
$returnedValues = explode(',', $returnedValues);
|
||||
}
|
||||
|
||||
foreach ($returnedValues as $key) {
|
||||
switch ($key) {
|
||||
case 'name':
|
||||
$fileInfo['name'] = basename($file);
|
||||
break;
|
||||
|
||||
case 'server_path':
|
||||
$fileInfo['server_path'] = $file;
|
||||
break;
|
||||
|
||||
case 'size':
|
||||
$fileInfo['size'] = filesize($file);
|
||||
break;
|
||||
|
||||
case 'date':
|
||||
$fileInfo['date'] = filemtime($file);
|
||||
break;
|
||||
|
||||
case 'readable':
|
||||
$fileInfo['readable'] = is_readable($file);
|
||||
break;
|
||||
|
||||
case 'writable':
|
||||
$fileInfo['writable'] = is_really_writable($file);
|
||||
break;
|
||||
|
||||
case 'executable':
|
||||
$fileInfo['executable'] = is_executable($file);
|
||||
break;
|
||||
|
||||
case 'fileperms':
|
||||
$fileInfo['fileperms'] = fileperms($file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $fileInfo;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('symbolic_permissions')) {
|
||||
/**
|
||||
* Symbolic Permissions
|
||||
*
|
||||
* Takes a numeric value representing a file's permissions and returns
|
||||
* standard symbolic notation representing that value
|
||||
*
|
||||
* @param int $perms Permissions
|
||||
*/
|
||||
function symbolic_permissions(int $perms): string
|
||||
{
|
||||
if (($perms & 0xC000) === 0xC000) {
|
||||
$symbolic = 's'; // Socket
|
||||
} elseif (($perms & 0xA000) === 0xA000) {
|
||||
$symbolic = 'l'; // Symbolic Link
|
||||
} elseif (($perms & 0x8000) === 0x8000) {
|
||||
$symbolic = '-'; // Regular
|
||||
} elseif (($perms & 0x6000) === 0x6000) {
|
||||
$symbolic = 'b'; // Block special
|
||||
} elseif (($perms & 0x4000) === 0x4000) {
|
||||
$symbolic = 'd'; // Directory
|
||||
} elseif (($perms & 0x2000) === 0x2000) {
|
||||
$symbolic = 'c'; // Character special
|
||||
} elseif (($perms & 0x1000) === 0x1000) {
|
||||
$symbolic = 'p'; // FIFO pipe
|
||||
} else {
|
||||
$symbolic = 'u'; // Unknown
|
||||
}
|
||||
|
||||
// Owner
|
||||
$symbolic .= (($perms & 0x0100) ? 'r' : '-')
|
||||
. (($perms & 0x0080) ? 'w' : '-')
|
||||
. (($perms & 0x0040) ? (($perms & 0x0800) ? 's' : 'x') : (($perms & 0x0800) ? 'S' : '-'));
|
||||
|
||||
// Group
|
||||
$symbolic .= (($perms & 0x0020) ? 'r' : '-')
|
||||
. (($perms & 0x0010) ? 'w' : '-')
|
||||
. (($perms & 0x0008) ? (($perms & 0x0400) ? 's' : 'x') : (($perms & 0x0400) ? 'S' : '-'));
|
||||
|
||||
// World
|
||||
$symbolic .= (($perms & 0x0004) ? 'r' : '-')
|
||||
. (($perms & 0x0002) ? 'w' : '-')
|
||||
. (($perms & 0x0001) ? (($perms & 0x0200) ? 't' : 'x') : (($perms & 0x0200) ? 'T' : '-'));
|
||||
|
||||
return $symbolic;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('octal_permissions')) {
|
||||
/**
|
||||
* Octal Permissions
|
||||
*
|
||||
* Takes a numeric value representing a file's permissions and returns
|
||||
* a three character string representing the file's octal permissions
|
||||
*
|
||||
* @param int $perms Permissions
|
||||
*/
|
||||
function octal_permissions(int $perms): string
|
||||
{
|
||||
return substr(sprintf('%o', $perms), -3);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('same_file')) {
|
||||
/**
|
||||
* Checks if two files both exist and have identical hashes
|
||||
*
|
||||
* @return bool Same or not
|
||||
*/
|
||||
function same_file(string $file1, string $file2): bool
|
||||
{
|
||||
return is_file($file1) && is_file($file2) && md5_file($file1) === md5_file($file2);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('set_realpath')) {
|
||||
/**
|
||||
* Set Realpath
|
||||
*
|
||||
* @param bool $checkExistence Checks to see if the path exists
|
||||
*/
|
||||
function set_realpath(string $path, bool $checkExistence = false): string
|
||||
{
|
||||
// Security check to make sure the path is NOT a URL. No remote file inclusion!
|
||||
if (preg_match('#^(http:\/\/|https:\/\/|www\.|ftp)#i', $path) || filter_var($path, FILTER_VALIDATE_IP) === $path) {
|
||||
throw new InvalidArgumentException('The path you submitted must be a local server path, not a URL');
|
||||
}
|
||||
|
||||
// Resolve the path
|
||||
if (realpath($path) !== false) {
|
||||
$path = realpath($path);
|
||||
} elseif ($checkExistence && ! is_dir($path) && ! is_file($path)) {
|
||||
throw new InvalidArgumentException('Not a valid path: ' . $path);
|
||||
}
|
||||
|
||||
// Add a trailing slash, if this is a directory
|
||||
return is_dir($path) ? rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : $path;
|
||||
}
|
||||
}
|
||||
726
system/Helpers/form_helper.php
Normal file
726
system/Helpers/form_helper.php
Normal file
@@ -0,0 +1,726 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Config\App;
|
||||
use Config\Services;
|
||||
|
||||
// CodeIgniter Form Helpers
|
||||
|
||||
if (! function_exists('form_open')) {
|
||||
/**
|
||||
* Form Declaration
|
||||
*
|
||||
* Creates the opening portion of the form.
|
||||
*
|
||||
* @param string $action the URI segments of the form destination
|
||||
* @param array|string $attributes a key/value pair of attributes, or string representation
|
||||
* @param array $hidden a key/value pair hidden data
|
||||
*/
|
||||
function form_open(string $action = '', $attributes = [], array $hidden = []): string
|
||||
{
|
||||
// If no action is provided then set to the current url
|
||||
if (! $action) {
|
||||
$action = current_url(true);
|
||||
} // If an action is not a full URL then turn it into one
|
||||
elseif (strpos($action, '://') === false) {
|
||||
// If an action has {locale}
|
||||
if (strpos($action, '{locale}') !== false) {
|
||||
$action = str_replace('{locale}', Services::request()->getLocale(), $action);
|
||||
}
|
||||
|
||||
$action = site_url($action);
|
||||
}
|
||||
|
||||
if (is_array($attributes) && array_key_exists('csrf_id', $attributes)) {
|
||||
$csrfId = $attributes['csrf_id'];
|
||||
unset($attributes['csrf_id']);
|
||||
}
|
||||
|
||||
$attributes = stringify_attributes($attributes);
|
||||
|
||||
if (stripos($attributes, 'method=') === false) {
|
||||
$attributes .= ' method="post"';
|
||||
}
|
||||
if (stripos($attributes, 'accept-charset=') === false) {
|
||||
$config = config(App::class);
|
||||
$attributes .= ' accept-charset="' . strtolower($config->charset) . '"';
|
||||
}
|
||||
|
||||
$form = '<form action="' . $action . '"' . $attributes . ">\n";
|
||||
|
||||
// Add CSRF field if enabled, but leave it out for GET requests and requests to external websites
|
||||
$before = Services::filters()->getFilters()['before'];
|
||||
|
||||
if ((in_array('csrf', $before, true) || array_key_exists('csrf', $before)) && strpos($action, base_url()) !== false && ! stripos($form, 'method="get"')) {
|
||||
$form .= csrf_field($csrfId ?? null);
|
||||
}
|
||||
|
||||
if (is_array($hidden)) {
|
||||
foreach ($hidden as $name => $value) {
|
||||
$form .= form_hidden($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_open_multipart')) {
|
||||
/**
|
||||
* Form Declaration - Multipart type
|
||||
*
|
||||
* Creates the opening portion of the form, but with "multipart/form-data".
|
||||
*
|
||||
* @param string $action The URI segments of the form destination
|
||||
* @param array|string $attributes A key/value pair of attributes, or the same as a string
|
||||
* @param array $hidden A key/value pair hidden data
|
||||
*/
|
||||
function form_open_multipart(string $action = '', $attributes = [], array $hidden = []): string
|
||||
{
|
||||
if (is_string($attributes)) {
|
||||
$attributes .= ' enctype="' . esc('multipart/form-data') . '"';
|
||||
} else {
|
||||
$attributes['enctype'] = 'multipart/form-data';
|
||||
}
|
||||
|
||||
return form_open($action, $attributes, $hidden);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_hidden')) {
|
||||
/**
|
||||
* Hidden Input Field
|
||||
*
|
||||
* Generates hidden fields. You can pass a simple key/value string or
|
||||
* an associative array with multiple values.
|
||||
*
|
||||
* @param array|string $name Field name or associative array to create multiple fields
|
||||
* @param array|string $value Field value
|
||||
*/
|
||||
function form_hidden($name, $value = '', bool $recursing = false): string
|
||||
{
|
||||
static $form;
|
||||
|
||||
if ($recursing === false) {
|
||||
$form = "\n";
|
||||
}
|
||||
|
||||
if (is_array($name)) {
|
||||
foreach ($name as $key => $val) {
|
||||
form_hidden($key, $val, true);
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
if (! is_array($value)) {
|
||||
$form .= form_input($name, $value, '', 'hidden');
|
||||
} else {
|
||||
foreach ($value as $k => $v) {
|
||||
$k = is_int($k) ? '' : $k;
|
||||
form_hidden($name . '[' . $k . ']', $v, true);
|
||||
}
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_input')) {
|
||||
/**
|
||||
* Text Input Field. If 'type' is passed in the $type field, it will be
|
||||
* used as the input type, for making 'email', 'phone', etc input fields.
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param mixed $extra
|
||||
*/
|
||||
function form_input($data = '', string $value = '', $extra = '', string $type = 'text'): string
|
||||
{
|
||||
$defaults = [
|
||||
'type' => $type,
|
||||
'name' => is_array($data) ? '' : $data,
|
||||
'value' => $value,
|
||||
];
|
||||
|
||||
return '<input ' . parse_form_attributes($data, $defaults) . stringify_attributes($extra) . " />\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_password')) {
|
||||
/**
|
||||
* Password Field
|
||||
*
|
||||
* Identical to the input function but adds the "password" type
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param mixed $extra
|
||||
*/
|
||||
function form_password($data = '', string $value = '', $extra = ''): string
|
||||
{
|
||||
if (! is_array($data)) {
|
||||
$data = ['name' => $data];
|
||||
}
|
||||
$data['type'] = 'password';
|
||||
|
||||
return form_input($data, $value, $extra);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_upload')) {
|
||||
/**
|
||||
* Upload Field
|
||||
*
|
||||
* Identical to the input function but adds the "file" type
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param mixed $extra
|
||||
*/
|
||||
function form_upload($data = '', string $value = '', $extra = ''): string
|
||||
{
|
||||
$defaults = [
|
||||
'type' => 'file',
|
||||
'name' => '',
|
||||
];
|
||||
|
||||
if (! is_array($data)) {
|
||||
$data = ['name' => $data];
|
||||
}
|
||||
|
||||
$data['type'] = 'file';
|
||||
|
||||
return '<input ' . parse_form_attributes($data, $defaults) . stringify_attributes($extra) . " />\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_textarea')) {
|
||||
/**
|
||||
* Textarea field
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param mixed $extra
|
||||
*/
|
||||
function form_textarea($data = '', string $value = '', $extra = ''): string
|
||||
{
|
||||
$defaults = [
|
||||
'name' => is_array($data) ? '' : $data,
|
||||
'cols' => '40',
|
||||
'rows' => '10',
|
||||
];
|
||||
if (! is_array($data) || ! isset($data['value'])) {
|
||||
$val = $value;
|
||||
} else {
|
||||
$val = $data['value'];
|
||||
unset($data['value']); // textareas don't use the value attribute
|
||||
}
|
||||
|
||||
// Unsets default rows and cols if defined in extra field as array or string.
|
||||
if ((is_array($extra) && array_key_exists('rows', $extra)) || (is_string($extra) && stripos(preg_replace('/\s+/', '', $extra), 'rows=') !== false)) {
|
||||
unset($defaults['rows']);
|
||||
}
|
||||
|
||||
if ((is_array($extra) && array_key_exists('cols', $extra)) || (is_string($extra) && stripos(preg_replace('/\s+/', '', $extra), 'cols=') !== false)) {
|
||||
unset($defaults['cols']);
|
||||
}
|
||||
|
||||
return '<textarea ' . rtrim(parse_form_attributes($data, $defaults)) . stringify_attributes($extra) . '>'
|
||||
. htmlspecialchars($val)
|
||||
. "</textarea>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_multiselect')) {
|
||||
/**
|
||||
* Multi-select menu
|
||||
*
|
||||
* @param mixed $name
|
||||
* @param mixed $extra
|
||||
*/
|
||||
function form_multiselect($name = '', array $options = [], array $selected = [], $extra = ''): string
|
||||
{
|
||||
$extra = stringify_attributes($extra);
|
||||
|
||||
if (stripos($extra, 'multiple') === false) {
|
||||
$extra .= ' multiple="multiple"';
|
||||
}
|
||||
|
||||
return form_dropdown($name, $options, $selected, $extra);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_dropdown')) {
|
||||
/**
|
||||
* Drop-down Menu
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param mixed $options
|
||||
* @param mixed $selected
|
||||
* @param mixed $extra
|
||||
*/
|
||||
function form_dropdown($data = '', $options = [], $selected = [], $extra = ''): string
|
||||
{
|
||||
$defaults = [];
|
||||
if (is_array($data)) {
|
||||
if (isset($data['selected'])) {
|
||||
$selected = $data['selected'];
|
||||
unset($data['selected']); // select tags don't have a selected attribute
|
||||
}
|
||||
if (isset($data['options'])) {
|
||||
$options = $data['options'];
|
||||
unset($data['options']); // select tags don't use an options attribute
|
||||
}
|
||||
} else {
|
||||
$defaults = ['name' => $data];
|
||||
}
|
||||
|
||||
if (! is_array($selected)) {
|
||||
$selected = [$selected];
|
||||
}
|
||||
if (! is_array($options)) {
|
||||
$options = [$options];
|
||||
}
|
||||
|
||||
// If no selected state was submitted we will attempt to set it automatically
|
||||
if (empty($selected)) {
|
||||
if (is_array($data)) {
|
||||
if (isset($data['name'], $_POST[$data['name']])) {
|
||||
$selected = [$_POST[$data['name']]];
|
||||
}
|
||||
} elseif (isset($_POST[$data])) {
|
||||
$selected = [$_POST[$data]];
|
||||
}
|
||||
}
|
||||
|
||||
// Standardize selected as strings, like the option keys will be
|
||||
foreach ($selected as $key => $item) {
|
||||
$selected[$key] = (string) $item;
|
||||
}
|
||||
|
||||
$extra = stringify_attributes($extra);
|
||||
$multiple = (count($selected) > 1 && stripos($extra, 'multiple') === false) ? ' multiple="multiple"' : '';
|
||||
$form = '<select ' . rtrim(parse_form_attributes($data, $defaults)) . $extra . $multiple . ">\n";
|
||||
|
||||
foreach ($options as $key => $val) {
|
||||
// Keys should always be strings for strict comparison
|
||||
$key = (string) $key;
|
||||
|
||||
if (is_array($val)) {
|
||||
if (empty($val)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$form .= '<optgroup label="' . $key . "\">\n";
|
||||
|
||||
foreach ($val as $optgroupKey => $optgroupVal) {
|
||||
// Keys should always be strings for strict comparison
|
||||
$optgroupKey = (string) $optgroupKey;
|
||||
|
||||
$sel = in_array($optgroupKey, $selected, true) ? ' selected="selected"' : '';
|
||||
$form .= '<option value="' . htmlspecialchars($optgroupKey) . '"' . $sel . '>' . $optgroupVal . "</option>\n";
|
||||
}
|
||||
|
||||
$form .= "</optgroup>\n";
|
||||
} else {
|
||||
$form .= '<option value="' . htmlspecialchars($key) . '"'
|
||||
. (in_array($key, $selected, true) ? ' selected="selected"' : '') . '>'
|
||||
. $val . "</option>\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $form . "</select>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_checkbox')) {
|
||||
/**
|
||||
* Checkbox Field
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param mixed $extra
|
||||
*/
|
||||
function form_checkbox($data = '', string $value = '', bool $checked = false, $extra = ''): string
|
||||
{
|
||||
$defaults = [
|
||||
'type' => 'checkbox',
|
||||
'name' => (! is_array($data) ? $data : ''),
|
||||
'value' => $value,
|
||||
];
|
||||
|
||||
if (is_array($data) && array_key_exists('checked', $data)) {
|
||||
$checked = $data['checked'];
|
||||
if ($checked === false) {
|
||||
unset($data['checked']);
|
||||
} else {
|
||||
$data['checked'] = 'checked';
|
||||
}
|
||||
}
|
||||
|
||||
if ($checked === true) {
|
||||
$defaults['checked'] = 'checked';
|
||||
} elseif (isset($defaults['checked'])) {
|
||||
unset($defaults['checked']);
|
||||
}
|
||||
|
||||
return '<input ' . parse_form_attributes($data, $defaults) . stringify_attributes($extra) . " />\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_radio')) {
|
||||
/**
|
||||
* Radio Button
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param mixed $extra
|
||||
*/
|
||||
function form_radio($data = '', string $value = '', bool $checked = false, $extra = ''): string
|
||||
{
|
||||
if (! is_array($data)) {
|
||||
$data = ['name' => $data];
|
||||
}
|
||||
$data['type'] = 'radio';
|
||||
|
||||
return form_checkbox($data, $value, $checked, $extra);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_submit')) {
|
||||
/**
|
||||
* Submit Button
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param mixed $extra
|
||||
*/
|
||||
function form_submit($data = '', string $value = '', $extra = ''): string
|
||||
{
|
||||
return form_input($data, $value, $extra, 'submit');
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_reset')) {
|
||||
/**
|
||||
* Reset Button
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param mixed $extra
|
||||
*/
|
||||
function form_reset($data = '', string $value = '', $extra = ''): string
|
||||
{
|
||||
return form_input($data, $value, $extra, 'reset');
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_button')) {
|
||||
/**
|
||||
* Form Button
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param mixed $extra
|
||||
*/
|
||||
function form_button($data = '', string $content = '', $extra = ''): string
|
||||
{
|
||||
$defaults = [
|
||||
'name' => is_array($data) ? '' : $data,
|
||||
'type' => 'button',
|
||||
];
|
||||
|
||||
if (is_array($data) && isset($data['content'])) {
|
||||
$content = $data['content'];
|
||||
unset($data['content']); // content is not an attribute
|
||||
}
|
||||
|
||||
return '<button ' . parse_form_attributes($data, $defaults) . stringify_attributes($extra) . '>'
|
||||
. $content
|
||||
. "</button>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_label')) {
|
||||
/**
|
||||
* Form Label Tag
|
||||
*
|
||||
* @param string $labelText The text to appear onscreen
|
||||
* @param string $id The id the label applies to
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
function form_label(string $labelText = '', string $id = '', array $attributes = []): string
|
||||
{
|
||||
$label = '<label';
|
||||
|
||||
if ($id !== '') {
|
||||
$label .= ' for="' . $id . '"';
|
||||
}
|
||||
|
||||
if (is_array($attributes) && $attributes) {
|
||||
foreach ($attributes as $key => $val) {
|
||||
$label .= ' ' . $key . '="' . $val . '"';
|
||||
}
|
||||
}
|
||||
|
||||
return $label . '>' . $labelText . '</label>';
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_datalist')) {
|
||||
/**
|
||||
* Datalist
|
||||
*
|
||||
* The <datalist> element specifies a list of pre-defined options for an <input> element.
|
||||
* Users will see a drop-down list of pre-defined options as they input data.
|
||||
* The list attribute of the <input> element, must refer to the id attribute of the <datalist> element.
|
||||
*/
|
||||
function form_datalist(string $name, string $value, array $options): string
|
||||
{
|
||||
$data = [
|
||||
'type' => 'text',
|
||||
'name' => $name,
|
||||
'list' => $name . '_list',
|
||||
'value' => $value,
|
||||
];
|
||||
|
||||
$out = form_input($data) . "\n";
|
||||
|
||||
$out .= "<datalist id='" . $name . '_list' . "'>";
|
||||
|
||||
foreach ($options as $option) {
|
||||
$out .= "<option value='{$option}'>" . "\n";
|
||||
}
|
||||
|
||||
return $out . ('</datalist>' . "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_fieldset')) {
|
||||
/**
|
||||
* Fieldset Tag
|
||||
*
|
||||
* Used to produce <fieldset><legend>text</legend>. To close fieldset
|
||||
* use form_fieldset_close()
|
||||
*
|
||||
* @param string $legendText The legend text
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
function form_fieldset(string $legendText = '', array $attributes = []): string
|
||||
{
|
||||
$fieldset = '<fieldset' . stringify_attributes($attributes) . ">\n";
|
||||
|
||||
if ($legendText !== '') {
|
||||
return $fieldset . '<legend>' . $legendText . "</legend>\n";
|
||||
}
|
||||
|
||||
return $fieldset;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_fieldset_close')) {
|
||||
/**
|
||||
* Fieldset Close Tag
|
||||
*/
|
||||
function form_fieldset_close(string $extra = ''): string
|
||||
{
|
||||
return '</fieldset>' . $extra;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('form_close')) {
|
||||
/**
|
||||
* Form Close Tag
|
||||
*/
|
||||
function form_close(string $extra = ''): string
|
||||
{
|
||||
return '</form>' . $extra;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('set_value')) {
|
||||
/**
|
||||
* Form Value
|
||||
*
|
||||
* Grabs a value from the POST array for the specified field so you can
|
||||
* re-populate an input field or textarea
|
||||
*
|
||||
* @param string $field Field name
|
||||
* @param string|string[] $default Default value
|
||||
* @param bool $htmlEscape Whether to escape HTML special characters or not
|
||||
*
|
||||
* @return string|string[]
|
||||
*/
|
||||
function set_value(string $field, $default = '', bool $htmlEscape = true)
|
||||
{
|
||||
$request = Services::request();
|
||||
|
||||
// Try any old input data we may have first
|
||||
$value = $request->getOldInput($field);
|
||||
|
||||
if ($value === null) {
|
||||
$value = $request->getPost($field) ?? $default;
|
||||
}
|
||||
|
||||
return ($htmlEscape) ? esc($value) : $value;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('set_select')) {
|
||||
/**
|
||||
* Set Select
|
||||
*
|
||||
* Let's you set the selected value of a <select> menu via data in the POST array.
|
||||
* If Form Validation is active it retrieves the info from the validation class
|
||||
*/
|
||||
function set_select(string $field, string $value = '', bool $default = false): string
|
||||
{
|
||||
$request = Services::request();
|
||||
|
||||
// Try any old input data we may have first
|
||||
$input = $request->getOldInput($field);
|
||||
|
||||
if ($input === null) {
|
||||
$input = $request->getPost($field);
|
||||
}
|
||||
|
||||
if ($input === null) {
|
||||
return ($default === true) ? ' selected="selected"' : '';
|
||||
}
|
||||
|
||||
if (is_array($input)) {
|
||||
// Note: in_array('', array(0)) returns TRUE, do not use it
|
||||
foreach ($input as &$v) {
|
||||
if ($value === $v) {
|
||||
return ' selected="selected"';
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
return ($input === $value) ? ' selected="selected"' : '';
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('set_checkbox')) {
|
||||
/**
|
||||
* Set Checkbox
|
||||
*
|
||||
* Let's you set the selected value of a checkbox via the value in the POST array.
|
||||
* If Form Validation is active it retrieves the info from the validation class
|
||||
*/
|
||||
function set_checkbox(string $field, string $value = '', bool $default = false): string
|
||||
{
|
||||
$request = Services::request();
|
||||
|
||||
// Try any old input data we may have first
|
||||
$input = $request->getOldInput($field);
|
||||
|
||||
if ($input === null) {
|
||||
$input = $request->getPost($field);
|
||||
}
|
||||
|
||||
if (is_array($input)) {
|
||||
// Note: in_array('', array(0)) returns TRUE, do not use it
|
||||
foreach ($input as &$v) {
|
||||
if ($value === $v) {
|
||||
return ' checked="checked"';
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
// Unchecked checkbox and radio inputs are not even submitted by browsers ...
|
||||
if ((string) $input === '0' || ! empty($request->getPost()) || ! empty(old($field))) {
|
||||
return ($input === $value) ? ' checked="checked"' : '';
|
||||
}
|
||||
|
||||
return ($default === true) ? ' checked="checked"' : '';
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('set_radio')) {
|
||||
/**
|
||||
* Set Radio
|
||||
*
|
||||
* Let's you set the selected value of a radio field via info in the POST array.
|
||||
* If Form Validation is active it retrieves the info from the validation class
|
||||
*/
|
||||
function set_radio(string $field, string $value = '', bool $default = false): string
|
||||
{
|
||||
$request = Services::request();
|
||||
|
||||
// Try any old input data we may have first
|
||||
$input = $request->getOldInput($field);
|
||||
if ($input === null) {
|
||||
$input = $request->getPost($field) ?? $default;
|
||||
}
|
||||
|
||||
if (is_array($input)) {
|
||||
// Note: in_array('', array(0)) returns TRUE, do not use it
|
||||
foreach ($input as &$v) {
|
||||
if ($value === $v) {
|
||||
return ' checked="checked"';
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
// Unchecked checkbox and radio inputs are not even submitted by browsers ...
|
||||
$result = '';
|
||||
if ((string) $input === '0' || ! empty($input = $request->getPost($field)) || ! empty($input = old($field))) {
|
||||
$result = ($input === $value) ? ' checked="checked"' : '';
|
||||
}
|
||||
|
||||
if (empty($result)) {
|
||||
$result = ($default === true) ? ' checked="checked"' : '';
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('parse_form_attributes')) {
|
||||
/**
|
||||
* Parse the form attributes
|
||||
*
|
||||
* Helper function used by some of the form helpers
|
||||
*
|
||||
* @param array|string $attributes List of attributes
|
||||
* @param array $default Default values
|
||||
*/
|
||||
function parse_form_attributes($attributes, array $default): string
|
||||
{
|
||||
if (is_array($attributes)) {
|
||||
foreach (array_keys($default) as $key) {
|
||||
if (isset($attributes[$key])) {
|
||||
$default[$key] = $attributes[$key];
|
||||
unset($attributes[$key]);
|
||||
}
|
||||
}
|
||||
if (! empty($attributes)) {
|
||||
$default = array_merge($default, $attributes);
|
||||
}
|
||||
}
|
||||
|
||||
$att = '';
|
||||
|
||||
foreach ($default as $key => $val) {
|
||||
if (! is_bool($val)) {
|
||||
if ($key === 'value') {
|
||||
$val = esc($val);
|
||||
} elseif ($key === 'name' && ! strlen($default['name'])) {
|
||||
continue;
|
||||
}
|
||||
$att .= $key . '="' . $val . '"' . ($key === array_key_last($default) ? '' : ' ');
|
||||
} else {
|
||||
$att .= $key . ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return $att;
|
||||
}
|
||||
}
|
||||
542
system/Helpers/html_helper.php
Normal file
542
system/Helpers/html_helper.php
Normal file
@@ -0,0 +1,542 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use CodeIgniter\Files\Exceptions\FileNotFoundException;
|
||||
use Config\DocTypes;
|
||||
use Config\Mimes;
|
||||
|
||||
// CodeIgniter HTML Helpers
|
||||
|
||||
if (! function_exists('ul')) {
|
||||
/**
|
||||
* Unordered List
|
||||
*
|
||||
* Generates an HTML unordered list from an single or
|
||||
* multi-dimensional array.
|
||||
*
|
||||
* @param mixed $attributes HTML attributes string, array, object
|
||||
*/
|
||||
function ul(array $list, $attributes = ''): string
|
||||
{
|
||||
return _list('ul', $list, $attributes);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('ol')) {
|
||||
/**
|
||||
* Ordered List
|
||||
*
|
||||
* Generates an HTML ordered list from an single or multi-dimensional array.
|
||||
*
|
||||
* @param mixed $attributes HTML attributes string, array, object
|
||||
*/
|
||||
function ol(array $list, $attributes = ''): string
|
||||
{
|
||||
return _list('ol', $list, $attributes);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('_list')) {
|
||||
/**
|
||||
* Generates the list
|
||||
*
|
||||
* Generates an HTML ordered list from an single or multi-dimensional array.
|
||||
*
|
||||
* @param mixed $list
|
||||
* @param mixed $attributes string, array, object
|
||||
*/
|
||||
function _list(string $type = 'ul', $list = [], $attributes = '', int $depth = 0): string
|
||||
{
|
||||
// Set the indentation based on the depth
|
||||
$out = str_repeat(' ', $depth)
|
||||
// Write the opening list tag
|
||||
. '<' . $type . stringify_attributes($attributes) . ">\n";
|
||||
|
||||
// Cycle through the list elements. If an array is
|
||||
// encountered we will recursively call _list()
|
||||
|
||||
foreach ($list as $key => $val) {
|
||||
$out .= str_repeat(' ', $depth + 2) . '<li>';
|
||||
|
||||
if (! is_array($val)) {
|
||||
$out .= $val;
|
||||
} else {
|
||||
$out .= $key
|
||||
. "\n"
|
||||
. _list($type, $val, '', $depth + 4)
|
||||
. str_repeat(' ', $depth + 2);
|
||||
}
|
||||
|
||||
$out .= "</li>\n";
|
||||
}
|
||||
|
||||
// Set the indentation for the closing tag and apply it
|
||||
return $out . str_repeat(' ', $depth) . '</' . $type . ">\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('img')) {
|
||||
/**
|
||||
* Image
|
||||
*
|
||||
* Generates an image element
|
||||
*
|
||||
* @param array|string $src Image source URI, or array of attributes and values
|
||||
* @param bool $indexPage Whether to treat $src as a routed URI string
|
||||
* @param array|object|string $attributes Additional HTML attributes
|
||||
*/
|
||||
function img($src = '', bool $indexPage = false, $attributes = ''): string
|
||||
{
|
||||
if (! is_array($src)) {
|
||||
$src = ['src' => $src];
|
||||
}
|
||||
if (! isset($src['src'])) {
|
||||
$src['src'] = $attributes['src'] ?? '';
|
||||
}
|
||||
if (! isset($src['alt'])) {
|
||||
$src['alt'] = $attributes['alt'] ?? '';
|
||||
}
|
||||
|
||||
$img = '<img';
|
||||
|
||||
// Check for a relative URI
|
||||
if (! preg_match('#^([a-z]+:)?//#i', $src['src']) && strpos($src['src'], 'data:') !== 0) {
|
||||
if ($indexPage === true) {
|
||||
$img .= ' src="' . site_url($src['src']) . '"';
|
||||
} else {
|
||||
$img .= ' src="' . slash_item('baseURL') . $src['src'] . '"';
|
||||
}
|
||||
|
||||
unset($src['src']);
|
||||
}
|
||||
|
||||
// Append any other values
|
||||
foreach ($src as $key => $value) {
|
||||
$img .= ' ' . $key . '="' . $value . '"';
|
||||
}
|
||||
|
||||
// Prevent passing completed values to stringify_attributes
|
||||
if (is_array($attributes)) {
|
||||
unset($attributes['alt'], $attributes['src']);
|
||||
}
|
||||
|
||||
return $img . stringify_attributes($attributes) . ' />';
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('img_data')) {
|
||||
/**
|
||||
* Image (data)
|
||||
*
|
||||
* Generates a src-ready string from an image using the "data:" protocol
|
||||
*
|
||||
* @param string $path Image source path
|
||||
* @param string|null $mime MIME type to use, or null to guess
|
||||
*/
|
||||
function img_data(string $path, ?string $mime = null): string
|
||||
{
|
||||
if (! is_file($path) || ! is_readable($path)) {
|
||||
throw FileNotFoundException::forFileNotFound($path);
|
||||
}
|
||||
|
||||
// Read in file binary data
|
||||
$handle = fopen($path, 'rb');
|
||||
$data = fread($handle, filesize($path));
|
||||
fclose($handle);
|
||||
|
||||
// Encode as base64
|
||||
$data = base64_encode($data);
|
||||
|
||||
// Figure out the type (Hail Mary to JPEG)
|
||||
$mime = $mime ?? Mimes::guessTypeFromExtension(pathinfo($path, PATHINFO_EXTENSION)) ?? 'image/jpg';
|
||||
|
||||
return 'data:' . $mime . ';base64,' . $data;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('doctype')) {
|
||||
/**
|
||||
* Doctype
|
||||
*
|
||||
* Generates a page document type declaration
|
||||
*
|
||||
* Examples of valid options: html5, xhtml-11, xhtml-strict, xhtml-trans,
|
||||
* xhtml-frame, html4-strict, html4-trans, and html4-frame.
|
||||
* All values are saved in the doctypes config file.
|
||||
*
|
||||
* @param string $type The doctype to be generated
|
||||
*/
|
||||
function doctype(string $type = 'html5'): string
|
||||
{
|
||||
$config = new DocTypes();
|
||||
$doctypes = $config->list;
|
||||
|
||||
return $doctypes[$type] ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('script_tag')) {
|
||||
/**
|
||||
* Script
|
||||
*
|
||||
* Generates link to a JS file
|
||||
*
|
||||
* @param mixed $src Script source or an array
|
||||
* @param bool $indexPage Should indexPage be added to the JS path
|
||||
*/
|
||||
function script_tag($src = '', bool $indexPage = false): string
|
||||
{
|
||||
$script = '<script ';
|
||||
if (! is_array($src)) {
|
||||
$src = ['src' => $src];
|
||||
}
|
||||
|
||||
foreach ($src as $k => $v) {
|
||||
if ($k === 'src' && ! preg_match('#^([a-z]+:)?//#i', $v)) {
|
||||
if ($indexPage === true) {
|
||||
$script .= 'src="' . site_url($v) . '" ';
|
||||
} else {
|
||||
$script .= 'src="' . slash_item('baseURL') . $v . '" ';
|
||||
}
|
||||
} else {
|
||||
$script .= $k . '="' . $v . '" ';
|
||||
}
|
||||
}
|
||||
|
||||
return $script . 'type="text/javascript"' . '></script>';
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('link_tag')) {
|
||||
/**
|
||||
* Link
|
||||
*
|
||||
* Generates link to a CSS file
|
||||
*
|
||||
* @param mixed $href Stylesheet href or an array
|
||||
* @param bool $indexPage should indexPage be added to the CSS path.
|
||||
*/
|
||||
function link_tag($href = '', string $rel = 'stylesheet', string $type = 'text/css', string $title = '', string $media = '', bool $indexPage = false, string $hreflang = ''): string
|
||||
{
|
||||
$link = '<link ';
|
||||
|
||||
// extract fields if needed
|
||||
if (is_array($href)) {
|
||||
$rel = $href['rel'] ?? $rel;
|
||||
$type = $href['type'] ?? $type;
|
||||
$title = $href['title'] ?? $title;
|
||||
$media = $href['media'] ?? $media;
|
||||
$hreflang = $href['hreflang'] ?? '';
|
||||
$indexPage = $href['indexPage'] ?? $indexPage;
|
||||
$href = $href['href'] ?? '';
|
||||
}
|
||||
|
||||
if (! preg_match('#^([a-z]+:)?//#i', $href)) {
|
||||
if ($indexPage === true) {
|
||||
$link .= 'href="' . site_url($href) . '" ';
|
||||
} else {
|
||||
$link .= 'href="' . slash_item('baseURL') . $href . '" ';
|
||||
}
|
||||
} else {
|
||||
$link .= 'href="' . $href . '" ';
|
||||
}
|
||||
|
||||
if ($hreflang !== '') {
|
||||
$link .= 'hreflang="' . $hreflang . '" ';
|
||||
}
|
||||
|
||||
$link .= 'rel="' . $rel . '" ';
|
||||
|
||||
if (! in_array($rel, ['alternate', 'canonical'], true)) {
|
||||
$link .= 'type="' . $type . '" ';
|
||||
}
|
||||
|
||||
if ($media !== '') {
|
||||
$link .= 'media="' . $media . '" ';
|
||||
}
|
||||
|
||||
if ($title !== '') {
|
||||
$link .= 'title="' . $title . '" ';
|
||||
}
|
||||
|
||||
return $link . '/>';
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('video')) {
|
||||
/**
|
||||
* Video
|
||||
*
|
||||
* Generates a video element to embed videos. The video element can
|
||||
* contain one or more video sources
|
||||
*
|
||||
* @param mixed $src Either a source string or an array of sources
|
||||
* @param string $unsupportedMessage The message to display if the media tag is not supported by the browser
|
||||
* @param string $attributes HTML attributes
|
||||
*/
|
||||
function video($src, string $unsupportedMessage = '', string $attributes = '', array $tracks = [], bool $indexPage = false): string
|
||||
{
|
||||
if (is_array($src)) {
|
||||
return _media('video', $src, $unsupportedMessage, $attributes, $tracks);
|
||||
}
|
||||
|
||||
$video = '<video';
|
||||
|
||||
if (_has_protocol($src)) {
|
||||
$video .= ' src="' . $src . '"';
|
||||
} elseif ($indexPage === true) {
|
||||
$video .= ' src="' . site_url($src) . '"';
|
||||
} else {
|
||||
$video .= ' src="' . slash_item('baseURL') . $src . '"';
|
||||
}
|
||||
|
||||
if ($attributes !== '') {
|
||||
$video .= ' ' . $attributes;
|
||||
}
|
||||
|
||||
$video .= ">\n";
|
||||
|
||||
foreach ($tracks as $track) {
|
||||
$video .= _space_indent() . $track . "\n";
|
||||
}
|
||||
|
||||
if (! empty($unsupportedMessage)) {
|
||||
$video .= _space_indent()
|
||||
. $unsupportedMessage
|
||||
. "\n";
|
||||
}
|
||||
|
||||
return $video . "</video>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('audio')) {
|
||||
/**
|
||||
* Audio
|
||||
*
|
||||
* Generates an audio element to embed sounds
|
||||
*
|
||||
* @param mixed $src Either a source string or an array of sources
|
||||
* @param string $unsupportedMessage The message to display if the media tag is not supported by the browser.
|
||||
* @param string $attributes HTML attributes
|
||||
*/
|
||||
function audio($src, string $unsupportedMessage = '', string $attributes = '', array $tracks = [], bool $indexPage = false): string
|
||||
{
|
||||
if (is_array($src)) {
|
||||
return _media('audio', $src, $unsupportedMessage, $attributes, $tracks);
|
||||
}
|
||||
|
||||
$audio = '<audio';
|
||||
|
||||
if (_has_protocol($src)) {
|
||||
$audio .= ' src="' . $src . '"';
|
||||
} elseif ($indexPage === true) {
|
||||
$audio .= ' src="' . site_url($src) . '"';
|
||||
} else {
|
||||
$audio .= ' src="' . slash_item('baseURL') . $src . '"';
|
||||
}
|
||||
|
||||
if ($attributes !== '') {
|
||||
$audio .= ' ' . $attributes;
|
||||
}
|
||||
|
||||
$audio .= '>';
|
||||
|
||||
foreach ($tracks as $track) {
|
||||
$audio .= "\n" . _space_indent() . $track;
|
||||
}
|
||||
|
||||
if (! empty($unsupportedMessage)) {
|
||||
$audio .= "\n" . _space_indent() . $unsupportedMessage . "\n";
|
||||
}
|
||||
|
||||
return $audio . "</audio>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('_media')) {
|
||||
/**
|
||||
* Generate media based tag
|
||||
*
|
||||
* @param string $unsupportedMessage The message to display if the media tag is not supported by the browser.
|
||||
*/
|
||||
function _media(string $name, array $types = [], string $unsupportedMessage = '', string $attributes = '', array $tracks = []): string
|
||||
{
|
||||
$media = '<' . $name;
|
||||
|
||||
if (empty($attributes)) {
|
||||
$media .= '>';
|
||||
} else {
|
||||
$media .= ' ' . $attributes . '>';
|
||||
}
|
||||
|
||||
$media .= "\n";
|
||||
|
||||
foreach ($types as $option) {
|
||||
$media .= _space_indent() . $option . "\n";
|
||||
}
|
||||
|
||||
foreach ($tracks as $track) {
|
||||
$media .= _space_indent() . $track . "\n";
|
||||
}
|
||||
|
||||
if (! empty($unsupportedMessage)) {
|
||||
$media .= _space_indent() . $unsupportedMessage . "\n";
|
||||
}
|
||||
|
||||
return $media . ('</' . $name . ">\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('source')) {
|
||||
/**
|
||||
* Source
|
||||
*
|
||||
* Generates a source element that specifies multiple media resources
|
||||
* for either audio or video element
|
||||
*
|
||||
* @param string $src The path of the media resource
|
||||
* @param string $type The MIME-type of the resource with optional codecs parameters
|
||||
* @param string $attributes HTML attributes
|
||||
*/
|
||||
function source(string $src, string $type = 'unknown', string $attributes = '', bool $indexPage = false): string
|
||||
{
|
||||
if (! _has_protocol($src)) {
|
||||
$src = $indexPage === true ? site_url($src) : slash_item('baseURL') . $src;
|
||||
}
|
||||
|
||||
$source = '<source src="' . $src
|
||||
. '" type="' . $type . '"';
|
||||
|
||||
if (! empty($attributes)) {
|
||||
$source .= ' ' . $attributes;
|
||||
}
|
||||
|
||||
return $source . ' />';
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('track')) {
|
||||
/**
|
||||
* Track
|
||||
*
|
||||
* Generates a track element to specify timed tracks. The tracks are
|
||||
* formatted in WebVTT format.
|
||||
*
|
||||
* @param string $src The path of the .VTT file
|
||||
*/
|
||||
function track(string $src, string $kind, string $srcLanguage, string $label): string
|
||||
{
|
||||
return '<track src="' . $src
|
||||
. '" kind="' . $kind
|
||||
. '" srclang="' . $srcLanguage
|
||||
. '" label="' . $label
|
||||
. '" />';
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('object')) {
|
||||
/**
|
||||
* Object
|
||||
*
|
||||
* Generates an object element that represents the media
|
||||
* as either image or a resource plugin such as audio, video,
|
||||
* Java applets, ActiveX, PDF and Flash
|
||||
*
|
||||
* @param string $data A resource URL
|
||||
* @param string $type Content-type of the resource
|
||||
* @param string $attributes HTML attributes
|
||||
*/
|
||||
function object(string $data, string $type = 'unknown', string $attributes = '', array $params = [], bool $indexPage = false): string
|
||||
{
|
||||
if (! _has_protocol($data)) {
|
||||
$data = $indexPage === true ? site_url($data) : slash_item('baseURL') . $data;
|
||||
}
|
||||
|
||||
$object = '<object data="' . $data . '" '
|
||||
. $attributes . '>';
|
||||
|
||||
if (! empty($params)) {
|
||||
$object .= "\n";
|
||||
}
|
||||
|
||||
foreach ($params as $param) {
|
||||
$object .= _space_indent() . $param . "\n";
|
||||
}
|
||||
|
||||
return $object . "</object>\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('param')) {
|
||||
/**
|
||||
* Param
|
||||
*
|
||||
* Generates a param element that defines parameters
|
||||
* for the object element.
|
||||
*
|
||||
* @param string $name The name of the parameter
|
||||
* @param string $value The value of the parameter
|
||||
* @param string $type The MIME-type
|
||||
* @param string $attributes HTML attributes
|
||||
*/
|
||||
function param(string $name, string $value, string $type = 'ref', string $attributes = ''): string
|
||||
{
|
||||
return '<param name="' . $name
|
||||
. '" type="' . $type
|
||||
. '" value="' . $value
|
||||
. '" ' . $attributes . ' />';
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('embed')) {
|
||||
/**
|
||||
* Embed
|
||||
*
|
||||
* Generates an embed element
|
||||
*
|
||||
* @param string $src The path of the resource to embed
|
||||
* @param string $type MIME-type
|
||||
* @param string $attributes HTML attributes
|
||||
*/
|
||||
function embed(string $src, string $type = 'unknown', string $attributes = '', bool $indexPage = false): string
|
||||
{
|
||||
if (! _has_protocol($src)) {
|
||||
$src = $indexPage === true ? site_url($src) : slash_item('baseURL') . $src;
|
||||
}
|
||||
|
||||
return '<embed src="' . $src
|
||||
. '" type="' . $type . '" '
|
||||
. $attributes . " />\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('_has_protocol')) {
|
||||
/**
|
||||
* Test the protocol of a URI.
|
||||
*
|
||||
* @return false|int
|
||||
*/
|
||||
function _has_protocol(string $url)
|
||||
{
|
||||
return preg_match('#^([a-z]+:)?//#i', $url);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('_space_indent')) {
|
||||
/**
|
||||
* Provide space indenting.
|
||||
*/
|
||||
function _space_indent(int $depth = 2): string
|
||||
{
|
||||
return str_repeat(' ', $depth);
|
||||
}
|
||||
}
|
||||
322
system/Helpers/inflector_helper.php
Normal file
322
system/Helpers/inflector_helper.php
Normal file
@@ -0,0 +1,322 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
// CodeIgniter Inflector Helpers
|
||||
|
||||
if (! function_exists('singular')) {
|
||||
/**
|
||||
* Singular
|
||||
*
|
||||
* Takes a plural word and makes it singular
|
||||
*
|
||||
* @param string $string Input string
|
||||
*/
|
||||
function singular(string $string): string
|
||||
{
|
||||
$result = $string;
|
||||
|
||||
if (! is_pluralizable($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Arranged in order.
|
||||
$singularRules = [
|
||||
'/(matr)ices$/' => '\1ix',
|
||||
'/(vert|ind)ices$/' => '\1ex',
|
||||
'/^(ox)en/' => '\1',
|
||||
'/(alias)es$/' => '\1',
|
||||
'/([octop|vir])i$/' => '\1us',
|
||||
'/(cris|ax|test)es$/' => '\1is',
|
||||
'/(shoe)s$/' => '\1',
|
||||
'/(o)es$/' => '\1',
|
||||
'/(bus|campus)es$/' => '\1',
|
||||
'/([m|l])ice$/' => '\1ouse',
|
||||
'/(x|ch|ss|sh)es$/' => '\1',
|
||||
'/(m)ovies$/' => '\1\2ovie',
|
||||
'/(s)eries$/' => '\1\2eries',
|
||||
'/([^aeiouy]|qu)ies$/' => '\1y',
|
||||
'/([lr])ves$/' => '\1f',
|
||||
'/(tive)s$/' => '\1',
|
||||
'/(hive)s$/' => '\1',
|
||||
'/([^f])ves$/' => '\1fe',
|
||||
'/(^analy)ses$/' => '\1sis',
|
||||
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/' => '\1\2sis',
|
||||
'/([ti])a$/' => '\1um',
|
||||
'/(p)eople$/' => '\1\2erson',
|
||||
'/(m)en$/' => '\1an',
|
||||
'/(s)tatuses$/' => '\1\2tatus',
|
||||
'/(c)hildren$/' => '\1\2hild',
|
||||
'/(n)ews$/' => '\1\2ews',
|
||||
'/(quiz)zes$/' => '\1',
|
||||
'/([^us])s$/' => '\1',
|
||||
];
|
||||
|
||||
foreach ($singularRules as $rule => $replacement) {
|
||||
if (preg_match($rule, $result)) {
|
||||
$result = preg_replace($rule, $replacement, $result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('plural')) {
|
||||
/**
|
||||
* Plural
|
||||
*
|
||||
* Takes a singular word and makes it plural
|
||||
*
|
||||
* @param string $string Input string
|
||||
*/
|
||||
function plural(string $string): string
|
||||
{
|
||||
$result = $string;
|
||||
|
||||
if (! is_pluralizable($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$pluralRules = [
|
||||
'/(quiz)$/' => '\1zes', // quizzes
|
||||
'/^(ox)$/' => '\1\2en', // ox
|
||||
'/([m|l])ouse$/' => '\1ice', // mouse, louse
|
||||
'/(matr|vert|ind)ix|ex$/' => '\1ices', // matrix, vertex, index
|
||||
'/(x|ch|ss|sh)$/' => '\1es', // search, switch, fix, box, process, address
|
||||
'/([^aeiouy]|qu)y$/' => '\1ies', // query, ability, agency
|
||||
'/(hive)$/' => '\1s', // archive, hive
|
||||
'/(?:([^f])fe|([lr])f)$/' => '\1\2ves', // half, safe, wife
|
||||
'/sis$/' => 'ses', // basis, diagnosis
|
||||
'/([ti])um$/' => '\1a', // datum, medium
|
||||
'/(p)erson$/' => '\1eople', // person, salesperson
|
||||
'/(m)an$/' => '\1en', // man, woman, spokesman
|
||||
'/(c)hild$/' => '\1hildren', // child
|
||||
'/(buffal|tomat)o$/' => '\1\2oes', // buffalo, tomato
|
||||
'/(bu|campu)s$/' => '\1\2ses', // bus, campus
|
||||
'/(alias|status|virus)$/' => '\1es', // alias
|
||||
'/(octop)us$/' => '\1i', // octopus
|
||||
'/(ax|cris|test)is$/' => '\1es', // axis, crisis
|
||||
'/s$/' => 's', // no change (compatibility)
|
||||
'/$/' => 's',
|
||||
];
|
||||
|
||||
foreach ($pluralRules as $rule => $replacement) {
|
||||
if (preg_match($rule, $result)) {
|
||||
$result = preg_replace($rule, $replacement, $result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('counted')) {
|
||||
/**
|
||||
* Counted
|
||||
*
|
||||
* Takes a number and a word to return the plural or not
|
||||
* E.g. 0 cats, 1 cat, 2 cats, ...
|
||||
*
|
||||
* @param int $count Number of items
|
||||
* @param string $string Input string
|
||||
*/
|
||||
function counted(int $count, string $string): string
|
||||
{
|
||||
$result = "{$count} ";
|
||||
|
||||
return $result . ($count === 1 ? singular($string) : plural($string));
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('camelize')) {
|
||||
/**
|
||||
* Camelize
|
||||
*
|
||||
* Takes multiple words separated by spaces or
|
||||
* underscores and converts them to camel case.
|
||||
*
|
||||
* @param string $string Input string
|
||||
*/
|
||||
function camelize(string $string): string
|
||||
{
|
||||
return lcfirst(str_replace(' ', '', ucwords(preg_replace('/[\s_]+/', ' ', $string))));
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('pascalize')) {
|
||||
/**
|
||||
* Pascalize
|
||||
*
|
||||
* Takes multiple words separated by spaces or
|
||||
* underscores and converts them to Pascal case,
|
||||
* which is camel case with an uppercase first letter.
|
||||
*
|
||||
* @param string $string Input string
|
||||
*/
|
||||
function pascalize(string $string): string
|
||||
{
|
||||
return ucfirst(camelize($string));
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('underscore')) {
|
||||
/**
|
||||
* Underscore
|
||||
*
|
||||
* Takes multiple words separated by spaces and underscores them
|
||||
*
|
||||
* @param string $string Input string
|
||||
*/
|
||||
function underscore(string $string): string
|
||||
{
|
||||
$replacement = trim($string);
|
||||
|
||||
return preg_replace('/[\s]+/', '_', $replacement);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('humanize')) {
|
||||
/**
|
||||
* Humanize
|
||||
*
|
||||
* Takes multiple words separated by the separator,
|
||||
* camelizes and changes them to spaces
|
||||
*
|
||||
* @param string $string Input string
|
||||
* @param string $separator Input separator
|
||||
*/
|
||||
function humanize(string $string, string $separator = '_'): string
|
||||
{
|
||||
$replacement = trim($string);
|
||||
|
||||
return ucwords(preg_replace('/[' . $separator . ']+/', ' ', $replacement));
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('is_pluralizable')) {
|
||||
/**
|
||||
* Checks if the given word has a plural version.
|
||||
*
|
||||
* @param string $word Word to check
|
||||
*/
|
||||
function is_pluralizable(string $word): bool
|
||||
{
|
||||
$uncountables = in_array(
|
||||
strtolower($word),
|
||||
[
|
||||
'advice',
|
||||
'bravery',
|
||||
'butter',
|
||||
'chaos',
|
||||
'clarity',
|
||||
'coal',
|
||||
'courage',
|
||||
'cowardice',
|
||||
'curiosity',
|
||||
'education',
|
||||
'equipment',
|
||||
'evidence',
|
||||
'fish',
|
||||
'fun',
|
||||
'furniture',
|
||||
'greed',
|
||||
'help',
|
||||
'homework',
|
||||
'honesty',
|
||||
'information',
|
||||
'insurance',
|
||||
'jewelry',
|
||||
'knowledge',
|
||||
'livestock',
|
||||
'love',
|
||||
'luck',
|
||||
'marketing',
|
||||
'meta',
|
||||
'money',
|
||||
'mud',
|
||||
'news',
|
||||
'patriotism',
|
||||
'racism',
|
||||
'rice',
|
||||
'satisfaction',
|
||||
'scenery',
|
||||
'series',
|
||||
'sexism',
|
||||
'silence',
|
||||
'species',
|
||||
'spelling',
|
||||
'sugar',
|
||||
'water',
|
||||
'weather',
|
||||
'wisdom',
|
||||
'work',
|
||||
],
|
||||
true
|
||||
);
|
||||
|
||||
return ! $uncountables;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('dasherize')) {
|
||||
/**
|
||||
* Replaces underscores with dashes in the string.
|
||||
*
|
||||
* @param string $string Input string
|
||||
*/
|
||||
function dasherize(string $string): string
|
||||
{
|
||||
return str_replace('_', '-', $string);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('ordinal')) {
|
||||
/**
|
||||
* Returns the suffix that should be added to a
|
||||
* number to denote the position in an ordered
|
||||
* sequence such as 1st, 2nd, 3rd, 4th.
|
||||
*
|
||||
* @param int $integer The integer to determine the suffix
|
||||
*/
|
||||
function ordinal(int $integer): string
|
||||
{
|
||||
$suffixes = [
|
||||
'th',
|
||||
'st',
|
||||
'nd',
|
||||
'rd',
|
||||
'th',
|
||||
'th',
|
||||
'th',
|
||||
'th',
|
||||
'th',
|
||||
'th',
|
||||
];
|
||||
|
||||
return $integer % 100 >= 11 && $integer % 100 <= 13 ? 'th' : $suffixes[$integer % 10];
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('ordinalize')) {
|
||||
/**
|
||||
* Turns a number into an ordinal string used
|
||||
* to denote the position in an ordered sequence
|
||||
* such as 1st, 2nd, 3rd, 4th.
|
||||
*
|
||||
* @param int $integer The integer to ordinalize
|
||||
*/
|
||||
function ordinalize(int $integer): string
|
||||
{
|
||||
return $integer . ordinal($integer);
|
||||
}
|
||||
}
|
||||
213
system/Helpers/number_helper.php
Normal file
213
system/Helpers/number_helper.php
Normal file
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Config\Services;
|
||||
|
||||
// CodeIgniter Number Helpers
|
||||
|
||||
if (! function_exists('number_to_size')) {
|
||||
/**
|
||||
* Formats a numbers as bytes, based on size, and adds the appropriate suffix
|
||||
*
|
||||
* @param mixed $num Will be cast as int
|
||||
* @param string $locale
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
function number_to_size($num, int $precision = 1, ?string $locale = null)
|
||||
{
|
||||
// Strip any formatting & ensure numeric input
|
||||
try {
|
||||
$num = 0 + str_replace(',', '', $num);
|
||||
} catch (ErrorException $ee) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ignore sub part
|
||||
$generalLocale = $locale;
|
||||
if (! empty($locale) && ($underscorePos = strpos($locale, '_'))) {
|
||||
$generalLocale = substr($locale, 0, $underscorePos);
|
||||
}
|
||||
|
||||
if ($num >= 1000000000000) {
|
||||
$num = round($num / 1099511627776, $precision);
|
||||
$unit = lang('Number.terabyteAbbr', [], $generalLocale);
|
||||
} elseif ($num >= 1000000000) {
|
||||
$num = round($num / 1073741824, $precision);
|
||||
$unit = lang('Number.gigabyteAbbr', [], $generalLocale);
|
||||
} elseif ($num >= 1000000) {
|
||||
$num = round($num / 1048576, $precision);
|
||||
$unit = lang('Number.megabyteAbbr', [], $generalLocale);
|
||||
} elseif ($num >= 1000) {
|
||||
$num = round($num / 1024, $precision);
|
||||
$unit = lang('Number.kilobyteAbbr', [], $generalLocale);
|
||||
} else {
|
||||
$unit = lang('Number.bytes', [], $generalLocale);
|
||||
}
|
||||
|
||||
return format_number($num, $precision, $locale, ['after' => ' ' . $unit]);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('number_to_amount')) {
|
||||
/**
|
||||
* Converts numbers to a more readable representation
|
||||
* when dealing with very large numbers (in the thousands or above),
|
||||
* up to the quadrillions, because you won't often deal with numbers
|
||||
* larger than that.
|
||||
*
|
||||
* It uses the "short form" numbering system as this is most commonly
|
||||
* used within most English-speaking countries today.
|
||||
*
|
||||
* @see https://simple.wikipedia.org/wiki/Names_for_large_numbers
|
||||
*
|
||||
* @param string $num
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
function number_to_amount($num, int $precision = 0, ?string $locale = null)
|
||||
{
|
||||
// Strip any formatting & ensure numeric input
|
||||
try {
|
||||
$num = 0 + str_replace(',', '', $num);
|
||||
} catch (ErrorException $ee) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$suffix = '';
|
||||
|
||||
// ignore sub part
|
||||
$generalLocale = $locale;
|
||||
if (! empty($locale) && ($underscorePos = strpos($locale, '_'))) {
|
||||
$generalLocale = substr($locale, 0, $underscorePos);
|
||||
}
|
||||
|
||||
if ($num > 1000000000000000) {
|
||||
$suffix = lang('Number.quadrillion', [], $generalLocale);
|
||||
$num = round(($num / 1000000000000000), $precision);
|
||||
} elseif ($num > 1000000000000) {
|
||||
$suffix = lang('Number.trillion', [], $generalLocale);
|
||||
$num = round(($num / 1000000000000), $precision);
|
||||
} elseif ($num > 1000000000) {
|
||||
$suffix = lang('Number.billion', [], $generalLocale);
|
||||
$num = round(($num / 1000000000), $precision);
|
||||
} elseif ($num > 1000000) {
|
||||
$suffix = lang('Number.million', [], $generalLocale);
|
||||
$num = round(($num / 1000000), $precision);
|
||||
} elseif ($num > 1000) {
|
||||
$suffix = lang('Number.thousand', [], $generalLocale);
|
||||
$num = round(($num / 1000), $precision);
|
||||
}
|
||||
|
||||
return format_number($num, $precision, $locale, ['after' => $suffix]);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('number_to_currency')) {
|
||||
function number_to_currency(float $num, string $currency, ?string $locale = null, int $fraction = 0): string
|
||||
{
|
||||
return format_number($num, 1, $locale, [
|
||||
'type' => NumberFormatter::CURRENCY,
|
||||
'currency' => $currency,
|
||||
'fraction' => $fraction,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('format_number')) {
|
||||
/**
|
||||
* A general purpose, locale-aware, number_format method.
|
||||
* Used by all of the functions of the number_helper.
|
||||
*/
|
||||
function format_number(float $num, int $precision = 1, ?string $locale = null, array $options = []): string
|
||||
{
|
||||
// Locale is either passed in here, negotiated with client, or grabbed from our config file.
|
||||
$locale = $locale ?? Services::request()->getLocale();
|
||||
|
||||
// Type can be any of the NumberFormatter options, but provide a default.
|
||||
$type = (int) ($options['type'] ?? NumberFormatter::DECIMAL);
|
||||
|
||||
$formatter = new NumberFormatter($locale, $type);
|
||||
|
||||
// Try to format it per the locale
|
||||
if ($type === NumberFormatter::CURRENCY) {
|
||||
$formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $options['fraction']);
|
||||
$output = $formatter->formatCurrency($num, $options['currency']);
|
||||
} else {
|
||||
// In order to specify a precision, we'll have to modify
|
||||
// the pattern used by NumberFormatter.
|
||||
$pattern = '#,##0.' . str_repeat('#', $precision);
|
||||
|
||||
$formatter->setPattern($pattern);
|
||||
$output = $formatter->format($num);
|
||||
}
|
||||
|
||||
// This might lead a trailing period if $precision == 0
|
||||
$output = trim($output, '. ');
|
||||
|
||||
if (intl_is_failure($formatter->getErrorCode())) {
|
||||
throw new BadFunctionCallException($formatter->getErrorMessage());
|
||||
}
|
||||
|
||||
// Add on any before/after text.
|
||||
if (isset($options['before']) && is_string($options['before'])) {
|
||||
$output = $options['before'] . $output;
|
||||
}
|
||||
|
||||
if (isset($options['after']) && is_string($options['after'])) {
|
||||
$output .= $options['after'];
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('number_to_roman')) {
|
||||
/**
|
||||
* Convert a number to a roman numeral.
|
||||
*
|
||||
* @param string $num it will convert to int
|
||||
*/
|
||||
function number_to_roman(string $num): ?string
|
||||
{
|
||||
static $map = [
|
||||
'M' => 1000,
|
||||
'CM' => 900,
|
||||
'D' => 500,
|
||||
'CD' => 400,
|
||||
'C' => 100,
|
||||
'XC' => 90,
|
||||
'L' => 50,
|
||||
'XL' => 40,
|
||||
'X' => 10,
|
||||
'IX' => 9,
|
||||
'V' => 5,
|
||||
'IV' => 4,
|
||||
'I' => 1,
|
||||
];
|
||||
|
||||
$num = (int) $num;
|
||||
|
||||
if ($num < 1 || $num > 3999) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$result = '';
|
||||
|
||||
foreach ($map as $roman => $arabic) {
|
||||
$repeat = (int) floor($num / $arabic);
|
||||
$result .= str_repeat($roman, $repeat);
|
||||
$num %= $arabic;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
51
system/Helpers/security_helper.php
Normal file
51
system/Helpers/security_helper.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Config\Services;
|
||||
|
||||
// CodeIgniter Security Helpers
|
||||
|
||||
if (! function_exists('sanitize_filename')) {
|
||||
/**
|
||||
* Sanitize a filename to use in a URI.
|
||||
*/
|
||||
function sanitize_filename(string $filename): string
|
||||
{
|
||||
return Services::security()->sanitizeFilename($filename);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('strip_image_tags')) {
|
||||
/**
|
||||
* Strip Image Tags
|
||||
*/
|
||||
function strip_image_tags(string $str): string
|
||||
{
|
||||
return preg_replace(
|
||||
[
|
||||
'#<img[\s/]+.*?src\s*=\s*(["\'])([^\\1]+?)\\1.*?\>#i',
|
||||
'#<img[\s/]+.*?src\s*=\s*?(([^\s"\'=<>`]+)).*?\>#i',
|
||||
],
|
||||
'\\2',
|
||||
$str
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('encode_php_tags')) {
|
||||
/**
|
||||
* Convert PHP tags to entities
|
||||
*/
|
||||
function encode_php_tags(string $str): string
|
||||
{
|
||||
return str_replace(['<?', '?>'], ['<?', '?>'], $str);
|
||||
}
|
||||
}
|
||||
68
system/Helpers/test_helper.php
Normal file
68
system/Helpers/test_helper.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use CodeIgniter\Exceptions\TestException;
|
||||
use CodeIgniter\Model;
|
||||
use CodeIgniter\Test\Fabricator;
|
||||
use Config\Services;
|
||||
|
||||
// CodeIgniter Test Helpers
|
||||
|
||||
if (! function_exists('fake')) {
|
||||
/**
|
||||
* Creates a single item using Fabricator.
|
||||
*
|
||||
* @param Model|object|string $model Instance or name of the model
|
||||
* @param array|null $overrides Overriding data to pass to Fabricator::setOverrides()
|
||||
* @param bool $persist
|
||||
*
|
||||
* @return array|object
|
||||
*/
|
||||
function fake($model, ?array $overrides = null, $persist = true)
|
||||
{
|
||||
$fabricator = new Fabricator($model);
|
||||
|
||||
if ($overrides) {
|
||||
$fabricator->setOverrides($overrides);
|
||||
}
|
||||
|
||||
if ($persist) {
|
||||
return $fabricator->create();
|
||||
}
|
||||
|
||||
return $fabricator->make();
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('mock')) {
|
||||
/**
|
||||
* Used within our test suite to mock certain system tools.
|
||||
*
|
||||
* @param string $className Fully qualified class name
|
||||
*/
|
||||
function mock(string $className)
|
||||
{
|
||||
$mockClass = $className::$mockClass;
|
||||
$mockService = $className::$mockServiceName ?? '';
|
||||
|
||||
if (empty($mockClass) || ! class_exists($mockClass)) {
|
||||
throw TestException::forInvalidMockClass($mockClass);
|
||||
}
|
||||
|
||||
$mock = new $mockClass();
|
||||
|
||||
if (! empty($mockService)) {
|
||||
Services::injectMock($mockService, $mock);
|
||||
}
|
||||
|
||||
return $mock;
|
||||
}
|
||||
}
|
||||
674
system/Helpers/text_helper.php
Normal file
674
system/Helpers/text_helper.php
Normal file
@@ -0,0 +1,674 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Config\ForeignCharacters;
|
||||
|
||||
// CodeIgniter Text Helpers
|
||||
|
||||
if (! function_exists('word_limiter')) {
|
||||
/**
|
||||
* Word Limiter
|
||||
*
|
||||
* Limits a string to X number of words.
|
||||
*
|
||||
* @param string $endChar the end character. Usually an ellipsis
|
||||
*/
|
||||
function word_limiter(string $str, int $limit = 100, string $endChar = '…'): string
|
||||
{
|
||||
if (trim($str) === '') {
|
||||
return $str;
|
||||
}
|
||||
|
||||
preg_match('/^\s*+(?:\S++\s*+){1,' . $limit . '}/', $str, $matches);
|
||||
|
||||
if (strlen($str) === strlen($matches[0])) {
|
||||
$endChar = '';
|
||||
}
|
||||
|
||||
return rtrim($matches[0]) . $endChar;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('character_limiter')) {
|
||||
/**
|
||||
* Character Limiter
|
||||
*
|
||||
* Limits the string based on the character count. Preserves complete words
|
||||
* so the character count may not be exactly as specified.
|
||||
*
|
||||
* @param string $endChar the end character. Usually an ellipsis
|
||||
*/
|
||||
function character_limiter(string $str, int $n = 500, string $endChar = '…'): string
|
||||
{
|
||||
if (mb_strlen($str) < $n) {
|
||||
return $str;
|
||||
}
|
||||
|
||||
// a bit complicated, but faster than preg_replace with \s+
|
||||
$str = preg_replace('/ {2,}/', ' ', str_replace(["\r", "\n", "\t", "\x0B", "\x0C"], ' ', $str));
|
||||
|
||||
if (mb_strlen($str) <= $n) {
|
||||
return $str;
|
||||
}
|
||||
|
||||
$out = '';
|
||||
|
||||
foreach (explode(' ', trim($str)) as $val) {
|
||||
$out .= $val . ' ';
|
||||
if (mb_strlen($out) >= $n) {
|
||||
$out = trim($out);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (mb_strlen($out) === mb_strlen($str)) ? $out : $out . $endChar;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('ascii_to_entities')) {
|
||||
/**
|
||||
* High ASCII to Entities
|
||||
*
|
||||
* Converts high ASCII text and MS Word special characters to character entities
|
||||
*/
|
||||
function ascii_to_entities(string $str): string
|
||||
{
|
||||
$out = '';
|
||||
|
||||
for ($i = 0, $s = strlen($str) - 1, $count = 1, $temp = []; $i <= $s; $i++) {
|
||||
$ordinal = ord($str[$i]);
|
||||
|
||||
if ($ordinal < 128) {
|
||||
/*
|
||||
If the $temp array has a value but we have moved on, then it seems only
|
||||
fair that we output that entity and restart $temp before continuing.
|
||||
*/
|
||||
if (count($temp) === 1) {
|
||||
$out .= '&#' . array_shift($temp) . ';';
|
||||
$count = 1;
|
||||
}
|
||||
|
||||
$out .= $str[$i];
|
||||
} else {
|
||||
if (empty($temp)) {
|
||||
$count = ($ordinal < 224) ? 2 : 3;
|
||||
}
|
||||
|
||||
$temp[] = $ordinal;
|
||||
|
||||
if (count($temp) === $count) {
|
||||
$number = ($count === 3) ? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64) : (($temp[0] % 32) * 64) + ($temp[1] % 64);
|
||||
$out .= '&#' . $number . ';';
|
||||
$count = 1;
|
||||
$temp = [];
|
||||
}
|
||||
// If this is the last iteration, just output whatever we have
|
||||
elseif ($i === $s) {
|
||||
$out .= '&#' . implode(';', $temp) . ';';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('entities_to_ascii')) {
|
||||
/**
|
||||
* Entities to ASCII
|
||||
*
|
||||
* Converts character entities back to ASCII
|
||||
*/
|
||||
function entities_to_ascii(string $str, bool $all = true): string
|
||||
{
|
||||
if (preg_match_all('/\&#(\d+)\;/', $str, $matches)) {
|
||||
for ($i = 0, $s = count($matches[0]); $i < $s; $i++) {
|
||||
$digits = $matches[1][$i];
|
||||
$out = '';
|
||||
if ($digits < 128) {
|
||||
$out .= chr($digits);
|
||||
} elseif ($digits < 2048) {
|
||||
$out .= chr(192 + (($digits - ($digits % 64)) / 64)) . chr(128 + ($digits % 64));
|
||||
} else {
|
||||
$out .= chr(224 + (($digits - ($digits % 4096)) / 4096))
|
||||
. chr(128 + ((($digits % 4096) - ($digits % 64)) / 64))
|
||||
. chr(128 + ($digits % 64));
|
||||
}
|
||||
$str = str_replace($matches[0][$i], $out, $str);
|
||||
}
|
||||
}
|
||||
|
||||
if ($all) {
|
||||
return str_replace(
|
||||
['&', '<', '>', '"', ''', '-'],
|
||||
['&', '<', '>', '"', "'", '-'],
|
||||
$str
|
||||
);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('word_censor')) {
|
||||
/**
|
||||
* Word Censoring Function
|
||||
*
|
||||
* Supply a string and an array of disallowed words and any
|
||||
* matched words will be converted to #### or to the replacement
|
||||
* word you've submitted.
|
||||
*
|
||||
* @param string $str the text string
|
||||
* @param array $censored the array of censored words
|
||||
* @param string $replacement the optional replacement value
|
||||
*/
|
||||
function word_censor(string $str, array $censored, string $replacement = ''): string
|
||||
{
|
||||
if (empty($censored)) {
|
||||
return $str;
|
||||
}
|
||||
|
||||
$str = ' ' . $str . ' ';
|
||||
|
||||
// \w, \b and a few others do not match on a unicode character
|
||||
// set for performance reasons. As a result words like über
|
||||
// will not match on a word boundary. Instead, we'll assume that
|
||||
// a bad word will be bookended by any of these characters.
|
||||
$delim = '[-_\'\"`(){}<>\[\]|!?@#%&,.:;^~*+=\/ 0-9\n\r\t]';
|
||||
|
||||
foreach ($censored as $badword) {
|
||||
$badword = str_replace('\*', '\w*?', preg_quote($badword, '/'));
|
||||
|
||||
if ($replacement !== '') {
|
||||
$str = preg_replace(
|
||||
"/({$delim})(" . $badword . ")({$delim})/i",
|
||||
"\\1{$replacement}\\3",
|
||||
$str
|
||||
);
|
||||
} elseif (preg_match_all("/{$delim}(" . $badword . "){$delim}/i", $str, $matches, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE)) {
|
||||
$matches = $matches[1];
|
||||
|
||||
for ($i = count($matches) - 1; $i >= 0; $i--) {
|
||||
$length = strlen($matches[$i][0]);
|
||||
|
||||
$str = substr_replace(
|
||||
$str,
|
||||
str_repeat('#', $length),
|
||||
$matches[$i][1],
|
||||
$length
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return trim($str);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('highlight_code')) {
|
||||
/**
|
||||
* Code Highlighter
|
||||
*
|
||||
* Colorizes code strings
|
||||
*
|
||||
* @param string $str the text string
|
||||
*/
|
||||
function highlight_code(string $str): string
|
||||
{
|
||||
/* The highlight string function encodes and highlights
|
||||
* brackets so we need them to start raw.
|
||||
*
|
||||
* Also replace any existing PHP tags to temporary markers
|
||||
* so they don't accidentally break the string out of PHP,
|
||||
* and thus, thwart the highlighting.
|
||||
*/
|
||||
$str = str_replace(
|
||||
['<', '>', '<?', '?>', '<%', '%>', '\\', '</script>'],
|
||||
['<', '>', 'phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'],
|
||||
$str
|
||||
);
|
||||
|
||||
// The highlight_string function requires that the text be surrounded
|
||||
// by PHP tags, which we will remove later
|
||||
$str = highlight_string('<?php ' . $str . ' ?>', true);
|
||||
|
||||
// Remove our artificially added PHP, and the syntax highlighting that came with it
|
||||
$str = preg_replace(
|
||||
[
|
||||
'/<span style="color: #([A-Z0-9]+)"><\?php( | )/i',
|
||||
'/(<span style="color: #[A-Z0-9]+">.*?)\?><\/span>\n<\/span>\n<\/code>/is',
|
||||
'/<span style="color: #[A-Z0-9]+"\><\/span>/i',
|
||||
],
|
||||
[
|
||||
'<span style="color: #$1">',
|
||||
"$1</span>\n</span>\n</code>",
|
||||
'',
|
||||
],
|
||||
$str
|
||||
);
|
||||
|
||||
// Replace our markers back to PHP tags.
|
||||
return str_replace(
|
||||
[
|
||||
'phptagopen',
|
||||
'phptagclose',
|
||||
'asptagopen',
|
||||
'asptagclose',
|
||||
'backslashtmp',
|
||||
'scriptclose',
|
||||
],
|
||||
[
|
||||
'<?',
|
||||
'?>',
|
||||
'<%',
|
||||
'%>',
|
||||
'\\',
|
||||
'</script>',
|
||||
],
|
||||
$str
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('highlight_phrase')) {
|
||||
/**
|
||||
* Phrase Highlighter
|
||||
*
|
||||
* Highlights a phrase within a text string
|
||||
*
|
||||
* @param string $str the text string
|
||||
* @param string $phrase the phrase you'd like to highlight
|
||||
* @param string $tagOpen the opening tag to precede the phrase with
|
||||
* @param string $tagClose the closing tag to end the phrase with
|
||||
*/
|
||||
function highlight_phrase(string $str, string $phrase, string $tagOpen = '<mark>', string $tagClose = '</mark>'): string
|
||||
{
|
||||
return ($str !== '' && $phrase !== '') ? preg_replace('/(' . preg_quote($phrase, '/') . ')/i', $tagOpen . '\\1' . $tagClose, $str) : $str;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('convert_accented_characters')) {
|
||||
/**
|
||||
* Convert Accented Foreign Characters to ASCII
|
||||
*
|
||||
* @param string $str Input string
|
||||
*/
|
||||
function convert_accented_characters(string $str): string
|
||||
{
|
||||
static $arrayFrom, $arrayTo;
|
||||
|
||||
if (! is_array($arrayFrom)) {
|
||||
$config = new ForeignCharacters();
|
||||
|
||||
if (empty($config->characterList) || ! is_array($config->characterList)) {
|
||||
$arrayFrom = [];
|
||||
$arrayTo = [];
|
||||
|
||||
return $str;
|
||||
}
|
||||
$arrayFrom = array_keys($config->characterList);
|
||||
$arrayTo = array_values($config->characterList);
|
||||
|
||||
unset($config);
|
||||
}
|
||||
|
||||
return preg_replace($arrayFrom, $arrayTo, $str);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('word_wrap')) {
|
||||
/**
|
||||
* Word Wrap
|
||||
*
|
||||
* Wraps text at the specified character. Maintains the integrity of words.
|
||||
* Anything placed between {unwrap}{/unwrap} will not be word wrapped, nor
|
||||
* will URLs.
|
||||
*
|
||||
* @param string $str the text string
|
||||
* @param int $charlim = 76 the number of characters to wrap at
|
||||
*/
|
||||
function word_wrap(string $str, int $charlim = 76): string
|
||||
{
|
||||
// Reduce multiple spaces
|
||||
$str = preg_replace('| +|', ' ', $str);
|
||||
|
||||
// Standardize newlines
|
||||
if (strpos($str, "\r") !== false) {
|
||||
$str = str_replace(["\r\n", "\r"], "\n", $str);
|
||||
}
|
||||
|
||||
// If the current word is surrounded by {unwrap} tags we'll
|
||||
// strip the entire chunk and replace it with a marker.
|
||||
$unwrap = [];
|
||||
|
||||
if (preg_match_all('|\{unwrap\}(.+?)\{/unwrap\}|s', $str, $matches)) {
|
||||
for ($i = 0, $c = count($matches[0]); $i < $c; $i++) {
|
||||
$unwrap[] = $matches[1][$i];
|
||||
$str = str_replace($matches[0][$i], '{{unwrapped' . $i . '}}', $str);
|
||||
}
|
||||
}
|
||||
|
||||
// Use PHP's native function to do the initial wordwrap.
|
||||
// We set the cut flag to FALSE so that any individual words that are
|
||||
// too long get left alone. In the next step we'll deal with them.
|
||||
$str = wordwrap($str, $charlim, "\n", false);
|
||||
|
||||
// Split the string into individual lines of text and cycle through them
|
||||
$output = '';
|
||||
|
||||
foreach (explode("\n", $str) as $line) {
|
||||
// Is the line within the allowed character count?
|
||||
// If so we'll join it to the output and continue
|
||||
if (mb_strlen($line) <= $charlim) {
|
||||
$output .= $line . "\n";
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$temp = '';
|
||||
|
||||
while (mb_strlen($line) > $charlim) {
|
||||
// If the over-length word is a URL we won't wrap it
|
||||
if (preg_match('!\[url.+\]|://|www\.!', $line)) {
|
||||
break;
|
||||
}
|
||||
// Trim the word down
|
||||
$temp .= mb_substr($line, 0, $charlim - 1);
|
||||
$line = mb_substr($line, $charlim - 1);
|
||||
}
|
||||
|
||||
// If $temp contains data it means we had to split up an over-length
|
||||
// word into smaller chunks so we'll add it back to our current line
|
||||
if ($temp !== '') {
|
||||
$output .= $temp . "\n" . $line . "\n";
|
||||
} else {
|
||||
$output .= $line . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Put our markers back
|
||||
foreach ($unwrap as $key => $val) {
|
||||
$output = str_replace('{{unwrapped' . $key . '}}', $val, $output);
|
||||
}
|
||||
|
||||
// remove any trailing newline
|
||||
return rtrim($output);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('ellipsize')) {
|
||||
/**
|
||||
* Ellipsize String
|
||||
*
|
||||
* This function will strip tags from a string, split it at its max_length and ellipsize
|
||||
*
|
||||
* @param string $str String to ellipsize
|
||||
* @param int $maxLength Max length of string
|
||||
* @param mixed $position int (1|0) or float, .5, .2, etc for position to split
|
||||
* @param string $ellipsis ellipsis ; Default '...'
|
||||
*
|
||||
* @return string Ellipsized string
|
||||
*/
|
||||
function ellipsize(string $str, int $maxLength, $position = 1, string $ellipsis = '…'): string
|
||||
{
|
||||
// Strip tags
|
||||
$str = trim(strip_tags($str));
|
||||
|
||||
// Is the string long enough to ellipsize?
|
||||
if (mb_strlen($str) <= $maxLength) {
|
||||
return $str;
|
||||
}
|
||||
|
||||
$beg = mb_substr($str, 0, (int) floor($maxLength * $position));
|
||||
$position = ($position > 1) ? 1 : $position;
|
||||
|
||||
if ($position === 1) {
|
||||
$end = mb_substr($str, 0, -($maxLength - mb_strlen($beg)));
|
||||
} else {
|
||||
$end = mb_substr($str, -($maxLength - mb_strlen($beg)));
|
||||
}
|
||||
|
||||
return $beg . $ellipsis . $end;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('strip_slashes')) {
|
||||
/**
|
||||
* Strip Slashes
|
||||
*
|
||||
* Removes slashes contained in a string or in an array
|
||||
*
|
||||
* @param mixed $str string or array
|
||||
*
|
||||
* @return mixed string or array
|
||||
*/
|
||||
function strip_slashes($str)
|
||||
{
|
||||
if (! is_array($str)) {
|
||||
return stripslashes($str);
|
||||
}
|
||||
|
||||
foreach ($str as $key => $val) {
|
||||
$str[$key] = strip_slashes($val);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('strip_quotes')) {
|
||||
/**
|
||||
* Strip Quotes
|
||||
*
|
||||
* Removes single and double quotes from a string
|
||||
*/
|
||||
function strip_quotes(string $str): string
|
||||
{
|
||||
return str_replace(['"', "'"], '', $str);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('quotes_to_entities')) {
|
||||
/**
|
||||
* Quotes to Entities
|
||||
*
|
||||
* Converts single and double quotes to entities
|
||||
*/
|
||||
function quotes_to_entities(string $str): string
|
||||
{
|
||||
return str_replace(["\\'", '"', "'", '"'], [''', '"', ''', '"'], $str);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('reduce_double_slashes')) {
|
||||
/**
|
||||
* Reduce Double Slashes
|
||||
*
|
||||
* Converts double slashes in a string to a single slash,
|
||||
* except those found in http://
|
||||
*
|
||||
* http://www.some-site.com//index.php
|
||||
*
|
||||
* becomes:
|
||||
*
|
||||
* http://www.some-site.com/index.php
|
||||
*/
|
||||
function reduce_double_slashes(string $str): string
|
||||
{
|
||||
return preg_replace('#(^|[^:])//+#', '\\1/', $str);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('reduce_multiples')) {
|
||||
/**
|
||||
* Reduce Multiples
|
||||
*
|
||||
* Reduces multiple instances of a particular character. Example:
|
||||
*
|
||||
* Fred, Bill,, Joe, Jimmy
|
||||
*
|
||||
* becomes:
|
||||
*
|
||||
* Fred, Bill, Joe, Jimmy
|
||||
*
|
||||
* @param string $character the character you wish to reduce
|
||||
* @param bool $trim TRUE/FALSE - whether to trim the character from the beginning/end
|
||||
*/
|
||||
function reduce_multiples(string $str, string $character = ',', bool $trim = false): string
|
||||
{
|
||||
$str = preg_replace('#' . preg_quote($character, '#') . '{2,}#', $character, $str);
|
||||
|
||||
return ($trim) ? trim($str, $character) : $str;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('random_string')) {
|
||||
/**
|
||||
* Create a Random String
|
||||
*
|
||||
* Useful for generating passwords or hashes.
|
||||
*
|
||||
* @param string $type Type of random string. basic, alpha, alnum, numeric, nozero, md5, sha1, and crypto
|
||||
* @param int $len Number of characters
|
||||
*/
|
||||
function random_string(string $type = 'alnum', int $len = 8): string
|
||||
{
|
||||
switch ($type) {
|
||||
case 'alnum':
|
||||
case 'numeric':
|
||||
case 'nozero':
|
||||
case 'alpha':
|
||||
switch ($type) {
|
||||
case 'alpha':
|
||||
$pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
break;
|
||||
|
||||
case 'alnum':
|
||||
$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
break;
|
||||
|
||||
case 'numeric':
|
||||
$pool = '0123456789';
|
||||
break;
|
||||
|
||||
case 'nozero':
|
||||
$pool = '123456789';
|
||||
break;
|
||||
}
|
||||
|
||||
return substr(str_shuffle(str_repeat($pool, ceil($len / strlen($pool)))), 0, $len);
|
||||
|
||||
case 'md5':
|
||||
return md5(uniqid((string) mt_rand(), true));
|
||||
|
||||
case 'sha1':
|
||||
return sha1(uniqid((string) mt_rand(), true));
|
||||
|
||||
case 'crypto':
|
||||
return bin2hex(random_bytes($len / 2));
|
||||
}
|
||||
// 'basic' type treated as default
|
||||
return (string) mt_rand();
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('increment_string')) {
|
||||
/**
|
||||
* Add's _1 to a string or increment the ending number to allow _2, _3, etc
|
||||
*
|
||||
* @param string $str Required
|
||||
* @param string $separator What should the duplicate number be appended with
|
||||
* @param int $first Which number should be used for the first dupe increment
|
||||
*/
|
||||
function increment_string(string $str, string $separator = '_', int $first = 1): string
|
||||
{
|
||||
preg_match('/(.+)' . preg_quote($separator, '/') . '([0-9]+)$/', $str, $match);
|
||||
|
||||
return isset($match[2]) ? $match[1] . $separator . ($match[2] + 1) : $str . $separator . $first;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('alternator')) {
|
||||
/**
|
||||
* Alternator
|
||||
*
|
||||
* Allows strings to be alternated. See docs...
|
||||
*
|
||||
* @param string ...$args (as many parameters as needed)
|
||||
*/
|
||||
function alternator(...$args): string
|
||||
{
|
||||
static $i;
|
||||
|
||||
if (func_num_args() === 0) {
|
||||
$i = 0;
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
return $args[($i++ % count($args))];
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('excerpt')) {
|
||||
/**
|
||||
* Excerpt.
|
||||
*
|
||||
* Allows to extract a piece of text surrounding a word or phrase.
|
||||
*
|
||||
* @param string $text String to search the phrase
|
||||
* @param string $phrase Phrase that will be searched for.
|
||||
* @param int $radius The amount of characters returned around the phrase.
|
||||
* @param string $ellipsis Ending that will be appended
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* If no $phrase is passed, will generate an excerpt of $radius characters
|
||||
* from the beginning of $text.
|
||||
*/
|
||||
function excerpt(string $text, ?string $phrase = null, int $radius = 100, string $ellipsis = '...'): string
|
||||
{
|
||||
if (isset($phrase)) {
|
||||
$phrasePos = stripos($text, $phrase);
|
||||
$phraseLen = strlen($phrase);
|
||||
} else {
|
||||
$phrasePos = $radius / 2;
|
||||
$phraseLen = 1;
|
||||
}
|
||||
|
||||
$pre = explode(' ', substr($text, 0, $phrasePos));
|
||||
$pos = explode(' ', substr($text, $phrasePos + $phraseLen));
|
||||
|
||||
$prev = ' ';
|
||||
$post = ' ';
|
||||
$count = 0;
|
||||
|
||||
foreach (array_reverse($pre) as $e) {
|
||||
if ((strlen($e) + $count + 1) < $radius) {
|
||||
$prev = ' ' . $e . $prev;
|
||||
}
|
||||
$count = ++$count + strlen($e);
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
|
||||
foreach ($pos as $s) {
|
||||
if ((strlen($s) + $count + 1) < $radius) {
|
||||
$post .= $s . ' ';
|
||||
}
|
||||
$count = ++$count + strlen($s);
|
||||
}
|
||||
|
||||
$ellPre = $phrase ? $ellipsis : '';
|
||||
|
||||
return str_replace(' ', ' ', $ellPre . $prev . $phrase . $post . $ellipsis);
|
||||
}
|
||||
}
|
||||
562
system/Helpers/url_helper.php
Normal file
562
system/Helpers/url_helper.php
Normal file
@@ -0,0 +1,562 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use CodeIgniter\HTTP\IncomingRequest;
|
||||
use CodeIgniter\HTTP\URI;
|
||||
use CodeIgniter\Router\Exceptions\RouterException;
|
||||
use Config\App;
|
||||
use Config\Services;
|
||||
|
||||
// CodeIgniter URL Helpers
|
||||
|
||||
if (! function_exists('_get_uri')) {
|
||||
/**
|
||||
* Used by the other URL functions to build a
|
||||
* framework-specific URI based on the App config.
|
||||
*
|
||||
* @internal Outside of the framework this should not be used directly.
|
||||
*
|
||||
* @param string $relativePath May include queries or fragments
|
||||
*
|
||||
* @throws InvalidArgumentException For invalid paths or config
|
||||
*/
|
||||
function _get_uri(string $relativePath = '', ?App $config = null): URI
|
||||
{
|
||||
$config = $config ?? config('App');
|
||||
|
||||
if ($config->baseURL === '') {
|
||||
throw new InvalidArgumentException('_get_uri() requires a valid baseURL.');
|
||||
}
|
||||
|
||||
// If a full URI was passed then convert it
|
||||
if (is_int(strpos($relativePath, '://'))) {
|
||||
$full = new URI($relativePath);
|
||||
$relativePath = URI::createURIString(null, null, $full->getPath(), $full->getQuery(), $full->getFragment());
|
||||
}
|
||||
|
||||
$relativePath = URI::removeDotSegments($relativePath);
|
||||
|
||||
// Build the full URL based on $config and $relativePath
|
||||
$url = rtrim($config->baseURL, '/ ') . '/';
|
||||
|
||||
// Check for an index page
|
||||
if ($config->indexPage !== '') {
|
||||
$url .= $config->indexPage;
|
||||
|
||||
// Check if we need a separator
|
||||
if ($relativePath !== '' && $relativePath[0] !== '/' && $relativePath[0] !== '?') {
|
||||
$url .= '/';
|
||||
}
|
||||
}
|
||||
|
||||
$url .= $relativePath;
|
||||
|
||||
$uri = new URI($url);
|
||||
|
||||
// Check if the baseURL scheme needs to be coerced into its secure version
|
||||
if ($config->forceGlobalSecureRequests && $uri->getScheme() === 'http') {
|
||||
$uri->setScheme('https');
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('site_url')) {
|
||||
/**
|
||||
* Returns a site URL as defined by the App config.
|
||||
*
|
||||
* @param mixed $relativePath URI string or array of URI segments
|
||||
* @param App|null $config Alternate configuration to use
|
||||
*/
|
||||
function site_url($relativePath = '', ?string $scheme = null, ?App $config = null): string
|
||||
{
|
||||
// Convert array of segments to a string
|
||||
if (is_array($relativePath)) {
|
||||
$relativePath = implode('/', $relativePath);
|
||||
}
|
||||
|
||||
$uri = _get_uri($relativePath, $config);
|
||||
|
||||
return URI::createURIString($scheme ?? $uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery(), $uri->getFragment());
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('base_url')) {
|
||||
/**
|
||||
* Returns the base URL as defined by the App config.
|
||||
* Base URLs are trimmed site URLs without the index page.
|
||||
*
|
||||
* @param mixed $relativePath URI string or array of URI segments
|
||||
* @param string $scheme
|
||||
*/
|
||||
function base_url($relativePath = '', ?string $scheme = null): string
|
||||
{
|
||||
$config = clone config('App');
|
||||
$config->indexPage = '';
|
||||
|
||||
return rtrim(site_url($relativePath, $scheme, $config), '/');
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('current_url')) {
|
||||
/**
|
||||
* Returns the current full URL based on the IncomingRequest.
|
||||
* String returns ignore query and fragment parts.
|
||||
*
|
||||
* @param bool $returnObject True to return an object instead of a string
|
||||
* @param IncomingRequest|null $request A request to use when retrieving the path
|
||||
*
|
||||
* @return string|URI
|
||||
*/
|
||||
function current_url(bool $returnObject = false, ?IncomingRequest $request = null)
|
||||
{
|
||||
$request = $request ?? Services::request();
|
||||
$path = $request->getPath();
|
||||
|
||||
// Append queries and fragments
|
||||
if ($query = $request->getUri()->getQuery()) {
|
||||
$path .= '?' . $query;
|
||||
}
|
||||
if ($fragment = $request->getUri()->getFragment()) {
|
||||
$path .= '#' . $fragment;
|
||||
}
|
||||
|
||||
$uri = _get_uri($path);
|
||||
|
||||
return $returnObject ? $uri : URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath());
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('previous_url')) {
|
||||
/**
|
||||
* Returns the previous URL the current visitor was on. For security reasons
|
||||
* we first check in a saved session variable, if it exists, and use that.
|
||||
* If that's not available, however, we'll use a sanitized url from $_SERVER['HTTP_REFERER']
|
||||
* which can be set by the user so is untrusted and not set by certain browsers/servers.
|
||||
*
|
||||
* @return mixed|string|URI
|
||||
*/
|
||||
function previous_url(bool $returnObject = false)
|
||||
{
|
||||
// Grab from the session first, if we have it,
|
||||
// since it's more reliable and safer.
|
||||
// Otherwise, grab a sanitized version from $_SERVER.
|
||||
$referer = $_SESSION['_ci_previous_url'] ?? Services::request()->getServer('HTTP_REFERER', FILTER_SANITIZE_URL);
|
||||
|
||||
$referer = $referer ?? site_url('/');
|
||||
|
||||
return $returnObject ? new URI($referer) : $referer;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('uri_string')) {
|
||||
/**
|
||||
* URL String
|
||||
*
|
||||
* Returns the path part of the current URL
|
||||
*
|
||||
* @param bool $relative Whether the resulting path should be relative to baseURL
|
||||
*/
|
||||
function uri_string(bool $relative = false): string
|
||||
{
|
||||
return $relative
|
||||
? ltrim(Services::request()->getPath(), '/')
|
||||
: Services::request()->getUri()->getPath();
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('index_page')) {
|
||||
/**
|
||||
* Index page
|
||||
*
|
||||
* Returns the "index_page" from your config file
|
||||
*
|
||||
* @param App|null $altConfig Alternate configuration to use
|
||||
*/
|
||||
function index_page(?App $altConfig = null): string
|
||||
{
|
||||
// use alternate config if provided, else default one
|
||||
$config = $altConfig ?? config(App::class);
|
||||
|
||||
return $config->indexPage;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('anchor')) {
|
||||
/**
|
||||
* Anchor Link
|
||||
*
|
||||
* Creates an anchor based on the local URL.
|
||||
*
|
||||
* @param mixed $uri URI string or array of URI segments
|
||||
* @param string $title The link title
|
||||
* @param mixed $attributes Any attributes
|
||||
* @param App|null $altConfig Alternate configuration to use
|
||||
*/
|
||||
function anchor($uri = '', string $title = '', $attributes = '', ?App $altConfig = null): string
|
||||
{
|
||||
// use alternate config if provided, else default one
|
||||
$config = $altConfig ?? config(App::class);
|
||||
|
||||
$siteUrl = is_array($uri) ? site_url($uri, null, $config) : (preg_match('#^(\w+:)?//#i', $uri) ? $uri : site_url($uri, null, $config));
|
||||
// eliminate trailing slash
|
||||
$siteUrl = rtrim($siteUrl, '/');
|
||||
|
||||
if ($title === '') {
|
||||
$title = $siteUrl;
|
||||
}
|
||||
|
||||
if ($attributes !== '') {
|
||||
$attributes = stringify_attributes($attributes);
|
||||
}
|
||||
|
||||
return '<a href="' . $siteUrl . '"' . $attributes . '>' . $title . '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('anchor_popup')) {
|
||||
/**
|
||||
* Anchor Link - Pop-up version
|
||||
*
|
||||
* Creates an anchor based on the local URL. The link
|
||||
* opens a new window based on the attributes specified.
|
||||
*
|
||||
* @param string $uri the URL
|
||||
* @param string $title the link title
|
||||
* @param mixed $attributes any attributes
|
||||
* @param App|null $altConfig Alternate configuration to use
|
||||
*/
|
||||
function anchor_popup($uri = '', string $title = '', $attributes = false, ?App $altConfig = null): string
|
||||
{
|
||||
// use alternate config if provided, else default one
|
||||
$config = $altConfig ?? config(App::class);
|
||||
|
||||
$siteUrl = preg_match('#^(\w+:)?//#i', $uri) ? $uri : site_url($uri, null, $config);
|
||||
$siteUrl = rtrim($siteUrl, '/');
|
||||
|
||||
if ($title === '') {
|
||||
$title = $siteUrl;
|
||||
}
|
||||
|
||||
if ($attributes === false) {
|
||||
return '<a href="' . $siteUrl . '" onclick="window.open(\'' . $siteUrl . "', '_blank'); return false;\">" . $title . '</a>';
|
||||
}
|
||||
|
||||
if (! is_array($attributes)) {
|
||||
$attributes = [$attributes];
|
||||
|
||||
// Ref: http://www.w3schools.com/jsref/met_win_open.asp
|
||||
$windowName = '_blank';
|
||||
} elseif (! empty($attributes['window_name'])) {
|
||||
$windowName = $attributes['window_name'];
|
||||
unset($attributes['window_name']);
|
||||
} else {
|
||||
$windowName = '_blank';
|
||||
}
|
||||
|
||||
foreach (['width' => '800', 'height' => '600', 'scrollbars' => 'yes', 'menubar' => 'no', 'status' => 'yes', 'resizable' => 'yes', 'screenx' => '0', 'screeny' => '0'] as $key => $val) {
|
||||
$atts[$key] = $attributes[$key] ?? $val;
|
||||
unset($attributes[$key]);
|
||||
}
|
||||
|
||||
$attributes = stringify_attributes($attributes);
|
||||
|
||||
return '<a href="' . $siteUrl
|
||||
. '" onclick="window.open(\'' . $siteUrl . "', '" . $windowName . "', '" . stringify_attributes($atts, true) . "'); return false;\""
|
||||
. $attributes . '>' . $title . '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('mailto')) {
|
||||
/**
|
||||
* Mailto Link
|
||||
*
|
||||
* @param string $email the email address
|
||||
* @param string $title the link title
|
||||
* @param mixed $attributes any attributes
|
||||
*/
|
||||
function mailto(string $email, string $title = '', $attributes = ''): string
|
||||
{
|
||||
if (trim($title) === '') {
|
||||
$title = $email;
|
||||
}
|
||||
|
||||
return '<a href="mailto:' . $email . '"' . stringify_attributes($attributes) . '>' . $title . '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('safe_mailto')) {
|
||||
/**
|
||||
* Encoded Mailto Link
|
||||
*
|
||||
* Create a spam-protected mailto link written in Javascript
|
||||
*
|
||||
* @param string $email the email address
|
||||
* @param string $title the link title
|
||||
* @param mixed $attributes any attributes
|
||||
*/
|
||||
function safe_mailto(string $email, string $title = '', $attributes = ''): string
|
||||
{
|
||||
if (trim($title) === '') {
|
||||
$title = $email;
|
||||
}
|
||||
|
||||
$x = str_split('<a href="mailto:', 1);
|
||||
|
||||
for ($i = 0, $l = strlen($email); $i < $l; $i++) {
|
||||
$x[] = '|' . ord($email[$i]);
|
||||
}
|
||||
|
||||
$x[] = '"';
|
||||
|
||||
if ($attributes !== '') {
|
||||
if (is_array($attributes)) {
|
||||
foreach ($attributes as $key => $val) {
|
||||
$x[] = ' ' . $key . '="';
|
||||
|
||||
for ($i = 0, $l = strlen($val); $i < $l; $i++) {
|
||||
$x[] = '|' . ord($val[$i]);
|
||||
}
|
||||
|
||||
$x[] = '"';
|
||||
}
|
||||
} else {
|
||||
for ($i = 0, $l = mb_strlen($attributes); $i < $l; $i++) {
|
||||
$x[] = mb_substr($attributes, $i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$x[] = '>';
|
||||
|
||||
$temp = [];
|
||||
|
||||
for ($i = 0, $l = strlen($title); $i < $l; $i++) {
|
||||
$ordinal = ord($title[$i]);
|
||||
|
||||
if ($ordinal < 128) {
|
||||
$x[] = '|' . $ordinal;
|
||||
} else {
|
||||
if (empty($temp)) {
|
||||
$count = ($ordinal < 224) ? 2 : 3;
|
||||
}
|
||||
|
||||
$temp[] = $ordinal;
|
||||
|
||||
if (count($temp) === $count) {
|
||||
$number = ($count === 3) ? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64) : (($temp[0] % 32) * 64) + ($temp[1] % 64);
|
||||
$x[] = '|' . $number;
|
||||
$count = 1;
|
||||
$temp = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$x[] = '<';
|
||||
$x[] = '/';
|
||||
$x[] = 'a';
|
||||
$x[] = '>';
|
||||
|
||||
$x = array_reverse($x);
|
||||
|
||||
// improve obfuscation by eliminating newlines & whitespace
|
||||
$output = '<script type="text/javascript">'
|
||||
. 'var l=new Array();';
|
||||
|
||||
foreach ($x as $i => $value) {
|
||||
$output .= 'l[' . $i . "] = '" . $value . "';";
|
||||
}
|
||||
|
||||
return $output . ('for (var i = l.length-1; i >= 0; i=i-1) {'
|
||||
. "if (l[i].substring(0, 1) === '|') document.write(\"&#\"+unescape(l[i].substring(1))+\";\");"
|
||||
. 'else document.write(unescape(l[i]));'
|
||||
. '}'
|
||||
. '</script>');
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('auto_link')) {
|
||||
/**
|
||||
* Auto-linker
|
||||
*
|
||||
* Automatically links URL and Email addresses.
|
||||
* Note: There's a bit of extra code here to deal with
|
||||
* URLs or emails that end in a period. We'll strip these
|
||||
* off and add them after the link.
|
||||
*
|
||||
* @param string $str the string
|
||||
* @param string $type the type: email, url, or both
|
||||
* @param bool $popup whether to create pop-up links
|
||||
*/
|
||||
function auto_link(string $str, string $type = 'both', bool $popup = false): string
|
||||
{
|
||||
// Find and replace any URLs.
|
||||
if ($type !== 'email' && preg_match_all('#(\w*://|www\.)[^\s()<>;]+\w#i', $str, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
|
||||
// Set our target HTML if using popup links.
|
||||
$target = ($popup) ? ' target="_blank"' : '';
|
||||
|
||||
// We process the links in reverse order (last -> first) so that
|
||||
// the returned string offsets from preg_match_all() are not
|
||||
// moved as we add more HTML.
|
||||
foreach (array_reverse($matches) as $match) {
|
||||
// $match[0] is the matched string/link
|
||||
// $match[1] is either a protocol prefix or 'www.'
|
||||
//
|
||||
// With PREG_OFFSET_CAPTURE, both of the above is an array,
|
||||
// where the actual value is held in [0] and its offset at the [1] index.
|
||||
$a = '<a href="' . (strpos($match[1][0], '/') ? '' : 'http://') . $match[0][0] . '"' . $target . '>' . $match[0][0] . '</a>';
|
||||
$str = substr_replace($str, $a, $match[0][1], strlen($match[0][0]));
|
||||
}
|
||||
}
|
||||
|
||||
// Find and replace any emails.
|
||||
if ($type !== 'url' && preg_match_all('#([\w\.\-\+]+@[a-z0-9\-]+\.[a-z0-9\-\.]+[^[:punct:]\s])#i', $str, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
foreach (array_reverse($matches[0]) as $match) {
|
||||
if (filter_var($match[0], FILTER_VALIDATE_EMAIL) !== false) {
|
||||
$str = substr_replace($str, safe_mailto($match[0]), $match[1], strlen($match[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('prep_url')) {
|
||||
/**
|
||||
* Prep URL - Simply adds the http:// or https:// part if no scheme is included.
|
||||
*
|
||||
* Formerly used URI, but that does not play nicely with URIs missing
|
||||
* the scheme.
|
||||
*
|
||||
* @param string $str the URL
|
||||
* @param bool $secure set true if you want to force https://
|
||||
*/
|
||||
function prep_url(string $str = '', bool $secure = false): string
|
||||
{
|
||||
if (in_array($str, ['http://', 'https://', '//', ''], true)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (parse_url($str, PHP_URL_SCHEME) === null) {
|
||||
$str = 'http://' . ltrim($str, '/');
|
||||
}
|
||||
|
||||
// force replace http:// with https://
|
||||
if ($secure) {
|
||||
$str = preg_replace('/^(?:http):/i', 'https:', $str);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('url_title')) {
|
||||
/**
|
||||
* Create URL Title
|
||||
*
|
||||
* Takes a "title" string as input and creates a
|
||||
* human-friendly URL string with a "separator" string
|
||||
* as the word separator.
|
||||
*
|
||||
* @param string $str Input string
|
||||
* @param string $separator Word separator (usually '-' or '_')
|
||||
* @param bool $lowercase Whether to transform the output string to lowercase
|
||||
*/
|
||||
function url_title(string $str, string $separator = '-', bool $lowercase = false): string
|
||||
{
|
||||
$qSeparator = preg_quote($separator, '#');
|
||||
|
||||
$trans = [
|
||||
'&.+?;' => '',
|
||||
'[^\w\d\pL\pM _-]' => '',
|
||||
'\s+' => $separator,
|
||||
'(' . $qSeparator . ')+' => $separator,
|
||||
];
|
||||
|
||||
$str = strip_tags($str);
|
||||
|
||||
foreach ($trans as $key => $val) {
|
||||
$str = preg_replace('#' . $key . '#iu', $val, $str);
|
||||
}
|
||||
|
||||
if ($lowercase === true) {
|
||||
$str = mb_strtolower($str);
|
||||
}
|
||||
|
||||
return trim(trim($str, $separator));
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('mb_url_title')) {
|
||||
/**
|
||||
* Create URL Title that takes into account accented characters
|
||||
*
|
||||
* Takes a "title" string as input and creates a
|
||||
* human-friendly URL string with a "separator" string
|
||||
* as the word separator.
|
||||
*
|
||||
* @param string $str Input string
|
||||
* @param string $separator Word separator (usually '-' or '_')
|
||||
* @param bool $lowercase Whether to transform the output string to lowercase
|
||||
*/
|
||||
function mb_url_title(string $str, string $separator = '-', bool $lowercase = false): string
|
||||
{
|
||||
helper('text');
|
||||
|
||||
return url_title(convert_accented_characters($str), $separator, $lowercase);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('url_to')) {
|
||||
/**
|
||||
* Get the full, absolute URL to a controller method
|
||||
* (with additional arguments)
|
||||
*
|
||||
* @param mixed ...$args
|
||||
*
|
||||
* @throws RouterException
|
||||
*/
|
||||
function url_to(string $controller, ...$args): string
|
||||
{
|
||||
if (! $route = route_to($controller, ...$args)) {
|
||||
$explode = explode('::', $controller);
|
||||
|
||||
if (isset($explode[1])) {
|
||||
throw RouterException::forControllerNotFound($explode[0], $explode[1]);
|
||||
}
|
||||
|
||||
throw RouterException::forInvalidRoute($controller);
|
||||
}
|
||||
|
||||
return site_url($route);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('url_is')) {
|
||||
/**
|
||||
* Determines if current url path contains
|
||||
* the given path. It may contain a wildcard (*)
|
||||
* which will allow any valid character.
|
||||
*
|
||||
* Example:
|
||||
* if (url_is('admin*)) ...
|
||||
*/
|
||||
function url_is(string $path): bool
|
||||
{
|
||||
// Setup our regex to allow wildcards
|
||||
$path = '/' . trim(str_replace('*', '(\S)*', $path), '/ ');
|
||||
$currentPath = '/' . trim(uri_string(true), '/ ');
|
||||
|
||||
return (bool) preg_match("|^{$path}$|", $currentPath, $matches);
|
||||
}
|
||||
}
|
||||
59
system/Helpers/xml_helper.php
Normal file
59
system/Helpers/xml_helper.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
// CodeIgniter XML Helpers
|
||||
|
||||
if (! function_exists('xml_convert')) {
|
||||
/**
|
||||
* Convert Reserved XML characters to Entities
|
||||
*/
|
||||
function xml_convert(string $str, bool $protectAll = false): string
|
||||
{
|
||||
$temp = '__TEMP_AMPERSANDS__';
|
||||
|
||||
// Replace entities to temporary markers so that
|
||||
// ampersands won't get messed up
|
||||
$str = preg_replace('/&#(\d+);/', $temp . '\\1;', $str);
|
||||
|
||||
if ($protectAll === true) {
|
||||
$str = preg_replace('/&(\w+);/', $temp . '\\1;', $str);
|
||||
}
|
||||
|
||||
$original = [
|
||||
'&',
|
||||
'<',
|
||||
'>',
|
||||
'"',
|
||||
"'",
|
||||
'-',
|
||||
];
|
||||
|
||||
$replacement = [
|
||||
'&',
|
||||
'<',
|
||||
'>',
|
||||
'"',
|
||||
''',
|
||||
'-',
|
||||
];
|
||||
|
||||
$str = str_replace($original, $replacement, $str);
|
||||
|
||||
// Decode the temp markers back to entities
|
||||
$str = preg_replace('/' . $temp . '(\d+);/', '&#\\1;', $str);
|
||||
|
||||
if ($protectAll === true) {
|
||||
return preg_replace('/' . $temp . '(\w+);/', '&\\1;', $str);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user