From 434883baa8b499993f5c8fe3a8d3dbdaa7beaa23 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 20 Jan 2026 16:50:34 -0500 Subject: [PATCH] more --- README.md | 5 +- src/Framework/Arrays/CommonStuff.php | 102 ++ src/Framework/Arrays/Countries.php | 262 ++++ src/Framework/Arrays/Mimes.php | 166 +++ src/Framework/Arrays/Mocking/Address.php | 45 + src/Framework/Arrays/Mocking/Phone.php | 45 + src/Framework/Arrays/Mocking/RndNames.php | 1179 +++++++++++++++++ src/Framework/Arrays/Shortn.php | 29 + src/Framework/Arrays/ZipCodes.php | 185 +++ src/Framework/Assets.php | 267 ++++ .../Attributes/Validators/MyValidator.php | 229 ++++ src/Framework/BbCodeParser.php | 176 +++ src/Framework/Collection.php | 32 + src/Framework/Common.php | 4 +- src/Framework/Dollars.php | 31 + src/Framework/Enum/CompressionMethod.php | 18 + src/Framework/Enum/ViewType.php | 22 + src/Framework/GzCompression.php | 53 + src/Framework/Html.php | 229 ++++ src/Framework/HtmlDocument.php | 435 ++++++ src/Framework/HtmlParser.php | 175 +++ src/Framework/{ => Http/App}/App.php | 18 +- src/Framework/Http/App/AppHandler.php | 22 +- .../Contract/MiddlewareAwareInterface.php | 16 + .../Http/Contract/MiddlewareInterface.php | 19 + .../Http/Contract/RouterInterface.php | 2 +- .../RouteMiddlewareNotFoundException.php | 15 + src/Framework/Http/Kernel.php | 45 +- src/Framework/Http/MiddlewareQueueHandler.php | 6 +- .../Http/Routing/RouterMiddlewareHandler.php | 44 + src/Framework/Http/Routing/RoutingHandler.php | 19 +- src/Framework/LazyCollection.php | 103 ++ src/Framework/LazyObject.php | 32 + src/Framework/MemoryUsage.php | 66 + src/Framework/PhpFileCache.php | 46 + src/Framework/RandomEngine.php | 106 ++ src/Framework/RssFeed.php | 135 ++ src/Framework/Scalar.php | 21 + src/Framework/SessionManagement.php | 94 ++ src/Framework/String/StringFacade.php | 1 + src/Framework/TagMatches.php | 66 + src/Framework/TimeZoneSelection.php | 48 + src/Framework/TimeZones.php | 287 ++++ src/Framework/Trait/Database/RunSql.php | 79 ++ src/Framework/Trait/Database/Validation.php | 208 +++ src/Framework/Trait/FormValidator.php | 156 +++ src/Framework/Trait/Macroable.php | 64 + src/Framework/Uuids/Base62.php | 36 + src/Framework/Uuids/UuidV7.php | 113 ++ src/Framework/Validator.php | 121 ++ src/Framework/View.php | 282 ++++ 51 files changed, 5934 insertions(+), 25 deletions(-) create mode 100644 src/Framework/Arrays/CommonStuff.php create mode 100644 src/Framework/Arrays/Countries.php create mode 100644 src/Framework/Arrays/Mimes.php create mode 100644 src/Framework/Arrays/Mocking/Address.php create mode 100644 src/Framework/Arrays/Mocking/Phone.php create mode 100644 src/Framework/Arrays/Mocking/RndNames.php create mode 100644 src/Framework/Arrays/Shortn.php create mode 100644 src/Framework/Arrays/ZipCodes.php create mode 100644 src/Framework/Assets.php create mode 100644 src/Framework/Attributes/Validators/MyValidator.php create mode 100644 src/Framework/BbCodeParser.php create mode 100644 src/Framework/Collection.php create mode 100644 src/Framework/Dollars.php create mode 100644 src/Framework/Enum/CompressionMethod.php create mode 100644 src/Framework/Enum/ViewType.php create mode 100644 src/Framework/GzCompression.php create mode 100644 src/Framework/Html.php create mode 100644 src/Framework/HtmlDocument.php create mode 100644 src/Framework/HtmlParser.php rename src/Framework/{ => Http/App}/App.php (93%) create mode 100644 src/Framework/Http/Contract/MiddlewareAwareInterface.php create mode 100644 src/Framework/Http/Contract/MiddlewareInterface.php create mode 100644 src/Framework/Http/Exception/RouteMiddlewareNotFoundException.php create mode 100644 src/Framework/Http/Routing/RouterMiddlewareHandler.php create mode 100644 src/Framework/LazyCollection.php create mode 100644 src/Framework/LazyObject.php create mode 100644 src/Framework/MemoryUsage.php create mode 100644 src/Framework/PhpFileCache.php create mode 100644 src/Framework/RandomEngine.php create mode 100644 src/Framework/RssFeed.php create mode 100644 src/Framework/Scalar.php create mode 100644 src/Framework/SessionManagement.php create mode 100644 src/Framework/TagMatches.php create mode 100644 src/Framework/TimeZoneSelection.php create mode 100644 src/Framework/TimeZones.php create mode 100644 src/Framework/Trait/Database/RunSql.php create mode 100644 src/Framework/Trait/Database/Validation.php create mode 100644 src/Framework/Trait/FormValidator.php create mode 100644 src/Framework/Trait/Macroable.php create mode 100644 src/Framework/Uuids/Base62.php create mode 100644 src/Framework/Uuids/UuidV7.php create mode 100644 src/Framework/Validator.php create mode 100644 src/Framework/View.php diff --git a/README.md b/README.md index 5095dd3..c9056ab 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # IOcornerstone PHP 8.5 Framework -Author Robert Strutts -Copyright (c) 2010-2026 MIT +## Author Robert Strutts +## Copyright (c) 2010-2026 Robert Strutts +## License MIT diff --git a/src/Framework/Arrays/CommonStuff.php b/src/Framework/Arrays/CommonStuff.php new file mode 100644 index 0000000..d828e30 --- /dev/null +++ b/src/Framework/Arrays/CommonStuff.php @@ -0,0 +1,102 @@ + '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 statesArray(): 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', + ); + } + +} \ No newline at end of file diff --git a/src/Framework/Arrays/Countries.php b/src/Framework/Arrays/Countries.php new file mode 100644 index 0000000..381413d --- /dev/null +++ b/src/Framework/Arrays/Countries.php @@ -0,0 +1,262 @@ + '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' + ); + } +} \ No newline at end of file diff --git a/src/Framework/Arrays/Mimes.php b/src/Framework/Arrays/Mimes.php new file mode 100644 index 0000000..66b24bc --- /dev/null +++ b/src/Framework/Arrays/Mimes.php @@ -0,0 +1,166 @@ + [ + '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 mimesDangerious(): 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 getMimeType(string $filename, array $allowed = ['all']) { + $ext = strtolower(array_pop(explode('.', $filename))); + $bad = self::mimesDangerious(); + + if (array_key_exists($ext, $bad)) { + return false; + } + + $mime_types = self::mimesArray(); + + $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; + } + +} diff --git a/src/Framework/Arrays/Mocking/Address.php b/src/Framework/Arrays/Mocking/Address.php new file mode 100644 index 0000000..2ef743f --- /dev/null +++ b/src/Framework/Arrays/Mocking/Address.php @@ -0,0 +1,45 @@ + 'Ave', + 'BOULEVARD' => 'Blvd', + 'DRIVE' => 'Dr', + 'LANE' => 'Ln', + 'MOUNT' => 'Mt', + 'ROAD' => 'Rd', + 'STREET' => 'St', + ' NORTH ' => ' N. ', + ' SOUTH ' => ' S. ', + ' EAST ' => ' E. ', + ' WEST ' => ' W. ' + ]; + foreach ($uspsAbbreviations as $key => $value) { + $text = str_ireplace($key, $value, $text); + } + return $text; + } + +} \ No newline at end of file diff --git a/src/Framework/Arrays/ZipCodes.php b/src/Framework/Arrays/ZipCodes.php new file mode 100644 index 0000000..85dbedc --- /dev/null +++ b/src/Framework/Arrays/ZipCodes.php @@ -0,0 +1,185 @@ += 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]; + } + +} \ No newline at end of file diff --git a/src/Framework/Assets.php b/src/Framework/Assets.php new file mode 100644 index 0000000..b8fb6fb --- /dev/null +++ b/src/Framework/Assets.php @@ -0,0 +1,267 @@ +$a_media) { + $ret .= self::wrapCss($file, $scope, $a_media); + } + return $ret; + } + + public static function loadallJs(array $files, string $scope='project'): string { + $ret = ''; + foreach($files as $file=>$a) { + $ret .= self::wrapJs($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::wrapAsset($file, $scope); + if ($file === false) { + return ''; + } + return "\r\n"; + } + + public static function alert($msg) { + return self::inlineJs('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 wrapAsset(string $file, string $scope = 'project') { + $scope = StringFacade::strtolower($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 (str_contains($file, '://') === true) ? $file : $protocol . $file; + } + if ($scope === 'project' || $scope === 'app') { + $path = PROJECT_ASSETS_DIR . "/"; + $ism = self::isMinified($path, $file); + return ($ism !== false) ? PROJECT_ASSETS_BASE_REF . "/" . $ism : false; + } + if ($scope === 'assets') { + $path = ASSETS_DIR . "/"; + $ism = self::isMinified($path, $file); + return ($ism !== false) ? ASSETS_BASE_REF . "/" . $ism : false; + } + return $file; + } + /** + * Fetch Version of file if exists + * @param string $file + * @param string $scope + * @return string|bool + */ + private static function projectPaths(string $file, string $scope = 'project'): string | bool { + $scope = stringFacade::strtolower($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 wrapCss(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::projectPaths($file, $scope); + $wrap_file = self::wrapAsset($file, $scope); + if ($ver === false || $wrap_file === false) { + return ""; + } + return "\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 wrapJs(string $file, string $scope = 'project', array $a = array()): string { + $more = ''; + if (count($a)) { + foreach ($a as $k => $v) { + $more .= (isset($k) && $k !=0 ) ? " {$k}=\"{$v}\"" : " {$v}"; + } + } + + $ver = self::projectPaths($file, $scope); + $wrap_file = self::wrapAsset($file, $scope); + if ($ver === false || $wrap_file === false) { + return ""; + } + return "\r\n"; + //return ""; + } + + /** + * Purpose: To do inline JavaScript. + * @param type $code string of code to inline into page. + * @retval type + */ + public static function inlineJs(string $code): string { + return "\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 jqueryLoad(string $code): string { + return "\r\n$(function() { \r\n \t {$code} \r\n }); \r\n"; + } + + public static function isMinified(string $path, string $file) { + if (self::attemptsRootDir($path)) { + return false; + } + $safe_path = Security::filterUri($path); + $safe_file = Security::filterUri($file); + + if (str_contains($safe_file, '.auto.js')) { + $production = (isLive()); + $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 (str_contains($safe_file, '.auto.css')) { + $production = (isLive()); + $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 gotoUrl(string $url): void { + echo ''; + 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 redirectUrl(string $url): void { + $url = str_replace(array('&', "\n", "\r"), array('&', '', ''), $url); + if (!headers_sent()) { + header('Location: ' . $url); + } else { + self::goto_url($url); + } + exit; + } + +} diff --git a/src/Framework/Attributes/Validators/MyValidator.php b/src/Framework/Attributes/Validators/MyValidator.php new file mode 100644 index 0000000..674eefb --- /dev/null +++ b/src/Framework/Attributes/Validators/MyValidator.php @@ -0,0 +1,229 @@ + is_string($message)); + // overwrite the default message + $validationErrors = array_merge(self::DEFAULT_VALIDATION_ERRORS, $ruleMessages); + + $fn = 'is_' . $rule_name; + $field = $name; + $data[$name] = $value; + + $callable = self::class . "::{$fn}"; + + $string_params = array_map('strval', $params); + + if (is_callable($callable)) { + $pass = $callable($data, $field, ...$string_params); + if (!$pass) { + $lookfor = $messages[$field][$rule_name] ?? $validationErrors[$rule_name]; + $new_params = array_values($params); + $this->errors[$field] = sprintf( + $lookfor, + $field, + ...$params + ); + } + } + } + + /** + * + * @param object $object + * @param array $messages defined in trait + * @param type $default null avoids an error on no-entry, false gives errors on no-entry + * @return void + */ + + public function validate(object $object, array $messages = [], DEFAULT_VALUE $default_value = DEFAULT_VALUE::do_not_error_on_null): void { + +$handlers = [ + Positive::class => function (string $name, $value, $attr, array $messages) { + $this->handleErrors("positive", $name, $value, messages: $messages); + }, + + Required::class => function (string $name, $value, $attr, array $messages) { + $this->handleErrors("required", $name, $value, messages: $messages); + }, + + Email::class => function (string $name, $value, $attr, array $messages) { + $this->handleErrors("email", $name, $value, messages: $messages); + }, + + GreaterThan::class => function (string $name, $value, $attr, array $messages) { + $params[] = $attr->value; + $this->handleErrors("greaterThan", $name, $value, $params, $messages); + }, + + LessThan::class => function (string $name, $value, $attr, array $messages) { + $params[] = $attr->value; + $this->handleErrors("lessThan", $name, $value, $params, $messages); + }, + + Min::class => function (string $name, $value, $attr, array $messages) { + $params[] = $attr->value; + $this->handleErrors("min", $name, $value, $params, $messages); + }, + + Max::class => function (string $name, $value, $attr, array $messages) { + $params[] = $attr->value; + $this->handleErrors("max", $name, $value, $params, $messages); + }, + + NumberRange::class => function (string $name, $value, $attr, array $messages) { + $params[] = $attr->min; + $params[] = $attr->max; + + $this->handleErrors("numberRange", $name, $value, $params, $messages); + }, + + Between::class => function (string $name, $value, $attr, array $messages) { + $params[] = $attr->min; + $params[] = $attr->max; + + $this->handleErrors("between", $name, $value, $params, $messages); + }, + + Same::class => function (string $name, $value, $attr, array $messages) { + $params[] = $attr->value; + $this->handleErrors("same", $name, $value, $params, $messages); + }, + + Alphanumeric::class => function (string $name, $value, $attr, array $messages) { + $this->handleErrors("alphanumeric", $name, $value, messages: $messages); + }, + + Secure::class => function (string $name, $value, $attr, array $messages) { + $this->handleErrors("secure", $name, $value, messages: $messages); + }, + + ValidEmailDomain::class => function (string $name, $value, $attr, array $messages) { + $this->handleErrors("validEmailDomain", $name, $value, messages: $messages); + }, + + ValidDomain::class => function (string $name, $value, $attr, array $messages) { + $this->handleErrors("validDomain", $name, $value, messages: $messages); + }, + +]; + + $default = match($default_value) { + DEFAULT_VALUE::do_not_error_on_null => null, + // Fail validation as user requested false on default + DEFAULT_VALUE::do_error_on_null => false, + default => null, // Pass validation as null or value unset + }; + + $ref = new \ReflectionObject($object); + + foreach ($ref->getProperties() as $property) { + $name = $property->getName(); + $property->setAccessible(true); + $value = $property->getValue($object) ?? $default; + + foreach ($property->getAttributes() as $attribute) { + $class = $attribute->getName(); + + if (!isset($handlers[$class])) { + continue; + } + + $handlers[$class]( + $name, + $value, + $attribute->newInstance(), + $messages + ); + } + } + } + + public function getErrors(): array { + return $this->errors; + } +} \ No newline at end of file diff --git a/src/Framework/BbCodeParser.php b/src/Framework/BbCodeParser.php new file mode 100644 index 0000000..07d0cea --- /dev/null +++ b/src/Framework/BbCodeParser.php @@ -0,0 +1,176 @@ + [ + 'pattern' => '/\[h1\](.*?)\[\/h1\]/s', + 'replace' => '

$1

', + 'content' => '$1' + ], + 'h2' => [ + 'pattern' => '/\[h2\](.*?)\[\/h2\]/s', + 'replace' => '

$1

', + 'content' => '$1' + ], + 'h3' => [ + 'pattern' => '/\[h3\](.*?)\[\/h3\]/s', + 'replace' => '

$1

', + 'content' => '$1' + ], + 'h4' => [ + 'pattern' => '/\[h4\](.*?)\[\/h4\]/s', + 'replace' => '

$1

', + 'content' => '$1' + ], + 'h5' => [ + 'pattern' => '/\[h5\](.*?)\[\/h5\]/s', + 'replace' => '
$1
', + 'content' => '$1' + ], + 'h6' => [ + 'pattern' => '/\[h6\](.*?)\[\/h6\]/s', + 'replace' => '
$1
', + 'content' => '$1' + ], + 'bold' => [ + 'pattern' => '/\[b\](.*?)\[\/b\]/s', + 'replace' => '$1', + 'content' => '$1' + ], + 'italic' => [ + 'pattern' => '/\[i\](.*?)\[\/i\]/s', + 'replace' => '$1', + 'content' => '$1' + ], + 'underline' => [ + 'pattern' => '/\[u\](.*?)\[\/u\]/s', + 'replace' => '$1', + 'content' => '$1' + ], + 'strikethrough' => [ + 'pattern' => '/\[s\](.*?)\[\/s\]/s', + 'replace' => '$1', + 'content' => '$1' + ], + 'quote' => [ + 'pattern' => '/\[quote\](.*?)\[\/quote\]/s', + 'replace' => '
$1
', + 'content' => '$1' + ], + 'link' => [ + 'pattern' => '/\[url\](.*?)\[\/url\]/s', + 'replace' => '$1', + 'content' => '$1' + ], + 'namedlink' => [ + 'pattern' => '/\[url\=(.*?)\](.*?)\[\/url\]/s', + 'replace' => '$2', + 'content' => '$2' + ], + 'image' => [ + 'pattern' => '/\[img\](.*?)\[\/img\]/s', + 'replace' => '', + 'content' => '$1' + ], + 'orderedlistnumerical' => [ + 'pattern' => '/\[list=1\](.*?)\[\/list\]/s', + 'replace' => '
    $1
', + 'content' => '$1' + ], + 'orderedlistalpha' => [ + 'pattern' => '/\[list=a\](.*?)\[\/list\]/s', + 'replace' => '
    $1
', + 'content' => '$1' + ], + 'unorderedlist' => [ + 'pattern' => '/\[list\](.*?)\[\/list\]/s', + 'replace' => '', + 'content' => '$1' + ], + 'listitem' => [ + 'pattern' => '/\[\*\](.*)/', + 'replace' => '
  • $1
  • ', + 'content' => '$1' + ], + 'code' => [ + 'pattern' => '/\[code\](.*?)\[\/code\]/s', + 'replace' => '$1', + 'content' => '$1' + ], + 'youtube' => [ + 'pattern' => '/\[youtube\](.*?)\[\/youtube\]/s', + 'replace' => '', + 'content' => '$1' + ], + 'sub' => [ + 'pattern' => '/\[sub\](.*?)\[\/sub\]/s', + 'replace' => '$1', + 'content' => '$1' + ], + 'sup' => [ + 'pattern' => '/\[sup\](.*?)\[\/sup\]/s', + 'replace' => '$1', + 'content' => '$1' + ], + 'small' => [ + 'pattern' => '/\[small\](.*?)\[\/small\]/s', + 'replace' => '$1', + 'content' => '$1' + ], + 'table' => [ + 'pattern' => '/\[table\](.*?)\[\/table\]/s', + 'replace' => '$1
    ', + 'content' => '$1', + ], + 'table-row' => [ + 'pattern' => '/\[tr\](.*?)\[\/tr\]/s', + 'replace' => '$1', + 'content' => '$1', + ], + 'table-data' => [ + 'pattern' => '/\[td\](.*?)\[\/td\]/s', + 'replace' => '$1', + '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; + } +} diff --git a/src/Framework/Collection.php b/src/Framework/Collection.php new file mode 100644 index 0000000..d2aaeb2 --- /dev/null +++ b/src/Framework/Collection.php @@ -0,0 +1,32 @@ + $items + */ + public function __construct( + private array $items + ) { + } + + /** + * @return array + */ + public function all(): array { + return $this->items; + } + +} \ No newline at end of file diff --git a/src/Framework/Common.php b/src/Framework/Common.php index 147997d..b17394a 100644 --- a/src/Framework/Common.php +++ b/src/Framework/Common.php @@ -22,7 +22,7 @@ final class Common unset($sensitive_data); } - public static function get_count($i): int + public static function getCount($i): int { return (is_array($i) || is_object($i)) ? count($i) : 0; } @@ -86,7 +86,7 @@ final class Common echo 'It is TRUE!'; } elseif (is_resource($var)) { echo 'VAR IS a RESOURCE'; - } elseif (is_array($var) && self::get_count($var) == 0) { + } elseif (is_array($var) && self::getCount($var) == 0) { echo 'VAR IS an EMPTY ARRAY!'; } elseif (is_numeric($var)) { echo 'VAR is a NUMBER = ' . $var; diff --git a/src/Framework/Dollars.php b/src/Framework/Dollars.php new file mode 100644 index 0000000..d72c6a2 --- /dev/null +++ b/src/Framework/Dollars.php @@ -0,0 +1,31 @@ +moneyAsFloat($money), 2, '.', ','); + } + + public function intl_USD(Number $money): string|false { + if (class_exists('NumberFormatter')) { + $formatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); + return $formatter->formatCurrency($this->moneyAsFloat($money), 'USD'); + } + return false; + } +} diff --git a/src/Framework/Enum/CompressionMethod.php b/src/Framework/Enum/CompressionMethod.php new file mode 100644 index 0000000..23c5147 --- /dev/null +++ b/src/Framework/Enum/CompressionMethod.php @@ -0,0 +1,18 @@ +value; + } +} diff --git a/src/Framework/GzCompression.php b/src/Framework/GzCompression.php new file mode 100644 index 0000000..bbec03f --- /dev/null +++ b/src/Framework/GzCompression.php @@ -0,0 +1,53 @@ +useCompression === false) { + return false; + } + + $level = ($this->compressionLevel < 10 && $this->compressionLevel > 0) ? $this->compressionLevel : 4; + + $c = match ($this->method) { + Method::DEFLATE => gzdeflate($data, $level), + Method::GZIP => gzencode($data, $level), + Method::ZLIB => gzcompress($data, $level), + }; + return base64_encode($c); + } + + public function decompress(string $compressed_data): string|false + { + if ($this->useCompression === false) { + return false; + } + $d = base64_decode($compressed_data); + return match ($this->method) { + Method::DEFLATE => gzinflate($d), + Method::GZIP => gzdecode($d), + Method::ZLIB => gzuncompress($d), + }; + } +} diff --git a/src/Framework/Html.php b/src/Framework/Html.php new file mode 100644 index 0000000..093a37d --- /dev/null +++ b/src/Framework/Html.php @@ -0,0 +1,229 @@ +value + * @param string $default Item to select on. + * @param string $select_by ['value'] for most of your needs. + * @param array $a as optional options + * @param bool $escape XSS prevention... + * @retval string of option values... + */ + public static function doOptions( + array $options, + string $default = '', + string $select_by = 'text', + array $a = array(), + bool $escape = true + ): string { + $more = ''; + if (count($a)) { + foreach ($a as $k => $v) { + if ($escape) { + $more .= " ". self::h($k) . "=\"" . self::h($v) . "\""; + } else { + $more .= " {$k}=\"{$v}\""; + } + } + } + + $values = ''; + foreach ($options as $value => $text) { + $compair_to = ($select_by == 'text') ? $text : $value; + $selected = (!empty($default) && $default == $compair_to) ? 'selected' : ''; + if ($escape) { + $value = self::h($value); + $text = self::h($text); + } + $values .= ""; + } + return $values; + } + + private static function makeHeadersOnTable(array $header_fields, array $options = []) { + $echo = $options['echo'] ?? self::ECHO; + $nl = PHP_EOL; + $default_table_setup = "border='1' cellpadding='1' cellspacing='1'"; + $table = $options['table_setup'] ?? $default_table_setup; + $escape = $options['escape'] ?? true; + $th = $options['th'] ?? ""; + $th_class = (! empty($th)) ? " class=\"$th\" " : ""; + + $ret = self::doEcho("{$nl}{$nl}", $echo); + $ret .= self::doEcho("\t{$nl}", $echo); + foreach($header_fields as $name=>$header_field) { + $skipping = $options['skip_output'][$name] ?? false; + if ($skipping) continue; + + $field = ($escape) ? self::h($header_field) : $header_field; + $ret .= self::doEcho("\t\t{$field}{$nl}", $echo); + } + $ret .= self::doEcho("\t{$nl}", $echo); + return $ret; + } + + /** + * Used by Memory_Usage script. + * Displays a table from input arrays -- fields + * @param array $header_fields - TH + * @param array $fields - TD + * @param bool $escape XSS prevention... + * @retval void + */ + public static function showTable( + array $header_fields, + array $fields, + array $options = [] + ): ?string { + $echo = $options['echo'] ?? self::ECHO; + $nl = PHP_EOL; + $ret = self::makeHeadersOnTable($header_fields, $options); + $escape = $options['escape'] ?? true; + foreach($fields as $field) { + $ret .= self::doEcho("\t{$nl}", $echo); + foreach($field as $td) { + $cell = ($escape) ? self::h($td) : $td; + $ret .= self::doEcho("\t\t{$nl}", $echo); + } + $ret .= self::doEcho("\t{$nl}", $echo); + } + $ret .= self::doEcho("
    {$cell}
    {$nl}", $echo); + return $ret; + } + + private static function makeCellTableHelperForIO(\Iterator $record, array $options = []): array { + $echo = $options['echo'] ?? self::ECHO; + $escape = $options['escape'] ?? true; + $cell_class = $options['cell_class'] ?? ""; + $row_class = $options['row_class'] ?? ""; + $cell_class_tag = (! empty($cell_class)) ? " class=\"$cell_class\" " : ""; + $row_class_tag = (! empty($row_class)) ? " class=\"$row_class\" " : ""; + $nl = PHP_EOL; + $ret = self::doEcho("\t{$nl}", $echo); + + $errors = []; + foreach($record as $html) { + $key = $html['name'] ?? ""; + $value = $html['html']; + + if (\CodeHydrater\common::get_count($html['errors'])) { + $errors[$key] = $html['errors'][$key]; + } + + $td = $value ?? ""; + if (is_string($td)) { + $cell = ($escape) ? self::h($td) : $td; + } else { + $cell = (string) $td; + } + $ret .= self::doEcho("\t\t{$cell}{$nl}", $echo); + } + $ret .= self::doEcho("\t{$nl}", $echo); + return ['errors' => $errors, 'data' => $ret]; + } + + private static function makeCellTableHelper(array $record, array $options = []): ?string { + $echo = $options['echo'] ?? self::ECHO; + $escape = $options['escape'] ?? true; + $cell_class = $options['cell_class'] ?? ""; + $row_class = $options['row_class'] ?? ""; + $cell_class_tag = (! empty($cell_class)) ? " class=\"$cell_class\" " : ""; + $row_class_tag = (! empty($row_class)) ? " class=\"$row_class\" " : ""; + $nl = PHP_EOL; + $ret = self::doEcho("\t{$nl}", $echo); + foreach($record as $key => $value) { + $skipping = $options['skip_output'][$key] ?? false; + if ($skipping) continue; + + if (! is_string($key)) { + continue; // Remove Duplicate records + } + $td = $value ?? ""; + if (is_string($td)) { + $cell = ($escape) ? self::h($td) : $td; + } else { + $cell = (string) $td; + } + $ret .= self::doEcho("\t\t{$cell}{$nl}", $echo); + } + $ret .= self::doEcho("\t{$nl}", $echo); + return $ret; + } + + /** + * Generators use Memory in an Effient way!!!! So use this. + * @param array $header_fields + * @param array $db_field_names + * @param $records, note: \Iterator not always can be used here + * @param bool $escape + * @return void + */ + public static function showTableFrom( + array $header_fields, + $records, + array $options = [], + ) { + $echo = $options['echo'] ?? self::ECHO; + $ret = self::makeHeadersOnTable($header_fields, $options); + switch($options['helper']) { + case "single-row": + $ret .= self::makeCellTableHelper($records, $options); + break; + case "io": + $ret = self::makeCellTableHelperForIO($records, $options); + $ret['data'] .= self::doEcho($ret['data'] . "" . PHP_EOL); + return $ret; + default: + foreach($records as $record) { + self::makeCellTableHelper($record, $options); + } + } + $ret .= self::doEcho("" . PHP_EOL, $echo); + return $ret; + } + + public static function showErrors( + ?array $errors = [], + array $options = [] + ): ?string { + $echo = $options['echo'] ?? self::ECHO; + $ret = ""; + if ($errors) { + $message = "Please correct the following errors: "; + $i = 0; + foreach($errors as $error) { + $i++; + $message .= "
    {$i}) " . $error; + } + $ret .= self::doEcho($message, $echo); + } + return $ret; + } +} diff --git a/src/Framework/HtmlDocument.php b/src/Framework/HtmlDocument.php new file mode 100644 index 0000000..b7cbaec --- /dev/null +++ b/src/Framework/HtmlDocument.php @@ -0,0 +1,435 @@ +title = Configure::get('html', 'title') ?? ''; + $this->author = Configure::get('html', 'author') ?? ''; + $this->footer = Configure::get('html', 'footer') ?? ''; + $this->keywords = Configure::get('html', 'keywords') ?? ''; + $this->description = Configure::get('html', 'description') ?? ''; + $this->robots = Configure::get('html', 'robots'); + $css = Configure::get('html', 'css'); + if (Common::getCount($css) > 0) { + foreach($css as $file=>$path) { + if (is_array($file)) continue; + if (is_array($path)) { + if (isset($path['path'])) { + $pathType = $path['path']; + unset($path['path']); + } else { + $pathType = "project"; + } + $this->addCss($file, $pathType, $path); + } else { + $this->addCss($file, $path); + } + } + } + $js = Configure::get('html', 'javascript'); + if (Common::getCount($js) >0) { + foreach($js as $file=>$path) { + if (is_array($file)) continue; + if (is_array($path)) { + if (isset($path['path'])) { + $pathType = $path['path']; + unset($path['path']); + } else { + $pathType = "project"; + } + $this->addJs($file, $pathType, $path); + } else { + $this->addJs($file, $path); + } + } + } + } + + public function clearCss(): void { + $this->styles = ''; + } + + public function clearJs(): void { + $this->scripts = ''; + } + + /** + * Set both Title and Header for HTML + * @param string $title + */ + public function setTitleAndHeader(string $title): void { + $this->title = $title; + $this->header = $title; + } + + /** + * Set Author for HTML + * @param string $title + */ + public function setAuthor(string $author): void { + $this->author = $author; + } + + /** + * Set Title for HTML + * @param string $title + */ + public function setTitle(string $title): void { + $this->title = $title; + } + + /** + * Set Header for HTML + * @param string $header + */ + public function setHeader(string $header): void { + $this->header = $header; + } + + public function setHead(string $head): void { + $this->head = $head; + } + + /** + * Set Footer for HTML + * @param string $footer + */ + public function setFooter(string $footer): void { +// $this->add_css('footer.css', 'project'); + $this->footer = $footer; + } + + /** + * Set Description for HTML + * @param string $description + */ + public function setDescription(string $description): void { + $this->description = $description; + } + + /** + * Set Keywords for HTML + * @param string $keywords + */ + public function setKeywords(string $keywords): void { + $this->keywords = $keywords; + } + + /** + * Set Robots for HTML + * @param string $robot + */ + public function setRobots(string $robot): void { + $this->robots = $robot; + } + + public function setBody(string $body): void { + $this->body = $body; + } + + /** + * Set Active BreadCrumb in HTML + * @param string $active + */ + public function setActiveCrumb(string $active): void { + $this->activeCrumb = $active; + } + + /** + * Set BreadCrumbs using array (HyperLink => Name of Crumb) + * @param array $crumbs Array(href => name) + */ + public function setBreadcrumbs(array $crumbs): void { + $this->breadcrumb = $crumbs; + } + + public function setAssetsFromArray(array $files, string $which, string $scope = 'project'): void { + foreach($files as $file => $a) { + switch($which) { + case 'main_css': + $this->addMainCss($file, $scope, $a); + break; + case 'css': + $this->addCss($file, $scope, $a); + break; + case 'main_js': + $this->addMainJs($file, $scope, $a); + break; + case 'js': + $this->addJs($file, $scope, $a); + break; + } + } + } + + private function missingFile(string $file, string $scope, string $kind) { + $failed = strtoupper($kind) . " filename of {$file} - {$scope} Asset Failed to Load!"; + $this->addToJavascript("console.log(\"%c {$failed}\", \"color: red\")"); + $comment = ""; + if ($kind === "css") { + $this->styles .= $comment; + } else if ($kind === "main_css") { + $this->mainStyles .= $comment; + } else if ($kind === "js") { + $this->scripts .= $comment; + } else if ($kind === "main_js") { + $this->mainScripts .= $comment; + } + } + + /** + * Add CSS stylesheet to HTML under main CSS + * @param string $file + * @param string $scope (project, framework, cdn) + * @return bool was successful + */ + public function addCss(string $file, string $scope = 'project', array $a = array()): bool { + $css = Assets::wrapAsset($file, $scope); + if ($css === false) { + $this->missingFile($file, $scope, "css"); + return false; + } + $this->styles .= Assets::wrapCss($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 addJs(string $file, string $scope = 'project', array $a = array()): bool { + $js = Assets::wrapAsset($file, $scope); + if ($js === false) { + $this->js_log($file . " - {$scope} Asset Failed to Load!"); + return false; + } + $this->scripts .= Assets::wrapJs($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 addMainCss(string $file, string $scope = 'project', array $a = array()): bool { + $css = Assets::wrapAsset($file, $scope); + if ($css === false) { + $this->js_log($file . " - {$scope} Asset Failed to Load!"); + return false; + } + $this->mainStyles .= Assets::wrapCss($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 addMainJs(string $file, string $scope = 'project', array $a = array()): bool { + $js = Assets::wrapAsset($file, $scope); + if ($js === false) { + $this->js_log($file . " - {$scope} Asset Failed to Load!"); + return false; + } + $this->mainScripts .= Assets::wrapJs($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 jsLog(string $log): void { + $this->addToJavascript("console.log('{$log}');"); + } + + /** + * Place JavaScript in HTML + * @param string $js + */ + public function addToJavascript(string $js): void { + if (! empty($js)) { + $this->scripts .= Assets::inlineJs($js); + } + } + + /** + * Use CSS/JS for Database SSP + public function datatables_code(): void { + $this->addCss('datatables/datatables.min.css', 'cl'); + $this->addJs('datatables/datatables_no_jquery.min.js', 'cl'); + } + * + */ + + /** + * Used by Template file to render HTML Author + * @return string HTML Author + */ + public function getAuthor(): string { + return $this->author; + } + + /** + * Used by Template file to render HTML TITLE + * @return string HTML TITLE + */ + public function getTitle(): string { + return $this->title; + } + + /** + * Used by Template file to render HTML Header + * @return string HTML Header + */ + public function getHeader(): string { + return $this->header; + } + + public function getBody(): string { + return $this->body; + } + + /** + * Used by Template file to render HTML Footer + * @return string HTML Footer + */ + public function getFooter(): string { + return $this->footer; + } + + /** + * Used by Template file to render HTML Meta data for Description + * @return string HTML Meta Description + */ + public function getDescription(): string { + return $this->description; + } + + /** + * Used by Template file to render HTML Meta data for Keywords + * @return string HTML Meta Keywords + */ + public function getKeywords(): string { + return $this->keywords; + } + + /** + * Used by Template file to render HTML Meta data for Robots + * @return string HTML Meta Robots + */ + public function getRobots(): ?string { + return $this->robots; + } + + /** + * Used by Template file to render HTML CSS + * @return string HTML CSS + */ + public function getStyles(): string { + return $this->styles; + } + + /** + * Used by Template file to render HTML JavaScripts + * @return string HTML JS + */ + public function getScripts(): string { + return $this->scripts; + } + + /** + * Used by Template file to render HTML main CSS @Top + * @return string HTML CSS + */ + public function getMainStyles(): string { + return $this->mainStyles; + } + + /** + * Used by Template file to render HTML main JS @Top + * @return string HTML JavaScript + */ + public function getMainScripts(): string { + return $this->mainScripts; + } + + /** + * Used by Template file to render HTML JS after main JS + * @return string HTML JS + */ + public function getJsOnReady(): string { + return $this->jsOnReady; + } + +/** + * Used by Template file to render HTML Active BreadCrumb + * @return string HTML Active BreadCrumb + */ + public function getActiveCrumb(): string { + return $this->activeCrumb; + } + + /** + * Used by Template file to render HTML BreadCrumbs + * @return string HTML BreadCrumbs + */ + public function getBreadcrumbs(): array { + return $this->breadcrumb; + } + + public function getHead(): string { + return $this->head; + } +} diff --git a/src/Framework/HtmlParser.php b/src/Framework/HtmlParser.php new file mode 100644 index 0000000..11031b5 --- /dev/null +++ b/src/Framework/HtmlParser.php @@ -0,0 +1,175 @@ + [ + 'pattern' => '/

    (.*?)<\/h1>/s', + 'replace' => '[h1]$1[/h1]', + 'content' => '$1' + ], + 'h2' => [ + 'pattern' => '/

    (.*?)<\/h2>/s', + 'replace' => '[h2]$1[/h2]', + 'content' => '$1' + ], + 'h3' => [ + 'pattern' => '/

    (.*?)<\/h3>/s', + 'replace' => '[h3]$1[/h3]', + 'content' => '$1' + ], + 'h4' => [ + 'pattern' => '/

    (.*?)<\/h4>/s', + 'replace' => '[h4]$1[/h4]', + 'content' => '$1' + ], + 'h5' => [ + 'pattern' => '/

    (.*?)<\/h5>/s', + 'replace' => '[h5]$1[/h5]', + 'content' => '$1' + ], + 'h6' => [ + 'pattern' => '/
    (.*?)<\/h6>/s', + 'replace' => '[h6]$1[/h6]', + 'content' => '$1' + ], + 'bold' => [ + 'pattern' => '/(.*?)<\/b>/s', + 'replace' => '[b]$1[/b]', + 'content' => '$1', + ], + 'strong' => [ + 'pattern' => '/(.*?)<\/strong>/s', + 'replace' => '[b]$1[/b]', + 'content' => '$1', + ], + 'italic' => [ + 'pattern' => '/(.*?)<\/i>/s', + 'replace' => '[i]$1[/i]', + 'content' => '$1' + ], + 'em' => [ + 'pattern' => '/(.*?)<\/em>/s', + 'replace' => '[i]$1[/i]', + 'content' => '$1' + ], + 'underline' => [ + 'pattern' => '/(.*?)<\/u>/s', + 'replace' => '[u]$1[/u]', + 'content' => '$1', + ], + 'strikethrough' => [ + 'pattern' => '/(.*?)<\/s>/s', + 'replace' => '[s]$1[/s]', + 'content' => '$1', + ], + 'del' => [ + 'pattern' => '/(.*?)<\/del>/s', + 'replace' => '[s]$1[/s]', + 'content' => '$1', + ], + 'code' => [ + 'pattern' => '/(.*?)<\/code>/s', + 'replace' => '[code]$1[/code]', + 'content' => '$1' + ], + 'orderedlistnumerical' => [ + 'pattern' => '/
      (.*?)<\/ol>/s', + 'replace' => '[list=1]$1[/list]', + 'content' => '$1' + ], + 'unorderedlist' => [ + 'pattern' => '/