parent
2fae0452e9
commit
dde2638f10
@ -0,0 +1,23 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
/** |
||||||
|
* @template TItem |
||||||
|
*/ |
||||||
|
final readonly class Collection { |
||||||
|
/** |
||||||
|
* @param array<int, TItem> $items |
||||||
|
*/ |
||||||
|
public function __construct( |
||||||
|
private array $items |
||||||
|
) { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return array<int, TItem> |
||||||
|
*/ |
||||||
|
public function all(): array { |
||||||
|
return $this->items; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,29 @@ |
|||||||
|
<?php |
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
/** |
||||||
|
* @todo sudo apt install php8.4-bcmath |
||||||
|
* @todo sudo apt install php8.4-intl |
||||||
|
*/ |
||||||
|
|
||||||
|
use BcMath\Number; |
||||||
|
|
||||||
|
class Dollars { |
||||||
|
private function moneyAsFloat(Number $money): float { |
||||||
|
// Remove any existing currency symbols and thousands separators |
||||||
|
$t = preg_replace('/[^\d.-]/', '', $money); |
||||||
|
return (float)$t; |
||||||
|
} |
||||||
|
|
||||||
|
public function formatAsUSD(Number $money): string { |
||||||
|
return '$' . number_format($this->moneyAsFloat($money), 2, '.', ','); |
||||||
|
} |
||||||
|
|
||||||
|
public function intlUSD(Number $money): string|false { |
||||||
|
if (class_exists('NumberFormatter')) { |
||||||
|
$formatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); |
||||||
|
return $formatter->formatCurrency($this->moneyAsFloat($money), 'USD'); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,95 @@ |
|||||||
|
<?php |
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
/** |
||||||
|
* @template TKey |
||||||
|
* @template TValue |
||||||
|
* @implements \IteratorAggregate<TKey, TValue> |
||||||
|
*/ |
||||||
|
class LazyCollection implements \IteratorAggregate |
||||||
|
{ |
||||||
|
/** @var \Closure|self|array<TKey, TValue>|null */ |
||||||
|
protected $source; |
||||||
|
|
||||||
|
/** |
||||||
|
* @param \Closure(): iterable<TKey, TValue>|self<TKey, TValue>|iterable<TKey, TValue>|null $source |
||||||
|
*/ |
||||||
|
public function __construct($source = null) |
||||||
|
{ |
||||||
|
if ($source instanceof \Closure || $source instanceof self) { |
||||||
|
$this->source = $source; |
||||||
|
} elseif (is_null($source)) { |
||||||
|
$this->source = static::empty(); |
||||||
|
} else { |
||||||
|
$this->source = $this->getArrayableItems($source); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return \Traversable<TKey, TValue> |
||||||
|
*/ |
||||||
|
public function getIterator(): \Traversable |
||||||
|
{ |
||||||
|
return $this->makeIterator($this->source); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param \Closure(): iterable<TKey, TValue>|self<TKey, TValue>|array<TKey, TValue> $source |
||||||
|
* @return \Traversable<TKey, TValue> |
||||||
|
*/ |
||||||
|
protected function makeIterator($source) |
||||||
|
{ |
||||||
|
if ($source instanceof \Closure) { |
||||||
|
$source = $source(); |
||||||
|
} |
||||||
|
|
||||||
|
if (is_array($source)) { |
||||||
|
return new \ArrayIterator($source); |
||||||
|
} |
||||||
|
|
||||||
|
return $source; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @template TNewKey |
||||||
|
* @template TNewValue |
||||||
|
* @param \Closure(): iterable<TNewKey, TNewValue>|iterable<TNewKey, TNewValue>|null $source |
||||||
|
* @return self<TNewKey, TNewValue> |
||||||
|
*/ |
||||||
|
public static function make($source = null) |
||||||
|
{ |
||||||
|
return new static($source instanceof \Closure ? $source() : $source); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param callable(TValue, TKey): bool $callback |
||||||
|
* @return self<TKey, TValue> |
||||||
|
*/ |
||||||
|
public function each(callable $callback): LazyCollection |
||||||
|
{ |
||||||
|
foreach ($this->getIterator() as $key => $value) { |
||||||
|
if ($callback($value, $key) === false) { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param mixed $items |
||||||
|
* @return array<TKey, TValue> |
||||||
|
*/ |
||||||
|
protected function getArrayableItems($items): array |
||||||
|
{ |
||||||
|
if (is_array($items)) { |
||||||
|
return $items; |
||||||
|
} elseif ($items instanceof \Traversable) { |
||||||
|
return iterator_to_array($items); |
||||||
|
} elseif (is_object($items) && method_exists($items, 'toArray')) { |
||||||
|
return $items->toArray(); |
||||||
|
} |
||||||
|
|
||||||
|
return (array) $items; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,24 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
class LazyObject { |
||||||
|
public function __construct(public string $className) {} |
||||||
|
|
||||||
|
public function proxy(mixed ...$args): Object { |
||||||
|
$className = $this->className; |
||||||
|
if (!class_exists($className, true)) { |
||||||
|
throw new \InvalidArgumentException("Class {$className} does not exist"); |
||||||
|
} |
||||||
|
$reflector = new \ReflectionClass($className); |
||||||
|
if (!$reflector->isInstantiable()) { |
||||||
|
throw new \InvalidArgumentException("Class {$className} cannot be instantiated"); |
||||||
|
} |
||||||
|
|
||||||
|
$initializer = static function () use ($className, $args) { |
||||||
|
return new $className(...$args); |
||||||
|
}; |
||||||
|
|
||||||
|
return $reflector->newLazyProxy($initializer); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,66 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
interface Middleware |
||||||
|
{ |
||||||
|
public function handle(array $request, \Closure $next, mixed ...$parameters): mixed; |
||||||
|
} |
||||||
|
|
||||||
|
class Pipeline |
||||||
|
{ |
||||||
|
protected array $middleware = []; |
||||||
|
protected $request; |
||||||
|
|
||||||
|
public function send(array $request): Object |
||||||
|
{ |
||||||
|
$this->request = $request; |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
public function through(array $middleware): Object |
||||||
|
{ |
||||||
|
$this->middleware = $middleware; |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
public function then(\Closure $destination): array |
||||||
|
{ |
||||||
|
$pipeline = array_reduce( |
||||||
|
array_reverse($this->parseMiddleware($this->middleware)), |
||||||
|
$this->carry(), |
||||||
|
function ($request) use ($destination) { |
||||||
|
return $destination($request); |
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
return $pipeline($this->request); |
||||||
|
} |
||||||
|
|
||||||
|
protected function parseMiddleware(array $middleware): array |
||||||
|
{ |
||||||
|
return array_map(function ($m) { |
||||||
|
return is_string($m) ? explode(':', $m, 2) : $m; |
||||||
|
}, $middleware); |
||||||
|
} |
||||||
|
|
||||||
|
protected function carry(): mixed |
||||||
|
{ |
||||||
|
return function ($stack, $middleware) { |
||||||
|
return function ($request) use ($stack, $middleware) { |
||||||
|
if (is_array($middleware)) { |
||||||
|
[$middleware, $parameters] = [ |
||||||
|
$middleware[0], |
||||||
|
isset($middleware[1]) ? explode(',', $middleware[1]) : [] |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
if (is_string($middleware)) { |
||||||
|
$middleware = new $middleware; |
||||||
|
} |
||||||
|
|
||||||
|
return $middleware->handle($request, $stack, ...$parameters ?? []); |
||||||
|
}; |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
class Scalar { |
||||||
|
public function intoString(mixed $name): string { |
||||||
|
if (is_scalar($name) || (is_object($name) && method_exists($name, '__toString'))) { |
||||||
|
return (string)$name; |
||||||
|
} else { |
||||||
|
throw new \Exception("Cannot convert to string!"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,102 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
namespace CodeHydrater\arrays; |
||||||
|
|
||||||
|
class common_stuff { |
||||||
|
|
||||||
|
public static function get_ordinal_number_suffix(int $number): string { |
||||||
|
$number = abs($number); |
||||||
|
if (in_array(($number % 100),array(11,12,13))){ |
||||||
|
return 'th'; |
||||||
|
} |
||||||
|
switch ($number % 10) { |
||||||
|
case 1: return 'st'; |
||||||
|
case 2: return 'nd'; |
||||||
|
case 3: return 'rd'; |
||||||
|
default: return 'th'; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Fetch Months |
||||||
|
* @return array of months |
||||||
|
*/ |
||||||
|
public static function months(): array { |
||||||
|
return array( |
||||||
|
'1' => 'January', |
||||||
|
'2' => 'February', |
||||||
|
'3' => 'March', |
||||||
|
'4' => 'April', |
||||||
|
'5' => 'May', |
||||||
|
'6' => 'June', |
||||||
|
'7' => 'July', |
||||||
|
'8' => 'August', |
||||||
|
'9' => 'September', |
||||||
|
'10' => 'October', |
||||||
|
'11' => 'November', |
||||||
|
'12' => 'December' |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Fetch States in USA |
||||||
|
* @return array of states |
||||||
|
*/ |
||||||
|
public static function states_array(): array { |
||||||
|
return array( |
||||||
|
'AL' => 'Alabama', |
||||||
|
'AK' => 'Alaska', |
||||||
|
'AZ' => 'Arizona', |
||||||
|
'AR' => 'Arkansas', |
||||||
|
'CA' => 'California', |
||||||
|
'CO' => 'Colorado', |
||||||
|
'CT' => 'Connecticut', |
||||||
|
'DE' => 'Delaware', |
||||||
|
'DC' => 'District of Columbia', |
||||||
|
'FL' => 'Florida', |
||||||
|
'GA' => 'Georgia', |
||||||
|
'HI' => 'Hawaii', |
||||||
|
'ID' => 'Idaho', |
||||||
|
'IL' => 'Illinois', |
||||||
|
'IN' => 'Indiana', |
||||||
|
'IA' => 'Iowa', |
||||||
|
'KS' => 'Kansas', |
||||||
|
'KY' => 'Kentucky', |
||||||
|
'LA' => 'Louisiana', |
||||||
|
'ME' => 'Maine', |
||||||
|
'MD' => 'Maryland', |
||||||
|
'MA' => 'Massachusetts', |
||||||
|
'MI' => 'Michigan', |
||||||
|
'MN' => 'Minnesota', |
||||||
|
'MS' => 'Mississippi', |
||||||
|
'MO' => 'Missouri', |
||||||
|
'MT' => 'Montana', |
||||||
|
'NE' => 'Nebraska', |
||||||
|
'NV' => 'Nevada', |
||||||
|
'NH' => 'New Hampshire', |
||||||
|
'NJ' => 'New Jersey', |
||||||
|
'NM' => 'New Mexico', |
||||||
|
'NY' => 'New York', |
||||||
|
'NC' => 'North Carolina', |
||||||
|
'ND' => 'North Dakota', |
||||||
|
'OH' => 'Ohio', |
||||||
|
'OK' => 'Oklahoma', |
||||||
|
'OR' => 'Oregon', |
||||||
|
'PA' => 'Pennsylvania', |
||||||
|
'RI' => 'Rhode Island', |
||||||
|
'SC' => 'South Carolina', |
||||||
|
'SD' => 'South Dakota', |
||||||
|
'TN' => 'Tennessee', |
||||||
|
'TX' => 'Texas', |
||||||
|
'UT' => 'Utah', |
||||||
|
'VT' => 'Vermont', |
||||||
|
'VA' => 'Virginia', |
||||||
|
'WA' => 'Washington', |
||||||
|
'WV' => 'West Virginia', |
||||||
|
'WI' => 'Wisconsin', |
||||||
|
'WY' => 'Wyoming', |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,262 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace CodeHydrater\arrays; |
||||||
|
|
||||||
|
class countries { |
||||||
|
|
||||||
|
/** |
||||||
|
* Fetch countries |
||||||
|
* @return array of countries |
||||||
|
*/ |
||||||
|
public static function countries_array(): array { |
||||||
|
return array( |
||||||
|
'AX' => 'Aland Islands', |
||||||
|
'AF' => 'Afghanistan', |
||||||
|
'AL' => 'Albania', |
||||||
|
'DZ' => 'Algeria', |
||||||
|
'AS' => 'American Samoa', |
||||||
|
'AD' => 'Andorra', |
||||||
|
'AO' => 'Angola', |
||||||
|
'AI' => 'Anguilla', |
||||||
|
'AQ' => 'Antarctica', |
||||||
|
'AG' => 'Antigua And Barbuda', |
||||||
|
'AR' => 'Argentina', |
||||||
|
'AM' => 'Armenia', |
||||||
|
'AW' => 'Aruba', |
||||||
|
'AU' => 'Australia', |
||||||
|
'AT' => 'Austria', |
||||||
|
'AZ' => 'Azerbaijan', |
||||||
|
'BS' => 'Bahamas', |
||||||
|
'BH' => 'Bahrain', |
||||||
|
'BD' => 'Bangladesh', |
||||||
|
'BB' => 'Barbados', |
||||||
|
'BY' => 'Belarus', |
||||||
|
'BE' => 'Belgium', |
||||||
|
'BZ' => 'Belize', |
||||||
|
'BJ' => 'Benin', |
||||||
|
'BM' => 'Bermuda', |
||||||
|
'BT' => 'Bhutan', |
||||||
|
'BO' => 'Bolivia', |
||||||
|
'BA' => 'Bosnia And Herzegovina', |
||||||
|
'BW' => 'Botswana', |
||||||
|
'BV' => 'Bouvet Island', |
||||||
|
'BR' => 'Brazil', |
||||||
|
'IO' => 'British Indian Ocean Territory', |
||||||
|
'BN' => 'Brunei', |
||||||
|
'BG' => 'Bulgaria', |
||||||
|
'BF' => 'Burkina Faso', |
||||||
|
'AR' => 'Burma', |
||||||
|
'BI' => 'Burundi', |
||||||
|
'KH' => 'Cambodia', |
||||||
|
'CM' => 'Cameroon', |
||||||
|
'CA' => 'Canada', |
||||||
|
'CV' => 'Cape Verde', |
||||||
|
'KY' => 'Cayman Islands', |
||||||
|
'CF' => 'Central African Republic', |
||||||
|
'TD' => 'Chad', |
||||||
|
'CL' => 'Chile', |
||||||
|
'CN' => 'China', |
||||||
|
'CX' => 'Christmas Island', |
||||||
|
'CC' => 'Cocos (Keeling) Islands', |
||||||
|
'CO' => 'Columbia', |
||||||
|
'KM' => 'Comoros', |
||||||
|
'CG' => 'Congo', |
||||||
|
'CK' => 'Cook Islands', |
||||||
|
'CR' => 'Costa Rica', |
||||||
|
'CI' => 'Cote D\'Ivorie (Ivory Coast)', |
||||||
|
'HR' => 'Croatia (Hrvatska)', |
||||||
|
'CU' => 'Cuba', |
||||||
|
'CY' => 'Cyprus', |
||||||
|
'CZ' => 'Czech Republic static', |
||||||
|
'CD' => 'Democratic Republic Of Congo (Zaire)', |
||||||
|
'DK' => 'Denmark', |
||||||
|
'DJ' => 'Djibouti', |
||||||
|
'DM' => 'Dominica', |
||||||
|
'DO' => 'Dominican Republic', |
||||||
|
'TP' => 'East Timor', |
||||||
|
'EC' => 'Ecuador', |
||||||
|
'EG' => 'Egypt', |
||||||
|
'SV' => 'El Salvador', |
||||||
|
'GB' => 'England', |
||||||
|
'GQ' => 'Equatorial Guinea', |
||||||
|
'ER' => 'Eritrea', |
||||||
|
'EE' => 'Estonia', |
||||||
|
'ET' => 'Ethiopia', |
||||||
|
'EU' => 'European Union', |
||||||
|
'FK' => 'Falkland Islands (Malvinas)', |
||||||
|
'FO' => 'Faroe Islands', |
||||||
|
'FJ' => 'Fiji', |
||||||
|
'FI' => 'Finland', |
||||||
|
'FR' => 'France', |
||||||
|
'FX' => 'France, Metropolitan', |
||||||
|
'GF' => 'French Guinea', |
||||||
|
'PF' => 'French Polynesia', |
||||||
|
'TF' => 'French Southern Territories', |
||||||
|
'GA' => 'Gabon', |
||||||
|
'GM' => 'Gambia', |
||||||
|
'GE' => 'Georgia', |
||||||
|
'DE' => 'Germany', |
||||||
|
'GH' => 'Ghana', |
||||||
|
'GI' => 'Gibraltar', |
||||||
|
'GR' => 'Greece', |
||||||
|
'GL' => 'Greenland', |
||||||
|
'GD' => 'Grenada', |
||||||
|
'GP' => 'Guadeloupe', |
||||||
|
'GU' => 'Guam', |
||||||
|
'GT' => 'Guatemala', |
||||||
|
'GN' => 'Guinea', |
||||||
|
'GW' => 'Guinea-Bissau', |
||||||
|
'GY' => 'Guyana', |
||||||
|
'HT' => 'Haiti', |
||||||
|
'HM' => 'Heard And McDonald Islands', |
||||||
|
'HN' => 'Honduras', |
||||||
|
'HK' => 'Hong Kong', |
||||||
|
'HU' => 'Hungary', |
||||||
|
'IS' => 'Iceland', |
||||||
|
'IN' => 'India', |
||||||
|
'ID' => 'Indonesia', |
||||||
|
'IR' => 'Iran', |
||||||
|
'IQ' => 'Iraq', |
||||||
|
'IE' => 'Ireland', |
||||||
|
'IL' => 'Israel', |
||||||
|
'IT' => 'Italy', |
||||||
|
'JM' => 'Jamaica', |
||||||
|
'JP' => 'Japan', |
||||||
|
'JO' => 'Jordan', |
||||||
|
'KZ' => 'Kazakhstan', |
||||||
|
'KE' => 'Kenya', |
||||||
|
'KI' => 'Kiribati', |
||||||
|
'KW' => 'Kuwait', |
||||||
|
'KG' => 'Kyrgyzstan', |
||||||
|
'LA' => 'Laos', |
||||||
|
'LV' => 'Latvia', |
||||||
|
'LB' => 'Lebanon', |
||||||
|
'LS' => 'Lesotho', |
||||||
|
'LR' => 'Liberia', |
||||||
|
'LY' => 'Libya', |
||||||
|
'LI' => 'Liechtenstein', |
||||||
|
'LT' => 'Lithuania', |
||||||
|
'LU' => 'Luxembourg', |
||||||
|
'MO' => 'Macau', |
||||||
|
'MK' => 'Macedonia', |
||||||
|
'MG' => 'Madagascar', |
||||||
|
'MW' => 'Malawi', |
||||||
|
'MY' => 'Malaysia', |
||||||
|
'MV' => 'Maldives', |
||||||
|
'ML' => 'Mali', |
||||||
|
'MT' => 'Malta', |
||||||
|
'MH' => 'Marshall Islands', |
||||||
|
'MQ' => 'Martinique', |
||||||
|
'MR' => 'Mauritania', |
||||||
|
'MU' => 'Mauritius', |
||||||
|
'YT' => 'Mayotte', |
||||||
|
'MX' => 'Mexico', |
||||||
|
'FM' => 'Micronesia', |
||||||
|
'MD' => 'Moldova', |
||||||
|
'MC' => 'Monaco', |
||||||
|
'MN' => 'Mongolia', |
||||||
|
'ME' => 'Montenegro', |
||||||
|
'MS' => 'Montserrat', |
||||||
|
'MA' => 'Morocco', |
||||||
|
'MZ' => 'Mozambique', |
||||||
|
'MM' => 'Myanmar (Burma)', |
||||||
|
'NA' => 'Namibia', |
||||||
|
'NR' => 'Nauru', |
||||||
|
'NP' => 'Nepal', |
||||||
|
'NL' => 'Netherlands', |
||||||
|
'AN' => 'Netherlands Antilles', |
||||||
|
'NC' => 'New Caledonia', |
||||||
|
'NZ' => 'New Zealand', |
||||||
|
'NI' => 'Nicaragua', |
||||||
|
'NE' => 'Niger', |
||||||
|
'NG' => 'Nigeria', |
||||||
|
'NU' => 'Niue', |
||||||
|
'NF' => 'Norfolk Island', |
||||||
|
'KP' => 'North Korea', |
||||||
|
'MP' => 'Northern Mariana Islands', |
||||||
|
'NO' => 'Norway', |
||||||
|
'OM' => 'Oman', |
||||||
|
'PK' => 'Pakistan', |
||||||
|
'PW' => 'Palau', |
||||||
|
'PS' => 'Palestine', |
||||||
|
'PA' => 'Panama', |
||||||
|
'PG' => 'Papua New Guinea', |
||||||
|
'PY' => 'Paraguay', |
||||||
|
'PE' => 'Peru', |
||||||
|
'PH' => 'Philippines', |
||||||
|
'PN' => 'Pitcairn', |
||||||
|
'PL' => 'Poland', |
||||||
|
'PT' => 'Portugal', |
||||||
|
'PR' => 'Puerto Rico', |
||||||
|
'QA' => 'Qatar', |
||||||
|
'RE' => 'Reunion', |
||||||
|
'RO' => 'Romania', |
||||||
|
'RU' => 'Russia', |
||||||
|
'RW' => 'Rwanda', |
||||||
|
'SH' => 'Saint Helena', |
||||||
|
'KN' => 'Saint Kitts And Nevis', |
||||||
|
'LC' => 'Saint Lucia', |
||||||
|
'PM' => 'Saint Pierre And Miquelon', |
||||||
|
'VC' => 'Saint Vincent And The Grenadines', |
||||||
|
'SM' => 'San Marino', |
||||||
|
'ST' => 'Sao Tome And Principe', |
||||||
|
'SA' => 'Saudi Arabia', |
||||||
|
'SN' => 'Senegal', |
||||||
|
'SC' => 'Seychelles', |
||||||
|
'SL' => 'Sierra Leone', |
||||||
|
'SG' => 'Singapore', |
||||||
|
'SK' => 'Slovakia', |
||||||
|
'SI' => 'Slovenia', |
||||||
|
'SB' => 'Solomon Islands', |
||||||
|
'SO' => 'Somalia', |
||||||
|
'ZA' => 'South Africa', |
||||||
|
'GS' => 'South Georgia And South Sandwich Islands', |
||||||
|
'KR' => 'South Korea', |
||||||
|
'ES' => 'Spain', |
||||||
|
'LK' => 'Sri Lanka', |
||||||
|
'SD' => 'Sudan', |
||||||
|
'SR' => 'Suriname', |
||||||
|
'SJ' => 'Svalbard And Jan Mayen', |
||||||
|
'SZ' => 'Swaziland', |
||||||
|
'SE' => 'Sweden', |
||||||
|
'CH' => 'Switzerland', |
||||||
|
'SY' => 'Syria', |
||||||
|
'TW' => 'Taiwan', |
||||||
|
'TJ' => 'Tajikistan', |
||||||
|
'TZ' => 'Tanzania', |
||||||
|
'TH' => 'Thailand', |
||||||
|
'TG' => 'Togo', |
||||||
|
'TK' => 'Tokelau', |
||||||
|
'TO' => 'Tonga', |
||||||
|
'TT' => 'Trinidad And Tobago', |
||||||
|
'TN' => 'Tunisia', |
||||||
|
'TR' => 'Turkey', |
||||||
|
'TM' => 'Turkmenistan', |
||||||
|
'TC' => 'Turks And Caicos Islands', |
||||||
|
'TV' => 'Tuvalu', |
||||||
|
'UG' => 'Uganda', |
||||||
|
'UA' => 'Ukraine', |
||||||
|
'AE' => 'United Arab Emirates', |
||||||
|
'UK' => 'United Kingdom', |
||||||
|
'US' => 'United States', |
||||||
|
'UM' => 'United States Minor Outlying Islands', |
||||||
|
'UY' => 'Uruguay', |
||||||
|
'UZ' => 'Uzbekistan', |
||||||
|
'VU' => 'Vanuatu', |
||||||
|
'VA' => 'Vatican City', |
||||||
|
'VE' => 'Venezuela', |
||||||
|
'VN' => 'Vietnam', |
||||||
|
'VG' => 'Virgin Islands (British)', |
||||||
|
'VI' => 'Virgin Islands (US)', |
||||||
|
'WF' => 'Wallis And Futuna Islands', |
||||||
|
'EH' => 'Western Sahara', |
||||||
|
'WS' => 'Western Samoa', |
||||||
|
'YE' => 'Yemen', |
||||||
|
'YU' => 'Yugoslavia', |
||||||
|
'ZM' => 'Zambia', |
||||||
|
'ZW' => 'Zimbabwe' |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,166 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace CodeHydrater\arrays; |
||||||
|
|
||||||
|
class mimes { |
||||||
|
|
||||||
|
/** |
||||||
|
* Fetch Mime Types |
||||||
|
* @return array of mime types |
||||||
|
*/ |
||||||
|
public static function mimes_array(): array { |
||||||
|
return [ |
||||||
|
'text' => [ |
||||||
|
'txt' => 'text/plain', |
||||||
|
], |
||||||
|
'web' => [ |
||||||
|
'htm' => 'text/html', |
||||||
|
'html' => 'text/html', |
||||||
|
'css' => 'text/css', |
||||||
|
'json' => 'application/json', |
||||||
|
'xml' => 'application/xml' |
||||||
|
], |
||||||
|
'images' => [ |
||||||
|
'png' => 'image/png', |
||||||
|
'jpe' => 'image/jpeg', |
||||||
|
'jpeg' => 'image/jpeg', |
||||||
|
'jpg' => 'image/jpeg', |
||||||
|
'gif' => 'image/gif', |
||||||
|
'bmp' => 'image/bmp', |
||||||
|
'ico' => 'image/vnd.microsoft.icon', |
||||||
|
'tiff' => 'image/tiff', |
||||||
|
'tif' => 'image/tiff', |
||||||
|
'svg' => 'image/svg+xml', |
||||||
|
'svgz' => 'image/svg+xml', |
||||||
|
'webp' => 'image/webp' |
||||||
|
], |
||||||
|
'archives' => [ |
||||||
|
'zip' => 'application/zip', |
||||||
|
'rar' => 'application/x-rar-compressed', |
||||||
|
'cab' => 'application/vnd.ms-cab-compressed', |
||||||
|
'gz' => 'application/gzip', |
||||||
|
'tgz' => 'application/x-compressed', |
||||||
|
'tar' => 'application/x-tar', |
||||||
|
'iso' => 'application/x-iso9660-image', |
||||||
|
'bz2' => 'application/x-bzip2', |
||||||
|
'lz' => 'application/x-lzip', |
||||||
|
'xz' => 'application/x-xz', |
||||||
|
'7z' => 'application/x-7z-compressed', |
||||||
|
], |
||||||
|
'audio' => [ |
||||||
|
'oga' => 'audio/ogg', 'ogg' => 'audio/ogg', 'opus' => 'audio/ogg', 'spx' => 'audio/ogg', |
||||||
|
'mp3' => 'audio/mpeg', |
||||||
|
'wav' => 'audio/x-wav' |
||||||
|
], |
||||||
|
'video' => [ |
||||||
|
'mpeg' => 'video/mpeg', 'mpg' => 'video/mpeg', 'mpe' => 'video/mpeg', |
||||||
|
'mp4' => 'video/mp4', |
||||||
|
'qt' => 'video/quicktime', |
||||||
|
'mov' => 'video/quicktime', |
||||||
|
'ogv' => 'video/ogg' |
||||||
|
], |
||||||
|
'adobe' => [ |
||||||
|
'pdf' => 'application/pdf', |
||||||
|
'psd' => 'image/vnd.adobe.photoshop', |
||||||
|
'ai' => 'application/postscript', |
||||||
|
'eps' => 'application/postscript', |
||||||
|
'ps' => 'application/postscript' |
||||||
|
], |
||||||
|
'office' => [ |
||||||
|
'doc' => 'application/msword', |
||||||
|
'rtf' => 'application/rtf', |
||||||
|
'xls' => 'application/vnd.ms-excel', |
||||||
|
'ppt' => 'application/vnd.ms-powerpoint', |
||||||
|
'odt' => 'application/vnd.oasis.opendocument.text', |
||||||
|
'ods' => 'application/vnd.oasis.opendocument.spreadsheet' |
||||||
|
] |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
public static function mimes_dangerious(): array { |
||||||
|
return [ |
||||||
|
// Programming |
||||||
|
'js' => 'application/javascript', |
||||||
|
'php' => 'application/x-php-code', |
||||||
|
'py' => 'application/x-python-code', |
||||||
|
'pyc' => 'application/x-python-code', |
||||||
|
'pyo' => 'application/x-python-code', |
||||||
|
'torrent' => 'application/x-bittorrent', |
||||||
|
// Linux |
||||||
|
'deb' => 'application/vnd.debian.binary-package', |
||||||
|
'rpm' => 'application/x-redhat-package-manager', |
||||||
|
'bash' => 'application/x-shellscript', |
||||||
|
'sh' => 'application/x-sh', |
||||||
|
'jar' => 'application/java', |
||||||
|
'java' => 'application/java', |
||||||
|
// Windows |
||||||
|
'swf' => 'application/x-shockwave-flash', 'swfl' => 'application/x-shockwave-flash', |
||||||
|
'reg' => 'application/registry', |
||||||
|
'lnk' => 'application/shortcut', |
||||||
|
'inf' => 'application/config', |
||||||
|
'scf' => 'application/explorer', |
||||||
|
// A Monad script file. Monad was later renamed PowerShell. |
||||||
|
'msh' => 'shell', 'msh1' => 'shell', 'msh2' => 'shell', 'mshxml' => 'shell', 'msh1xml' => 'shell', 'msh2xml' => 'shell', |
||||||
|
// Power Shell |
||||||
|
'ps1' => 'shell', 'ps1xml' => 'shell', 'ps2' => 'shell', 'ps2xml' => 'shell', 'psc1' => 'shell', 'psc2' => 'shell', |
||||||
|
'wsc' => 'application/scripting-component', 'wsh' => 'application/scripting-host', 'ws' => 'application/scripting', 'wsf' => 'application/scripting', |
||||||
|
'jse' => 'application/javascript-encrypted', |
||||||
|
'vbe' => 'application/vbscript-encrypted', |
||||||
|
'vb' => 'application/visualbasic', |
||||||
|
'vbs' => 'application/visualbasic', |
||||||
|
'bat' => 'application/batch', |
||||||
|
'cmd' => 'application/batch', |
||||||
|
'exe' => 'application/x-msdownload', |
||||||
|
'pif' => 'application/executiable', |
||||||
|
'application' => 'application/oneclick', |
||||||
|
'gadget' => 'vista/desktop', |
||||||
|
'msi' => 'application/x-msdownload', |
||||||
|
'msp' => 'application/patch', |
||||||
|
'com' => 'application/dos', |
||||||
|
'scr' => 'application/screen-saver', |
||||||
|
'hta' => 'html/application', |
||||||
|
'cpl' => 'application/control-panel', |
||||||
|
'msc' => 'application/m-console', |
||||||
|
// Office 2007 Macros |
||||||
|
'docm' => 'macro/msword', |
||||||
|
'dotm' => 'macro/template', |
||||||
|
'xlsm' => 'macro/excel', |
||||||
|
'xltm' => 'macro', 'xlam' => 'macro', 'pptm' => 'macro', 'potm' => 'macro', 'ppam' => 'macro', 'ppsm' => 'macro', 'sldm' => 'marco' |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
public static function get_mime_type(string $filename, array $allowed = ['all']) { |
||||||
|
$ext = strtolower(array_pop(explode('.', $filename))); |
||||||
|
$bad = self::mimes_dangerious(); |
||||||
|
|
||||||
|
if (array_key_exists($ext, $bad)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
$mime_types = self::mimes_array(); |
||||||
|
|
||||||
|
$everyone = in_array('all', $allowed); |
||||||
|
|
||||||
|
foreach ($mime_types as $key => $mime) { |
||||||
|
if (($everyone || in_array($key, $allowed) ) && array_key_exists($ext, $mime)) { |
||||||
|
return $mime[$ext]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if ($everyone) { |
||||||
|
if (function_exists('finfo_open')) { |
||||||
|
$finfo = finfo_open(FILEINFO_MIME); |
||||||
|
$mimetype = finfo_file($finfo, $filename); |
||||||
|
finfo_close($finfo); |
||||||
|
return $mimetype; |
||||||
|
} else { |
||||||
|
return 'application/octet-stream'; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,43 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace CodeHydrater\arrays\mocking; |
||||||
|
|
||||||
|
class phone { |
||||||
|
|
||||||
|
const TOLLFREE = [800, 844, 855, 866, 877, 888]; |
||||||
|
const AREACODES = [201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 212, 213, 214, 215, 216, 217, 218, 219, 220, 224, 225, 226, 228, 229, 231, 234, 236, 239, 240, 242, 246, 248, 249, 250, 251, 252, 253, 254, 256, 260, 262, 264, 267, 268, 269, 270, 272, 276, 281, 284, 289, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 323, 325, 330, 331, 334, 336, 337, 339, 340, 343, 345, 346, 347, 351, 352, 360, 361, 364, 365, 380, 385, 386, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 412, 413, 414, 415, 416, 417, 418, 419, 423, 424, 425, 430, 431, 432, 434, 435, 437, 438, 440, 441, 442, 443, 450, 458, 469, 470, 473, 475, 478, 479, 480, 484, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 512, 513, 514, 515, 516, 517, 518, 519, 520, 530, 531, 534, 539, 540, 541, 548, 551, 559, 561, 562, 563, 567, 570, 571, 573, 574, 575, 579, 580, 581, 585, 586, 587, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 612, 613, 614, 615, 616, 617, 618, 619, 620, 623, 626, 628, 629, 630, 631, 636, 639, 641, 646, 647, 649, 650, 651, 657, 660, 661, 662, 664, 667, 669, 670, 671, 678, 681, 682, 684, 701, 702, 703, 704, 705, 706, 707, 708, 709, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 724, 725, 727, 731, 732, 734, 737, 740, 743, 747, 754, 757, 758, 760, 762, 763, 765, 767, 769, 770, 772, 773, 774, 775, 778, 779, 780, 781, 782, 784, 785, 786, 787, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 812, 813, 814, 815, 816, 817, 818, 819, 825, 828, 829, 830, 831, 832, 843, 845, 847, 848, 849, 850, 854, 856, 857, 858, 859, 860, 862, 863, 864, 865, 867, 868, 869, 870, 872, 873, 876, 878, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 912, 913, 914, 915, 916, 917, 918, 919, 920, 925, 928, 929, 930, 931, 934, 936, 937, 938, 939, 940, 941, 947, 949, 951, 952, 954, 956, 959, 970, 971, 972, 973, 978, 979, 980, 984, 985, 989]; |
||||||
|
|
||||||
|
private static function rnd_a(array $a) { |
||||||
|
$array_count = \CodeHydrater\bootstrap\common::get_count($a); |
||||||
|
return $a[rand(0, $array_count - 1)]; |
||||||
|
} |
||||||
|
|
||||||
|
public static function get_phone(int $rows = 100, bool $formatted = true, bool $tollfree = false): array { |
||||||
|
$phone_numbers = []; |
||||||
|
for($i =0; $i < $rows; $i++) { |
||||||
|
$use_tollfree = ($tollfree && rand(0,9) === 4) ? true : false; |
||||||
|
$random_number = (string) rand(1000, 9999); |
||||||
|
$prefix = (string) rand(111,899); |
||||||
|
$toll = ""; |
||||||
|
if ($use_tollfree) { |
||||||
|
$toll = (string) self::rnd_a(self::TOLLFREE); |
||||||
|
if ($formatted) { |
||||||
|
$phone_numbers[] = "1-(" . $toll . ")" . $prefix . "-" . $random_number; |
||||||
|
} else { |
||||||
|
$phone_numbers[] = "1" . $toll . $prefix . $random_number; |
||||||
|
} |
||||||
|
} else { |
||||||
|
$areacode = (string) self::rnd_a(self::AREACODES); |
||||||
|
if ($formatted) { |
||||||
|
$phone_numbers[] = "(" . $areacode . ")" . $prefix . "-". $random_number; |
||||||
|
} else { |
||||||
|
$phone_numbers[] = $areacode . $prefix . $random_number; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return $phone_numbers; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,29 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace CodeHydrater\arrays; |
||||||
|
|
||||||
|
final class shortn { |
||||||
|
|
||||||
|
public static function short_street_suffix($text) { |
||||||
|
$usps_abbreviations = [ |
||||||
|
'AVENUE' => 'Ave', |
||||||
|
'BOULEVARD' => 'Blvd', |
||||||
|
'DRIVE' => 'Dr', |
||||||
|
'LANE' => 'Ln', |
||||||
|
'MOUNT' => 'Mt', |
||||||
|
'ROAD' => 'Rd', |
||||||
|
'STREET' => 'St', |
||||||
|
' NORTH ' => ' N. ', |
||||||
|
' SOUTH ' => ' S. ', |
||||||
|
' EAST ' => ' E. ', |
||||||
|
' WEST ' => ' W. ' |
||||||
|
]; |
||||||
|
foreach ($usps_abbreviations as $key => $value) { |
||||||
|
$text = str_ireplace($key, $value, $text); |
||||||
|
} |
||||||
|
return $text; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,185 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace CodeHydrater\arrays; |
||||||
|
|
||||||
|
class zipcodes { |
||||||
|
|
||||||
|
public static function get_state(string $zipcode): array { |
||||||
|
|
||||||
|
/* Ensure we have exactly 5 characters to parse */ |
||||||
|
if (strlen($zipcode) !== 5) { |
||||||
|
return 'Must pass a 5-digit $zipcode.'; |
||||||
|
} |
||||||
|
|
||||||
|
$st = ''; |
||||||
|
$state = ''; |
||||||
|
|
||||||
|
/* Code cases alphabetized by state */ |
||||||
|
if ($zipcode >= 35000 && $zipcode <= 36999) { |
||||||
|
$st = 'AL'; |
||||||
|
$state = 'Alabama'; |
||||||
|
} else if ($zipcode >= 99500 && $zipcode <= 99999) { |
||||||
|
$st = 'AK'; |
||||||
|
$state = 'Alaska'; |
||||||
|
} else if ($zipcode >= 85000 && $zipcode <= 86999) { |
||||||
|
$st = 'AZ'; |
||||||
|
$state = 'Arizona'; |
||||||
|
} else if ($zipcode >= 71600 && $zipcode <= 72999) { |
||||||
|
$st = 'AR'; |
||||||
|
$state = 'Arkansas'; |
||||||
|
} else if ($zipcode >= 90000 && $zipcode <= 96699) { |
||||||
|
$st = 'CA'; |
||||||
|
$state = 'California'; |
||||||
|
} else if ($zipcode >= 80000 && $zipcode <= 81999) { |
||||||
|
$st = 'CO'; |
||||||
|
$state = 'Colorado'; |
||||||
|
} else if (($zipcode >= 6000 && $zipcode <= 6389) || ($zipcode >= 6391 && $zipcode <= 6999)) { |
||||||
|
$st = 'CT'; |
||||||
|
$state = 'Connecticut'; |
||||||
|
} else if ($zipcode >= 19700 && $zipcode <= 19999) { |
||||||
|
$st = 'DE'; |
||||||
|
$state = 'Delaware'; |
||||||
|
} else if ($zipcode >= 32000 && $zipcode <= 34999) { |
||||||
|
$st = 'FL'; |
||||||
|
$state = 'Florida'; |
||||||
|
} else if (($zipcode >= 30000 && $zipcode <= 31999) || ($zipcode >= 39800 && $zipcode <= 39999)) { |
||||||
|
$st = 'GA'; |
||||||
|
$state = 'Georgia'; |
||||||
|
} else if ($zipcode >= 96700 && $zipcode <= 96999) { |
||||||
|
$st = 'HI'; |
||||||
|
$state = 'Hawaii'; |
||||||
|
} else if ($zipcode >= 83200 && $zipcode <= 83999) { |
||||||
|
$st = 'ID'; |
||||||
|
$state = 'Idaho'; |
||||||
|
} else if ($zipcode >= 60000 && $zipcode <= 62999) { |
||||||
|
$st = 'IL'; |
||||||
|
$state = 'Illinois'; |
||||||
|
} else if ($zipcode >= 46000 && $zipcode <= 47999) { |
||||||
|
$st = 'IN'; |
||||||
|
$state = 'Indiana'; |
||||||
|
} else if ($zipcode >= 50000 && $zipcode <= 52999) { |
||||||
|
$st = 'IA'; |
||||||
|
$state = 'Iowa'; |
||||||
|
} else if ($zipcode >= 66000 && $zipcode <= 67999) { |
||||||
|
$st = 'KS'; |
||||||
|
$state = 'Kansas'; |
||||||
|
} else if ($zipcode >= 40000 && $zipcode <= 42999) { |
||||||
|
$st = 'KY'; |
||||||
|
$state = 'Kentucky'; |
||||||
|
} else if ($zipcode >= 70000 && $zipcode <= 71599) { |
||||||
|
$st = 'LA'; |
||||||
|
$state = 'Louisiana'; |
||||||
|
} else if ($zipcode >= 3900 && $zipcode <= 4999) { |
||||||
|
$st = 'ME'; |
||||||
|
$state = 'Maine'; |
||||||
|
} else if ($zipcode >= 20600 && $zipcode <= 21999) { |
||||||
|
$st = 'MD'; |
||||||
|
$state = 'Maryland'; |
||||||
|
} else if (($zipcode >= 1000 && $zipcode <= 2799) || ($zipcode == 5501) || ($zipcode == 5544 )) { |
||||||
|
$st = 'MA'; |
||||||
|
$state = 'Massachusetts'; |
||||||
|
} else if ($zipcode >= 48000 && $zipcode <= 49999) { |
||||||
|
$st = 'MI'; |
||||||
|
$state = 'Michigan'; |
||||||
|
} else if ($zipcode >= 55000 && $zipcode <= 56899) { |
||||||
|
$st = 'MN'; |
||||||
|
$state = 'Minnesota'; |
||||||
|
} else if ($zipcode >= 38600 && $zipcode <= 39999) { |
||||||
|
$st = 'MS'; |
||||||
|
$state = 'Mississippi'; |
||||||
|
} else if ($zipcode >= 63000 && $zipcode <= 65999) { |
||||||
|
$st = 'MO'; |
||||||
|
$state = 'Missouri'; |
||||||
|
} else if ($zipcode >= 59000 && $zipcode <= 59999) { |
||||||
|
$st = 'MT'; |
||||||
|
$state = 'Montana'; |
||||||
|
} else if ($zipcode >= 27000 && $zipcode <= 28999) { |
||||||
|
$st = 'NC'; |
||||||
|
$state = 'North Carolina'; |
||||||
|
} else if ($zipcode >= 58000 && $zipcode <= 58999) { |
||||||
|
$st = 'ND'; |
||||||
|
$state = 'North Dakota'; |
||||||
|
} else if ($zipcode >= 68000 && $zipcode <= 69999) { |
||||||
|
$st = 'NE'; |
||||||
|
$state = 'Nebraska'; |
||||||
|
} else if ($zipcode >= 88900 && $zipcode <= 89999) { |
||||||
|
$st = 'NV'; |
||||||
|
$state = 'Nevada'; |
||||||
|
} else if ($zipcode >= 3000 && $zipcode <= 3899) { |
||||||
|
$st = 'NH'; |
||||||
|
$state = 'New Hampshire'; |
||||||
|
} else if ($zipcode >= 7000 && $zipcode <= 8999) { |
||||||
|
$st = 'NJ'; |
||||||
|
$state = 'New Jersey'; |
||||||
|
} else if ($zipcode >= 87000 && $zipcode <= 88499) { |
||||||
|
$st = 'NM'; |
||||||
|
$state = 'New Mexico'; |
||||||
|
} else if (($zipcode >= 10000 && $zipcode <= 14999) || ($zipcode == 6390) || ($zipcode == 501) || ($zipcode == 544)) { |
||||||
|
$st = 'NY'; |
||||||
|
$state = 'New York'; |
||||||
|
} else if ($zipcode >= 43000 && $zipcode <= 45999) { |
||||||
|
$st = 'OH'; |
||||||
|
$state = 'Ohio'; |
||||||
|
} else if (($zipcode >= 73000 && $zipcode <= 73199) || ($zipcode >= 73400 && $zipcode <= 74999)) { |
||||||
|
$st = 'OK'; |
||||||
|
$state = 'Oklahoma'; |
||||||
|
} else if ($zipcode >= 97000 && $zipcode <= 97999) { |
||||||
|
$st = 'OR'; |
||||||
|
$state = 'Oregon'; |
||||||
|
} else if ($zipcode >= 15000 && $zipcode <= 19699) { |
||||||
|
$st = 'PA'; |
||||||
|
$state = 'Pennsylvania'; |
||||||
|
} else if ($zipcode >= 300 && $zipcode <= 999) { |
||||||
|
$st = 'PR'; |
||||||
|
$state = 'Puerto Rico'; |
||||||
|
} else if ($zipcode >= 2800 && $zipcode <= 2999) { |
||||||
|
$st = 'RI'; |
||||||
|
$state = 'Rhode Island'; |
||||||
|
} else if ($zipcode >= 29000 && $zipcode <= 29999) { |
||||||
|
$st = 'SC'; |
||||||
|
$state = 'South Carolina'; |
||||||
|
} else if ($zipcode >= 57000 && $zipcode <= 57999) { |
||||||
|
$st = 'SD'; |
||||||
|
$state = 'South Dakota'; |
||||||
|
} else if ($zipcode >= 37000 && $zipcode <= 38599) { |
||||||
|
$st = 'TN'; |
||||||
|
$state = 'Tennessee'; |
||||||
|
} else if (($zipcode >= 75000 && $zipcode <= 79999) || ($zipcode >= 73301 && $zipcode <= 73399) || ($zipcode >= 88500 && $zipcode <= 88599)) { |
||||||
|
$st = 'TX'; |
||||||
|
$state = 'Texas'; |
||||||
|
} else if ($zipcode >= 84000 && $zipcode <= 84999) { |
||||||
|
$st = 'UT'; |
||||||
|
$state = 'Utah'; |
||||||
|
} else if ($zipcode >= 5000 && $zipcode <= 5999) { |
||||||
|
$st = 'VT'; |
||||||
|
$state = 'Vermont'; |
||||||
|
} else if (($zipcode >= 20100 && $zipcode <= 20199) || ($zipcode >= 22000 && $zipcode <= 24699) || ($zipcode == 20598)) { |
||||||
|
$st = 'VA'; |
||||||
|
$state = 'Virgina'; |
||||||
|
} else if (($zipcode >= 20000 && $zipcode <= 20099) || ($zipcode >= 20200 && $zipcode <= 20599) || ($zipcode >= 56900 && $zipcode <= 56999)) { |
||||||
|
$st = 'DC'; |
||||||
|
$state = 'Washington DC'; |
||||||
|
} else if ($zipcode >= 98000 && $zipcode <= 99499) { |
||||||
|
$st = 'WA'; |
||||||
|
$state = 'Washington'; |
||||||
|
} else if ($zipcode >= 24700 && $zipcode <= 26999) { |
||||||
|
$st = 'WV'; |
||||||
|
$state = 'West Virginia'; |
||||||
|
} else if ($zipcode >= 53000 && $zipcode <= 54999) { |
||||||
|
$st = 'WI'; |
||||||
|
$state = 'Wisconsin'; |
||||||
|
} else if ($zipcode >= 82000 && $zipcode <= 83199) { |
||||||
|
$st = 'WY'; |
||||||
|
$state = 'Wyoming'; |
||||||
|
} else { |
||||||
|
$st = 'none'; |
||||||
|
$state = 'none'; |
||||||
|
return 'No state found matching' . $zipcode; |
||||||
|
} |
||||||
|
|
||||||
|
return ['abbr' => $st, 'state' => $state]; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,262 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts |
||||||
|
* @copyright Copyright (c) 2022, Robert Strutts. |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
final class assets { |
||||||
|
|
||||||
|
public static function get_ver(string $filename): string { |
||||||
|
if (self::attempts_root_dir($filename)) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
|
||||||
|
$safe_file = security::filter_uri($filename); |
||||||
|
if (! file_exists($safe_file)) { |
||||||
|
return "?ver=false"; |
||||||
|
} |
||||||
|
return "?ver=" . date('Y.m.d_H.i.s', filemtime($safe_file)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Check for / or absolute path not belonging to /var/www or PRJ:ROOT |
||||||
|
* @param string|null $path |
||||||
|
* @return bool |
||||||
|
*/ |
||||||
|
private static function attempts_root_dir(?string $path): bool { |
||||||
|
// up from src and back up to public |
||||||
|
$open_base_dir_path = dirname(bootstrap\site_helper::get_root(), 1) . '/public/'; |
||||||
|
if ($path === null || $path === '') { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (bootstrap\common::get_string_left($path, strlen($open_base_dir_path)) == $open_base_dir_path) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (bootstrap\common::get_string_left($path, 1) == '/') { |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public static function get_ajax_files(string $ajax_folder): string { |
||||||
|
if (self::attempts_root_dir($ajax_folder)) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
$safe_folder = security::filter_uri($ajax_folder); |
||||||
|
|
||||||
|
$ret = "var assets_files = [];" . PHP_EOL; |
||||||
|
$js = glob($safe_folder . "*.{js,css}", GLOB_BRACE); |
||||||
|
foreach($js as $file) { |
||||||
|
$ret .= 'assets_files.push({ filename: "' . basename($file) . '", ts: "' . self::get_ver($file) . '" });' . PHP_EOL; |
||||||
|
} |
||||||
|
return $ret; |
||||||
|
} |
||||||
|
|
||||||
|
public static function loadall_css(array $files, string $scope='project'): string { |
||||||
|
$ret = ''; |
||||||
|
foreach($files as $file=>$a_media) { |
||||||
|
$ret .= self::wrap_css($file, $scope, $a_media); |
||||||
|
} |
||||||
|
return $ret; |
||||||
|
} |
||||||
|
|
||||||
|
public static function loadall_js(array $files, string $scope='project'): string { |
||||||
|
$ret = ''; |
||||||
|
foreach($files as $file=>$a) { |
||||||
|
$ret .= self::wrap_js($file, $scope, $a); |
||||||
|
} |
||||||
|
return $ret; |
||||||
|
} |
||||||
|
|
||||||
|
public static function image(string $file, string $scope = '', array $a = array()): string { |
||||||
|
$more = ''; |
||||||
|
if (count($a)) { |
||||||
|
foreach ($a as $k => $v) { |
||||||
|
$more .= " {$k}=\"{$v}\""; |
||||||
|
} |
||||||
|
} |
||||||
|
$file = self::wrap_asset($file, $scope); |
||||||
|
if ($file === false) { |
||||||
|
return ''; |
||||||
|
} |
||||||
|
return "<img src=\"{$file}\" {$more}/>\r\n"; |
||||||
|
} |
||||||
|
|
||||||
|
public static function alert($msg) { |
||||||
|
return self::inline_js('alert("'.$msg.'");'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Wrapper for JS/CSS assets for the page. |
||||||
|
* @param string $file or CDN |
||||||
|
* @param string $scope (project/framework/cdn) |
||||||
|
* @retval boolean|string false is not found, else Asset REF |
||||||
|
*/ |
||||||
|
public static function wrap_asset(string $file, string $scope = 'project') { |
||||||
|
$scope = bootstrap\common::string_to_lowercase($scope); |
||||||
|
if ($scope === 'cdn') { |
||||||
|
$proto = bootstrap\safer_io::get_clean_server_var('SERVER_PROTOCOL'); |
||||||
|
if ($proto === null) { |
||||||
|
$protocol = '://'; |
||||||
|
} else { |
||||||
|
$protocol = strtolower(substr($proto, 0, strpos($proto, '/'))) . '://'; |
||||||
|
} |
||||||
|
return (bootstrap\common::is_string_found($file, '://') === true) ? $file : $protocol . $file; |
||||||
|
} |
||||||
|
if ($scope === 'project' || $scope === 'app') { |
||||||
|
$path = PROJECT_ASSETS_DIR . "/"; |
||||||
|
$tts = self::is_minified($path, $file); |
||||||
|
return ($tts !== false) ? PROJECT_ASSETS_BASE_REF . "/" . $tts : false; |
||||||
|
} |
||||||
|
if ($scope === 'assets') { |
||||||
|
$path = ASSETS_DIR . "/"; |
||||||
|
$tts = self::is_minified($path, $file); |
||||||
|
return ($tts !== false) ? ASSETS_BASE_REF . "/" . $tts : false; |
||||||
|
} |
||||||
|
return $file; |
||||||
|
} |
||||||
|
/** |
||||||
|
* Fetch Version of file if exists |
||||||
|
* @param string $file |
||||||
|
* @param string $scope |
||||||
|
* @return string|bool |
||||||
|
*/ |
||||||
|
private static function project_paths(string $file, string $scope = 'project'): string | bool { |
||||||
|
$scope = bootstrap\common::string_to_lowercase($scope); |
||||||
|
if ($scope === 'cdn') { |
||||||
|
return ""; |
||||||
|
} else if ($scope === 'project' || $scope === 'app') { |
||||||
|
$path = PROJECT_ASSETS_DIR . "/"; |
||||||
|
} else if ($scope === 'assets') { |
||||||
|
$path = ASSETS_DIR . "/"; |
||||||
|
} else { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
$check = self::is_minified($path, $file); |
||||||
|
return ($check !==false) ? self::get_ver($path . $check) : false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Wrapper to return the CSS href=file.. stylesheet code for use in page. |
||||||
|
* @param string $file - CSS file |
||||||
|
* @param string $media - default of all media |
||||||
|
* @retval string |
||||||
|
*/ |
||||||
|
public static function wrap_css(string $file, string $scope = 'project', array $a_media = array()): string { |
||||||
|
$more = ''; |
||||||
|
if (count($a_media)) { |
||||||
|
foreach ($a_media as $k => $v) { |
||||||
|
$more .= " {$k}=\"{$v}\""; |
||||||
|
} |
||||||
|
} else { |
||||||
|
$more .= " media=\"all\""; |
||||||
|
} |
||||||
|
|
||||||
|
$ver = self::project_paths($file, $scope); |
||||||
|
$wrap_file = self::wrap_asset($file, $scope); |
||||||
|
if ($ver === false || $wrap_file === false) { |
||||||
|
return "<!-- CSS: {$file} not Found -->"; |
||||||
|
} |
||||||
|
return "<link rel=\"stylesheet\" href=\"{$wrap_file}{$ver}\" type=\"text/css\"{$more}/>\r\n"; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Wrapper to return the JavaScript src=file... code for use with page. |
||||||
|
* @param type $file - external JS file. |
||||||
|
* @retval string of script src=file |
||||||
|
*/ |
||||||
|
public static function wrap_js(string $file, string $scope = 'project', array $a = array(), $type = "module"): string { |
||||||
|
$more = ''; |
||||||
|
if (count($a)) { |
||||||
|
foreach ($a as $k => $v) { |
||||||
|
$more .= (isset($k) && $k !=0 ) ? " {$k}=\"{$v}\"" : " {$v}"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
$ver = self::project_paths($file, $scope); |
||||||
|
$wrap_file = self::wrap_asset($file, $scope); |
||||||
|
if ($ver === false || $wrap_file === false) { |
||||||
|
return "<!-- Script: {$file} not Found -->"; |
||||||
|
} |
||||||
|
return "<script src=\"{$wrap_file}{$ver}\" type=\"{$type}\"{$more}></script>\r\n"; |
||||||
|
//return "<script type=\"text/javascript\">js_loader(\"{$file}\");</script>"; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Purpose: To do inline JavaScript. |
||||||
|
* @param type $code string of code to inline into page. |
||||||
|
* @retval type |
||||||
|
*/ |
||||||
|
public static function inline_js(string $code): string { |
||||||
|
return "<script type=\"text/javascript\">\r\n//<![CDATA[\r\n {$code}\r\n //]]> \r\n </script>\r\n"; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Purpose: To execute this JavaScript code once JQuery is Ready(). |
||||||
|
* @param string $code to do once JQuery is Ready |
||||||
|
* @retval string wrapped in ready code... |
||||||
|
*/ |
||||||
|
public static function jquery_load(string $code): string { |
||||||
|
return "\r\n$(function() { \r\n \t {$code} \r\n }); \r\n"; |
||||||
|
} |
||||||
|
|
||||||
|
public static function is_minified(string $path, string $file) { |
||||||
|
if (self::attempts_root_dir($path)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
$safe_path = security::filter_uri($path); |
||||||
|
$safe_file = security::filter_uri($file); |
||||||
|
|
||||||
|
if (bootstrap\common::is_string_found($safe_file, '.auto.js')) { |
||||||
|
$production = (bootstrap\is_live()); |
||||||
|
$safe_file = str_replace('.auto.js', '', $safe_file); |
||||||
|
if ( $production && file_exists($safe_path . $safe_file . '.min.js') ) { |
||||||
|
return $safe_file . '.min.js'; |
||||||
|
} |
||||||
|
return (file_exists($safe_path . $safe_file . '.js')) ? $safe_file . '.js' : false; |
||||||
|
} |
||||||
|
|
||||||
|
if (bootstrap\common::is_string_found($safe_file, '.auto.css')) { |
||||||
|
$production = (bootstrap\is_live()); |
||||||
|
$safe_file = str_replace('.auto.css', '', $safe_file); |
||||||
|
if ( $production && file_exists($safe_path . $safe_file . '.min.css') ) { |
||||||
|
return $safe_file . '.min.css'; |
||||||
|
} |
||||||
|
return (file_exists($safe_path . $safe_file . '.css')) ? $safe_file . '.css' : false; |
||||||
|
} |
||||||
|
return ( file_exists($safe_path . $safe_file) ) ? $safe_file : false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* meta redirect when headers are already sent... |
||||||
|
* @param string url - site to do redirect on |
||||||
|
* @reval none |
||||||
|
*/ |
||||||
|
public static function goto_url(string $url): void { |
||||||
|
echo '<META http-equiv="refresh" content="0;URL=' . $url . '">'; |
||||||
|
exit; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Rediect to url and attempt to send via header. |
||||||
|
* @param string $url - site to do redirect for |
||||||
|
* @retval none - exits once done |
||||||
|
*/ |
||||||
|
public static function redirect_url(string $url): void { |
||||||
|
$url = str_replace(array('&', "\n", "\r"), array('&', '', ''), $url); |
||||||
|
if (!headers_sent()) { |
||||||
|
header('Location: ' . $url); |
||||||
|
} else { |
||||||
|
self::goto_url($url); |
||||||
|
} |
||||||
|
exit; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,176 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @link https://github.com/genert/bbcode/blob/master/src/Parser/BBCodeParser.php |
||||||
|
* @license The MIT License (MIT) |
||||||
|
* @copyright (c) Genert 2017 - present. |
||||||
|
* |
||||||
|
* Take BB code 2 HTML, to display output |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
final class bb_code_parser { |
||||||
|
protected $parsers = [ |
||||||
|
'h1' => [ |
||||||
|
'pattern' => '/\[h1\](.*?)\[\/h1\]/s', |
||||||
|
'replace' => '<h1>$1</h1>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'h2' => [ |
||||||
|
'pattern' => '/\[h2\](.*?)\[\/h2\]/s', |
||||||
|
'replace' => '<h2>$1</h2>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'h3' => [ |
||||||
|
'pattern' => '/\[h3\](.*?)\[\/h3\]/s', |
||||||
|
'replace' => '<h3>$1</h3>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'h4' => [ |
||||||
|
'pattern' => '/\[h4\](.*?)\[\/h4\]/s', |
||||||
|
'replace' => '<h4>$1</h4>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'h5' => [ |
||||||
|
'pattern' => '/\[h5\](.*?)\[\/h5\]/s', |
||||||
|
'replace' => '<h5>$1</h5>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'h6' => [ |
||||||
|
'pattern' => '/\[h6\](.*?)\[\/h6\]/s', |
||||||
|
'replace' => '<h6>$1</h6>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'bold' => [ |
||||||
|
'pattern' => '/\[b\](.*?)\[\/b\]/s', |
||||||
|
'replace' => '<b>$1</b>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'italic' => [ |
||||||
|
'pattern' => '/\[i\](.*?)\[\/i\]/s', |
||||||
|
'replace' => '<i>$1</i>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'underline' => [ |
||||||
|
'pattern' => '/\[u\](.*?)\[\/u\]/s', |
||||||
|
'replace' => '<u>$1</u>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'strikethrough' => [ |
||||||
|
'pattern' => '/\[s\](.*?)\[\/s\]/s', |
||||||
|
'replace' => '<s>$1</s>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'quote' => [ |
||||||
|
'pattern' => '/\[quote\](.*?)\[\/quote\]/s', |
||||||
|
'replace' => '<blockquote>$1</blockquote>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'link' => [ |
||||||
|
'pattern' => '/\[url\](.*?)\[\/url\]/s', |
||||||
|
'replace' => '<a href="$1">$1</a>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'namedlink' => [ |
||||||
|
'pattern' => '/\[url\=(.*?)\](.*?)\[\/url\]/s', |
||||||
|
'replace' => '<a href="$1">$2</a>', |
||||||
|
'content' => '$2' |
||||||
|
], |
||||||
|
'image' => [ |
||||||
|
'pattern' => '/\[img\](.*?)\[\/img\]/s', |
||||||
|
'replace' => '<img src="$1">', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'orderedlistnumerical' => [ |
||||||
|
'pattern' => '/\[list=1\](.*?)\[\/list\]/s', |
||||||
|
'replace' => '<ol>$1</ol>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'orderedlistalpha' => [ |
||||||
|
'pattern' => '/\[list=a\](.*?)\[\/list\]/s', |
||||||
|
'replace' => '<ol type="a">$1</ol>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'unorderedlist' => [ |
||||||
|
'pattern' => '/\[list\](.*?)\[\/list\]/s', |
||||||
|
'replace' => '<ul>$1</ul>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'listitem' => [ |
||||||
|
'pattern' => '/\[\*\](.*)/', |
||||||
|
'replace' => '<li>$1</li>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'code' => [ |
||||||
|
'pattern' => '/\[code\](.*?)\[\/code\]/s', |
||||||
|
'replace' => '<code>$1</code>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'youtube' => [ |
||||||
|
'pattern' => '/\[youtube\](.*?)\[\/youtube\]/s', |
||||||
|
'replace' => '<iframe width="560" height="315" src="//www.youtube-nocookie.com/embed/$1" frameborder="0" allowfullscreen></iframe>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'sub' => [ |
||||||
|
'pattern' => '/\[sub\](.*?)\[\/sub\]/s', |
||||||
|
'replace' => '<sub>$1</sub>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'sup' => [ |
||||||
|
'pattern' => '/\[sup\](.*?)\[\/sup\]/s', |
||||||
|
'replace' => '<sup>$1</sup>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'small' => [ |
||||||
|
'pattern' => '/\[small\](.*?)\[\/small\]/s', |
||||||
|
'replace' => '<small>$1</small>', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'table' => [ |
||||||
|
'pattern' => '/\[table\](.*?)\[\/table\]/s', |
||||||
|
'replace' => '<table>$1</table>', |
||||||
|
'content' => '$1', |
||||||
|
], |
||||||
|
'table-row' => [ |
||||||
|
'pattern' => '/\[tr\](.*?)\[\/tr\]/s', |
||||||
|
'replace' => '<tr>$1</tr>', |
||||||
|
'content' => '$1', |
||||||
|
], |
||||||
|
'table-data' => [ |
||||||
|
'pattern' => '/\[td\](.*?)\[\/td\]/s', |
||||||
|
'replace' => '<td>$1</td>', |
||||||
|
'content' => '$1', |
||||||
|
], |
||||||
|
]; |
||||||
|
|
||||||
|
private function searchAndReplace(string $pattern, string $replace, string $source): string { |
||||||
|
while (preg_match($pattern, $source)) { |
||||||
|
$source = preg_replace($pattern, $replace, $source); |
||||||
|
} |
||||||
|
|
||||||
|
return $source; |
||||||
|
} |
||||||
|
|
||||||
|
public function stripTags(string $source): string { |
||||||
|
foreach ($this->parsers as $name => $parser) { |
||||||
|
$source = $this->searchAndReplace($parser['pattern'] . 'i', $parser['content'], $source); |
||||||
|
} |
||||||
|
|
||||||
|
return $source; |
||||||
|
} |
||||||
|
|
||||||
|
public function parse(string $source, $caseInsensitive = null): string { |
||||||
|
$caseInsensitive = $caseInsensitive === self::CASE_INSENSITIVE ? true : false; |
||||||
|
|
||||||
|
foreach ($this->parsers as $name => $parser) { |
||||||
|
$pattern = ($caseInsensitive) ? $parser['pattern'] . 'i' : $parser['pattern']; |
||||||
|
|
||||||
|
$source = $this->searchAndReplace($pattern, $parser['replace'], $source); |
||||||
|
} |
||||||
|
|
||||||
|
return $source; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,100 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts |
||||||
|
* @copyright Copyright (c) 2022, Robert Strutts. |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater\database; |
||||||
|
|
||||||
|
final class dummy_data { |
||||||
|
|
||||||
|
private $pdo; |
||||||
|
private $random_engine; |
||||||
|
|
||||||
|
public function __construct($pdo) { |
||||||
|
$this->pdo = $pdo; |
||||||
|
$this->random_engine = new \CodeHydrater\random_engine(); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Helper for add_dummy_data and get_dummy_data. |
||||||
|
* Purpose: To return ONE ROW of junk/dummy data from input data. |
||||||
|
* @param array $data |
||||||
|
* @retval array of random dummy data AKA one row worth of it. |
||||||
|
*/ |
||||||
|
|
||||||
|
private function use_dummy_data(array $data): array { |
||||||
|
$ret = []; |
||||||
|
foreach ($data as $field => $array_values) { |
||||||
|
$array_count = \CodeHydrater\common::get_count($array_values); |
||||||
|
if ($array_count) { |
||||||
|
$ret[$field] = $array_values[$this->random_engine->get_int(0, $array_count - 1)]; |
||||||
|
} |
||||||
|
} |
||||||
|
return $ret; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Inserts Dummy Data to DB |
||||||
|
* @param int $num_rows to add/make |
||||||
|
* @param array $data sample data EX: array('fname'=>array('bob','kim','lisa', ect...), ...) |
||||||
|
* @retval bool true |
||||||
|
*/ |
||||||
|
public function add_dummy_data(string $table, int $num_rows, array $data): bool { |
||||||
|
for ($i = 0; $i < $num_rows; $i++) { |
||||||
|
$bind_data = $this->use_dummy_data($data); |
||||||
|
$fields = []; |
||||||
|
foreach ($data as $field => $array_values) { |
||||||
|
$fields[] = $field; |
||||||
|
} |
||||||
|
|
||||||
|
$sql = "INSERT INTO `{$table}` " |
||||||
|
. "(" . implode(", ", $fields) . ") " |
||||||
|
. "VALUES (:" . implode(", :", $fields) . ");"; |
||||||
|
|
||||||
|
$bind = []; |
||||||
|
foreach ($fields as $field) { |
||||||
|
$bind[":$field"] = $bind_data[$field]; |
||||||
|
} |
||||||
|
unset($bind_data); |
||||||
|
unset($fields); |
||||||
|
|
||||||
|
$pdo_stmt = $this->pdo->prepare($sql); |
||||||
|
$exec = $pdo_stmt->execute($bind); |
||||||
|
unset($bind); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Make an array of fields for a fake row of dummy data out of input data. |
||||||
|
* @param int $num_rows to make |
||||||
|
* @param array $data sample data |
||||||
|
* @retval array of rows with dummy data in it. |
||||||
|
*/ |
||||||
|
public function get_dummy_data(int $num_rows, array $data): array { |
||||||
|
if ($num_rows > 100) { |
||||||
|
throw new \LengthException("Generating too much dummy data via \$num_rows!"); |
||||||
|
} |
||||||
|
$ret = []; |
||||||
|
for ($i = 0; $i < $num_rows; $i++) { |
||||||
|
$ret[] = $this->use_dummy_data($data); |
||||||
|
} |
||||||
|
return $ret; |
||||||
|
} |
||||||
|
|
||||||
|
public function get_dummy_data_generator( |
||||||
|
int $num_rows, |
||||||
|
array $data |
||||||
|
): \Generator { |
||||||
|
for ($i = 0; $i < $num_rows; $i++) { |
||||||
|
yield $this->use_dummy_data($data); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,357 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts <Robert@TryingToScale.com> |
||||||
|
* @copyright Copyright (c) 2022, Robert Strutts. |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater\database; |
||||||
|
|
||||||
|
use CodeHydrater\bootstrap\safer_io as SafeIO; |
||||||
|
|
||||||
|
class model { |
||||||
|
|
||||||
|
use \CodeHydrater\traits\database\run_sql; |
||||||
|
use \CodeHydrater\traits\database\validation; |
||||||
|
|
||||||
|
const successful_save = 1; |
||||||
|
const duplicate_found = 2; |
||||||
|
const validation_error = 3; |
||||||
|
const pre_save_failed = 4; |
||||||
|
const post_save_failed = 5; |
||||||
|
|
||||||
|
private $members = []; |
||||||
|
private $validation_members = []; |
||||||
|
private $missing = []; |
||||||
|
private $error_message; |
||||||
|
private $primary_key = 'id'; |
||||||
|
private $db_skiped = []; |
||||||
|
|
||||||
|
public function saved(bool $worked = true): bool { |
||||||
|
if (headers_sent()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
header("Content-Type: application/json; charset=UTF-8"); |
||||||
|
$time = \CodeHydrater\time_zones::convert_time_zone(array('format' => 'g:i a')); |
||||||
|
echo json_encode(['time' => $time, 'saved' => $worked]); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* JSON API inform AJAX that save failed |
||||||
|
*/ |
||||||
|
public function save_failed($msg = 'Save Failed!'): void { |
||||||
|
\CodeHydrater\api::error(array('code' => 500, 'success' => false, 'error' => $msg, 'responce' => \tts\api::INTERNAL_ERROR)); |
||||||
|
} |
||||||
|
|
||||||
|
public function dump_table_fields(string $table) { |
||||||
|
$fields = $this->get_fields($table); |
||||||
|
$this->do_dump($fields); |
||||||
|
} |
||||||
|
|
||||||
|
public function dump_diff(): bool { |
||||||
|
$fields = $this->get_fields($this->table); |
||||||
|
|
||||||
|
$diff = array_diff($fields, array_keys($this->members)); |
||||||
|
|
||||||
|
if (($key = array_search('id', $diff)) !== false) { |
||||||
|
unset($diff[$key]); // Who cares about IDs |
||||||
|
} |
||||||
|
|
||||||
|
foreach($this->db_skiped as $skip) { |
||||||
|
unset($diff[$skip]); |
||||||
|
} |
||||||
|
|
||||||
|
if (count($diff)) { |
||||||
|
echo "Diff on fields:<br>" . PHP_EOL; |
||||||
|
$this->do_dump($diff); |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
private function do_dump(array $data) { |
||||||
|
echo "<pre style=\"border: 1px solid #000; overflow: auto; margin: 0.5em;\">"; |
||||||
|
print_r($data); |
||||||
|
echo '</pre>'; |
||||||
|
} |
||||||
|
|
||||||
|
public function set_primary_key_name(string $key): void { |
||||||
|
$this->primary_key = $key; |
||||||
|
} |
||||||
|
|
||||||
|
public function set_members_by_generator(array $input): bool { |
||||||
|
$good = true; |
||||||
|
foreach(SafeIO::db_sanitize($input) as $data) { |
||||||
|
$key = $data['name'] ?? false; |
||||||
|
$value = $data['db'] ?? null; |
||||||
|
$error_count = (isset($data['errors'])) ? \CodeHydrater\bootstrap\common::get_count($data['errors']) : 0; |
||||||
|
if ($error_count) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if (isset($data['meta']['missing']) && \CodeHydrater\bootstrap\common::get_count($data['meta']['missing'])) { |
||||||
|
$this->missing = $data['meta']['missing']; |
||||||
|
} |
||||||
|
|
||||||
|
$meta = $data['meta'][$key] ?? false; |
||||||
|
if ($meta !== false) { |
||||||
|
$skip_db = $meta['skip_db'] ?? false; |
||||||
|
if ($skip_db === true) { |
||||||
|
$this->db_skiped[$key] = true; |
||||||
|
continue; // Skip Field |
||||||
|
} |
||||||
|
} |
||||||
|
if ($key !== false) { |
||||||
|
$this->members[$key] = $value; |
||||||
|
} else { |
||||||
|
$good = false; |
||||||
|
} |
||||||
|
} |
||||||
|
return $good; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Do not use this one in production! AS anyone can override |
||||||
|
* the DB security and Inject stuff into the DB via POST, etc... |
||||||
|
*/ |
||||||
|
public function auto_set_members(array $post = [], array $skip = ['route', 'm'], array $only_these = []): void { |
||||||
|
if (\CodeHydrater\bootstrap\is_live()) { |
||||||
|
return; // Bail if LIVE |
||||||
|
} |
||||||
|
if (isset($post['json'])) { |
||||||
|
$globals = \CodeHydrater\bootstrap\safer_io::get_json_post_data(); |
||||||
|
} else { |
||||||
|
$json_post = count($post); |
||||||
|
$globals = ($json_post) ? $post : filter_input_array(INPUT_POST) ?? []; |
||||||
|
} |
||||||
|
foreach ($globals as $key => $data) { |
||||||
|
if (count($skip) && in_array($key, $skip)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
if (in_array($key, $only_these) || !count($only_these)) { |
||||||
|
$this->members[$key] = (\CodeHydrater\misc::is_not_empty($data)) ? $data : ""; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public function get_missing() { |
||||||
|
return $this->missing; |
||||||
|
} |
||||||
|
|
||||||
|
public function get_member(string $member) { |
||||||
|
return $this->members[$member] ?? null; |
||||||
|
} |
||||||
|
|
||||||
|
public function get_members() { |
||||||
|
return $this->members; |
||||||
|
} |
||||||
|
|
||||||
|
public function set_member(string $member, string $data): void { |
||||||
|
$this->members[$member] = $data; |
||||||
|
} |
||||||
|
|
||||||
|
public function has_member($member): bool { |
||||||
|
return isset($this->members[$member]); |
||||||
|
} |
||||||
|
|
||||||
|
public function get_last_error(): string { |
||||||
|
return $this->error_message; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set Member for Validation |
||||||
|
* @param string $key |
||||||
|
* @param array $a |
||||||
|
*/ |
||||||
|
public function set_member_for_validation(string $key, array $a): void { |
||||||
|
$this->validation_members[$key] = $a; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get Validation Member |
||||||
|
* @param string $key |
||||||
|
* @return array |
||||||
|
*/ |
||||||
|
public function get_vaildation_member(string $key): array { |
||||||
|
return $this->validation_members[$key] ?? array(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Unset Validation Member |
||||||
|
* @param string $key |
||||||
|
*/ |
||||||
|
public function clear_validation_member(string $key): void { |
||||||
|
unset($this->validation_members[$key]); |
||||||
|
} |
||||||
|
|
||||||
|
private function cleanup($bind) { |
||||||
|
if (!is_array($bind)) { |
||||||
|
if (!empty($bind)) { |
||||||
|
$bind = array($bind); |
||||||
|
} else { |
||||||
|
$bind = array(); |
||||||
|
} |
||||||
|
} |
||||||
|
return $bind; |
||||||
|
} |
||||||
|
|
||||||
|
public static function empty_generator(): \Generator { |
||||||
|
yield from []; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Please use this fetch_lazy instead of fetch_all!!! |
||||||
|
* To AVOID running out of Memory!!!!!!!!!!!!!!!!!!!! |
||||||
|
* @param \PDOStatement $stmt |
||||||
|
* @return \Generator |
||||||
|
*/ |
||||||
|
public static function pdo_fetch_lazy(\PDOStatement $stmt): \Generator { |
||||||
|
foreach($stmt as $record) { |
||||||
|
yield $record; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static function is_valid(array $data): bool { |
||||||
|
$error_count = (isset($data['errors'])) ? count($data['errors']) : 0; |
||||||
|
return ($error_count === 0); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public function load(int $id): bool{ |
||||||
|
if (method_exists($this, 'pre_load')) { |
||||||
|
$this->pre_load(); |
||||||
|
} |
||||||
|
|
||||||
|
$sql = "SELECT * FROM {$this->table} WHERE {$this->primaryKey} = ?"; |
||||||
|
$query = $this->pdo->prepare($sql); |
||||||
|
$query->execute(array($id)); |
||||||
|
if ($query === false) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
$data = $query->fetch(\PDO::FETCH_ASSOC); |
||||||
|
if ($data === false) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
$this->members = array_merge($this->members, $data); |
||||||
|
|
||||||
|
if (method_exists($this, 'post_load')) { |
||||||
|
$this->post_load(); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public function insert($table, $info) { |
||||||
|
$fields = $this->filter($table, $info); |
||||||
|
|
||||||
|
if (strrpos($table, "`") === false) { |
||||||
|
$table = "`{$table}`"; |
||||||
|
} |
||||||
|
|
||||||
|
$sql = "INSERT INTO {$table} (" . implode(", ", $fields) . ") VALUES (:" . implode(", :", $fields) . ");"; |
||||||
|
$bind = array(); |
||||||
|
foreach ($fields as $field) { |
||||||
|
$bind[":$field"] = $info[$field]; |
||||||
|
} |
||||||
|
return $this->run($sql, $bind); |
||||||
|
} |
||||||
|
|
||||||
|
public function update($table, $info, $where, $bind = "") { |
||||||
|
$bind = $this->cleanup($bind); |
||||||
|
$fields = $this->filter($table, $info); |
||||||
|
|
||||||
|
if (strrpos($table, "`") === false) { |
||||||
|
$table = "`{$table}`"; |
||||||
|
} |
||||||
|
|
||||||
|
$sql = "UPDATE {$table} SET "; |
||||||
|
$f = 0; |
||||||
|
|
||||||
|
foreach ($fields as $key => $value) { |
||||||
|
if ($f > 0) { |
||||||
|
$sql .= ", "; |
||||||
|
} |
||||||
|
$f++; |
||||||
|
|
||||||
|
$value = trim($value); |
||||||
|
|
||||||
|
if (strrpos($value, "`") === false) { |
||||||
|
$cf = '`' . $value . '`'; |
||||||
|
} else { |
||||||
|
$cf = $value; |
||||||
|
} |
||||||
|
|
||||||
|
$sql .= $cf . " = :update_" . $value; |
||||||
|
$bind[":update_$value"] = $info[$value]; |
||||||
|
} |
||||||
|
|
||||||
|
$sql .= " WHERE " . $where . ";"; |
||||||
|
|
||||||
|
return $this->run($sql, $bind); |
||||||
|
} |
||||||
|
|
||||||
|
public static function make_db_time_stamp(): string { |
||||||
|
return \CodeHydrater\time_zones::convert_time_zone(['format' => 'database', 'timezone' => 'UTC']); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Save |
||||||
|
* |
||||||
|
* @param object $lcoal_model Should be $this from the Model |
||||||
|
* |
||||||
|
* Insert if primary key not set |
||||||
|
* Update if primary key set |
||||||
|
*/ |
||||||
|
public function save(bool $validate = true): int { |
||||||
|
if (method_exists($this, 'pre_save')) { |
||||||
|
$pre_was_successfull = $this->pre_save(); |
||||||
|
if (! $pre_was_successfull) { |
||||||
|
return self::pre_save_failed; |
||||||
|
} |
||||||
|
} |
||||||
|
$name = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME); // Get DB Driver |
||||||
|
if ($name === 'mysql' && $validate) { |
||||||
|
if (!$this->validate_mysql()) { |
||||||
|
return self::validation_error; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if ($this->has_member('modified')) { |
||||||
|
$this->set_member('modified', self::make_db_time_stamp()); |
||||||
|
} |
||||||
|
|
||||||
|
if (empty($this->members[$this->primary_key])) { |
||||||
|
if (method_exists($this, 'duplicate_check')) { |
||||||
|
$dup = $this->duplicate_check(); |
||||||
|
if ($dup) { |
||||||
|
return self::duplicate_found; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if ($this->has_member('created')) { |
||||||
|
$this->set_member('created', self::make_db_time_stamp()); |
||||||
|
} |
||||||
|
|
||||||
|
$this->members[$this->primary_key] = $this->insert($this->table, $this->members); |
||||||
|
} else { |
||||||
|
$this->set_member("row_count", $this->update($this->table, $this->members, |
||||||
|
"`{$this->primary_key}` = :search_key", |
||||||
|
array(':search_key' => $this->members[$this->primary_key]) |
||||||
|
)); |
||||||
|
} |
||||||
|
|
||||||
|
if (method_exists($this, 'post_save')) { |
||||||
|
$post_save_successfull = $this->post_save(); |
||||||
|
if (! $post_save_successfull) { |
||||||
|
return self::post_save_failed; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return self::successful_save; |
||||||
|
} |
||||||
|
|
||||||
|
/* End Model */ |
||||||
|
} |
||||||
@ -0,0 +1,255 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* Modified from: |
||||||
|
* @link https://code.tutsplus.com/tutorials/how-to-paginate-data-with-php--net-2928 |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace tts\database; |
||||||
|
|
||||||
|
class paginate { |
||||||
|
|
||||||
|
private $_conn; |
||||||
|
private int $_limit; |
||||||
|
private int $_page; |
||||||
|
private $_query; |
||||||
|
private $_total; |
||||||
|
private $_url; |
||||||
|
private $_url_limit; |
||||||
|
private $_url_page; |
||||||
|
public $max_limit = 500; |
||||||
|
|
||||||
|
/* |
||||||
|
* Query needs to be string for MySQL and array for MonogDB |
||||||
|
*/ |
||||||
|
public function __construct($conn, string|array $query, string $db_type = "mysql") { |
||||||
|
$this->_conn = $conn; |
||||||
|
$this->_query = $query; |
||||||
|
|
||||||
|
if ($db_type === "mysql") { |
||||||
|
$rs = $this->_conn->query($this->_query); |
||||||
|
$this->_total = $rs->rowCount(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private function set_limit(int $limit = 10): int { |
||||||
|
if ($limit < 1) { |
||||||
|
return 10; |
||||||
|
} |
||||||
|
return ($limit > $this->max_limit) ? $this->max_limit : $limit; |
||||||
|
} |
||||||
|
|
||||||
|
public function mongo_get_data(int $limit = 10, int $page = 1, array $options = []) { |
||||||
|
$this->_limit = $this->set_limit($limit); // Number of items per page |
||||||
|
$this->_page = $page; // The current page number |
||||||
|
|
||||||
|
$skip = (( $this->_page - 1 ) * $this->_limit ); |
||||||
|
|
||||||
|
if ($this->_limit === 0) { |
||||||
|
$db_options = $options; |
||||||
|
} else { |
||||||
|
$limits = ['limit' => $this->_limit, 'skip' => $skip]; |
||||||
|
$db_options = array_merge($limits, $options); |
||||||
|
} |
||||||
|
|
||||||
|
// NOTE _query is the WHERE condition as an array |
||||||
|
$collection = $this->_conn; |
||||||
|
$documents = $collection->find($this->_query, $db_options); |
||||||
|
|
||||||
|
// Calculate the total number of documents in the collection |
||||||
|
$this->_total = $collection->countDocuments($this->_query); |
||||||
|
|
||||||
|
$result = new \stdClass(); |
||||||
|
$result->page = $this->_page; |
||||||
|
$result->limit = $this->_limit; |
||||||
|
$result->total = $this->_total; |
||||||
|
$result->data = $documents; |
||||||
|
|
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
public function get_data(int $limit = 10, int $page = 1) { |
||||||
|
$this->_limit = $this->set_limit($limit); |
||||||
|
$this->_page = $page; |
||||||
|
|
||||||
|
if ($this->_limit === 0) { |
||||||
|
$query = $this->_query; |
||||||
|
} else { |
||||||
|
$query = $this->_query . " LIMIT " . ( ( $this->_page - 1 ) * $this->_limit ) . ", $this->_limit"; |
||||||
|
} |
||||||
|
$rs = $this->_conn->query($query); |
||||||
|
|
||||||
|
$results = []; |
||||||
|
while ($row = $rs->fetch(\PDO::FETCH_ASSOC)) { |
||||||
|
$results[] = $row; |
||||||
|
} |
||||||
|
|
||||||
|
$result = new \stdClass(); |
||||||
|
$result->page = $this->_page; |
||||||
|
$result->limit = $this->_limit; |
||||||
|
$result->total = $this->_total; |
||||||
|
$result->data = $results; |
||||||
|
|
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
public function use_hash_routes(string $url): void { |
||||||
|
$this->_url = $url; |
||||||
|
$this->_url_limit = "/"; |
||||||
|
$this->_url_page = "/"; |
||||||
|
} |
||||||
|
|
||||||
|
public function use_get_routes(string $url = ""): void { |
||||||
|
$this->_url = $url; |
||||||
|
$this->_url_limit = "?limit="; |
||||||
|
$this->_url_page = "&page="; |
||||||
|
} |
||||||
|
|
||||||
|
private function do_href(int $limit, int $page): string { |
||||||
|
return 'href="' . $this->_url . $this->_url_limit . $limit . $this->_url_page . $page . '"'; |
||||||
|
} |
||||||
|
|
||||||
|
public function create_links(int $links = 7, string $list_class = "ui pagination menu", string $item = "item") { |
||||||
|
$last = ceil($this->_total / $this->_limit); |
||||||
|
|
||||||
|
if ($this->_limit === 0 || $last < 2) { |
||||||
|
return ''; |
||||||
|
} |
||||||
|
|
||||||
|
$start = ( ( $this->_page - $links ) > 0 ) ? $this->_page - $links : 1; |
||||||
|
$end = ( ( $this->_page + $links ) < $last ) ? $this->_page + $links : $last; |
||||||
|
|
||||||
|
$html = '<div class="' . $list_class . '">'; |
||||||
|
|
||||||
|
$class = ( $this->_page == 1 ) ? "disabled " : ""; |
||||||
|
$item = " " . $item; |
||||||
|
|
||||||
|
$html .= '<a class="' . $class . $item . '" ' . $this->do_href($this->_limit, $this->_page - 1) . '>«</a>'; |
||||||
|
|
||||||
|
if ($start > 1) { |
||||||
|
$html .= '<a class="' . $item . '" ' . $this->do_href($this->_limit, 1) .'>1</a>'; |
||||||
|
$html .= '<div class="disabled' . $item . '"><span>...</span></div>'; |
||||||
|
} |
||||||
|
|
||||||
|
for ($i = $start; $i <= $end; $i++) { |
||||||
|
$class = ( $this->_page == $i ) ? "active" : ""; |
||||||
|
$html .= '<a class="' . $class . $item . '" ' . $this->do_href($this->_limit, $i) . '>' . $i . '</a>'; |
||||||
|
} |
||||||
|
|
||||||
|
if ($end < $last) { |
||||||
|
$html .= '<div class="disabled' . $item . '"><span>...</span></div>'; |
||||||
|
$html .= '<a class="' . $class . $item . '" ' . $this->do_href($this->_limit, $last) . '>' . $last . '</a>'; |
||||||
|
} |
||||||
|
|
||||||
|
$class = ( $this->_page == $last ) ? "disabled" : ""; |
||||||
|
$html .= '<a class="' . $class . $item . '" ' . $this->do_href($this->_limit, $this->_page + 1) . '>»</a>'; |
||||||
|
|
||||||
|
$html .= '</div>'; |
||||||
|
|
||||||
|
return $html; |
||||||
|
} |
||||||
|
|
||||||
|
public function create_jump_menu_with_links(int $links = 7, string $label = "Jump to ", string $end_label = " page.", string $item = "item"): string { |
||||||
|
if ($this->_limit === 0) { |
||||||
|
return ''; |
||||||
|
} |
||||||
|
|
||||||
|
$last = ceil($this->_total / $this->_limit); |
||||||
|
|
||||||
|
$start = ( ( $this->_page - $links ) > 0 ) ? $this->_page - $links : 1; |
||||||
|
$end = ( ( $this->_page + $links ) < $last ) ? $this->_page + $links : $last; |
||||||
|
|
||||||
|
// Prev. Page |
||||||
|
$class = ( $this->_page == 1 ) ? "disabled" : ""; |
||||||
|
$href = ( $this->_page == 1 ) ? "" : $this->do_href($this->_limit, $this->_page - 1 ); |
||||||
|
$html .= '<a class="' . $class . ' item" ' . $href . '>«</a>'; |
||||||
|
|
||||||
|
$html .= $this->create_jump_menu(); |
||||||
|
|
||||||
|
// Next Page |
||||||
|
$class = ( $this->_page == $last ) ? "disabled" : ""; |
||||||
|
$href = ( $this->_page == $last ) ? "" : $this->do_href($this->_limit, $this->_page + 1 ); |
||||||
|
$html .= '<a class="' . $class . ' item" ' . $href . '>»</a>'; |
||||||
|
|
||||||
|
return $html; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public function create_jump_menu(string $label = "Jump to ", string $end_label = " page.", string $item = "item"): string { |
||||||
|
$last = ceil($this->_total / $this->_limit); |
||||||
|
$option = ''; |
||||||
|
for($i=1; $i <= $last; $i++) { |
||||||
|
$option .= ($i == $this->_page) ? "<option value=\"{$i}\" selected>Page {$i}</option>\n":"<option value=\"{$i}\">Page {$i}</option>\n"; |
||||||
|
} |
||||||
|
return "<label>{$label}<select class=\"{$item}\" onchange=\"window.location='". $this->_url . $this->_url_limit . $this->_limit . $this->_url_page . "'+this[this.selectedIndex].value;return false;\">" |
||||||
|
. "{$option}</select>" |
||||||
|
. "{$end_label}</label>\n"; |
||||||
|
} |
||||||
|
|
||||||
|
public function create_items_per_page(string $label = "Items ", string $end_label = " per page.", string $item = "item"): string { |
||||||
|
$items = ''; |
||||||
|
$ipp_array = array(3,6,12,24,50,100); |
||||||
|
$found = false; |
||||||
|
foreach($ipp_array as $ipp_opt) { |
||||||
|
if ($ipp_opt == $this->_limit) { |
||||||
|
$found = true; |
||||||
|
} |
||||||
|
$items .= ($ipp_opt == $this->_limit) ? "<option selected value=\"{$ipp_opt}\">{$ipp_opt}</option>\n" : "<option value=\"{$ipp_opt}\">{$ipp_opt}</option>\n"; |
||||||
|
} |
||||||
|
|
||||||
|
if ($found === false) { |
||||||
|
$items = "<option selected value=\"{$this->_limit}\">{$this->_limit}</option>\n" . $items; |
||||||
|
} |
||||||
|
|
||||||
|
$my_page = str_replace("&", "?", $this->_url_page); |
||||||
|
$my_limit = str_replace("?", "&", $this->_url_limit); |
||||||
|
|
||||||
|
return "<label>{$label}<select class=\"{$item}\" onchange=\"window.location='". $my_page . "1" . $my_limit . "'+this[this.selectedIndex].value;return false;\">{$items}</select>" |
||||||
|
. "{$end_label}</label>\n"; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* mongo db |
||||||
|
$limit = $_GET['limit'] ?? 18; |
||||||
|
$page = $_GET['page'] ?? 1; |
||||||
|
$url = "#pages/bill"; |
||||||
|
$query = [ 'user_id' => (string) $user_id ]; |
||||||
|
$mongo_options = [ 'projection' => [ 'billing' => 1 ]]; |
||||||
|
|
||||||
|
$pag = new paginate($collection, $query, "mongodb"); |
||||||
|
$r = $pag->mongo_get_data($limit, $page, $mongo_options); |
||||||
|
$pag->use_hash_routes($url); |
||||||
|
|
||||||
|
foreach ($r->data as $bill) { |
||||||
|
echo $bill; |
||||||
|
} |
||||||
|
|
||||||
|
echo $pag->create_links(); |
||||||
|
*/ |
||||||
|
|
||||||
|
|
||||||
|
/* |
||||||
|
* css |
||||||
|
* |
||||||
|
.pagination { |
||||||
|
display: inline-block; |
||||||
|
} |
||||||
|
|
||||||
|
.pagination a { |
||||||
|
color: black; |
||||||
|
float: left; |
||||||
|
padding: 8px 16px; |
||||||
|
text-decoration: none; |
||||||
|
} |
||||||
|
|
||||||
|
.pagination a.active { |
||||||
|
background-color: #4CAF50; |
||||||
|
color: white; |
||||||
|
} |
||||||
|
|
||||||
|
.pagination a:hover:not(.active) {background-color: #ddd;} |
||||||
|
*/ |
||||||
@ -0,0 +1,30 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts <Bob_586@Yahoo.com> |
||||||
|
* @copyright (c) 2025, Robert Strutts |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
use HydraterBootloader\LicenseVerifier; |
||||||
|
|
||||||
|
const PublicPEM = BaseDir."/keydata/public.pem"; |
||||||
|
const AESKeysFile = BaseDir."/src/aeskeys.php"; |
||||||
|
const LicenseFile = BaseDir."/keydata/license.json"; |
||||||
|
|
||||||
|
class extras_booter { |
||||||
|
public static function tryToEnableFeature(string $featureName) { |
||||||
|
|
||||||
|
if (! class_exists("HydraterBootloader\LicenseVerifier")) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
$verifier = new LicenseVerifier(); |
||||||
|
return $verifier->tryEnabledItem(LicenseFile, AESKeysFile, $featureName, PublicPEM); |
||||||
|
} |
||||||
|
} |
||||||
|
// tryToEnableFeature("testing"); |
||||||
@ -0,0 +1,427 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts |
||||||
|
* @copyright Copyright (c) 2022, Robert Strutts. |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
/** |
||||||
|
* HTML Document |
||||||
|
*/ |
||||||
|
class html_document { |
||||||
|
private $title = ''; |
||||||
|
private $author = ''; |
||||||
|
private $description = ''; |
||||||
|
private $keywords = ''; |
||||||
|
private $robots = ''; |
||||||
|
private $head = ''; |
||||||
|
private $header = ''; |
||||||
|
private $body = ''; |
||||||
|
private $footer = ''; |
||||||
|
private $js_onready = ''; |
||||||
|
private $styles = ''; |
||||||
|
private $scripts = ''; |
||||||
|
private $main_styles = ''; |
||||||
|
private $main_scripts = ''; |
||||||
|
private $active_crumb = ''; |
||||||
|
private $breadcrumb = array(); |
||||||
|
|
||||||
|
public function __construct() { |
||||||
|
$this->title = bootstrap\configure::get('html', 'title') ?? ''; |
||||||
|
$this->author = bootstrap\configure::get('html', 'author') ?? ''; |
||||||
|
$this->keywords = bootstrap\configure::get('html', 'keywords') ?? ''; |
||||||
|
$this->description = bootstrap\configure::get('html', 'description') ?? ''; |
||||||
|
$this->robots = bootstrap\configure::get('html', 'robots'); |
||||||
|
$css = bootstrap\configure::get('html', 'css'); |
||||||
|
if (bootstrap\common::get_count($css) > 0) { |
||||||
|
foreach($css as $file=>$path) { |
||||||
|
if (is_array($file)) continue; |
||||||
|
if (is_array($path)) { |
||||||
|
if (isset($path['path'])) { |
||||||
|
$path_type = $path['path']; |
||||||
|
unset($path['path']); |
||||||
|
} else { |
||||||
|
$path_type = "project"; |
||||||
|
} |
||||||
|
$this->add_css($file, $path_type, $path); |
||||||
|
} else { |
||||||
|
$this->add_css($file, $path); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
$js = bootstrap\configure::get('html', 'javascript'); |
||||||
|
if (bootstrap\common::get_count($js) >0) { |
||||||
|
foreach($js as $file=>$path) { |
||||||
|
if (is_array($file)) continue; |
||||||
|
if (is_array($path)) { |
||||||
|
if (isset($path['path'])) { |
||||||
|
$path_type = $path['path']; |
||||||
|
unset($path['path']); |
||||||
|
} else { |
||||||
|
$path_type = "project"; |
||||||
|
} |
||||||
|
$this->add_js($file, $path_type, $path); |
||||||
|
} else { |
||||||
|
$this->add_js($file, $path); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public function clear_css(): void { |
||||||
|
$this->styles = ''; |
||||||
|
} |
||||||
|
|
||||||
|
public function clear_js(): void { |
||||||
|
$this->scripts = ''; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set both Title and Header for HTML |
||||||
|
* @param string $title |
||||||
|
*/ |
||||||
|
public function set_title_and_header(string $title): void { |
||||||
|
$this->title = $title; |
||||||
|
$this->header = $title; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set Author for HTML |
||||||
|
* @param string $title |
||||||
|
*/ |
||||||
|
public function set_author(string $author): void { |
||||||
|
$this->author = $author; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set Title for HTML |
||||||
|
* @param string $title |
||||||
|
*/ |
||||||
|
public function set_title(string $title): void { |
||||||
|
$this->title = $title; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set Header for HTML |
||||||
|
* @param string $header |
||||||
|
*/ |
||||||
|
public function set_header(string $header): void { |
||||||
|
$this->header = $header; |
||||||
|
} |
||||||
|
|
||||||
|
public function set_head(string $head): void { |
||||||
|
$this->head = $head; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set Footer for HTML |
||||||
|
* @param string $footer |
||||||
|
*/ |
||||||
|
public function set_footer(string $footer): void { |
||||||
|
// $this->add_css('footer.css', 'project'); |
||||||
|
$this->footer = $footer; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set Description for HTML |
||||||
|
* @param string $description |
||||||
|
*/ |
||||||
|
public function set_description(string $description): void { |
||||||
|
$this->description = $description; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set Keywords for HTML |
||||||
|
* @param string $keywords |
||||||
|
*/ |
||||||
|
public function set_keywords(string $keywords): void { |
||||||
|
$this->keywords = $keywords; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set Robots for HTML |
||||||
|
* @param string $robot |
||||||
|
*/ |
||||||
|
public function set_robots(string $robot): void { |
||||||
|
$this->robots = $robot; |
||||||
|
} |
||||||
|
|
||||||
|
public function set_body(string $body): void { |
||||||
|
$this->body = $body; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set Active BreadCrumb in HTML |
||||||
|
* @param string $active |
||||||
|
*/ |
||||||
|
public function set_active_crumb(string $active): void { |
||||||
|
$this->active_crumb = $active; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set BreadCrumbs using array (HyperLink => Name of Crumb) |
||||||
|
* @param array $crumbs Array(href => name) |
||||||
|
*/ |
||||||
|
public function set_breadcrumbs(array $crumbs): void { |
||||||
|
$this->breadcrumb = $crumbs; |
||||||
|
} |
||||||
|
|
||||||
|
public function set_assets_from_array(array $files, string $which, string $scope = 'project'): void { |
||||||
|
foreach($files as $file => $a) { |
||||||
|
switch($which) { |
||||||
|
case 'main_css': |
||||||
|
$this->add_main_css($file, $scope, $a); |
||||||
|
break; |
||||||
|
case 'css': |
||||||
|
$this->add_css($file, $scope, $a); |
||||||
|
break; |
||||||
|
case 'main_js': |
||||||
|
$this->add_main_js($file, $scope, $a); |
||||||
|
break; |
||||||
|
case 'js': |
||||||
|
$this->add_js($file, $scope, $a); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private function missing_file(string $file, string $scope, string $kind) { |
||||||
|
$failed = strtoupper($kind) . " filename of {$file} - {$scope} Asset Failed to Load!"; |
||||||
|
$this->add_to_javascript("console.log(\"%c {$failed}\", \"color: red\")"); |
||||||
|
$comment = "<!-- {$failed} -->"; |
||||||
|
if ($kind === "css") { |
||||||
|
$this->styles .= $comment; |
||||||
|
} else if ($kind === "main_css") { |
||||||
|
$this->main_styles .= $comment; |
||||||
|
} else if ($kind === "js") { |
||||||
|
$this->scripts .= $comment; |
||||||
|
} else if ($kind === "main_js") { |
||||||
|
$this->main_scripts .= $comment; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add CSS stylesheet to HTML under main CSS |
||||||
|
* @param string $file |
||||||
|
* @param string $scope (project, framework, cdn) |
||||||
|
* @return bool was successful |
||||||
|
*/ |
||||||
|
public function add_css(string $file, string $scope = 'project', array $a = array()): bool { |
||||||
|
$css = assets::wrap_asset($file, $scope); |
||||||
|
if ($css === false) { |
||||||
|
$this->missing_file($file, $scope, "css"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
$this->styles .= assets::wrap_css($file, $scope, $a); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add JS JavaScript to HTML under main JS |
||||||
|
* @param string $file |
||||||
|
* @param string $scope (project, framework, cdn) |
||||||
|
* @return bool was successful |
||||||
|
*/ |
||||||
|
public function add_js(string $file, string $scope = 'project', array $a = array()): bool { |
||||||
|
$js = assets::wrap_asset($file, $scope); |
||||||
|
if ($js === false) { |
||||||
|
$this->js_log($file . " - {$scope} Asset Failed to Load!"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
$this->scripts .= assets::wrap_js($file, $scope, $a); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add CSS stylesheet to HTML towards top of HTML for CSS |
||||||
|
* @param string $file |
||||||
|
* @param string $scope (project, framework, cdn) |
||||||
|
* @return bool was successful |
||||||
|
*/ |
||||||
|
public function add_main_css(string $file, string $scope = 'project', array $a = array()): bool { |
||||||
|
$css = assets::wrap_asset($file, $scope); |
||||||
|
if ($css === false) { |
||||||
|
$this->js_log($file . " - {$scope} Asset Failed to Load!"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
$this->main_styles .= assets::wrap_css($file, $scope, $a); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add JavaScript to HTML towards top of HTML for JS |
||||||
|
* @param string $file |
||||||
|
* @param string $scope (project, framework, cdn) |
||||||
|
* @return bool was successful |
||||||
|
*/ |
||||||
|
public function add_main_js(string $file, string $scope = 'project', array $a = array()): bool { |
||||||
|
$js = assets::wrap_asset($file, $scope); |
||||||
|
if ($js === false) { |
||||||
|
$this->js_log($file . " - {$scope} Asset Failed to Load!"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
$this->main_scripts .= assets::wrap_js($file, $scope, $a); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds JavaScript code to called after JQuery is ready. |
||||||
|
* @param string $code |
||||||
|
*/ |
||||||
|
//public function add_js_onready(string $code): void { |
||||||
|
// $this->js_onready .= \px_inline_js(\px_jquery_load($code)); |
||||||
|
//} |
||||||
|
|
||||||
|
/** |
||||||
|
* Log to JavaScript Console under Chrome Browser |
||||||
|
* @param string $log |
||||||
|
*/ |
||||||
|
public function js_log(string $log): void { |
||||||
|
$this->add_to_javascript("console.log('{$log}');"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Place JavaScript in HTML |
||||||
|
* @param string $js |
||||||
|
*/ |
||||||
|
public function add_to_javascript(string $js): void { |
||||||
|
if (! empty($js)) { |
||||||
|
$this->scripts .= assets::inline_js($js); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Use CSS/JS for Database SSP |
||||||
|
public function datatables_code(): void { |
||||||
|
$this->add_css('datatables/datatables.min.css', 'cl'); |
||||||
|
$this->add_js('datatables/datatables_no_jquery.min.js', 'cl'); |
||||||
|
} |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Used by Template file to render HTML Author |
||||||
|
* @return string HTML Author |
||||||
|
*/ |
||||||
|
public function get_author(): string { |
||||||
|
return $this->author; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used by Template file to render HTML TITLE |
||||||
|
* @return string HTML TITLE |
||||||
|
*/ |
||||||
|
public function get_title(): string { |
||||||
|
return $this->title; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used by Template file to render HTML Header |
||||||
|
* @return string HTML Header |
||||||
|
*/ |
||||||
|
public function get_header(): string { |
||||||
|
return $this->header; |
||||||
|
} |
||||||
|
|
||||||
|
public function get_body(): string { |
||||||
|
return $this->body; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used by Template file to render HTML Footer |
||||||
|
* @return string HTML Footer |
||||||
|
*/ |
||||||
|
public function get_footer(): string { |
||||||
|
return $this->footer; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used by Template file to render HTML Meta data for Description |
||||||
|
* @return string HTML Meta Description |
||||||
|
*/ |
||||||
|
public function get_description(): string { |
||||||
|
return $this->description; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used by Template file to render HTML Meta data for Keywords |
||||||
|
* @return string HTML Meta Keywords |
||||||
|
*/ |
||||||
|
public function get_keywords(): string { |
||||||
|
return $this->keywords; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used by Template file to render HTML Meta data for Robots |
||||||
|
* @return string HTML Meta Robots |
||||||
|
*/ |
||||||
|
public function get_robots(): string { |
||||||
|
return $this->robots; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used by Template file to render HTML CSS |
||||||
|
* @return string HTML CSS |
||||||
|
*/ |
||||||
|
public function get_styles(): string { |
||||||
|
return $this->styles; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used by Template file to render HTML JavaScripts |
||||||
|
* @return string HTML JS |
||||||
|
*/ |
||||||
|
public function get_scripts(): string { |
||||||
|
return $this->scripts; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used by Template file to render HTML main CSS @Top |
||||||
|
* @return string HTML CSS |
||||||
|
*/ |
||||||
|
public function get_main_styles(): string { |
||||||
|
return $this->main_styles; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used by Template file to render HTML main JS @Top |
||||||
|
* @return string HTML JavaScript |
||||||
|
*/ |
||||||
|
public function get_main_scripts(): string { |
||||||
|
return $this->main_scripts; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used by Template file to render HTML JS after main JS |
||||||
|
* @return string HTML JS |
||||||
|
*/ |
||||||
|
public function get_js_onready(): string { |
||||||
|
return $this->js_onready; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used by Template file to render HTML Active BreadCrumb |
||||||
|
* @return string HTML Active BreadCrumb |
||||||
|
*/ |
||||||
|
public function get_active_crumb(): string { |
||||||
|
return $this->active_crumb; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used by Template file to render HTML BreadCrumbs |
||||||
|
* @return string HTML BreadCrumbs |
||||||
|
*/ |
||||||
|
public function get_breadcrumbs(): array { |
||||||
|
return $this->breadcrumb; |
||||||
|
} |
||||||
|
|
||||||
|
public function get_head(): string { |
||||||
|
return $this->head; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,174 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @link https://github.com/genert/bbcode/blob/master/src/Parser/HTMLParser.php |
||||||
|
* @license The MIT License (MIT) |
||||||
|
* @copyright (c) Genert 2017 - present. |
||||||
|
* |
||||||
|
* Take HTML 2 BB code .. to save into db |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
final class html_parser { |
||||||
|
protected $parsers = [ |
||||||
|
'h1' => [ |
||||||
|
'pattern' => '/<h1>(.*?)<\/h1>/s', |
||||||
|
'replace' => '[h1]$1[/h1]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'h2' => [ |
||||||
|
'pattern' => '/<h2>(.*?)<\/h2>/s', |
||||||
|
'replace' => '[h2]$1[/h2]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'h3' => [ |
||||||
|
'pattern' => '/<h3>(.*?)<\/h3>/s', |
||||||
|
'replace' => '[h3]$1[/h3]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'h4' => [ |
||||||
|
'pattern' => '/<h4>(.*?)<\/h4>/s', |
||||||
|
'replace' => '[h4]$1[/h4]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'h5' => [ |
||||||
|
'pattern' => '/<h5>(.*?)<\/h5>/s', |
||||||
|
'replace' => '[h5]$1[/h5]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'h6' => [ |
||||||
|
'pattern' => '/<h6>(.*?)<\/h6>/s', |
||||||
|
'replace' => '[h6]$1[/h6]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'bold' => [ |
||||||
|
'pattern' => '/<b>(.*?)<\/b>/s', |
||||||
|
'replace' => '[b]$1[/b]', |
||||||
|
'content' => '$1', |
||||||
|
], |
||||||
|
'strong' => [ |
||||||
|
'pattern' => '/<strong>(.*?)<\/strong>/s', |
||||||
|
'replace' => '[b]$1[/b]', |
||||||
|
'content' => '$1', |
||||||
|
], |
||||||
|
'italic' => [ |
||||||
|
'pattern' => '/<i>(.*?)<\/i>/s', |
||||||
|
'replace' => '[i]$1[/i]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'em' => [ |
||||||
|
'pattern' => '/<em>(.*?)<\/em>/s', |
||||||
|
'replace' => '[i]$1[/i]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'underline' => [ |
||||||
|
'pattern' => '/<u>(.*?)<\/u>/s', |
||||||
|
'replace' => '[u]$1[/u]', |
||||||
|
'content' => '$1', |
||||||
|
], |
||||||
|
'strikethrough' => [ |
||||||
|
'pattern' => '/<s>(.*?)<\/s>/s', |
||||||
|
'replace' => '[s]$1[/s]', |
||||||
|
'content' => '$1', |
||||||
|
], |
||||||
|
'del' => [ |
||||||
|
'pattern' => '/<del>(.*?)<\/del>/s', |
||||||
|
'replace' => '[s]$1[/s]', |
||||||
|
'content' => '$1', |
||||||
|
], |
||||||
|
'code' => [ |
||||||
|
'pattern' => '/<code>(.*?)<\/code>/s', |
||||||
|
'replace' => '[code]$1[/code]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'orderedlistnumerical' => [ |
||||||
|
'pattern' => '/<ol>(.*?)<\/ol>/s', |
||||||
|
'replace' => '[list=1]$1[/list]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'unorderedlist' => [ |
||||||
|
'pattern' => '/<ul>(.*?)<\/ul>/s', |
||||||
|
'replace' => '[list]$1[/list]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'listitem' => [ |
||||||
|
'pattern' => '/<li>(.*?)<\/li>/s', |
||||||
|
'replace' => '[*]$1', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'link' => [ |
||||||
|
'pattern' => '/<a href="(.*?)">(.*?)<\/a>/s', |
||||||
|
'replace' => '[url=$1]$2[/url]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'quote' => [ |
||||||
|
'pattern' => '/<blockquote>(.*?)<\/blockquote>/s', |
||||||
|
'replace' => '[quote]$1[/quote]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'image' => [ |
||||||
|
'pattern' => '/<img src="(.*?)">/s', |
||||||
|
'replace' => '[img]$1[/img]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'youtube' => [ |
||||||
|
'pattern' => '/<iframe width="560" height="315" src="\/\/www\.youtube\.com\/embed\/(.*?)" frameborder="0" allowfullscreen><\/iframe>/s', |
||||||
|
'replace' => '[youtube]$1[/youtube]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'linebreak' => [ |
||||||
|
'pattern' => '/<br\s*\/?>/', |
||||||
|
'replace' => '/\r\n/', |
||||||
|
'content' => '', |
||||||
|
], |
||||||
|
'sub' => [ |
||||||
|
'pattern' => '/<sub>(.*?)<\/sub>/s', |
||||||
|
'replace' => '[sub]$1[/sub]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'sup' => [ |
||||||
|
'pattern' => '/<sup>(.*?)<\/sup>/s', |
||||||
|
'replace' => '[sup]$1[/sup]', |
||||||
|
'content' => '$1' |
||||||
|
], |
||||||
|
'small' => [ |
||||||
|
'pattern' => '/<small>(.*?)<\/small>/s', |
||||||
|
'replace' => '[small]$1[/small]', |
||||||
|
'content' => '$1', |
||||||
|
], |
||||||
|
'table' => [ |
||||||
|
'pattern' => '/<table>(.*?)<\/table>/s', |
||||||
|
'replace' => '[table]$1[/table]', |
||||||
|
'content' => '$1', |
||||||
|
], |
||||||
|
'table-row' => [ |
||||||
|
'pattern' => '/<tr>(.*?)<\/tr>/s', |
||||||
|
'replace' => '[tr]$1[/tr]', |
||||||
|
'content' => '$1', |
||||||
|
], |
||||||
|
'table-data' => [ |
||||||
|
'pattern' => '/<td>(.*?)<\/td>/s', |
||||||
|
'replace' => '[td]$1[/td]', |
||||||
|
'content' => '$1', |
||||||
|
], |
||||||
|
]; |
||||||
|
|
||||||
|
private function searchAndReplace(string $pattern, string $replace, string $source): string { |
||||||
|
while (preg_match($pattern, $source)) { |
||||||
|
$source = preg_replace($pattern, $replace, $source); |
||||||
|
} |
||||||
|
|
||||||
|
return $source; |
||||||
|
} |
||||||
|
|
||||||
|
public function parse(string $source): string { |
||||||
|
foreach ($this->parsers as $name => $parser) { |
||||||
|
$source = $this->searchAndReplace($parser['pattern'], $parser['replace'], $source); |
||||||
|
} |
||||||
|
|
||||||
|
return $source; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,44 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts <Bob_586@Yahoo.com> |
||||||
|
* @copyright (c) 2024, Robert Strutts |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
class mb_strings_fns { |
||||||
|
|
||||||
|
public static function isUTF8(string $string) { |
||||||
|
return mb_check_encoding($string, 'UTF-8'); |
||||||
|
} |
||||||
|
|
||||||
|
// Check if string contains multibyte characters |
||||||
|
public static function has_multibyte_chars(string $string) { |
||||||
|
return strlen($string) !== mb_strlen($string, 'UTF-8'); |
||||||
|
} |
||||||
|
|
||||||
|
// Override to get the length of a string with multibyte support |
||||||
|
public function strlen($string) { |
||||||
|
return mb_strlen($string); |
||||||
|
} |
||||||
|
|
||||||
|
// Override to convert a string to lowercase with multibyte support |
||||||
|
public function strtolower($string) { |
||||||
|
return mb_strtolower($string); |
||||||
|
} |
||||||
|
|
||||||
|
// Override to convert a string to uppercase with multibyte support |
||||||
|
public function strtoupper($string) { |
||||||
|
return mb_strtoupper($string); |
||||||
|
} |
||||||
|
|
||||||
|
// Override to get a substring from a string with multibyte support |
||||||
|
public function substr($string, $start, $length = null) { |
||||||
|
return ($length !== null) ? mb_substr($string, $start, $length) : mb_substr($string, $start); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,106 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts |
||||||
|
* @copyright Copyright (c) 2022, Robert Strutts. |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
/** |
||||||
|
* random_engine - Provides a high-level API to the randomness |
||||||
|
* provided by an Random\Engine OR uses the next Fall Back FN. |
||||||
|
* |
||||||
|
* @author Robert Strutts |
||||||
|
*/ |
||||||
|
class random_engine { |
||||||
|
|
||||||
|
private $engine = false; |
||||||
|
|
||||||
|
public function __construct() { |
||||||
|
$version = (float) phpversion(); |
||||||
|
if ($version > 8.1) { |
||||||
|
$this->engine = new \Random\Randomizer(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public function get_bytes(int $bytes_length = 16): string { |
||||||
|
return ($this->engine) ? $this->engine->getBytes($bytes_length) : |
||||||
|
random_bytes($bytes_length); |
||||||
|
} |
||||||
|
|
||||||
|
public function get_int(int $min, int $max): int { |
||||||
|
if ($this->engine) { |
||||||
|
return $this->engine->getInt($min, $max); |
||||||
|
} |
||||||
|
if (function_exists('random_int')) { |
||||||
|
return random_int($min, $max); // secure fallback |
||||||
|
} elseif (function_exists('mt_rand')) { |
||||||
|
return mt_rand($min, $max); // fast |
||||||
|
} |
||||||
|
return rand($min, $max); // old |
||||||
|
} |
||||||
|
|
||||||
|
// Took from source https://pageconfig.com/post/fixed-length-large-random-numbers-with-php |
||||||
|
private function big_rand(int $len = 18 ): int { |
||||||
|
$rand = ''; |
||||||
|
while( !( isset( $rand[$len-1] ) ) ) { |
||||||
|
$rand .= mt_rand( ); |
||||||
|
} |
||||||
|
return (int) substr( $rand , 0 , $len ); |
||||||
|
} |
||||||
|
|
||||||
|
public function get_next_big_postive_int(): int { |
||||||
|
if ($this->engine) { |
||||||
|
return $this->engine->nextInt(); |
||||||
|
} |
||||||
|
return $this->big_rand(); |
||||||
|
} |
||||||
|
|
||||||
|
private function select_from_array(array $a, int $num ): array { |
||||||
|
$array_count = \bs_tts\common::get_count($a) - 1; |
||||||
|
if ($array_count < 1) { |
||||||
|
return []; |
||||||
|
} |
||||||
|
$ret = []; |
||||||
|
for($i=0; $i<$num; $i++) { |
||||||
|
$ret[] = $a[$this->get_int(0, $array_count)]; |
||||||
|
} |
||||||
|
return $ret; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Pick random keys from an Array |
||||||
|
*/ |
||||||
|
public function get_array_keys(array $a, int $num): array { |
||||||
|
if ($this->engine) { |
||||||
|
return $this->engine->pickArrayKeys($a, $num); |
||||||
|
} |
||||||
|
return $this->select_from_array($a, $num); |
||||||
|
} |
||||||
|
|
||||||
|
public function get_shuffled_array(array $a): array { |
||||||
|
if ($this->engine) { |
||||||
|
return $this->engine->shuffleArray($a); |
||||||
|
} |
||||||
|
shuffle($a); |
||||||
|
return $a; |
||||||
|
} |
||||||
|
|
||||||
|
public function get_shuffled_bytes(string $bytes): string { |
||||||
|
if ($this->engine) { |
||||||
|
return $this->engine->shuffleBytes($bytes); |
||||||
|
} |
||||||
|
$len = mb_strlen($bytes); |
||||||
|
$a = []; |
||||||
|
while($len-- > 0) { |
||||||
|
$a[] = mb_substr($bytes, $len, 1); |
||||||
|
} |
||||||
|
shuffle($a); |
||||||
|
return join('', $a); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,115 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts |
||||||
|
* @copyright Copyright (c) 2022, Robert Strutts. |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater\services; |
||||||
|
|
||||||
|
final class log { |
||||||
|
|
||||||
|
private $handle; |
||||||
|
|
||||||
|
/** |
||||||
|
* Get Filename for writing to Log file |
||||||
|
* @param string $filename for log |
||||||
|
* @param int $max_count of lines before file wipe, to keep small logs. |
||||||
|
*/ |
||||||
|
public function __construct(string $filename = 'system', int $max_count = 1000) { |
||||||
|
if (strpos($filename, "..") !== false) { |
||||||
|
$this->handle = false; // Too dangerious, so return false |
||||||
|
} else { |
||||||
|
$log_dir = BaseDir . '/protected/logs'; |
||||||
|
if (! is_dir($log_dir)){ |
||||||
|
//Directory does not exist, so lets create it. |
||||||
|
mkdir($log_dir, 0775); |
||||||
|
} |
||||||
|
|
||||||
|
$filename = preg_replace("|[^A-Za-z0-9_]|", "", $filename); |
||||||
|
$filename = escapeshellcmd($filename); |
||||||
|
$file = $log_dir . '/' . $filename . ".log.txt"; |
||||||
|
|
||||||
|
if ($max_count > 1) { |
||||||
|
if ($this->get_lines($file) > $max_count) { |
||||||
|
unlink($file); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
$success = file_put_contents($file, "\n", FILE_APPEND); |
||||||
|
// $success = @touch($file); |
||||||
|
if ($success === false) { |
||||||
|
$this->handle = false; |
||||||
|
\CodeHydrater\bootstrap\common::dump($file); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
@chmod($file, 0660); |
||||||
|
@chgrp($file, "www-data"); |
||||||
|
if (! is_writable($file)) { |
||||||
|
$this->handle = false; |
||||||
|
return false; |
||||||
|
} |
||||||
|
$this->handle = fopen($file, 'a'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Count number of lines in Log File |
||||||
|
* @param string $file |
||||||
|
* @return int line count |
||||||
|
*/ |
||||||
|
public function get_lines(string $file): int { |
||||||
|
// No such file, so return zero for length. |
||||||
|
if (! file_exists($file)) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
$f = fopen($file, 'rb'); |
||||||
|
$lines = 0; |
||||||
|
|
||||||
|
if ($f === false || !is_resource($f)) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
while (!feof($f)) { |
||||||
|
$line = fread($f, 8192); |
||||||
|
if ($line === false) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
$lines += substr_count($line, "\n"); |
||||||
|
} |
||||||
|
|
||||||
|
fclose($f); |
||||||
|
|
||||||
|
return $lines; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Write to Log File |
||||||
|
* @param string $message to save |
||||||
|
* @return bool able to write to log file |
||||||
|
*/ |
||||||
|
public function write(string $message): bool { |
||||||
|
if ( $this->handle === false || ! is_resource($this->handle) ) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
$dt = new \DateTime(); |
||||||
|
$now = $dt->format('g:i A \o\n l jS F Y'); |
||||||
|
fwrite($this->handle, $now . ' - ' . print_r($message, true) . "\n"); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Close Log File Handle |
||||||
|
*/ |
||||||
|
public function __destruct() { |
||||||
|
if ($this->handle !== false && is_resource($this->handle)) { |
||||||
|
fclose($this->handle); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,238 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
/** |
||||||
|
* @license ISC |
||||||
|
* @copyright Copyright (c) 2016-2023, Paragon Initiative Enterprises |
||||||
|
* @link https://paragonie.com/book/pecl-libsodium/read/05-publickey-crypto.md |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater\services\paragon_crypto; |
||||||
|
|
||||||
|
class crypto { |
||||||
|
|
||||||
|
const single_key = true; |
||||||
|
const multiple_keys = false; |
||||||
|
|
||||||
|
private $rnd; |
||||||
|
|
||||||
|
|
||||||
|
public function __construct(#[\SensitiveParameter] private string $key) { |
||||||
|
$this->rnd = new \tts\random_engine(); |
||||||
|
} |
||||||
|
/* |
||||||
|
* Secret key encryption (or symmetric encryption as it’s also |
||||||
|
* known) uses a single key to both encrypt and decrypt data. |
||||||
|
* In the past PHP relied on mcrypt and openssl for secret key |
||||||
|
* encryption. PHP 7.2 introduced Sodium, which is more modern |
||||||
|
* and widely considered more secure. |
||||||
|
* |
||||||
|
* In order to encrypt a value, first you’ll need an encryption |
||||||
|
* key, which can be generated using the |
||||||
|
* sodium_crypto_secretbox_keygen() function. |
||||||
|
* |
||||||
|
* $key = sodium_crypto_secretbox_keygen(); |
||||||
|
* You can also use the random_bytes() function with the |
||||||
|
* SODIUM_CRYPTO_SECRETBOX_KEYBYTES integer constant for the |
||||||
|
* key length, but using sodium_crypto_secretbox_keygen() |
||||||
|
* ensures that the key length is always correct (i.e. not too |
||||||
|
* short), and it’s easier. |
||||||
|
* |
||||||
|
* $key = random_bytes( SODIUM_CRYPTO_SECRETBOX_KEYBYTES ); |
||||||
|
* Either way, you’ll usually only do this once and store the |
||||||
|
* result as an environment variable. Remember that this key |
||||||
|
* must be kept secret at all costs. If the key is ever |
||||||
|
* compromised, so is any data encrypted by using it. |
||||||
|
*/ |
||||||
|
|
||||||
|
public function encrypt( |
||||||
|
#[\SensitiveParameter] string $message, |
||||||
|
bool $key_usage = self::single_key |
||||||
|
): string { |
||||||
|
$key = $this->key; |
||||||
|
|
||||||
|
$nonce = $this->rnd->get_bytes( |
||||||
|
SODIUM_CRYPTO_SECRETBOX_NONCEBYTES |
||||||
|
); |
||||||
|
$fn = ($key_usage == self::single_key) ? "sodium_crypto_secretbox" : "sodium_crypto_box"; |
||||||
|
$cipher = base64_encode( |
||||||
|
$nonce . |
||||||
|
$fn( |
||||||
|
$message, |
||||||
|
$nonce, |
||||||
|
base64_decode($key) |
||||||
|
) |
||||||
|
); |
||||||
|
sodium_memzero($message); |
||||||
|
sodium_memzero($key); |
||||||
|
return $cipher; |
||||||
|
} |
||||||
|
|
||||||
|
public function decrypt( |
||||||
|
string $encrypted, |
||||||
|
bool $key_usage = self::single_key |
||||||
|
): string | false { |
||||||
|
$key = $this->key; |
||||||
|
|
||||||
|
$decoded = base64_decode($encrypted); |
||||||
|
if ($decoded === false) { |
||||||
|
throw new Exception('Unable to decode'); |
||||||
|
} |
||||||
|
if (mb_strlen($decoded, '8bit') < (SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + SODIUM_CRYPTO_SECRETBOX_MACBYTES)) { |
||||||
|
throw new Exception('Message was truncated'); |
||||||
|
} |
||||||
|
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit'); |
||||||
|
$ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit'); |
||||||
|
|
||||||
|
$fn = ($key_usage == self::single_key) ? "sodium_crypto_secretbox_open" : "sodium_crypto_box_open"; |
||||||
|
$plain = $fn( |
||||||
|
$ciphertext, |
||||||
|
$nonce, |
||||||
|
base64_decode($key) |
||||||
|
); |
||||||
|
sodium_memzero($ciphertext); |
||||||
|
sodium_memzero($key); |
||||||
|
return $plain; |
||||||
|
} |
||||||
|
|
||||||
|
public static function make_user_box_kp() { |
||||||
|
return sodium_crypto_box_keypair(); |
||||||
|
} |
||||||
|
|
||||||
|
public static function make_user_sign_kp() { |
||||||
|
return sodium_crypto_sign_keypair(); |
||||||
|
} |
||||||
|
|
||||||
|
public static function get_user_box_secret_key(string $from_make_user_box_kp): string { |
||||||
|
return base64_encode(sodium_crypto_box_secretkey($from_make_user_box_kp)); |
||||||
|
} |
||||||
|
|
||||||
|
public static function get_user_box_public_key(string $from_make_user_box_kp): string { |
||||||
|
return base64_encode(sodium_crypto_box_publickey($from_make_user_box_kp)); |
||||||
|
} |
||||||
|
|
||||||
|
public static function get_user_sign_secret_key(string $from_make_user_sign_secret_kp): string { |
||||||
|
return sodium_crypto_sign_secretkey($from_make_user_sign_secret_kp); |
||||||
|
} |
||||||
|
|
||||||
|
public static function get_user_sign_public_key(string $from_make_user_sign_public_kp): string { |
||||||
|
return sodium_crypto_sign_secretkey($from_make_user_sign_public_kp); |
||||||
|
} |
||||||
|
|
||||||
|
public static function box_reassemble_keypair( |
||||||
|
string $from_get_userA_box_secret_key, |
||||||
|
string $from_get_userB_box_public_key |
||||||
|
): string { |
||||||
|
return base64_encode(sodium_crypto_box_keypair_from_secretkey_and_publickey( |
||||||
|
base64_decode($from_get_userA_box_secret_key), |
||||||
|
base64_decode($from_get_userB_box_public_key) |
||||||
|
)); |
||||||
|
} |
||||||
|
|
||||||
|
public static function sign_message(#[\SensitiveParameter] string $message, #[\SensitiveParameter] string $user_sign_secretkey): string { |
||||||
|
return sodium_crypto_sign( |
||||||
|
$message, |
||||||
|
$user_sign_secretkey |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
public static function get_signed_message(#[\SensitiveParameter] string $signed_message, #[\SensitiveParameter] string $user_sign_publickey): string | false { |
||||||
|
return sodium_crypto_sign_open( |
||||||
|
$signed_message, |
||||||
|
$user_sign_publickey |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
public static function make_just_signature(#[\SensitiveParameter] string $message, #[\SensitiveParameter] string $user_sign_secretkey): string { |
||||||
|
return sodium_crypto_sign_detached( |
||||||
|
$message, |
||||||
|
$user_sign_secretkey |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
public static function is_a_valid_signature( |
||||||
|
#[\SensitiveParameter] string $signature, |
||||||
|
#[\SensitiveParameter] string $message, |
||||||
|
#[\SensitiveParameter] string $user_sign_public_key |
||||||
|
): bool { |
||||||
|
if ( sodium_crypto_sign_verify_detached( |
||||||
|
$signature, |
||||||
|
$message, |
||||||
|
$user_sign_publickey |
||||||
|
) ) { |
||||||
|
return true; |
||||||
|
} else { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static function a_single_key_maker(): string { |
||||||
|
$rnd = new \tts\random_engine(); |
||||||
|
return base64_encode($rnd->get_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES)); |
||||||
|
} |
||||||
|
/* |
||||||
|
* Extract the public key from the secret key |
||||||
|
*/ |
||||||
|
public static function sign_publickey_from_secretkey(#[\SensitiveParameter] string $key) { |
||||||
|
return sodium_crypto_sign_publickey_from_secretkey($key); |
||||||
|
} |
||||||
|
|
||||||
|
public static function increment_sequential_nonce($x) { |
||||||
|
return sodium_increment($x); // The obtain the next nonce |
||||||
|
} |
||||||
|
|
||||||
|
// Should you Proceed with crypto_box decryption, if true go ahead do it. |
||||||
|
public static function is_safe_to_decode($message_nonce, $expected_nonce): bool { |
||||||
|
return (sodium_compare($message_nonce, $expected_nonce) === 0); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Sometimes you don't need to hide the contents of a message with encryption, |
||||||
|
* but you still want to ensure that nobody on the network can tamper with |
||||||
|
* it. For example, if you want to eschew server-side session storage and |
||||||
|
* instead use HTTP cookies as your storage mechanism. |
||||||
|
*/ |
||||||
|
public static function sign_outbound_message_only(#[\SensitiveParameter] string $message, #[\SensitiveParameter] string $key): string { |
||||||
|
$mac = sodium_crypto_auth($message, $key); |
||||||
|
return $mac . "@@" . $message; |
||||||
|
} |
||||||
|
|
||||||
|
public static function is_valid_inbound_message(#[\SensitiveParameter] string $message, #[\SensitiveParameter] string $key): bool { |
||||||
|
$a = explode("@@", $message, 2); |
||||||
|
$mac = $a[0]; |
||||||
|
$old_message = $a[1]; |
||||||
|
$ret_bool = (sodium_crypto_auth_verify($mac, $old_message, $key)); |
||||||
|
if ($ret_bool === false) { |
||||||
|
sodium_memzero($key); |
||||||
|
throw new \Exception("Malformed message or invalid MAC"); |
||||||
|
} |
||||||
|
return $ret_bool; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
/* |
||||||
|
* Usage: |
||||||
|
* |
||||||
|
$key = tts\services\paragon_crypto\crypto::a_single_key_maker(); |
||||||
|
$enc = tts\services\paragon_crypto\crypto::safe_encrypt('Encrypt This String...', $key, \tts\services\paragon_crypto\crypto::single_key); |
||||||
|
echo $enc . "<br/>"; |
||||||
|
$dec = \tts\services\paragon_crypto\crypto::safe_decrypt($enc, $key, \tts\services\paragon_crypto\crypto::single_key); |
||||||
|
echo $dec . "<br/>";; |
||||||
|
// -------------------- |
||||||
|
|
||||||
|
$key_pair_Alice = \tts\services\paragon_crypto\crypto::make_user_box_kp(); |
||||||
|
$secret_Alice = \tts\services\paragon_crypto\crypto::get_user_box_secret_key($key_pair_Alice); |
||||||
|
$public_Alice = \tts\services\paragon_crypto\crypto::get_user_box_public_key($key_pair_Alice); |
||||||
|
|
||||||
|
$key_pair_Bob = \tts\services\paragon_crypto\crypto::make_user_box_kp(); |
||||||
|
$secret_Bob = \tts\services\paragon_crypto\crypto::get_user_box_secret_key($key_pair_Bob); |
||||||
|
$public_Bob = \tts\services\paragon_crypto\crypto::get_user_box_public_key($key_pair_Bob); |
||||||
|
|
||||||
|
$kA = \tts\services\paragon_crypto\crypto::box_reassemble_keypair($secret_Alice, $public_Bob); |
||||||
|
$enc = \tts\services\paragon_crypto\crypto::safe_encrypt('Encrypt This String2...', $kA, \tts\services\paragon_crypto\crypto::multiple_keys); |
||||||
|
echo $enc . "<br/>"; |
||||||
|
|
||||||
|
$kB = \tts\services\paragon_crypto\crypto::box_reassemble_keypair($secret_Bob, $public_Alice); |
||||||
|
$dec = \tts\services\paragon_crypto\crypto::safe_decrypt($enc, $kB, \tts\services\paragon_crypto\crypto::multiple_keys); |
||||||
|
echo $dec; |
||||||
|
*/ |
||||||
@ -0,0 +1,127 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace CodeHydrater\services\paragon_crypto; |
||||||
|
|
||||||
|
/** |
||||||
|
* @copyright Paragon Initiative Enterprises |
||||||
|
* @license Creative Commons Attribution 4.0 International / ISC |
||||||
|
* @link https://github.com/paragonie/pecl-libsodium-doc/blob/master/chapters/09-recipes.md |
||||||
|
*/ |
||||||
|
|
||||||
|
class password_storage { |
||||||
|
|
||||||
|
const SALT_SIZE_IN_BYTES = 16; |
||||||
|
private $random_engine; |
||||||
|
|
||||||
|
public function __construct() { |
||||||
|
$this->random_engine = new \tts\random_engine(); |
||||||
|
} |
||||||
|
|
||||||
|
public function generate_a_key(): string { |
||||||
|
return sodium_bin2hex($this->random_engine->get_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Hash then encrypt a password |
||||||
|
* |
||||||
|
* @param string $password - The user's password |
||||||
|
* @param string $secret_key - The main_magic key for all passwords |
||||||
|
* @return string |
||||||
|
*/ |
||||||
|
public function hash(#[\SensitiveParameter] string $password, #[\SensitiveParameter] string $secret_key): string { |
||||||
|
// First, let's calculate the hash |
||||||
|
$hashed = sodium_crypto_pwhash_scryptsalsa208sha256_str( |
||||||
|
$password, |
||||||
|
SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE, |
||||||
|
SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE |
||||||
|
); |
||||||
|
$salt = $this->random_engine->get_bytes(self::SALT_SIZE_IN_BYTES); |
||||||
|
list ($enc_key, $auth_key) = $this->split_keys($secret_key, sodium_bin2hex($salt)); |
||||||
|
sodium_memzero($secret_key); |
||||||
|
sodium_memzero($password); |
||||||
|
$nonce = $this->random_engine->get_bytes( |
||||||
|
SODIUM_CRYPTO_STREAM_NONCEBYTES |
||||||
|
); |
||||||
|
$cipher_text = sodium_crypto_stream_xor( |
||||||
|
$hashed, |
||||||
|
$nonce, |
||||||
|
$enc_key |
||||||
|
); |
||||||
|
|
||||||
|
$mac = sodium_crypto_auth($nonce . $cipher_text, $auth_key); |
||||||
|
sodium_memzero($enc_key); |
||||||
|
sodium_memzero($auth_key); |
||||||
|
|
||||||
|
return sodium_bin2hex($mac . $nonce . $salt . $cipher_text); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Decrypt then verify a password |
||||||
|
* |
||||||
|
* @param string $password - The user-provided password |
||||||
|
* @param string $stored - The encrypted password hash |
||||||
|
* @param string $secret_key - The main_magic key for all passwords |
||||||
|
*/ |
||||||
|
public function verify(#[\SensitiveParameter] string $password, string $stored, #[\SensitiveParameter] string $secret_key): bool { |
||||||
|
$data = sodium_hex2bin($stored); |
||||||
|
$mac = mb_substr( |
||||||
|
$data, |
||||||
|
0, |
||||||
|
SODIUM_CRYPTO_AUTH_BYTES, |
||||||
|
'8bit' |
||||||
|
); |
||||||
|
$nonce = mb_substr( |
||||||
|
$data, |
||||||
|
SODIUM_CRYPTO_AUTH_BYTES, |
||||||
|
SODIUM_CRYPTO_STREAM_NONCEBYTES, |
||||||
|
'8bit' |
||||||
|
); |
||||||
|
$salt = mb_substr( |
||||||
|
$data, |
||||||
|
SODIUM_CRYPTO_AUTH_BYTES + SODIUM_CRYPTO_STREAM_NONCEBYTES, |
||||||
|
self::SALT_SIZE_IN_BYTES, |
||||||
|
'8bit' |
||||||
|
); |
||||||
|
$cipher_text = mb_substr( |
||||||
|
$data, |
||||||
|
SODIUM_CRYPTO_AUTH_BYTES + SODIUM_CRYPTO_STREAM_NONCEBYTES + self::SALT_SIZE_IN_BYTES, |
||||||
|
null, |
||||||
|
'8bit' |
||||||
|
); |
||||||
|
list ($enc_key, $auth_key) = $this->split_keys($secret_key, sodium_bin2hex($salt)); |
||||||
|
|
||||||
|
if (sodium_crypto_auth_verify($mac, $nonce . $cipher_text, $auth_key)) { |
||||||
|
sodium_memzero($auth_key); |
||||||
|
$hash_str = sodium_crypto_stream_xor($cipher_text, $nonce, $enc_key); |
||||||
|
sodium_memzero($enc_key); |
||||||
|
if ($hash_str !== false) { |
||||||
|
$ret = sodium_crypto_pwhash_scryptsalsa208sha256_str_verify($hash_str, $password); |
||||||
|
sodium_memzero($password); |
||||||
|
return $ret; |
||||||
|
} |
||||||
|
} else { |
||||||
|
sodium_memzero($auth_key); |
||||||
|
sodium_memzero($enc_key); |
||||||
|
} |
||||||
|
throw new \Exception('Decryption failed.'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return array(2) [encryption key, authentication key] |
||||||
|
*/ |
||||||
|
private function split_keys(#[\SensitiveParameter] string $secret_key, #[\SensitiveParameter] string $salt): array { |
||||||
|
$enc_key = hash_hkdf('sha256', $secret_key, SODIUM_CRYPTO_STREAM_KEYBYTES, 'encryption', $salt); |
||||||
|
$auth_key = hash_hkdf('sha256', $secret_key, SODIUM_CRYPTO_AUTH_KEYBYTES, 'authentication', $salt); |
||||||
|
return [$enc_key, $auth_key]; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
$c = new \tts\services\paragon_crypto\password_storage(); |
||||||
|
$k = $c->generate_a_key(); |
||||||
|
$h = $c->hash("HelpMe", $k); |
||||||
|
var_dump( $c->verify("HelpMe", $h, $k) ); |
||||||
|
*/ |
||||||
@ -0,0 +1,133 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @license MIT/ISC |
||||||
|
* @author by Paragon Initiative Enterprises |
||||||
|
* @link https://github.com/paragonie/pecl-libsodium-doc/blob/master/chapters/09-recipes.md |
||||||
|
* |
||||||
|
* I've added HKDF extracts a pseudorandom key (PRK) using an HMAC hash function |
||||||
|
* (e.g. HMAC-SHA256) on salt (acting as a key) to secure the input key |
||||||
|
* |
||||||
|
* |
||||||
|
* Encrypted Storage |
||||||
|
* Problem: We want to store data in a cookie such that user cannot read nor alter its contents. |
||||||
|
* Desired Solution: Authenticated secret-key encryption, wherein the nonce is stored with the ciphertext. |
||||||
|
* Each encryption and authentication key should be attached to the cookie name. |
||||||
|
* This strategy combines both sodium_crypto_stream_xor() with sodium_crypto_auth(). |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater\services\paragon_crypto; |
||||||
|
|
||||||
|
class sodium_storage { |
||||||
|
private $random_engine; |
||||||
|
|
||||||
|
const SALT_SIZE_IN_BYTES = 16; |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the encryption key |
||||||
|
*/ |
||||||
|
public function __construct(#[\SensitiveParameter] private string $key) { |
||||||
|
$this->random_engine = new \tts\random_engine(); |
||||||
|
} |
||||||
|
|
||||||
|
public function encrypt(#[\SensitiveParameter] string $plain_text, string $item_name = ""): string { |
||||||
|
$nonce = $this->random_engine->get_bytes( |
||||||
|
SODIUM_CRYPTO_STREAM_NONCEBYTES |
||||||
|
); |
||||||
|
$salt = $this->random_engine->get_bytes(self::SALT_SIZE_IN_BYTES); |
||||||
|
list ($enc_key, $auth_key) = $this->split_keys($item_name, sodium_bin2hex($salt)); |
||||||
|
$cipher_text = sodium_crypto_stream_xor( |
||||||
|
$plain_text, |
||||||
|
$nonce, |
||||||
|
$enc_key |
||||||
|
); |
||||||
|
sodium_memzero($plain_text); |
||||||
|
|
||||||
|
$mac = sodium_crypto_auth($nonce . $cipher_text, $auth_key); |
||||||
|
|
||||||
|
sodium_memzero($enc_key); |
||||||
|
sodium_memzero($auth_key); |
||||||
|
|
||||||
|
return sodium_bin2hex($mac . $nonce . $salt . $cipher_text); |
||||||
|
} |
||||||
|
|
||||||
|
public function decrypt(string $cypher_data, string $item_name = ""): string { |
||||||
|
$bin_data = sodium_hex2bin($cypher_data); |
||||||
|
|
||||||
|
$mac = mb_substr( |
||||||
|
$bin_data, |
||||||
|
0, |
||||||
|
SODIUM_CRYPTO_AUTH_BYTES, |
||||||
|
'8bit' |
||||||
|
); |
||||||
|
$nonce = mb_substr( |
||||||
|
$bin_data, |
||||||
|
SODIUM_CRYPTO_AUTH_BYTES, |
||||||
|
SODIUM_CRYPTO_STREAM_NONCEBYTES, |
||||||
|
'8bit' |
||||||
|
); |
||||||
|
$salt = mb_substr( |
||||||
|
$bin_data, |
||||||
|
SODIUM_CRYPTO_AUTH_BYTES + SODIUM_CRYPTO_STREAM_NONCEBYTES, |
||||||
|
self::SALT_SIZE_IN_BYTES, |
||||||
|
'8bit' |
||||||
|
); |
||||||
|
$cipher_text = mb_substr( |
||||||
|
$bin_data, |
||||||
|
SODIUM_CRYPTO_AUTH_BYTES + SODIUM_CRYPTO_STREAM_NONCEBYTES + self::SALT_SIZE_IN_BYTES, |
||||||
|
null, |
||||||
|
'8bit' |
||||||
|
); |
||||||
|
|
||||||
|
list ($enc_key, $auth_key) = $this->split_keys($item_name, sodium_bin2hex($salt)); |
||||||
|
|
||||||
|
if (sodium_crypto_auth_verify($mac, $nonce . $cipher_text, $auth_key)) { |
||||||
|
sodium_memzero($auth_key); |
||||||
|
$plaintext = sodium_crypto_stream_xor($cipher_text, $nonce, $enc_key); |
||||||
|
sodium_memzero($enc_key); |
||||||
|
if ($plaintext !== false) { |
||||||
|
return $plaintext; |
||||||
|
} |
||||||
|
} else { |
||||||
|
sodium_memzero($auth_key); |
||||||
|
sodium_memzero($enc_key); |
||||||
|
} |
||||||
|
throw new \Exception('Decryption failed.'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return array(2) [encryption key, authentication key] |
||||||
|
*/ |
||||||
|
private function split_keys(string $item_name, #[\SensitiveParameter] string $salt): array { |
||||||
|
$enc_key = hash_hkdf('sha256', $this->key, SODIUM_CRYPTO_STREAM_KEYBYTES, md5('encryption' . $item_name), $salt); |
||||||
|
$auth_key = hash_hkdf('sha256', $this->key, SODIUM_CRYPTO_AUTH_KEYBYTES, md5('authentication' . $item_name), $salt); |
||||||
|
return [$enc_key, $auth_key]; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Example: |
||||||
|
$secretkey = "78a5011b9997cd03a28a3412c66565b7c32715b35e055d7abfc228236308d3b2"; |
||||||
|
$plain_text = "Hello World!"; |
||||||
|
|
||||||
|
$sc = new \tts\services\paragon_crypto\sodium_storage($secretkey); |
||||||
|
$index = "sensitive"; |
||||||
|
$encoded = $sc->encode($index, $plain_text); |
||||||
|
setcookie($index, $encoded); |
||||||
|
|
||||||
|
// On the next page load: |
||||||
|
try { |
||||||
|
if (!array_key_exists($index, $_COOKIE)) { |
||||||
|
throw new \Exception('No Cookie!'); |
||||||
|
} |
||||||
|
$data = $_COOKIE[$index]; |
||||||
|
$plain_text = $sc->decode($index, $data); |
||||||
|
echo $plain_text; |
||||||
|
} catch (Exception $ex) { |
||||||
|
// Handle the exception here |
||||||
|
echo $ex->getMessage(); |
||||||
|
} |
||||||
|
*/ |
||||||
@ -0,0 +1,98 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts <Bob_586@Yahoo.com> |
||||||
|
* @copyright (c) 2024, Robert Strutts |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
class String_fns { |
||||||
|
public static function isUTF8(string $string) { |
||||||
|
// Empty string is valid UTF-8 |
||||||
|
if ($string === '') { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
// Convert string to array of bytes |
||||||
|
$bytes = unpack('C*', $string); |
||||||
|
|
||||||
|
// Pattern matching state |
||||||
|
$state = 0; |
||||||
|
$expectedBytes = 0; |
||||||
|
|
||||||
|
foreach ($bytes as $byte) { |
||||||
|
// Single byte character (0xxxxxxx) |
||||||
|
if ($byte <= 0x7F) { |
||||||
|
$state = 0; |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
// Start of multibyte sequence |
||||||
|
if ($state === 0) { |
||||||
|
// 2 bytes (110xxxxx) |
||||||
|
if (($byte & 0xE0) === 0xC0) { |
||||||
|
$expectedBytes = 1; |
||||||
|
} |
||||||
|
// 3 bytes (1110xxxx) |
||||||
|
elseif (($byte & 0xF0) === 0xE0) { |
||||||
|
$expectedBytes = 2; |
||||||
|
} |
||||||
|
// 4 bytes (11110xxx) |
||||||
|
elseif (($byte & 0xF8) === 0xF0) { |
||||||
|
$expectedBytes = 3; |
||||||
|
} |
||||||
|
// Invalid UTF-8 start byte |
||||||
|
else { |
||||||
|
return false; |
||||||
|
} |
||||||
|
$state = $expectedBytes; |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
// Continuation byte (10xxxxxx) |
||||||
|
if (($byte & 0xC0) !== 0x80) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
$state--; |
||||||
|
} |
||||||
|
|
||||||
|
// Check if we finished the last multibyte sequence |
||||||
|
return $state === 0; |
||||||
|
} |
||||||
|
|
||||||
|
// Check if string contains multibyte characters |
||||||
|
public static function has_multibyte_chars(string $string) { |
||||||
|
return (bool) preg_match('/[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2}/', $string); |
||||||
|
} |
||||||
|
|
||||||
|
// Get the length of a string |
||||||
|
public function strlen($string) { |
||||||
|
return strlen($string); |
||||||
|
} |
||||||
|
|
||||||
|
// Convert a string to lowercase |
||||||
|
public function strtolower($string) { |
||||||
|
return strtolower($string); |
||||||
|
} |
||||||
|
|
||||||
|
// Convert a string to uppercase |
||||||
|
public function strtoupper($string) { |
||||||
|
return strtoupper($string); |
||||||
|
} |
||||||
|
|
||||||
|
// Get a substring from a string |
||||||
|
public function substr($string, $start, $length = null) { |
||||||
|
return ($length !== null) ? substr($string, $start, $length) : substr($string, $start); |
||||||
|
} |
||||||
|
|
||||||
|
// Reverse a string |
||||||
|
public function strrev($string) { |
||||||
|
return strrev($string); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,63 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts <Robert@TryingToScale.com> |
||||||
|
* @copyright Copyright (c) 2022, Robert Strutts. |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace tts; |
||||||
|
|
||||||
|
final class tag_matches { |
||||||
|
|
||||||
|
const tags_to_check = array('div', 'span', 'form', 'i*', 'a*', 'h1', 'p*'); |
||||||
|
|
||||||
|
/** |
||||||
|
* Function checks tags to make sure they match. |
||||||
|
* Used by view.php |
||||||
|
* @param string $page |
||||||
|
* @return array [output, alert] |
||||||
|
*/ |
||||||
|
public static function check_tags(string $page): array { |
||||||
|
$alert = ''; |
||||||
|
$output = ''; |
||||||
|
$l_page = \bs_tts\common::string_to_lowercase($page); |
||||||
|
unset($page); |
||||||
|
|
||||||
|
$assets = \bs_tts\site_helper::get_asset("uikit/css/uikit.gradient.min.css"); |
||||||
|
$ui = '<link rel="stylesheet" href="' . $assets . '/uikit/css/uikit.gradient.min.css" type="text/css" media="all" />'; |
||||||
|
$ui .= '<div class="uk-alert uk-alert-danger"><b>'; |
||||||
|
$ui_end = '</b></div>'; |
||||||
|
|
||||||
|
foreach (self::tags_to_check as $tag_name) { |
||||||
|
if (\bs_tts\common::is_string_found($tag_name, '*')) { |
||||||
|
$tag_name = str_replace('*', '', $tag_name); |
||||||
|
$otag = "<{$tag_name}>"; // Open Tag |
||||||
|
$open = substr_count($l_page, $otag); // Count open tags in page |
||||||
|
$otag = "<{$tag_name} "; /* Open Tag with space */ |
||||||
|
$open += substr_count($l_page, $otag); // Count open tags in page |
||||||
|
} else { |
||||||
|
$otag = "<{$tag_name}"; // Open Tag |
||||||
|
$open = substr_count($l_page, $otag); // Count open tags in page |
||||||
|
} |
||||||
|
|
||||||
|
$ctag = "</{$tag_name}>"; // Close Tag |
||||||
|
$closed = substr_count($l_page, $ctag); // Count Close tags in page |
||||||
|
$total_still_open = $open - $closed; // Difference of open vs. closed.... |
||||||
|
|
||||||
|
if ($total_still_open > 0) { |
||||||
|
$msg = "{$total_still_open} possibly MISSING closing {$tag_name} !!!"; |
||||||
|
$alert .= "console.log('{$msg}');\r\n"; |
||||||
|
$output .= (\main_tts\is_live()) ? "<!-- {$msg} -->\r\n" : "{$ui}{$msg}{$ui_end}\r\n"; |
||||||
|
} elseif ($total_still_open < 0) { |
||||||
|
$msg = abs($total_still_open) . " possibly MISSING opening {$tag_name} !!!"; |
||||||
|
$alert .= "console.log('{$msg}');\r\n"; |
||||||
|
$output .= (\main_tts\is_live()) ? "<!-- {$msg} -->\r\n" : "{$ui}{$msg}{$ui_end}\r\n"; |
||||||
|
} |
||||||
|
} |
||||||
|
return array('output' => $output, 'alert' => $alert); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,49 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @folked from https://gist.github.com/Xeoncross/1204255 |
||||||
|
* @site https://gist.github.com/vrdriver/659562a150ba955063ad849e44dac2cc |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
final class time_zone_selection { |
||||||
|
|
||||||
|
protected $timezones = array(); |
||||||
|
|
||||||
|
public function __construct() { |
||||||
|
|
||||||
|
$regions = array( |
||||||
|
'America' => \DateTimeZone::AMERICA, |
||||||
|
'Europe' => \DateTimeZone::EUROPE, |
||||||
|
'Africa' => \DateTimeZone::AFRICA, |
||||||
|
'Antarctica' => \DateTimeZone::ANTARCTICA, |
||||||
|
'Aisa' => \DateTimeZone::ASIA, |
||||||
|
'Atlantic' => \DateTimeZone::ATLANTIC, |
||||||
|
'Indian' => \DateTimeZone::INDIAN, |
||||||
|
'Pacific' => \DateTimeZone::PACIFIC |
||||||
|
); |
||||||
|
|
||||||
|
foreach ($regions as $name => $mask) { |
||||||
|
$zones = \DateTimeZone::listIdentifiers($mask); |
||||||
|
foreach ($zones as $timezone) { |
||||||
|
$this->timezones[$name][$timezone] = substr($timezone, strlen($name) + 1); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public function view() { |
||||||
|
echo '<label>Select Your Timezone</label><br/><select id="timezone">'; |
||||||
|
foreach ($this->timezones as $region => $list) { |
||||||
|
echo '<optgroup label="' . $region . '">' . "\n"; |
||||||
|
foreach ($list as $timezone => $name) { |
||||||
|
echo '<option value="' . $timezone . '">' . $name . '</option>' . "\n"; |
||||||
|
} |
||||||
|
echo '<optgroup>' . "\n"; |
||||||
|
} |
||||||
|
echo '</select>'; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,274 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts |
||||||
|
* @copyright Copyright (c) 2022, Robert Strutts. |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
final class time_zones { |
||||||
|
|
||||||
|
/** |
||||||
|
* MySQL time conversion! |
||||||
|
* @param type $field time |
||||||
|
* @param type $time_zone_name, leave blank for users time zone! |
||||||
|
* @return type |
||||||
|
*/ |
||||||
|
public static function db_convert_tz($field, $time_zone_name = '') { |
||||||
|
$session_time_zone = (isset($_SESSION['time_zone'])) ? $_SESSION['time_zone'] : 'America/Detroit'; |
||||||
|
$tz = (!empty($time_zone_name) ) ? $time_zone_name : $session_time_zone; |
||||||
|
$to_tz = self::current_time_for_time_zone($tz); |
||||||
|
return "CONVERT_TZ({$field}, '+00:00', '{$to_tz}')"; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Purpose: To convert time zone to offset time |
||||||
|
* @param type $time_zone_name |
||||||
|
* @return offset |
||||||
|
*/ |
||||||
|
public static function current_time_for_time_zone($time_zone_name) { |
||||||
|
$time = new \DateTime('now', new \DateTimeZone($time_zone_name)); |
||||||
|
return $time->format('P'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Purpose: To make a temporary valid timestamp for a database |
||||||
|
*/ |
||||||
|
public static function expires_in_hours(int $hours = 1) { |
||||||
|
$hours = ($hours > 0 && $hours < 10) ? $hours : 1; |
||||||
|
$expires = new DateTime('NOW', new \DateTimeZone('UTC')); |
||||||
|
$expires->add(new DateInterval("PT0{$hours}H")); |
||||||
|
return $expires->format('Y-m-d H:i:s'); |
||||||
|
} |
||||||
|
|
||||||
|
private static function mdy($userTime, $format) { |
||||||
|
switch (bootstrap\common::string_to_lowercase($format)) { |
||||||
|
case 'actions': |
||||||
|
return $userTime->format('m-d-Y / h:iA'); |
||||||
|
case 'report': |
||||||
|
return $userTime->format('l jS \of F\, Y\, h:i a'); |
||||||
|
case 'fancy': |
||||||
|
return $userTime->format('l jS \of F Y h:i:s A'); |
||||||
|
case 'logging': |
||||||
|
case 'log': |
||||||
|
return $userTime->format('g:i A \o\n l jS F Y'); |
||||||
|
case 'legal_date': |
||||||
|
return $userTime->format('n/j/Y'); |
||||||
|
case 'date': |
||||||
|
return $userTime->format('m/d/Y'); |
||||||
|
case 'date-time': |
||||||
|
return $userTime->format('m/d/Y h:i:s A'); |
||||||
|
case 'full': |
||||||
|
return $userTime->format('m-d-Y h:i:s A'); |
||||||
|
case 'normal': |
||||||
|
return $userTime->format('m/d/Y h:i A'); |
||||||
|
case 'default': |
||||||
|
return $userTime->format('m-d-Y h:i A'); |
||||||
|
default: |
||||||
|
return $userTime->format($format); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static function dmy($userTime, $format) { |
||||||
|
switch (bootstrap\common::string_to_lowercase($format)) { |
||||||
|
case 'actions': |
||||||
|
return $userTime->format('d-m-Y / h:iA'); |
||||||
|
case 'report': |
||||||
|
return $userTime->format('l jS \of F\, Y\, h:i a'); |
||||||
|
case 'fancy': |
||||||
|
return $userTime->format('l jS \of F Y h:i:s A'); |
||||||
|
case 'logging': |
||||||
|
case 'log': |
||||||
|
return $userTime->format('g:i A \o\n l jS F Y'); |
||||||
|
case 'legal_date': |
||||||
|
return $userTime->format('j/n/Y'); |
||||||
|
case 'date': |
||||||
|
return $userTime->format('d/m/Y'); |
||||||
|
case 'date-time': |
||||||
|
return $userTime->format('d/m/Y h:i:s A'); |
||||||
|
case 'full': |
||||||
|
return $userTime->format('d-m-Y h:i:s A'); |
||||||
|
case 'normal': |
||||||
|
return $userTime->format('d/m/Y h:i A'); |
||||||
|
case 'default': |
||||||
|
return $userTime->format('d-m-Y h:i A'); |
||||||
|
default: |
||||||
|
return $userTime->format($format); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static function ymd($userTime, $format) { |
||||||
|
switch (bootstrap\common::string_to_lowercase($format)) { |
||||||
|
case 'actions': |
||||||
|
return $userTime->format('Y-m-d / h:iA'); |
||||||
|
case 'report': |
||||||
|
return $userTime->format('l jS \of F\, Y\, h:i a'); |
||||||
|
case 'fancy': |
||||||
|
return $userTime->format('l jS \of F Y h:i:s A'); |
||||||
|
case 'logging': |
||||||
|
case 'log': |
||||||
|
return $userTime->format('g:i A \o\n l jS F Y'); |
||||||
|
case 'legal_date': |
||||||
|
return $userTime->format('Y/n/j'); |
||||||
|
case 'date': |
||||||
|
return $userTime->format('Y/m/d'); |
||||||
|
case 'date-time': |
||||||
|
return $userTime->format('Y/m/d h:i:s A'); |
||||||
|
case 'full': |
||||||
|
return $userTime->format('Y-m-d h:i:s A'); |
||||||
|
case 'normal': |
||||||
|
return $userTime->format('Y/m/d h:i A'); |
||||||
|
case 'default': |
||||||
|
return $userTime->format('Y-m-d h:i A'); |
||||||
|
default: |
||||||
|
return $userTime->format($format); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static function dt_format($userTime, $format, $country) { |
||||||
|
switch (bootstrap\common::string_to_lowercase($format)) { |
||||||
|
case 'object': |
||||||
|
return $userTime; |
||||||
|
case 'unix': |
||||||
|
return $userTime->format('U'); |
||||||
|
case 'day': |
||||||
|
return $userTime->format('l'); |
||||||
|
case 'time': |
||||||
|
return $userTime->format('h:i A'); |
||||||
|
case 'military': |
||||||
|
return $userTime->format('H:i:s'); |
||||||
|
case 'atom': |
||||||
|
return $userTime->format(DateTime::ATOM); |
||||||
|
case 'cookie': |
||||||
|
return $userTime->format(DateTime::COOKIE); |
||||||
|
case 'iso8601': |
||||||
|
case 'iso': |
||||||
|
case '8601': |
||||||
|
return $userTime->format(DateTime::ISO8601); |
||||||
|
case 'rfc822': |
||||||
|
return $userTime->format(DateTime::RFC822); |
||||||
|
case 'rfc850': |
||||||
|
return $userTime->format(DateTime::RFC850); |
||||||
|
case 'rfc1036': |
||||||
|
return $userTime->format(DateTime::RFC1036); |
||||||
|
case 'rfc1123': |
||||||
|
return $userTime->format(DateTime::RFC1123); |
||||||
|
case 'rfc2822': |
||||||
|
return $userTime->format(DateTime::RFC2822); |
||||||
|
case 'rfc3339': |
||||||
|
return $userTime->format(DateTime::RFC3339); |
||||||
|
case 'rss': |
||||||
|
return $userTime->format(DateTime::RSS); |
||||||
|
case 'w3c': |
||||||
|
return $userTime->format(DateTime::W3C); |
||||||
|
case 'standard': |
||||||
|
case 'computer': |
||||||
|
case 'database': |
||||||
|
return $userTime->format('Y-m-d H:i:s'); |
||||||
|
} |
||||||
|
|
||||||
|
switch (bootstrap\common::string_to_lowercase($country)) { |
||||||
|
case 'china': |
||||||
|
return self::ymd($userTime, $format); |
||||||
|
case 'int': |
||||||
|
case 'other': |
||||||
|
return self::dmy($userTime, $format); |
||||||
|
default: |
||||||
|
return self::mdy($userTime, $format); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Purpose: To convert a database timestamp into the users own Time Zone. |
||||||
|
*/ |
||||||
|
public static function convert_time_zone($options) { |
||||||
|
$format = (isset($options['format'])) ? $options['format'] : 'normal'; |
||||||
|
|
||||||
|
$session_time_zone = (isset($_SESSION['time_zone'])) ? $_SESSION['time_zone'] : 'America/Detroit'; |
||||||
|
$tz = (isset($options['time_zone']) && !empty($options['time_zone'])) ? $options['time_zone'] : $session_time_zone; |
||||||
|
|
||||||
|
$offset = (isset($options['offset'])) ? $options['offset'] : ''; |
||||||
|
|
||||||
|
$db_time = (isset($options['time'])) ? $options['time'] : ''; |
||||||
|
if ($db_time === '0000-00-00 00:00:00') { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
$new_time = (empty($db_time)) ? self::get_offset($offset) : self::get_offset_by($offset, $db_time); |
||||||
|
|
||||||
|
// Convert date("U"); unix timestamps to proper format for DateTime function... |
||||||
|
if (substr_count($new_time, ':') == 0) { |
||||||
|
$the_time = (empty($new_time) || $new_time == 'now' || $new_time == 'current') ? gmdate("Y-m-d H:i:s") : gmdate("Y-m-d H:i:s", $new_time); |
||||||
|
} |
||||||
|
|
||||||
|
$userTime = new \DateTime($the_time, new \DateTimeZone('UTC')); |
||||||
|
|
||||||
|
// Set the users time_zone to their zone |
||||||
|
if ($tz !== 'UTC') { |
||||||
|
$userTime->setTimezone(new \DateTimeZone($tz)); |
||||||
|
} |
||||||
|
|
||||||
|
$country = (isset($options['country'])) ? $options['country'] : 'usa'; |
||||||
|
|
||||||
|
return self::dt_format($userTime, $format, $country); |
||||||
|
} |
||||||
|
|
||||||
|
public static function human_date($input_date) { |
||||||
|
if (empty($input_date)) { |
||||||
|
return ''; |
||||||
|
} |
||||||
|
$today = self::convert_time_zone(array('format' => 'm/d/Y')); |
||||||
|
$date = strtotime($input_date); |
||||||
|
if (date('m/d/Y', $date) == $today) { |
||||||
|
return date('g:i', $date) . "<span style=\"font-size: 0.65em; vertical-align: text-top; margin-left: 1px; text-transform: lowercase;\">" . date('A', $date) . "</span>"; |
||||||
|
} elseif (date('Y', $date) == date('Y')) { |
||||||
|
return "<span style=\"font-weight: 500;\">" . date('M', $date) . " " . date('j', $date) . "<span style=\"font-size: 0.65em; vertical-align: text-top; margin-left: 1px;\">" . date('S', $date) . "</span></span>"; |
||||||
|
} else { |
||||||
|
return date('m/d/y', $date); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static function is_valid_offset($offset) { |
||||||
|
if (substr_count($offset, 'second') > 0) { |
||||||
|
return true; |
||||||
|
} elseif (substr_count($offset, 'minute') > 0) { |
||||||
|
return true; |
||||||
|
} elseif (substr_count($offset, 'hour') > 0) { |
||||||
|
return true; |
||||||
|
} elseif (substr_count($offset, 'day') > 0) { |
||||||
|
return true; |
||||||
|
} elseif (substr_count($offset, 'week') > 0) { |
||||||
|
return true; |
||||||
|
} elseif (substr_count($offset, 'month') > 0) { |
||||||
|
return true; |
||||||
|
} elseif (substr_count($offset, 'year') > 0) { |
||||||
|
return true; |
||||||
|
} elseif (substr_count($offset, 'next') > 0) { |
||||||
|
return true; |
||||||
|
} elseif (substr_count($offset, 'last') > 0) { |
||||||
|
return true; |
||||||
|
} else { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static function get_offset($offset) { |
||||||
|
return (self::is_valid_offset($offset)) ? strtotime($offset) : $offset; |
||||||
|
} |
||||||
|
|
||||||
|
private static function get_offset_by($offset, $db_time) { |
||||||
|
// strtotime requires a int timestamp |
||||||
|
if (substr_count($db_time, ':') > 0) { |
||||||
|
$UTC = new \DateTime($db_time, new \DateTimeZone('UTC')); |
||||||
|
$db_time = $UTC->format('U'); |
||||||
|
} |
||||||
|
|
||||||
|
return (self::is_valid_offset($offset)) ? strtotime($offset, $db_time) : $db_time; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,60 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace CodeHydrater\traits; |
||||||
|
|
||||||
|
trait Macroable |
||||||
|
{ |
||||||
|
protected static array $macros = []; |
||||||
|
|
||||||
|
/** |
||||||
|
* Register a custom macro. |
||||||
|
*/ |
||||||
|
public static function macro(string $name, mixed $macro): void |
||||||
|
{ |
||||||
|
static::$macros[$name] = $macro; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks if macro is registered. |
||||||
|
*/ |
||||||
|
public static function hasMacro(string $name): bool |
||||||
|
{ |
||||||
|
return isset(static::$macros[$name]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Dynamically handle calls to the class. |
||||||
|
*/ |
||||||
|
public function __call(string $method, mixed $parameters): mixed |
||||||
|
{ |
||||||
|
if (!static::hasMacro($method)) { |
||||||
|
throw new \BadMethodCallException("Method {$method} does not exist."); |
||||||
|
} |
||||||
|
|
||||||
|
$macro = static::$macros[$method]; |
||||||
|
|
||||||
|
if ($macro instanceof \Closure) { |
||||||
|
return call_user_func_array($macro->bindTo($this, static::class), $parameters); |
||||||
|
} |
||||||
|
|
||||||
|
return call_user_func_array($macro, $parameters); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Dynamically handle static calls to the class. |
||||||
|
*/ |
||||||
|
public static function __callStatic(string $method, mixed $parameters): mixed |
||||||
|
{ |
||||||
|
if (!static::hasMacro($method)) { |
||||||
|
throw new \BadMethodCallException("Method {$method} does not exist."); |
||||||
|
} |
||||||
|
|
||||||
|
$macro = static::$macros[$method]; |
||||||
|
|
||||||
|
if ($macro instanceof \Closure) { |
||||||
|
return call_user_func_array(\Closure::bind($macro, null, static::class), $parameters); |
||||||
|
} |
||||||
|
|
||||||
|
return call_user_func_array($macro, $parameters); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,68 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types = 1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts <Bob_586@Yahoo.com> |
||||||
|
* @copyright (c) 2025, Robert Strutts |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
/** |
||||||
|
* Description of uuidv7 |
||||||
|
* |
||||||
|
* @author Robert Strutts <Bob_586@Yahoo.com> |
||||||
|
*/ |
||||||
|
class uuidv7 { |
||||||
|
|
||||||
|
public static function base32EncodedUUID(): string { |
||||||
|
$uuid = self::generateUUIDv7(); |
||||||
|
$uuidHex = str_replace('-', '', $uuid); |
||||||
|
return self::base32Encode($uuidHex); |
||||||
|
} |
||||||
|
|
||||||
|
public static function generateUUIDv7(): string { |
||||||
|
$timestamp = microtime(true) * 10000; // current timestamp in milliseconds |
||||||
|
$timeHex = str_pad(dechex((int)$timestamp), 12, '0', STR_PAD_LEFT); |
||||||
|
|
||||||
|
$randomHex = bin2hex(random_bytes(10)); |
||||||
|
|
||||||
|
return sprintf( |
||||||
|
'%s-%s-%s-%s-%s', |
||||||
|
substr($timeHex, 0, 8), |
||||||
|
substr($timeHex, 8, 4), |
||||||
|
'7' . substr($timeHex, 12, 3) . substr($randomHex, 0, 1), // UUIDv7 |
||||||
|
substr($randomHex, 1, 4), |
||||||
|
substr($randomHex, 5, 12) |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
public static function base32Encode(string $hex): string { |
||||||
|
$base32Chars = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; |
||||||
|
$binary = ''; |
||||||
|
|
||||||
|
// Convert hex to binary |
||||||
|
foreach (str_split($hex) as $hexChar) { |
||||||
|
$binary .= str_pad(base_convert($hexChar, 16, 2), 4, '0', STR_PAD_LEFT); |
||||||
|
} |
||||||
|
|
||||||
|
// Split binary string into 5-bit chunks and convert to base32 |
||||||
|
$base32 = ''; |
||||||
|
foreach (str_split($binary, 5) as $chunk) { |
||||||
|
$base32 .= $base32Chars[bindec(str_pad($chunk, 5, '0', STR_PAD_RIGHT))]; |
||||||
|
} |
||||||
|
|
||||||
|
return $base32; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @example Database SQL: |
||||||
|
CREATE TABLE test_table ( |
||||||
|
id CHAR(36) PRIMARY KEY, |
||||||
|
name VARCHAR(255) NOT NULL, |
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP |
||||||
|
); |
||||||
|
*/ |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,243 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Robert Strutts |
||||||
|
* @copyright Copyright (c) 2022, Robert Strutts. |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace CodeHydrater; |
||||||
|
|
||||||
|
final class view { |
||||||
|
public $white_space_control = false; |
||||||
|
public $page_output; |
||||||
|
private $vars = []; |
||||||
|
private $project_dir = ""; // Not used anymore |
||||||
|
private $files = []; |
||||||
|
private $template = false; |
||||||
|
private $use_template_engine = false; |
||||||
|
private $template_type = 'tpl'; |
||||||
|
protected $tempalte_engine = null; |
||||||
|
|
||||||
|
private function get_file(string $view_file, string $default): string { |
||||||
|
$file_ext = bootstrap\common::get_string_right($view_file, 4); |
||||||
|
if (! bootstrap\common::is_string_found($file_ext, '.')) { |
||||||
|
$view_file .= '.php'; |
||||||
|
} |
||||||
|
$file = (empty($default)) ? "{$this->project_dir}/views/{$view_file}" : "{$this->project_dir}/views/{$default}/{$view_file}"; |
||||||
|
$path = bootstrap\site_helper::get_root(); |
||||||
|
$vf = $path . $file; |
||||||
|
if ( bootstrap\requires::safer_file_exists($vf) !== false) { |
||||||
|
return $file; |
||||||
|
} |
||||||
|
return ''; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Alias to set_view |
||||||
|
*/ |
||||||
|
public function include(string $file): void { |
||||||
|
$this->set_view($file); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Alias to set_view |
||||||
|
*/ |
||||||
|
public function add_view(string $file): void { |
||||||
|
$this->set_view($file); |
||||||
|
} |
||||||
|
|
||||||
|
private function find_view_path(string $view_file) { |
||||||
|
$found = false; |
||||||
|
|
||||||
|
$default_paths = bootstrap\configure::get('view_mode', 'default_paths'); |
||||||
|
$get = misc::request_var('render'); |
||||||
|
if (in_array($get, $default_paths)) { |
||||||
|
if (($key = array_search($get, $default_paths)) !== false) { |
||||||
|
unset($default_paths[$key]); // Remove as we'll make it first later... |
||||||
|
} |
||||||
|
array_unshift($default_paths, $get); // Make First in Array! |
||||||
|
} |
||||||
|
|
||||||
|
foreach ($default_paths as $default) { |
||||||
|
$file = $this->get_file($view_file, $default); |
||||||
|
if ( ! empty($file) ) { |
||||||
|
$found = true; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
return ($found) ? $file : false; |
||||||
|
} |
||||||
|
|
||||||
|
private function find_template_path($tpl_file) { |
||||||
|
$file = "{$this->project_dir}/views/includes/{$tpl_file}"; |
||||||
|
$path = bootstrap\site_helper::get_root(); |
||||||
|
$vf = $path . $file; |
||||||
|
return bootstrap\requires::safer_file_exists($vf); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Use View File |
||||||
|
* @param string $view_file |
||||||
|
* @param string $render_path |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public function set_view(string $view_file = null): void { |
||||||
|
if ($view_file === null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
$file_ext = bootstrap\common::get_string_right($view_file, 4); |
||||||
|
if (! bootstrap\common::is_string_found($file_ext, '.')) { |
||||||
|
$file_ext = '.php'; |
||||||
|
} else if ($file_ext !== '.php') { |
||||||
|
$this->use_template_engine = true; |
||||||
|
$this->template_type = str_replace('.', '', $file_ext); |
||||||
|
} |
||||||
|
|
||||||
|
if ($file_ext === '.php') { |
||||||
|
$file = $this->find_view_path($view_file); |
||||||
|
} else { |
||||||
|
$file = $this->find_template_path($view_file); |
||||||
|
} |
||||||
|
|
||||||
|
if ($file === false) { |
||||||
|
echo "No view file exists for: {$view_file}!"; |
||||||
|
throw new \Exception("View File does not exist: " . $view_file); |
||||||
|
} else { |
||||||
|
$this->files[] = array('file'=>$file, 'path'=>"project", 'file_type'=>$file_ext); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public function clear_template(): void { |
||||||
|
$this->template = false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Use Template with view |
||||||
|
* @param string $render_page |
||||||
|
* @return bool was found |
||||||
|
*/ |
||||||
|
public function set_template(string $render_page): bool { |
||||||
|
if (! empty($render_page)) { |
||||||
|
$render_page = str_replace('.php', '', $render_page); |
||||||
|
$templ = "{$this->project_dir}/templates/{$render_page}"; |
||||||
|
if (bootstrap\requires::safer_file_exists(bootstrap\site_helper::get_root() . $templ. '.php') !== false) { |
||||||
|
$this->template = $templ; |
||||||
|
// echo $this->template; |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
$this->template = false; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
private function clear_ob(int $saved_ob_level): void { |
||||||
|
while (ob_get_level() > $saved_ob_level) { |
||||||
|
ob_end_flush(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets a variable in this view with the given name and value |
||||||
|
* |
||||||
|
* @param mixed $name Name of the variable to set in the view, or an array of key/value pairs where each key is the variable and each value is the value to set. |
||||||
|
* @param mixed $value Value of the variable to set in the view. |
||||||
|
*/ |
||||||
|
public function set($name, $value = null): void { |
||||||
|
if (is_array($name)) { |
||||||
|
foreach ($name as $var_name => $value) { |
||||||
|
$this->vars[$var_name] = $value; |
||||||
|
} |
||||||
|
} else { |
||||||
|
$this->vars[$name] = $value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Alias to fetch with Built-in echo |
||||||
|
* @param type $local |
||||||
|
* @param string $file |
||||||
|
*/ |
||||||
|
public function render($local, string $file = null) { |
||||||
|
echo $this->fetch($local, $file); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Outputs view |
||||||
|
* @param type $local = $this |
||||||
|
* @param $file (optional view file) |
||||||
|
*/ |
||||||
|
public function fetch($local, string $file = null): string { |
||||||
|
$page_output = ob_get_clean(); // Get echos before View |
||||||
|
bootstrap\views::ob_start(); |
||||||
|
$saved_ob_level = ob_get_level(); |
||||||
|
$this->set_view($file); |
||||||
|
|
||||||
|
unset($file); |
||||||
|
|
||||||
|
if (!is_object($local)) { |
||||||
|
$local = $this; // FALL Back, please use fetch($this); |
||||||
|
} |
||||||
|
|
||||||
|
if ($this->use_template_engine) { |
||||||
|
$this->tempalte_engine = bootstrap\registry::get('di')->get_service('templates', [$this->template_type]); |
||||||
|
if ($this->white_space_control) { |
||||||
|
$this->tempalte_engine->whitespace_control(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (count($this->files) > 0) { |
||||||
|
foreach ($this->files as $view_file) { |
||||||
|
if ($view_file['file_type'] == '.php') { |
||||||
|
bootstrap\requires::secure_include($view_file['file'], $view_file['path'], $local, $this->vars); // Include the file |
||||||
|
} else { |
||||||
|
$template_file = str_replace('.tpl', '', $view_file['file']); |
||||||
|
$this->tempalte_engine->parse_file($template_file); |
||||||
|
$assigns = $this->vars['template_assigns'] ?? []; |
||||||
|
$filters = $this->vars['template_filters'] ?? null; |
||||||
|
$registers = $this->vars['template_registers'] ?? []; |
||||||
|
$assigns['production'] =(\main_tts\is_live()); |
||||||
|
echo $this->tempalte_engine->render($assigns, $filters, $registers); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
$this->clear_ob($saved_ob_level); |
||||||
|
$page_output .= ob_get_clean(); |
||||||
|
|
||||||
|
try { |
||||||
|
if (bootstrap\common::get_bool(bootstrap\configure::get('tts', 'check_HTML_tags')) === true) { |
||||||
|
$tags = \tts\tag_matches::check_tags($page_output); |
||||||
|
if (! empty($tags['output'])) { |
||||||
|
$page_output .= $tags['output']; |
||||||
|
$page_output .= '<script type="text/javascript">'.$tags['alert'].'</script>'; |
||||||
|
foreach($this->files as $bad) { |
||||||
|
$page_output .= "<script type=\"text/javascript\">console.log'In view file:{$bad['file']}');\r\n</script>"; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (exceptions\Bool_Exception $e) { |
||||||
|
if (bootstrap\configure::get('tts', 'live') === false) { |
||||||
|
$page_output .= assets::alert('SET Config for tts: check_HTML_tags'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if ($this->template !== false && bootstrap\requires::safer_file_exists(bootstrap\site_helper::get_root() . $this->template . ".php") !== false) { |
||||||
|
bootstrap\views::ob_start(); |
||||||
|
$saved_ob_level = ob_get_level(); |
||||||
|
$local->page_output = $page_output; |
||||||
|
bootstrap\requires::secure_include($this->template, 'project', $local, $this->vars); |
||||||
|
$this->clear_ob($saved_ob_level); |
||||||
|
$page_output = ob_get_clean(); |
||||||
|
} |
||||||
|
|
||||||
|
// Reset Files to zero, as they were outputed.... |
||||||
|
unset($this->files); |
||||||
|
$this->files = []; |
||||||
|
|
||||||
|
return $page_output; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue