├── app ├── Language │ ├── .gitkeep │ └── en │ │ └── Validation.php ├── Libraries │ └── .gitkeep ├── ThirdParty │ └── .gitkeep ├── Views │ ├── pages │ │ ├── commons │ │ │ ├── dashboard.php │ │ │ ├── forbidden.php │ │ │ ├── login.php │ │ │ └── register.php │ │ └── settings │ │ │ └── role_access.php │ ├── errors │ │ ├── cli │ │ │ ├── error_404.php │ │ │ ├── production.php │ │ │ └── error_exception.php │ │ └── html │ │ │ ├── production.php │ │ │ ├── error_400.php │ │ │ ├── error_404.php │ │ │ ├── debug.js │ │ │ └── debug.css │ ├── layouts │ │ ├── footer.php │ │ ├── main.php │ │ ├── header.php │ │ └── sidebar.php │ ├── widgets │ │ └── users │ │ │ ├── role_form_modal.php │ │ │ └── user_form_modal.php │ └── components │ │ └── alerts.php ├── .htaccess ├── index.html ├── Config │ ├── ForeignCharacters.php │ ├── CURLRequest.php │ ├── Images.php │ ├── Publisher.php │ ├── Honeypot.php │ ├── Optimize.php │ ├── Services.php │ ├── Boot │ │ ├── production.php │ │ ├── development.php │ │ └── testing.php │ ├── Feature.php │ ├── Pager.php │ ├── Validation.php │ ├── Routes.php │ ├── Migrations.php │ ├── Events.php │ ├── Kint.php │ ├── Generators.php │ ├── View.php │ ├── Format.php │ ├── Modules.php │ ├── Email.php │ ├── Paths.php │ ├── DocTypes.php │ ├── Security.php │ ├── Encryption.php │ ├── Autoload.php │ ├── Constants.php │ ├── Cors.php │ ├── Cookie.php │ ├── Filters.php │ ├── Routing.php │ ├── Exceptions.php │ ├── Toolbar.php │ ├── ContentSecurityPolicy.php │ ├── Session.php │ ├── Cache.php │ ├── Logger.php │ └── Database.php ├── Controllers │ ├── Home.php │ ├── BaseController.php │ └── Auth.php ├── Common.php ├── Helpers │ ├── menu_helper.php │ └── useraccess_helper.php ├── Database │ ├── Migrations │ │ ├── 2025-06-15-113925_Session.php │ │ └── 2025-06-15-114014_UserManagement.php │ └── Seeds │ │ └── Users.php └── Filters │ ├── Authentication.php │ └── Authorization.php ├── public ├── robots.txt ├── favicon.ico ├── assets │ └── images │ │ └── avatar.png ├── .htaccess └── index.php ├── tests ├── .htaccess ├── index.html ├── session │ └── ExampleSessionTest.php ├── _support │ ├── Libraries │ │ └── ConfigReader.php │ ├── Models │ │ └── ExampleModel.php │ └── Database │ │ ├── Migrations │ │ └── 2020-02-22-222222_example_migration.php │ │ └── Seeds │ │ └── ExampleSeeder.php ├── database │ └── ExampleDatabaseTest.php ├── unit │ └── HealthTest.php └── README.md ├── writable ├── .htaccess ├── index.html ├── cache │ └── index.html ├── logs │ └── index.html ├── session │ └── index.html └── uploads │ └── index.html ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── LICENSE ├── composer.json ├── README.md ├── .gitignore ├── env ├── phpunit.xml.dist ├── spark └── preload.php /app/Language/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/Libraries/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/ThirdParty/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilangheavy/CI4-StarterPanel/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/assets/images/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilangheavy/CI4-StarterPanel/HEAD/public/assets/images/avatar.png -------------------------------------------------------------------------------- /app/Views/pages/commons/dashboard.php: -------------------------------------------------------------------------------- 1 | extend('layouts/main'); ?> 2 | section('content'); ?> 3 | 4 | endSection(); ?> -------------------------------------------------------------------------------- /app/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Require all denied 3 | 4 | 5 | Deny from all 6 | 7 | -------------------------------------------------------------------------------- /tests/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Require all denied 3 | 4 | 5 | Deny from all 6 | 7 | -------------------------------------------------------------------------------- /app/Language/en/Validation.php: -------------------------------------------------------------------------------- 1 | 2 | Require all denied 3 | 4 | 5 | Deny from all 6 | 7 | -------------------------------------------------------------------------------- /app/Views/errors/cli/error_404.php: -------------------------------------------------------------------------------- 1 | extend('layouts/main'); ?> 2 | section('content'); ?> 3 |

Forbidden Page!

4 | endSection(); ?> -------------------------------------------------------------------------------- /app/Views/errors/cli/production.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

Directory access is forbidden.

9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

Directory access is forbidden.

9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /writable/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

Directory access is forbidden.

9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /writable/cache/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

Directory access is forbidden.

9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /writable/logs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

Directory access is forbidden.

9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /writable/session/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

Directory access is forbidden.

9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /writable/uploads/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden 5 | 6 | 7 | 8 |

Directory access is forbidden.

9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/Config/ForeignCharacters.php: -------------------------------------------------------------------------------- 1 | data, [ 10 | 'title' => 'Dashboard Page' 11 | ]); 12 | return view('pages/commons/dashboard', $data); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/session/ExampleSessionTest.php: -------------------------------------------------------------------------------- 1 | set('logged_in', 123); 15 | $this->assertSame(123, $session->get('logged_in')); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/_support/Libraries/ConfigReader.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <?= lang('Errors.whoops') ?> 8 | 9 | 12 | 13 | 14 | 15 |
16 | 17 |

18 | 19 |

20 | 21 |
22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/Config/CURLRequest.php: -------------------------------------------------------------------------------- 1 | 26 | */ 27 | public array $handlers = [ 28 | 'gd' => GDHandler::class, 29 | 'imagick' => ImageMagickHandler::class, 30 | ]; 31 | } 32 | -------------------------------------------------------------------------------- /app/Helpers/menu_helper.php: -------------------------------------------------------------------------------- 1 | table('user_menu') 6 | ->orderBy('user_access.id', 'ASC') 7 | ->join('user_access', 'user_menu.id = user_access.menu_id') 8 | ->where(['menu_category' => $menu_category_id, 'user_access.role_id' => $role]) 9 | ->get()->getResultArray(); 10 | return $menu; 11 | } 12 | function getSubMenu($menu_id, $role) 13 | { 14 | $db = \Config\Database::connect(); 15 | $submenu = $db->table('user_submenu') 16 | ->orderBy('user_access.id', 'ASC') 17 | ->join('user_access', 'user_submenu.id = user_access.submenu_id') 18 | ->where(['user_submenu.menu' => $menu_id, 'user_access.role_id' => $role]) 19 | ->get()->getResultArray(); 20 | return $submenu; 21 | } 22 | -------------------------------------------------------------------------------- /app/Config/Publisher.php: -------------------------------------------------------------------------------- 1 | 23 | */ 24 | public $restrictions = [ 25 | ROOTPATH => '*', 26 | FCPATH => '#\.(s?css|js|map|html?|xml|json|webmanifest|ttf|eot|woff2?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i', 27 | ]; 28 | } 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /app/Database/Migrations/2025-06-15-113925_Session.php: -------------------------------------------------------------------------------- 1 | forge->addField([ 12 | 'id' => [ 13 | 'type' => 'VARCHAR', 14 | 'constraint' => 128 15 | ], 16 | 'ip_address' => [ 17 | 'type' => 'VARCHAR', 18 | 'constraint' => 45, 19 | ], 20 | 'timestamp' => [ 21 | 'type' => 'timestamp' 22 | ], 23 | 'data' => [ 24 | 'type' => 'blob' 25 | ], 26 | ]); 27 | $this->forge->addKey('id', true); 28 | $this->forge->addKey('timestamp', true); 29 | $this->forge->createTable('sessions'); 30 | } 31 | 32 | public function down() 33 | { 34 | $this->forge->dropTable('sessions'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/Config/Honeypot.php: -------------------------------------------------------------------------------- 1 | {label}'; 28 | 29 | /** 30 | * Honeypot container 31 | * 32 | * If you enabled CSP, you can remove `style="display:none"`. 33 | */ 34 | public string $container = '
{template}
'; 35 | 36 | /** 37 | * The id attribute for Honeypot container tag 38 | * 39 | * Used when CSP is enabled. 40 | */ 41 | public string $containerId = 'hpc'; 42 | } 43 | -------------------------------------------------------------------------------- /app/Config/Optimize.php: -------------------------------------------------------------------------------- 1 | table('user_access')->where(['role_id' => $role_id, 'menu_category_id' => $menu_category_id])->countAllResults(); 6 | if ($accessMenuCategory > 0) { 7 | return "checked"; 8 | } 9 | } 10 | function check_menu_access($role_id, $menu_id) 11 | { 12 | $db = \Config\Database::connect(); 13 | $accessMenu = $db->table('user_access')->where(['role_id' => $role_id, 'menu_id' => $menu_id])->countAllResults(); 14 | if ($accessMenu > 0) { 15 | return "checked"; 16 | } 17 | } 18 | function check_submenu_access($role_id, $submenu_id) 19 | { 20 | $db = \Config\Database::connect(); 21 | $accessMenu = $db->table('user_access')->where(['role_id' => $role_id, 'submenu_id' => $submenu_id])->countAllResults(); 22 | if ($accessMenu > 0) { 23 | return "checked"; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/Views/layouts/footer.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/Config/Boot/production.php: -------------------------------------------------------------------------------- 1 | 2 | 24 | -------------------------------------------------------------------------------- /app/Config/Pager.php: -------------------------------------------------------------------------------- 1 | 22 | */ 23 | public array $templates = [ 24 | 'default_full' => 'CodeIgniter\Pager\Views\default_full', 25 | 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', 26 | 'default_head' => 'CodeIgniter\Pager\Views\default_head', 27 | ]; 28 | 29 | /** 30 | * -------------------------------------------------------------------------- 31 | * Items Per Page 32 | * -------------------------------------------------------------------------- 33 | * 34 | * The default number of results shown in a single page. 35 | */ 36 | public int $perPage = 20; 37 | } 38 | -------------------------------------------------------------------------------- /tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php: -------------------------------------------------------------------------------- 1 | forge->addField('id'); 14 | $this->forge->addField([ 15 | 'name' => ['type' => 'varchar', 'constraint' => 31], 16 | 'uid' => ['type' => 'varchar', 'constraint' => 31], 17 | 'class' => ['type' => 'varchar', 'constraint' => 63], 18 | 'icon' => ['type' => 'varchar', 'constraint' => 31], 19 | 'summary' => ['type' => 'varchar', 'constraint' => 255], 20 | 'created_at' => ['type' => 'datetime', 'null' => true], 21 | 'updated_at' => ['type' => 'datetime', 'null' => true], 22 | 'deleted_at' => ['type' => 'datetime', 'null' => true], 23 | ]); 24 | 25 | $this->forge->addKey('name'); 26 | $this->forge->addKey('uid'); 27 | $this->forge->addKey(['deleted_at', 'id']); 28 | $this->forge->addKey('created_at'); 29 | 30 | $this->forge->createTable('factories'); 31 | } 32 | 33 | public function down(): void 34 | { 35 | $this->forge->dropTable('factories'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/Config/Validation.php: -------------------------------------------------------------------------------- 1 | 22 | */ 23 | public array $ruleSets = [ 24 | Rules::class, 25 | FormatRules::class, 26 | FileRules::class, 27 | CreditCardRules::class, 28 | ]; 29 | 30 | /** 31 | * Specifies the views that are used to display the 32 | * errors. 33 | * 34 | * @var array 35 | */ 36 | public array $templates = [ 37 | 'list' => 'CodeIgniter\Validation\Views\list', 38 | 'single' => 'CodeIgniter\Validation\Views\single', 39 | ]; 40 | 41 | // -------------------------------------------------------------------- 42 | // Rules 43 | // -------------------------------------------------------------------- 44 | } 45 | -------------------------------------------------------------------------------- /tests/_support/Database/Seeds/ExampleSeeder.php: -------------------------------------------------------------------------------- 1 | 'Test Factory', 14 | 'uid' => 'test001', 15 | 'class' => 'Factories\Tests\NewFactory', 16 | 'icon' => 'fas fa-puzzle-piece', 17 | 'summary' => 'Longer sample text for testing', 18 | ], 19 | [ 20 | 'name' => 'Widget Factory', 21 | 'uid' => 'widget', 22 | 'class' => 'Factories\Tests\WidgetPlant', 23 | 'icon' => 'fas fa-puzzle-piece', 24 | 'summary' => 'Create widgets in your factory', 25 | ], 26 | [ 27 | 'name' => 'Evil Factory', 28 | 'uid' => 'evil-maker', 29 | 'class' => 'Factories\Evil\MyFactory', 30 | 'icon' => 'fas fa-book-dead', 31 | 'summary' => 'Abandon all hope, ye who enter here', 32 | ], 33 | ]; 34 | 35 | $builder = $this->db->table('factories'); 36 | 37 | foreach ($factories as $factory) { 38 | $builder->insert($factory); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/database/ExampleDatabaseTest.php: -------------------------------------------------------------------------------- 1 | findAll(); 23 | 24 | // Make sure the count is as expected 25 | $this->assertCount(3, $objects); 26 | } 27 | 28 | public function testSoftDeleteLeavesRow(): void 29 | { 30 | $model = new ExampleModel(); 31 | $this->setPrivateProperty($model, 'useSoftDeletes', true); 32 | $this->setPrivateProperty($model, 'tempUseSoftDeletes', true); 33 | 34 | /** @var stdClass $object */ 35 | $object = $model->first(); 36 | $model->delete($object->id); 37 | 38 | // The model should no longer find it 39 | $this->assertNull($model->find($object->id)); 40 | 41 | // ... but it should still be in the database 42 | $result = $model->builder()->where('id', $object->id)->get()->getResult(); 43 | 44 | $this->assertCount(1, $result); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/Config/Boot/development.php: -------------------------------------------------------------------------------- 1 | assertTrue(defined('APPPATH')); 15 | } 16 | 17 | public function testBaseUrlHasBeenSet(): void 18 | { 19 | $validation = service('validation'); 20 | 21 | $env = false; 22 | 23 | // Check the baseURL in .env 24 | if (is_file(HOMEPATH . '.env')) { 25 | $env = preg_grep('/^app\.baseURL = ./', file(HOMEPATH . '.env')) !== false; 26 | } 27 | 28 | if ($env) { 29 | // BaseURL in .env is a valid URL? 30 | // phpunit.xml.dist sets app.baseURL in $_SERVER 31 | // So if you set app.baseURL in .env, it takes precedence 32 | $config = new App(); 33 | $this->assertTrue( 34 | $validation->check($config->baseURL, 'valid_url'), 35 | 'baseURL "' . $config->baseURL . '" in .env is not valid URL', 36 | ); 37 | } 38 | 39 | // Get the baseURL in app/Config/App.php 40 | // You can't use Config\App, because phpunit.xml.dist sets app.baseURL 41 | $reader = new ConfigReader(); 42 | 43 | // BaseURL in app/Config/App.php is a valid URL? 44 | $this->assertTrue( 45 | $validation->check($reader->baseURL, 'valid_url'), 46 | 'baseURL "' . $reader->baseURL . '" in app/Config/App.php is not valid URL', 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/Filters/Authentication.php: -------------------------------------------------------------------------------- 1 | get('isLoggedIn') != TRUE) : 29 | return redirect()->to(base_url('/')); 30 | endif; 31 | } 32 | 33 | /** 34 | * Allows After filters to inspect and modify the response 35 | * object as needed. This method does not allow any way 36 | * to stop execution of other after filters, short of 37 | * throwing an Exception or Error. 38 | * 39 | * @param RequestInterface $request 40 | * @param ResponseInterface $response 41 | * @param array|null $arguments 42 | * 43 | * @return ResponseInterface|void 44 | */ 45 | public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) 46 | { 47 | // 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/Config/Routes.php: -------------------------------------------------------------------------------- 1 | get('/', 'Auth::index'); 9 | $routes->get('login', 'Auth::index'); 10 | $routes->post('login', 'Auth::index'); 11 | $routes->get('logout', 'Auth::logout'); 12 | $routes->get('blocked', 'Auth::forbiddenPage'); 13 | $routes->get('register', 'Auth::register'); 14 | $routes->post('register', 'Auth::registration'); 15 | 16 | $routes->get('dashboard', 'Home::index'); 17 | 18 | // Setting Routes 19 | $routes->group('users', static function ($routes) { 20 | $routes->get('/', 'Settings::users'); 21 | $routes->post('create-role', 'Settings::createRole'); 22 | $routes->post('update-role', 'Settings::updateRole'); 23 | $routes->delete('delete-role/(:num)', 'Settings::deleteRole/$1'); 24 | 25 | $routes->get('role-access', 'Settings::roleAccess'); 26 | $routes->post('create-user', 'Settings::createUser'); 27 | $routes->post('update-user', 'Settings::updateUser'); 28 | $routes->delete('delete-user/(:num)', 'Settings::deleteUser/$1'); 29 | 30 | $routes->post('change-menu-permission', 'Settings::changeMenuPermission'); 31 | $routes->post('change-menu-category-permission', 'Settings::changeMenuCategoryPermission'); 32 | $routes->post('change-submenu-permission', 'Settings::changeSubMenuPermission'); 33 | }); 34 | 35 | $routes->group('menu-management', static function ($routes) { 36 | $routes->get('/', 'Settings::menuManagement'); 37 | $routes->post('create-menu-category', 'Settings::createMenuCategory'); 38 | $routes->post('create-menu', 'Settings::createMenu'); 39 | $routes->post('create-submenu', 'Settings::createSubMenu'); 40 | }); 41 | $routes->get('menu','Menu::index'); 42 | -------------------------------------------------------------------------------- /app/Views/layouts/main.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | CodeIgniter 4 Starter Panel 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | include('layouts/sidebar'); ?> 27 |
28 | include('layouts/header'); ?> 29 |
30 |
31 | include('components/alerts'); ?> 32 | renderSection('content'); ?> 33 |
34 |
35 | include('layouts/footer'); ?> 36 |
37 |
38 | renderSection('javascript'); ?> 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/Config/Migrations.php: -------------------------------------------------------------------------------- 1 | php spark make:migration 40 | * 41 | * NOTE: if you set an unsupported format, migration runner will not find 42 | * your migration files. 43 | * 44 | * Supported formats: 45 | * - YmdHis_ 46 | * - Y-m-d-His_ 47 | * - Y_m_d_His_ 48 | */ 49 | public string $timestampFormat = 'Y-m-d-His_'; 50 | } 51 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | # Disable directory browsing 2 | Options -Indexes 3 | 4 | # ---------------------------------------------------------------------- 5 | # Rewrite engine 6 | # ---------------------------------------------------------------------- 7 | 8 | # Turning on the rewrite engine is necessary for the following rules and features. 9 | # FollowSymLinks must be enabled for this to work. 10 | 11 | Options +FollowSymlinks 12 | RewriteEngine On 13 | 14 | # If you installed CodeIgniter in a subfolder, you will need to 15 | # change the following line to match the subfolder you need. 16 | # http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase 17 | # RewriteBase / 18 | 19 | # Redirect Trailing Slashes... 20 | RewriteCond %{REQUEST_FILENAME} !-d 21 | RewriteCond %{REQUEST_URI} (.+)/$ 22 | RewriteRule ^ %1 [L,R=301] 23 | 24 | # Rewrite "www.example.com -> example.com" 25 | RewriteCond %{HTTPS} !=on 26 | RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] 27 | RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] 28 | 29 | # Checks to see if the user is attempting to access a valid file, 30 | # such as an image or css document, if this isn't true it sends the 31 | # request to the front controller, index.php 32 | RewriteCond %{REQUEST_FILENAME} !-f 33 | RewriteCond %{REQUEST_FILENAME} !-d 34 | RewriteRule ^([\s\S]*)$ index.php/$1 [L,NC,QSA] 35 | 36 | # Ensure Authorization header is passed along 37 | RewriteCond %{HTTP:Authorization} . 38 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 39 | 40 | 41 | 42 | # If we don't have mod_rewrite installed, all 404's 43 | # can be sent to index.php, and everything works as normal. 44 | ErrorDocument 404 index.php 45 | 46 | 47 | # Disable server signature start 48 | ServerSignature Off 49 | # Disable server signature end 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CodeIgniter 4 Starter Panel 2 | 3 | CodeIgniter is a PHP full-stack web framework that is light, fast, flexible and secure. 4 | More information can be found at the [official site](https://codeigniter.com). 5 | 6 | This repository is a starter kit for CodeIgniter 4. Using codeigniter version 4.6.1, PHP version 8.4 and bootstrap version 5. 7 | ### Documentation 8 | 9 | The [User Guide](https://codeigniter.com/user_guide/) is the primary documentation for CodeIgniter 4. 10 | 11 | ## Installation 12 | 13 | `git clone` or download this source code then run `composer install` whenever there is a new release of the framework. 14 | 15 | ## Setup 16 | 17 | - Run `php spark db:create` to create a new database schema. 18 | - Copy `env` to `.env` and tailor for your app, specifically the baseURL and any database settings. 19 | - Run `php spark migrate` to running database migration 20 | - Run `php spark db:seed Users` to seeding default database user 21 | - Run `php spark key:generate` to create encrypter key 22 | - Run `php spark serve` to launching the CodeIgniter PHP-Development Server 23 | 24 | ## Server Requirements 25 | 26 | PHP version 8.4 is required, with the following extensions installed: 27 | - curl 28 | - fileinfo 29 | - gd 30 | - [intl](http://php.net/manual/en/intl.requirements.php) 31 | - [mbstring](http://php.net/manual/en/mbstring.installation.php) 32 | - [libcurl](http://php.net/manual/en/curl.requirements.php) if you plan to use the HTTP\CURLRequest library 33 | - [mysqlnd](http://php.net/manual/en/mysqlnd.install.php) 34 | - openssl 35 | 36 | Additionally, make sure that the following extensions are enabled in your PHP: 37 | - json (enabled by default - don't turn it off) 38 | - xml (enabled by default - don't turn it off) 39 | 40 | ## Features 41 | 42 | Features on this project: 43 | - Authentication 44 | - Authorization 45 | - User Registration 46 | - Menu Management with auto create controller and view file 47 | 48 | -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | systemDirectory . '/Boot.php'; 58 | 59 | exit(Boot::bootWeb($paths)); 60 | -------------------------------------------------------------------------------- /app/Views/layouts/header.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/Config/Events.php: -------------------------------------------------------------------------------- 1 | 0) { 33 | ob_end_flush(); 34 | } 35 | 36 | ob_start(static fn ($buffer) => $buffer); 37 | } 38 | 39 | /* 40 | * -------------------------------------------------------------------- 41 | * Debug Toolbar Listeners. 42 | * -------------------------------------------------------------------- 43 | * If you delete, they will no longer be collected. 44 | */ 45 | if (CI_DEBUG && ! is_cli()) { 46 | Events::on('DBQuery', 'CodeIgniter\Debug\Toolbar\Collectors\Database::collect'); 47 | service('toolbar')->respond(); 48 | // Hot Reload route - for framework use on the hot reloader. 49 | if (ENVIRONMENT === 'development') { 50 | service('routes')->get('__hot-reload', static function (): void { 51 | (new HotReloader())->run(); 52 | }); 53 | } 54 | } 55 | }); 56 | -------------------------------------------------------------------------------- /app/Config/Kint.php: -------------------------------------------------------------------------------- 1 | |ConstructablePluginInterface>|null 29 | */ 30 | public $plugins; 31 | 32 | public int $maxDepth = 6; 33 | public bool $displayCalledFrom = true; 34 | public bool $expanded = false; 35 | 36 | /* 37 | |-------------------------------------------------------------------------- 38 | | RichRenderer Settings 39 | |-------------------------------------------------------------------------- 40 | */ 41 | public string $richTheme = 'aante-light.css'; 42 | public bool $richFolder = false; 43 | 44 | /** 45 | * @var array>|null 46 | */ 47 | public $richObjectPlugins; 48 | 49 | /** 50 | * @var array>|null 51 | */ 52 | public $richTabPlugins; 53 | 54 | /* 55 | |-------------------------------------------------------------------------- 56 | | CLI Settings 57 | |-------------------------------------------------------------------------- 58 | */ 59 | public bool $cliColors = true; 60 | public bool $cliForceUTF8 = false; 61 | public bool $cliDetectWidth = true; 62 | public int $cliMinWidth = 40; 63 | } 64 | -------------------------------------------------------------------------------- /app/Config/Generators.php: -------------------------------------------------------------------------------- 1 | |string> 27 | */ 28 | public array $views = [ 29 | 'make:cell' => [ 30 | 'class' => 'CodeIgniter\Commands\Generators\Views\cell.tpl.php', 31 | 'view' => 'CodeIgniter\Commands\Generators\Views\cell_view.tpl.php', 32 | ], 33 | 'make:command' => 'CodeIgniter\Commands\Generators\Views\command.tpl.php', 34 | 'make:config' => 'CodeIgniter\Commands\Generators\Views\config.tpl.php', 35 | 'make:controller' => 'CodeIgniter\Commands\Generators\Views\controller.tpl.php', 36 | 'make:entity' => 'CodeIgniter\Commands\Generators\Views\entity.tpl.php', 37 | 'make:filter' => 'CodeIgniter\Commands\Generators\Views\filter.tpl.php', 38 | 'make:migration' => 'CodeIgniter\Commands\Generators\Views\migration.tpl.php', 39 | 'make:model' => 'CodeIgniter\Commands\Generators\Views\model.tpl.php', 40 | 'make:seeder' => 'CodeIgniter\Commands\Generators\Views\seeder.tpl.php', 41 | 'make:validation' => 'CodeIgniter\Commands\Generators\Views\validation.tpl.php', 42 | 'session:migration' => 'CodeIgniter\Commands\Generators\Views\migration.tpl.php', 43 | ]; 44 | } 45 | -------------------------------------------------------------------------------- /app/Config/View.php: -------------------------------------------------------------------------------- 1 | 38 | * @phpstan-var array 39 | */ 40 | public $filters = []; 41 | 42 | /** 43 | * Parser Plugins provide a way to extend the functionality provided 44 | * by the core Parser by creating aliases that will be replaced with 45 | * any callable. Can be single or tag pair. 46 | * 47 | * @var array|string> 48 | * @phpstan-var array|parser_callable_string|parser_callable> 49 | */ 50 | public $plugins = []; 51 | 52 | /** 53 | * View Decorators are class methods that will be run in sequence to 54 | * have a chance to alter the generated output just prior to caching 55 | * the results. 56 | * 57 | * All classes must implement CodeIgniter\View\ViewDecoratorInterface 58 | * 59 | * @var list> 60 | */ 61 | public array $decorators = []; 62 | } 63 | -------------------------------------------------------------------------------- /app/Views/errors/html/error_400.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <?= lang('Errors.badRequest') ?> 6 | 7 | 70 | 71 | 72 |
73 |

400

74 | 75 |

76 | 77 | 78 | 79 | 80 | 81 |

82 |
83 | 84 | 85 | -------------------------------------------------------------------------------- /app/Database/Seeds/Users.php: -------------------------------------------------------------------------------- 1 | db->table('user_menu_category')->insertBatch([ 13 | [ 14 | 'menu_category' => 'Common Page' 15 | ], 16 | [ 17 | 'menu_category' => 'Settings' 18 | ] 19 | ]); 20 | 21 | // Database seeding for user menu 22 | $this->db->table('user_menu')->insertBatch([ 23 | [ 24 | 'menu_category' => 1, 25 | 'title' => 'Dashboard', 26 | 'url' => 'dashboard', 27 | 'icon' => 'home', 28 | 'parent' => 0 29 | ], 30 | [ 31 | 'menu_category' => 2, 32 | 'title' => 'Users', 33 | 'url' => 'users', 34 | 'icon' => 'user', 35 | 'parent' => 0 36 | ], 37 | [ 38 | 'menu_category' => 2, 39 | 'title' => 'Menu Management', 40 | 'url' => 'menu-management', 41 | 'icon' => 'command', 42 | 'parent' => 0 43 | ], 44 | ]); 45 | 46 | // Database seeding for user role 47 | $this->db->table('user_role')->insert([ 48 | 'id' => 1, 49 | 'role_name' => 'Developer' 50 | ]); 51 | 52 | // Database seeding for users 53 | $this->db->table('users')->insert([ 54 | 'fullname' => 'Developer', 55 | 'username' => 'developer@mail.io', 56 | 'password' => password_hash('123456', PASSWORD_DEFAULT), 57 | 'role' => 1, 58 | 'created_at' => date('Y-m-d h:i:s') 59 | ]); 60 | 61 | // Database seeding for user access 62 | $this->db->table('user_access')->insertBatch([ 63 | [ 64 | 'role_id' => 1, 65 | 'menu_category_id' => 1, 66 | 'menu_id' => 0, 67 | 'submenu_id' => 0 68 | ], 69 | [ 70 | 'role_id' => 1, 71 | 'menu_category_id' => 0, 72 | 'menu_id' => 1, 73 | 'submenu_id' => 0 74 | ], 75 | [ 76 | 'role_id' => 1, 77 | 'menu_category_id' => 2, 78 | 'menu_id' => 0, 79 | 'submenu_id' => 0 80 | ], 81 | [ 82 | 'role_id' => 1, 83 | 'menu_category_id' => 0, 84 | 'menu_id' => 2, 85 | 'submenu_id' => 0 86 | ], 87 | [ 88 | 'role_id' => 1, 89 | 'menu_category_id' => 0, 90 | 'menu_id' => 3, 91 | 'submenu_id' => 0 92 | ], 93 | ]); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /app/Views/errors/html/error_404.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <?= lang('Errors.pageNotFound') ?> 6 | 7 | 70 | 71 | 72 |
73 |

404

74 | 75 |

76 | 77 | 78 | 79 | 80 | 81 |

82 |
83 | 84 | 85 | -------------------------------------------------------------------------------- /app/Config/Format.php: -------------------------------------------------------------------------------- 1 | 25 | */ 26 | public array $supportedResponseFormats = [ 27 | 'application/json', 28 | 'application/xml', // machine-readable XML 29 | 'text/xml', // human-readable XML 30 | ]; 31 | 32 | /** 33 | * -------------------------------------------------------------------------- 34 | * Formatters 35 | * -------------------------------------------------------------------------- 36 | * 37 | * Lists the class to use to format responses with of a particular type. 38 | * For each mime type, list the class that should be used. Formatters 39 | * can be retrieved through the getFormatter() method. 40 | * 41 | * @var array 42 | */ 43 | public array $formatters = [ 44 | 'application/json' => JSONFormatter::class, 45 | 'application/xml' => XMLFormatter::class, 46 | 'text/xml' => XMLFormatter::class, 47 | ]; 48 | 49 | /** 50 | * -------------------------------------------------------------------------- 51 | * Formatters Options 52 | * -------------------------------------------------------------------------- 53 | * 54 | * Additional Options to adjust default formatters behaviour. 55 | * For each mime type, list the additional options that should be used. 56 | * 57 | * @var array 58 | */ 59 | public array $formatterOptions = [ 60 | 'application/json' => JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES, 61 | 'application/xml' => 0, 62 | 'text/xml' => 0, 63 | ]; 64 | } 65 | -------------------------------------------------------------------------------- /app/Views/errors/cli/error_exception.php: -------------------------------------------------------------------------------- 1 | getFile()) . ':' . $exception->getLine(), 'green')); 9 | CLI::newLine(); 10 | 11 | $last = $exception; 12 | 13 | while ($prevException = $last->getPrevious()) { 14 | $last = $prevException; 15 | 16 | CLI::write(' Caused by:'); 17 | CLI::write(' [' . $prevException::class . ']', 'red'); 18 | CLI::write(' ' . $prevException->getMessage()); 19 | CLI::write(' at ' . CLI::color(clean_path($prevException->getFile()) . ':' . $prevException->getLine(), 'green')); 20 | CLI::newLine(); 21 | } 22 | 23 | // The backtrace 24 | if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) { 25 | $backtraces = $last->getTrace(); 26 | 27 | if ($backtraces) { 28 | CLI::write('Backtrace:', 'green'); 29 | } 30 | 31 | foreach ($backtraces as $i => $error) { 32 | $padFile = ' '; // 4 spaces 33 | $padClass = ' '; // 7 spaces 34 | $c = str_pad($i + 1, 3, ' ', STR_PAD_LEFT); 35 | 36 | if (isset($error['file'])) { 37 | $filepath = clean_path($error['file']) . ':' . $error['line']; 38 | 39 | CLI::write($c . $padFile . CLI::color($filepath, 'yellow')); 40 | } else { 41 | CLI::write($c . $padFile . CLI::color('[internal function]', 'yellow')); 42 | } 43 | 44 | $function = ''; 45 | 46 | if (isset($error['class'])) { 47 | $type = ($error['type'] === '->') ? '()' . $error['type'] : $error['type']; 48 | $function .= $padClass . $error['class'] . $type . $error['function']; 49 | } elseif (! isset($error['class']) && isset($error['function'])) { 50 | $function .= $padClass . $error['function']; 51 | } 52 | 53 | $args = implode(', ', array_map(static fn ($value): string => match (true) { 54 | is_object($value) => 'Object(' . $value::class . ')', 55 | is_array($value) => $value !== [] ? '[...]' : '[]', 56 | $value === null => 'null', // return the lowercased version 57 | default => var_export($value, true), 58 | }, array_values($error['args'] ?? []))); 59 | 60 | $function .= '(' . $args . ')'; 61 | 62 | CLI::write($function); 63 | CLI::newLine(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/Views/widgets/users/user_form_modal.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #------------------------- 2 | # Operating Specific Junk Files 3 | #------------------------- 4 | 5 | # OS X 6 | .DS_Store 7 | .AppleDouble 8 | .LSOverride 9 | 10 | # OS X Thumbnails 11 | ._* 12 | 13 | # Windows image file caches 14 | Thumbs.db 15 | ehthumbs.db 16 | Desktop.ini 17 | 18 | # Recycle Bin used on file shares 19 | $RECYCLE.BIN/ 20 | 21 | # Windows Installer files 22 | *.cab 23 | *.msi 24 | *.msm 25 | *.msp 26 | 27 | # Windows shortcuts 28 | *.lnk 29 | 30 | # Linux 31 | *~ 32 | 33 | # KDE directory preferences 34 | .directory 35 | 36 | # Linux trash folder which might appear on any partition or disk 37 | .Trash-* 38 | 39 | #------------------------- 40 | # Environment Files 41 | #------------------------- 42 | # These should never be under version control, 43 | # as it poses a security risk. 44 | .env 45 | .vagrant 46 | Vagrantfile 47 | 48 | #------------------------- 49 | # Temporary Files 50 | #------------------------- 51 | writable/cache/* 52 | !writable/cache/index.html 53 | 54 | writable/logs/* 55 | !writable/logs/index.html 56 | 57 | writable/session/* 58 | !writable/session/index.html 59 | 60 | writable/uploads/* 61 | !writable/uploads/index.html 62 | 63 | writable/debugbar/* 64 | !writable/debugbar/.gitkeep 65 | 66 | php_errors.log 67 | 68 | #------------------------- 69 | # User Guide Temp Files 70 | #------------------------- 71 | user_guide_src/build/* 72 | user_guide_src/cilexer/build/* 73 | user_guide_src/cilexer/dist/* 74 | user_guide_src/cilexer/pycilexer.egg-info/* 75 | 76 | #------------------------- 77 | # Test Files 78 | #------------------------- 79 | tests/coverage* 80 | 81 | # Don't save phpunit under version control. 82 | phpunit 83 | 84 | #------------------------- 85 | # Composer 86 | #------------------------- 87 | vendor/ 88 | 89 | #------------------------- 90 | # IDE / Development Files 91 | #------------------------- 92 | 93 | # Modules Testing 94 | _modules/* 95 | 96 | # phpenv local config 97 | .php-version 98 | 99 | # Jetbrains editors (PHPStorm, etc) 100 | .idea/ 101 | *.iml 102 | 103 | # NetBeans 104 | /nbproject/ 105 | /build/ 106 | /nbbuild/ 107 | /dist/ 108 | /nbdist/ 109 | /nbactions.xml 110 | /nb-configuration.xml 111 | /.nb-gradle/ 112 | 113 | # Sublime Text 114 | *.tmlanguage.cache 115 | *.tmPreferences.cache 116 | *.stTheme.cache 117 | *.sublime-workspace 118 | *.sublime-project 119 | .phpintel 120 | /api/ 121 | 122 | # Visual Studio Code 123 | .vscode/ 124 | 125 | /results/ 126 | /phpunit*.xml 127 | -------------------------------------------------------------------------------- /app/Filters/Authorization.php: -------------------------------------------------------------------------------- 1 | ApplicationModel = new ApplicationModel(); 33 | $segment = $uri->getSegment(1); 34 | 35 | if ($segment) { 36 | $menu = $this->ApplicationModel->getMenuByUrl($segment); 37 | if (!$menu) { 38 | //not found 39 | return redirect()->to(base_url('/')); 40 | } else { 41 | $dataAccess = [ 42 | 'roleID' => session()->get('role'), 43 | 'menuID' => $menu['id'] 44 | ]; 45 | $userAccess = $this->ApplicationModel->checkUserAccess($dataAccess); 46 | if (!$userAccess) { 47 | // not granted 48 | return redirect()->to(base_url('blocked')); 49 | } 50 | } 51 | } 52 | } 53 | 54 | /** 55 | * Allows After filters to inspect and modify the response 56 | * object as needed. This method does not allow any way 57 | * to stop execution of other after filters, short of 58 | * throwing an Exception or Error. 59 | * 60 | * @param RequestInterface $request 61 | * @param ResponseInterface $response 62 | * @param array|null $arguments 63 | * 64 | * @return ResponseInterface|void 65 | */ 66 | public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) 67 | { 68 | // 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/Views/components/alerts.php: -------------------------------------------------------------------------------- 1 | getFlashdata('notif_success')) : ?> 2 | 11 | 12 | getFlashdata('notif_warning')) : ?> 13 | 22 | 23 | getFlashdata('notif_primary')) : ?> 24 | 33 | 34 | getFlashdata('notif_info')) : ?> 35 | 44 | 45 | getFlashdata('notif_error')) : ?> 46 | 55 | -------------------------------------------------------------------------------- /app/Config/Modules.php: -------------------------------------------------------------------------------- 1 | [ 47 | * // List up all packages to auto-discover 48 | * 'codeigniter4/shield', 49 | * ], 50 | * ] 51 | * or 52 | * [ 53 | * 'exclude' => [ 54 | * // List up packages to exclude. 55 | * 'pestphp/pest', 56 | * ], 57 | * ] 58 | * 59 | * @var array{only?: list, exclude?: list} 60 | */ 61 | public $composerPackages = []; 62 | 63 | /** 64 | * -------------------------------------------------------------------------- 65 | * Auto-Discovery Rules 66 | * -------------------------------------------------------------------------- 67 | * 68 | * Aliases list of all discovery classes that will be active and used during 69 | * the current application request. 70 | * 71 | * If it is not listed, only the base application elements will be used. 72 | * 73 | * @var list 74 | */ 75 | public $aliases = [ 76 | 'events', 77 | 'filters', 78 | 'registrars', 79 | 'routes', 80 | 'services', 81 | ]; 82 | } 83 | -------------------------------------------------------------------------------- /env: -------------------------------------------------------------------------------- 1 | #-------------------------------------------------------------------- 2 | # Example Environment Configuration file 3 | # 4 | # This file can be used as a starting point for your own 5 | # custom .env files, and contains most of the possible settings 6 | # available in a default install. 7 | # 8 | # By default, all of the settings are commented out. If you want 9 | # to override the setting, you must un-comment it by removing the '#' 10 | # at the beginning of the line. 11 | #-------------------------------------------------------------------- 12 | 13 | #-------------------------------------------------------------------- 14 | # ENVIRONMENT 15 | #-------------------------------------------------------------------- 16 | 17 | # CI_ENVIRONMENT = production 18 | 19 | #-------------------------------------------------------------------- 20 | # APP 21 | #-------------------------------------------------------------------- 22 | 23 | # app.baseURL = '' 24 | # If you have trouble with `.`, you could also use `_`. 25 | # app_baseURL = '' 26 | # app.forceGlobalSecureRequests = false 27 | # app.CSPEnabled = false 28 | 29 | #-------------------------------------------------------------------- 30 | # DATABASE 31 | #-------------------------------------------------------------------- 32 | 33 | # database.default.hostname = localhost 34 | # database.default.database = ci4 35 | # database.default.username = root 36 | # database.default.password = root 37 | # database.default.DBDriver = MySQLi 38 | # database.default.DBPrefix = 39 | # database.default.port = 3306 40 | 41 | # If you use MySQLi as tests, first update the values of Config\Database::$tests. 42 | # database.tests.hostname = localhost 43 | # database.tests.database = ci4_test 44 | # database.tests.username = root 45 | # database.tests.password = root 46 | # database.tests.DBDriver = MySQLi 47 | # database.tests.DBPrefix = 48 | # database.tests.charset = utf8mb4 49 | # database.tests.DBCollat = utf8mb4_general_ci 50 | # database.tests.port = 3306 51 | 52 | #-------------------------------------------------------------------- 53 | # ENCRYPTION 54 | #-------------------------------------------------------------------- 55 | 56 | # encryption.key = 57 | 58 | #-------------------------------------------------------------------- 59 | # SESSION 60 | #-------------------------------------------------------------------- 61 | 62 | # session.driver = 'CodeIgniter\Session\Handlers\DatabaseHandler' 63 | # session.savePath = 'sessions' 64 | 65 | #-------------------------------------------------------------------- 66 | # LOGGER 67 | #-------------------------------------------------------------------- 68 | 69 | # logger.threshold = 4 70 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ./tests 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | ./app 38 | 39 | 40 | ./app/Views 41 | ./app/Config/Routes.php 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /app/Views/layouts/sidebar.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/Controllers/BaseController.php: -------------------------------------------------------------------------------- 1 | 38 | */ 39 | protected $helpers = ['cookie', 'date', 'security', 'menu', 'useraccess']; 40 | 41 | /** 42 | * Be sure to declare properties for any property fetch you initialized. 43 | * The creation of dynamic property is deprecated in PHP 8.2. 44 | */ 45 | protected $session, $segment, $validation, $encrypter, $ApplicationModel, $data = []; 46 | /** 47 | * @return void 48 | */ 49 | public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger) 50 | { 51 | // Do Not Edit This Line 52 | parent::initController($request, $response, $logger); 53 | 54 | // Preload any models, libraries, etc, here. 55 | 56 | $this->session = service('session'); 57 | $this->segment = service('uri'); 58 | $this->validation = \Config\Services::validation(); 59 | $this->encrypter = \Config\Services::encrypter(); 60 | $this->ApplicationModel = new ApplicationModel(); 61 | 62 | $user = $this->ApplicationModel->getUser(username: session()->get('username')); 63 | $segment = $this->segment->getSegment(1); 64 | if ($segment) { 65 | $subsegment = $this->segment->getSegment(2); 66 | } else { 67 | $subsegment = ''; 68 | } 69 | $this->data = [ 70 | 'segment' => $segment, 71 | 'subsegment' => $subsegment, 72 | 'user' => $user, 73 | 'MenuCategory' => $this->ApplicationModel->getAccessMenuCategory(session()->get('role')) 74 | ]; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/Config/Email.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * For the full copyright and license information, please view 10 | * the LICENSE file that was distributed with this source code. 11 | */ 12 | 13 | use CodeIgniter\Boot; 14 | use Config\Paths; 15 | 16 | /* 17 | * -------------------------------------------------------------------- 18 | * CODEIGNITER COMMAND-LINE TOOLS 19 | * -------------------------------------------------------------------- 20 | * The main entry point into the CLI system and allows you to run 21 | * commands and perform maintenance on your application. 22 | */ 23 | 24 | /* 25 | *--------------------------------------------------------------- 26 | * CHECK SERVER API 27 | *--------------------------------------------------------------- 28 | */ 29 | 30 | // Refuse to run when called from php-cgi 31 | if (str_starts_with(PHP_SAPI, 'cgi')) { 32 | exit("The cli tool is not supported when running php-cgi. It needs php-cli to function!\n\n"); 33 | } 34 | 35 | /* 36 | *--------------------------------------------------------------- 37 | * CHECK PHP VERSION 38 | *--------------------------------------------------------------- 39 | */ 40 | 41 | $minPhpVersion = '8.1'; // If you update this, don't forget to update `public/index.php`. 42 | if (version_compare(PHP_VERSION, $minPhpVersion, '<')) { 43 | $message = sprintf( 44 | 'Your PHP version must be %s or higher to run CodeIgniter. Current version: %s', 45 | $minPhpVersion, 46 | PHP_VERSION, 47 | ); 48 | 49 | exit($message); 50 | } 51 | 52 | // We want errors to be shown when using it from the CLI. 53 | error_reporting(E_ALL); 54 | ini_set('display_errors', '1'); 55 | 56 | /* 57 | *--------------------------------------------------------------- 58 | * SET THE CURRENT DIRECTORY 59 | *--------------------------------------------------------------- 60 | */ 61 | 62 | // Path to the front controller 63 | define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR); 64 | 65 | // Ensure the current directory is pointing to the front controller's directory 66 | chdir(FCPATH); 67 | 68 | /* 69 | *--------------------------------------------------------------- 70 | * BOOTSTRAP THE APPLICATION 71 | *--------------------------------------------------------------- 72 | * This process sets up the path constants, loads and registers 73 | * our autoloader, along with Composer's, loads our constants 74 | * and fires up an environment-specific bootstrapping. 75 | */ 76 | 77 | // LOAD OUR PATHS CONFIG FILE 78 | // This is the line that might need to be changed, depending on your folder structure. 79 | require FCPATH . '../app/Config/Paths.php'; 80 | // ^^^ Change this line if you move your application folder 81 | 82 | $paths = new Paths(); 83 | 84 | // LOAD THE FRAMEWORK BOOTSTRAP FILE 85 | require $paths->systemDirectory . '/Boot.php'; 86 | 87 | exit(Boot::bootSpark($paths)); 88 | -------------------------------------------------------------------------------- /app/Config/Paths.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | public array $list = [ 13 | 'xhtml11' => '', 14 | 'xhtml1-strict' => '', 15 | 'xhtml1-trans' => '', 16 | 'xhtml1-frame' => '', 17 | 'xhtml-basic11' => '', 18 | 'html5' => '', 19 | 'html4-strict' => '', 20 | 'html4-trans' => '', 21 | 'html4-frame' => '', 22 | 'mathml1' => '', 23 | 'mathml2' => '', 24 | 'svg10' => '', 25 | 'svg11' => '', 26 | 'svg11-basic' => '', 27 | 'svg11-tiny' => '', 28 | 'xhtml-math-svg-xh' => '', 29 | 'xhtml-math-svg-sh' => '', 30 | 'xhtml-rdfa-1' => '', 31 | 'xhtml-rdfa-2' => '', 32 | ]; 33 | 34 | /** 35 | * Whether to remove the solidus (`/`) character for void HTML elements (e.g. ``) 36 | * for HTML5 compatibility. 37 | * 38 | * Set to: 39 | * `true` - to be HTML5 compatible 40 | * `false` - to be XHTML compatible 41 | */ 42 | public bool $html5 = true; 43 | } 44 | -------------------------------------------------------------------------------- /app/Config/Security.php: -------------------------------------------------------------------------------- 1 | |string> 39 | */ 40 | public $psr4 = [ 41 | APP_NAMESPACE => APPPATH, 42 | ]; 43 | 44 | /** 45 | * ------------------------------------------------------------------- 46 | * Class Map 47 | * ------------------------------------------------------------------- 48 | * The class map provides a map of class names and their exact 49 | * location on the drive. Classes loaded in this manner will have 50 | * slightly faster performance because they will not have to be 51 | * searched for within one or more directories as they would if they 52 | * were being autoloaded through a namespace. 53 | * 54 | * Prototype: 55 | * $classmap = [ 56 | * 'MyClass' => '/path/to/class/file.php' 57 | * ]; 58 | * 59 | * @var array 60 | */ 61 | public $classmap = []; 62 | 63 | /** 64 | * ------------------------------------------------------------------- 65 | * Files 66 | * ------------------------------------------------------------------- 67 | * The files array provides a list of paths to __non-class__ files 68 | * that will be autoloaded. This can be useful for bootstrap operations 69 | * or for loading functions. 70 | * 71 | * Prototype: 72 | * $files = [ 73 | * '/path/to/my/file.php', 74 | * ]; 75 | * 76 | * @var list 77 | */ 78 | public $files = []; 79 | 80 | /** 81 | * ------------------------------------------------------------------- 82 | * Helpers 83 | * ------------------------------------------------------------------- 84 | * Prototype: 85 | * $helpers = [ 86 | * 'form', 87 | * ]; 88 | * 89 | * @var list 90 | */ 91 | public $helpers = []; 92 | } 93 | -------------------------------------------------------------------------------- /app/Views/errors/html/debug.js: -------------------------------------------------------------------------------- 1 | var tabLinks = new Array(); 2 | var contentDivs = new Array(); 3 | 4 | function init() 5 | { 6 | // Grab the tab links and content divs from the page 7 | var tabListItems = document.getElementById('tabs').childNodes; 8 | console.log(tabListItems); 9 | for (var i = 0; i < tabListItems.length; i ++) 10 | { 11 | if (tabListItems[i].nodeName == "LI") 12 | { 13 | var tabLink = getFirstChildWithTagName(tabListItems[i], 'A'); 14 | var id = getHash(tabLink.getAttribute('href')); 15 | tabLinks[id] = tabLink; 16 | contentDivs[id] = document.getElementById(id); 17 | } 18 | } 19 | 20 | // Assign onclick events to the tab links, and 21 | // highlight the first tab 22 | var i = 0; 23 | 24 | for (var id in tabLinks) 25 | { 26 | tabLinks[id].onclick = showTab; 27 | tabLinks[id].onfocus = function () { 28 | this.blur() 29 | }; 30 | if (i == 0) 31 | { 32 | tabLinks[id].className = 'active'; 33 | } 34 | i ++; 35 | } 36 | 37 | // Hide all content divs except the first 38 | var i = 0; 39 | 40 | for (var id in contentDivs) 41 | { 42 | if (i != 0) 43 | { 44 | console.log(contentDivs[id]); 45 | contentDivs[id].className = 'content hide'; 46 | } 47 | i ++; 48 | } 49 | } 50 | 51 | function showTab() 52 | { 53 | var selectedId = getHash(this.getAttribute('href')); 54 | 55 | // Highlight the selected tab, and dim all others. 56 | // Also show the selected content div, and hide all others. 57 | for (var id in contentDivs) 58 | { 59 | if (id == selectedId) 60 | { 61 | tabLinks[id].className = 'active'; 62 | contentDivs[id].className = 'content'; 63 | } 64 | else 65 | { 66 | tabLinks[id].className = ''; 67 | contentDivs[id].className = 'content hide'; 68 | } 69 | } 70 | 71 | // Stop the browser following the link 72 | return false; 73 | } 74 | 75 | function getFirstChildWithTagName(element, tagName) 76 | { 77 | for (var i = 0; i < element.childNodes.length; i ++) 78 | { 79 | if (element.childNodes[i].nodeName == tagName) 80 | { 81 | return element.childNodes[i]; 82 | } 83 | } 84 | } 85 | 86 | function getHash(url) 87 | { 88 | var hashPos = url.lastIndexOf('#'); 89 | return url.substring(hashPos + 1); 90 | } 91 | 92 | function toggle(elem) 93 | { 94 | elem = document.getElementById(elem); 95 | 96 | if (elem.style && elem.style['display']) 97 | { 98 | // Only works with the "style" attr 99 | var disp = elem.style['display']; 100 | } 101 | else if (elem.currentStyle) 102 | { 103 | // For MSIE, naturally 104 | var disp = elem.currentStyle['display']; 105 | } 106 | else if (window.getComputedStyle) 107 | { 108 | // For most other browsers 109 | var disp = document.defaultView.getComputedStyle(elem, null).getPropertyValue('display'); 110 | } 111 | 112 | // Toggle the state of the "display" style 113 | elem.style.display = disp == 'block' ? 'none' : 'block'; 114 | 115 | return false; 116 | } 117 | -------------------------------------------------------------------------------- /preload.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view 9 | * the LICENSE file that was distributed with this source code. 10 | */ 11 | 12 | use CodeIgniter\Boot; 13 | use Config\Paths; 14 | 15 | /* 16 | *--------------------------------------------------------------- 17 | * Sample file for Preloading 18 | *--------------------------------------------------------------- 19 | * See https://www.php.net/manual/en/opcache.preloading.php 20 | * 21 | * How to Use: 22 | * 0. Copy this file to your project root folder. 23 | * 1. Set the $paths property of the preload class below. 24 | * 2. Set opcache.preload in php.ini. 25 | * php.ini: 26 | * opcache.preload=/path/to/preload.php 27 | */ 28 | 29 | // Load the paths config file 30 | require __DIR__ . '/app/Config/Paths.php'; 31 | 32 | // Path to the front controller 33 | define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR); 34 | 35 | class preload 36 | { 37 | /** 38 | * @var array Paths to preload. 39 | */ 40 | private array $paths = [ 41 | [ 42 | 'include' => __DIR__ . '/vendor/codeigniter4/framework/system', // Change this path if using manual installation 43 | 'exclude' => [ 44 | // Not needed if you don't use them. 45 | '/system/Database/OCI8/', 46 | '/system/Database/Postgre/', 47 | '/system/Database/SQLite3/', 48 | '/system/Database/SQLSRV/', 49 | // Not needed for web apps. 50 | '/system/Database/Seeder.php', 51 | '/system/Test/', 52 | '/system/CLI/', 53 | '/system/Commands/', 54 | '/system/Publisher/', 55 | '/system/ComposerScripts.php', 56 | // Not Class/Function files. 57 | '/system/Config/Routes.php', 58 | '/system/Language/', 59 | '/system/bootstrap.php', 60 | '/system/rewrite.php', 61 | '/Views/', 62 | // Errors occur. 63 | '/system/ThirdParty/', 64 | ], 65 | ], 66 | ]; 67 | 68 | public function __construct() 69 | { 70 | $this->loadAutoloader(); 71 | } 72 | 73 | private function loadAutoloader(): void 74 | { 75 | $paths = new Paths(); 76 | require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'Boot.php'; 77 | 78 | Boot::preload($paths); 79 | } 80 | 81 | /** 82 | * Load PHP files. 83 | */ 84 | public function load(): void 85 | { 86 | foreach ($this->paths as $path) { 87 | $directory = new RecursiveDirectoryIterator($path['include']); 88 | $fullTree = new RecursiveIteratorIterator($directory); 89 | $phpFiles = new RegexIterator( 90 | $fullTree, 91 | '/.+((? $file) { 96 | foreach ($path['exclude'] as $exclude) { 97 | if (str_contains($file[0], $exclude)) { 98 | continue 2; 99 | } 100 | } 101 | 102 | require_once $file[0]; 103 | echo 'Loaded: ' . $file[0] . "\n"; 104 | } 105 | } 106 | } 107 | } 108 | 109 | (new preload())->load(); 110 | -------------------------------------------------------------------------------- /app/Views/pages/commons/login.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | CodeIgniter 4 Starter Panel 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 |
26 |
27 |
28 |
29 | include('components/alerts'); ?> 30 |
31 |
32 |
33 |

Welcome to CodeIgniter 4 Starter Panel

34 |

35 | Sign in to your account to continue 36 |

37 |
38 |
39 |
40 |
41 | 42 | 43 |
44 |
45 | 46 | 47 | 48 | Don't have an account? Register 49 | 50 |
51 |
52 | 53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | 64 | 65 | -------------------------------------------------------------------------------- /app/Controllers/Auth.php: -------------------------------------------------------------------------------- 1 | get('isLoggedIn') == TRUE) { 13 | return redirect()->to(base_url('dashboard')); 14 | } 15 | 16 | if (!$this->validate(['inputEmail' => 'required'])) { 17 | return view('pages/commons/login'); 18 | } else { 19 | $inputEmail = htmlspecialchars($this->request->getVar('inputEmail', FILTER_UNSAFE_RAW)); 20 | $inputPassword = htmlspecialchars($this->request->getVar('inputPassword', FILTER_UNSAFE_RAW)); 21 | $user = $this->ApplicationModel->getUser(username: $inputEmail); 22 | if ($user) { 23 | $password = $user['password']; 24 | $verify = password_verify($inputPassword, $password); 25 | if ($verify) { 26 | session()->set([ 27 | 'username' => $user['username'], 28 | 'role' => $user['role'], 29 | 'isLoggedIn' => TRUE 30 | ]); 31 | return redirect()->to(base_url('dashboard')); 32 | } else { 33 | session()->setFlashdata('notif_error', 'Your ID or Password is Wrong ! '); 34 | return redirect()->to(base_url()); 35 | } 36 | } else { 37 | session()->setFlashdata('notif_error', 'Your ID or Password is Wrong! '); 38 | return redirect()->to(base_url()); 39 | } 40 | } 41 | } 42 | public function logout() 43 | { 44 | $this->session->destroy(); 45 | return redirect()->to(base_url('/')); 46 | } 47 | 48 | public function forbiddenPage() 49 | { 50 | $data = array_merge($this->data, [ 51 | 'title' => 'Forbidden Page' 52 | ]); 53 | return view('pages/commons/forbidden', $data); 54 | } 55 | 56 | public function register() 57 | { 58 | return view('pages/commons/register'); 59 | } 60 | 61 | public function registration() 62 | { 63 | if (!$this->validate([ 64 | 'inputEmail' => ['label' => 'Email', 'rules' => 'is_unique[users.username]'], 65 | 'inputPassword' => ['label' => 'Password', 'rules' => 'required'], 66 | 'inputPassword2' => ['label' => 'Password Confirmation', 'rules' => 'matches[inputPassword]'], 67 | ])) { 68 | $data = array_merge($this->data, [ 69 | 'title' => 'Register Page', 70 | ]); 71 | 72 | session()->setFlashdata('notif_error', $this->validation->getError('inputPassword2') . ' ' . $this->validation->getError('inputEmail')); 73 | return view('pages/commons/register', $data); 74 | } else { 75 | $inputFullname = htmlspecialchars($this->request->getVar('inputFullname', FILTER_UNSAFE_RAW)); 76 | $inputEmail = htmlspecialchars($this->request->getVar('inputEmail', FILTER_UNSAFE_RAW)); 77 | $inputPassword = htmlspecialchars($this->request->getVar('inputPassword', FILTER_UNSAFE_RAW)); 78 | $dataUser = [ 79 | 'inputFullname' => $inputFullname, 80 | 'inputUsername' => $inputEmail, 81 | 'inputPassword' => $inputPassword, 82 | 'inputRole' => 1 83 | ]; 84 | $this->ApplicationModel->createUser($dataUser); 85 | session()->setFlashdata('notif_success', 'Registration Successfully! Please login with your account.'); 86 | return view('pages/commons/login'); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/Config/Constants.php: -------------------------------------------------------------------------------- 1 | , 19 | * allowedOriginsPatterns: list, 20 | * supportsCredentials: bool, 21 | * allowedHeaders: list, 22 | * exposedHeaders: list, 23 | * allowedMethods: list, 24 | * maxAge: int, 25 | * } 26 | */ 27 | public array $default = [ 28 | /** 29 | * Origins for the `Access-Control-Allow-Origin` header. 30 | * 31 | * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin 32 | * 33 | * E.g.: 34 | * - ['http://localhost:8080'] 35 | * - ['https://www.example.com'] 36 | */ 37 | 'allowedOrigins' => [], 38 | 39 | /** 40 | * Origin regex patterns for the `Access-Control-Allow-Origin` header. 41 | * 42 | * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin 43 | * 44 | * NOTE: A pattern specified here is part of a regular expression. It will 45 | * be actually `#\A\z#`. 46 | * 47 | * E.g.: 48 | * - ['https://\w+\.example\.com'] 49 | */ 50 | 'allowedOriginsPatterns' => [], 51 | 52 | /** 53 | * Weather to send the `Access-Control-Allow-Credentials` header. 54 | * 55 | * The Access-Control-Allow-Credentials response header tells browsers whether 56 | * the server allows cross-origin HTTP requests to include credentials. 57 | * 58 | * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials 59 | */ 60 | 'supportsCredentials' => false, 61 | 62 | /** 63 | * Set headers to allow. 64 | * 65 | * The Access-Control-Allow-Headers response header is used in response to 66 | * a preflight request which includes the Access-Control-Request-Headers to 67 | * indicate which HTTP headers can be used during the actual request. 68 | * 69 | * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers 70 | */ 71 | 'allowedHeaders' => [], 72 | 73 | /** 74 | * Set headers to expose. 75 | * 76 | * The Access-Control-Expose-Headers response header allows a server to 77 | * indicate which response headers should be made available to scripts running 78 | * in the browser, in response to a cross-origin request. 79 | * 80 | * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers 81 | */ 82 | 'exposedHeaders' => [], 83 | 84 | /** 85 | * Set methods to allow. 86 | * 87 | * The Access-Control-Allow-Methods response header specifies one or more 88 | * methods allowed when accessing a resource in response to a preflight 89 | * request. 90 | * 91 | * E.g.: 92 | * - ['GET', 'POST', 'PUT', 'DELETE'] 93 | * 94 | * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods 95 | */ 96 | 'allowedMethods' => [], 97 | 98 | /** 99 | * Set how many seconds the results of a preflight request can be cached. 100 | * 101 | * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age 102 | */ 103 | 'maxAge' => 7200, 104 | ]; 105 | } 106 | -------------------------------------------------------------------------------- /app/Config/Cookie.php: -------------------------------------------------------------------------------- 1 | > 25 | * 26 | * [filter_name => classname] 27 | * or [filter_name => [classname1, classname2, ...]] 28 | */ 29 | public array $aliases = [ 30 | 'csrf' => CSRF::class, 31 | 'toolbar' => DebugToolbar::class, 32 | 'honeypot' => Honeypot::class, 33 | 'invalidchars' => InvalidChars::class, 34 | 'secureheaders' => SecureHeaders::class, 35 | 'cors' => Cors::class, 36 | 'forcehttps' => ForceHTTPS::class, 37 | 'pagecache' => PageCache::class, 38 | 'performance' => PerformanceMetrics::class, 39 | 'isLoggedIn' => Authentication::class, 40 | 'isGranted' => Authorization::class, 41 | ]; 42 | 43 | /** 44 | * List of special required filters. 45 | * 46 | * The filters listed here are special. They are applied before and after 47 | * other kinds of filters, and always applied even if a route does not exist. 48 | * 49 | * Filters set by default provide framework functionality. If removed, 50 | * those functions will no longer work. 51 | * 52 | * @see https://codeigniter.com/user_guide/incoming/filters.html#provided-filters 53 | * 54 | * @var array{before: list, after: list} 55 | */ 56 | public array $required = [ 57 | 'before' => [ 58 | 'forcehttps', // Force Global Secure Requests 59 | 'pagecache', // Web Page Caching 60 | ], 61 | 'after' => [ 62 | 'pagecache', // Web Page Caching 63 | 'performance', // Performance Metrics 64 | 'toolbar', // Debug Toolbar 65 | ], 66 | ]; 67 | 68 | /** 69 | * List of filter aliases that are always 70 | * applied before and after every request. 71 | * 72 | * @var array>>|array> 73 | */ 74 | public array $globals = [ 75 | 'before' => [ 76 | 'isLoggedIn' => ['except' => ['/', 'register', 'login']], 77 | 'isGranted' => ['except' => ['/', 'register', 'login', 'logout', 'blocked']], 78 | // 'honeypot', 79 | // 'csrf', 80 | // 'invalidchars', 81 | ], 82 | 'after' => [ 83 | // 'honeypot', 84 | // 'secureheaders', 85 | ], 86 | ]; 87 | 88 | /** 89 | * List of filter aliases that works on a 90 | * particular HTTP method (GET, POST, etc.). 91 | * 92 | * Example: 93 | * 'POST' => ['foo', 'bar'] 94 | * 95 | * If you use this, you should disable auto-routing because auto-routing 96 | * permits any HTTP method to access a controller. Accessing the controller 97 | * with a method you don't expect could bypass the filter. 98 | * 99 | * @var array> 100 | */ 101 | public array $methods = []; 102 | 103 | /** 104 | * List of filter aliases that should run on any 105 | * before or after URI patterns. 106 | * 107 | * Example: 108 | * 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']] 109 | * 110 | * @var array>> 111 | */ 112 | public array $filters = []; 113 | } 114 | -------------------------------------------------------------------------------- /app/Config/Routing.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view 9 | * the LICENSE file that was distributed with this source code. 10 | */ 11 | 12 | namespace Config; 13 | 14 | use CodeIgniter\Config\Routing as BaseRouting; 15 | 16 | /** 17 | * Routing configuration 18 | */ 19 | class Routing extends BaseRouting 20 | { 21 | /** 22 | * For Defined Routes. 23 | * An array of files that contain route definitions. 24 | * Route files are read in order, with the first match 25 | * found taking precedence. 26 | * 27 | * Default: APPPATH . 'Config/Routes.php' 28 | * 29 | * @var list 30 | */ 31 | public array $routeFiles = [ 32 | APPPATH . 'Config/Routes.php', 33 | ]; 34 | 35 | /** 36 | * For Defined Routes and Auto Routing. 37 | * The default namespace to use for Controllers when no other 38 | * namespace has been specified. 39 | * 40 | * Default: 'App\Controllers' 41 | */ 42 | public string $defaultNamespace = 'App\Controllers'; 43 | 44 | /** 45 | * For Auto Routing. 46 | * The default controller to use when no other controller has been 47 | * specified. 48 | * 49 | * Default: 'Home' 50 | */ 51 | public string $defaultController = 'Home'; 52 | 53 | /** 54 | * For Defined Routes and Auto Routing. 55 | * The default method to call on the controller when no other 56 | * method has been set in the route. 57 | * 58 | * Default: 'index' 59 | */ 60 | public string $defaultMethod = 'index'; 61 | 62 | /** 63 | * For Auto Routing. 64 | * Whether to translate dashes in URIs for controller/method to underscores. 65 | * Primarily useful when using the auto-routing. 66 | * 67 | * Default: false 68 | */ 69 | public bool $translateURIDashes = false; 70 | 71 | /** 72 | * Sets the class/method that should be called if routing doesn't 73 | * find a match. It can be the controller/method name like: Users::index 74 | * 75 | * This setting is passed to the Router class and handled there. 76 | * 77 | * If you want to use a closure, you will have to set it in the 78 | * routes file by calling: 79 | * 80 | * $routes->set404Override(function() { 81 | * // Do something here 82 | * }); 83 | * 84 | * Example: 85 | * public $override404 = 'App\Errors::show404'; 86 | */ 87 | public ?string $override404 = null; 88 | 89 | /** 90 | * If TRUE, the system will attempt to match the URI against 91 | * Controllers by matching each segment against folders/files 92 | * in APPPATH/Controllers, when a match wasn't found against 93 | * defined routes. 94 | * 95 | * If FALSE, will stop searching and do NO automatic routing. 96 | */ 97 | public bool $autoRoute = false; 98 | 99 | /** 100 | * For Defined Routes. 101 | * If TRUE, will enable the use of the 'prioritize' option 102 | * when defining routes. 103 | * 104 | * Default: false 105 | */ 106 | public bool $prioritize = false; 107 | 108 | /** 109 | * For Defined Routes. 110 | * If TRUE, matched multiple URI segments will be passed as one parameter. 111 | * 112 | * Default: false 113 | */ 114 | public bool $multipleSegmentsOneParam = false; 115 | 116 | /** 117 | * For Auto Routing (Improved). 118 | * Map of URI segments and namespaces. 119 | * 120 | * The key is the first URI segment. The value is the controller namespace. 121 | * E.g., 122 | * [ 123 | * 'blog' => 'Acme\Blog\Controllers', 124 | * ] 125 | * 126 | * @var array 127 | */ 128 | public array $moduleRoutes = []; 129 | 130 | /** 131 | * For Auto Routing (Improved). 132 | * Whether to translate dashes in URIs for controller/method to CamelCase. 133 | * E.g., blog-controller -> BlogController 134 | * 135 | * If you enable this, $translateURIDashes is ignored. 136 | * 137 | * Default: false 138 | */ 139 | public bool $translateUriToCamelCase = true; 140 | } 141 | -------------------------------------------------------------------------------- /app/Config/Exceptions.php: -------------------------------------------------------------------------------- 1 | 35 | */ 36 | public array $ignoreCodes = [404]; 37 | 38 | /** 39 | * -------------------------------------------------------------------------- 40 | * Error Views Path 41 | * -------------------------------------------------------------------------- 42 | * This is the path to the directory that contains the 'cli' and 'html' 43 | * directories that hold the views used to generate errors. 44 | * 45 | * Default: APPPATH.'Views/errors' 46 | */ 47 | public string $errorViewPath = APPPATH . 'Views/errors'; 48 | 49 | /** 50 | * -------------------------------------------------------------------------- 51 | * HIDE FROM DEBUG TRACE 52 | * -------------------------------------------------------------------------- 53 | * Any data that you would like to hide from the debug trace. 54 | * In order to specify 2 levels, use "/" to separate. 55 | * ex. ['server', 'setup/password', 'secret_token'] 56 | * 57 | * @var list 58 | */ 59 | public array $sensitiveDataInTrace = []; 60 | 61 | /** 62 | * -------------------------------------------------------------------------- 63 | * WHETHER TO THROW AN EXCEPTION ON DEPRECATED ERRORS 64 | * -------------------------------------------------------------------------- 65 | * If set to `true`, DEPRECATED errors are only logged and no exceptions are 66 | * thrown. This option also works for user deprecations. 67 | */ 68 | public bool $logDeprecations = true; 69 | 70 | /** 71 | * -------------------------------------------------------------------------- 72 | * LOG LEVEL THRESHOLD FOR DEPRECATIONS 73 | * -------------------------------------------------------------------------- 74 | * If `$logDeprecations` is set to `true`, this sets the log level 75 | * to which the deprecation will be logged. This should be one of the log 76 | * levels recognized by PSR-3. 77 | * 78 | * The related `Config\Logger::$threshold` should be adjusted, if needed, 79 | * to capture logging the deprecations. 80 | */ 81 | public string $deprecationLogLevel = LogLevel::WARNING; 82 | 83 | /* 84 | * DEFINE THE HANDLERS USED 85 | * -------------------------------------------------------------------------- 86 | * Given the HTTP status code, returns exception handler that 87 | * should be used to deal with this error. By default, it will run CodeIgniter's 88 | * default handler and display the error information in the expected format 89 | * for CLI, HTTP, or AJAX requests, as determined by is_cli() and the expected 90 | * response format. 91 | * 92 | * Custom handlers can be returned if you want to handle one or more specific 93 | * error codes yourself like: 94 | * 95 | * if (in_array($statusCode, [400, 404, 500])) { 96 | * return new \App\Libraries\MyExceptionHandler(); 97 | * } 98 | * if ($exception instanceOf PageNotFoundException) { 99 | * return new \App\Libraries\MyExceptionHandler(); 100 | * } 101 | */ 102 | public function handler(int $statusCode, Throwable $exception): ExceptionHandlerInterface 103 | { 104 | return new ExceptionHandler($this); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/Views/errors/html/debug.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --main-bg-color: #fff; 3 | --main-text-color: #555; 4 | --dark-text-color: #222; 5 | --light-text-color: #c7c7c7; 6 | --brand-primary-color: #DC4814; 7 | --light-bg-color: #ededee; 8 | --dark-bg-color: #404040; 9 | } 10 | 11 | body { 12 | height: 100%; 13 | background: var(--main-bg-color); 14 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; 15 | color: var(--main-text-color); 16 | font-weight: 300; 17 | margin: 0; 18 | padding: 0; 19 | } 20 | h1 { 21 | font-weight: lighter; 22 | font-size: 3rem; 23 | color: var(--dark-text-color); 24 | margin: 0; 25 | } 26 | h1.headline { 27 | margin-top: 20%; 28 | font-size: 5rem; 29 | } 30 | .text-center { 31 | text-align: center; 32 | } 33 | p.lead { 34 | font-size: 1.6rem; 35 | } 36 | .container { 37 | max-width: 75rem; 38 | margin: 0 auto; 39 | padding: 1rem; 40 | } 41 | .header { 42 | background: var(--light-bg-color); 43 | color: var(--dark-text-color); 44 | margin-top: 2.17rem; 45 | } 46 | .header .container { 47 | padding: 1rem; 48 | } 49 | .header h1 { 50 | font-size: 2.5rem; 51 | font-weight: 500; 52 | } 53 | .header p { 54 | font-size: 1.2rem; 55 | margin: 0; 56 | line-height: 2.5; 57 | } 58 | .header a { 59 | color: var(--brand-primary-color); 60 | margin-left: 2rem; 61 | display: none; 62 | text-decoration: none; 63 | } 64 | .header:hover a { 65 | display: inline; 66 | } 67 | 68 | .environment { 69 | background: var(--brand-primary-color); 70 | color: var(--main-bg-color); 71 | text-align: center; 72 | padding: calc(4px + 0.2083vw); 73 | width: 100%; 74 | top: 0; 75 | position: fixed; 76 | } 77 | 78 | .source { 79 | background: #343434; 80 | color: var(--light-text-color); 81 | padding: 0.5em 1em; 82 | border-radius: 5px; 83 | font-family: Menlo, Monaco, Consolas, "Courier New", monospace; 84 | font-size: 0.85rem; 85 | margin: 0; 86 | overflow-x: scroll; 87 | } 88 | .source span.line { 89 | line-height: 1.4; 90 | } 91 | .source span.line .number { 92 | color: #666; 93 | } 94 | .source .line .highlight { 95 | display: block; 96 | background: var(--dark-text-color); 97 | color: var(--light-text-color); 98 | } 99 | .source span.highlight .number { 100 | color: #fff; 101 | } 102 | 103 | .tabs { 104 | list-style: none; 105 | list-style-position: inside; 106 | margin: 0; 107 | padding: 0; 108 | margin-bottom: -1px; 109 | } 110 | .tabs li { 111 | display: inline; 112 | } 113 | .tabs a:link, 114 | .tabs a:visited { 115 | padding: 0 1rem; 116 | line-height: 2.7; 117 | text-decoration: none; 118 | color: var(--dark-text-color); 119 | background: var(--light-bg-color); 120 | border: 1px solid rgba(0,0,0,0.15); 121 | border-bottom: 0; 122 | border-top-left-radius: 5px; 123 | border-top-right-radius: 5px; 124 | display: inline-block; 125 | } 126 | .tabs a:hover { 127 | background: var(--light-bg-color); 128 | border-color: rgba(0,0,0,0.15); 129 | } 130 | .tabs a.active { 131 | background: var(--main-bg-color); 132 | color: var(--main-text-color); 133 | } 134 | .tab-content { 135 | background: var(--main-bg-color); 136 | border: 1px solid rgba(0,0,0,0.15); 137 | } 138 | .content { 139 | padding: 1rem; 140 | } 141 | .hide { 142 | display: none; 143 | } 144 | 145 | .alert { 146 | margin-top: 2rem; 147 | display: block; 148 | text-align: center; 149 | line-height: 3.0; 150 | background: #d9edf7; 151 | border: 1px solid #bcdff1; 152 | border-radius: 5px; 153 | color: #31708f; 154 | } 155 | 156 | table { 157 | width: 100%; 158 | overflow: hidden; 159 | } 160 | th { 161 | text-align: left; 162 | border-bottom: 1px solid #e7e7e7; 163 | padding-bottom: 0.5rem; 164 | } 165 | td { 166 | padding: 0.2rem 0.5rem 0.2rem 0; 167 | } 168 | tr:hover td { 169 | background: #f1f1f1; 170 | } 171 | td pre { 172 | white-space: pre-wrap; 173 | } 174 | 175 | .trace a { 176 | color: inherit; 177 | } 178 | .trace table { 179 | width: auto; 180 | } 181 | .trace tr td:first-child { 182 | min-width: 5em; 183 | font-weight: bold; 184 | } 185 | .trace td { 186 | background: var(--light-bg-color); 187 | padding: 0 1rem; 188 | } 189 | .trace td pre { 190 | margin: 0; 191 | } 192 | .args { 193 | display: none; 194 | } 195 | -------------------------------------------------------------------------------- /app/Views/pages/commons/register.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | CodeIgniter 4 Starter Panel 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 |
28 |
29 |
30 | 31 |
32 |
33 |
34 | include('components/alerts'); ?> 35 | 36 |
37 |

Welcome to CodeIgniter 4 Starter Panel

38 |

Register New Account

39 |
40 | 41 |
42 | 47 |
48 | 49 | 50 |
51 |
52 | 53 | 54 |
55 |
56 | 57 | 58 | 59 |
60 |
61 | 62 | 63 | 64 | Have an account? Login 65 | 66 |
67 |
68 | 69 |
70 | 71 |
72 |
73 |
74 |
75 |
76 |
77 | 78 |
79 |
80 |
81 | 82 | 83 | -------------------------------------------------------------------------------- /app/Config/Toolbar.php: -------------------------------------------------------------------------------- 1 | 35 | */ 36 | public array $collectors = [ 37 | Timers::class, 38 | Database::class, 39 | Logs::class, 40 | Views::class, 41 | // \CodeIgniter\Debug\Toolbar\Collectors\Cache::class, 42 | Files::class, 43 | Routes::class, 44 | Events::class, 45 | ]; 46 | 47 | /** 48 | * -------------------------------------------------------------------------- 49 | * Collect Var Data 50 | * -------------------------------------------------------------------------- 51 | * 52 | * If set to false var data from the views will not be collected. Useful to 53 | * avoid high memory usage when there are lots of data passed to the view. 54 | */ 55 | public bool $collectVarData = true; 56 | 57 | /** 58 | * -------------------------------------------------------------------------- 59 | * Max History 60 | * -------------------------------------------------------------------------- 61 | * 62 | * `$maxHistory` sets a limit on the number of past requests that are stored, 63 | * helping to conserve file space used to store them. You can set it to 64 | * 0 (zero) to not have any history stored, or -1 for unlimited history. 65 | */ 66 | public int $maxHistory = 20; 67 | 68 | /** 69 | * -------------------------------------------------------------------------- 70 | * Toolbar Views Path 71 | * -------------------------------------------------------------------------- 72 | * 73 | * The full path to the the views that are used by the toolbar. 74 | * This MUST have a trailing slash. 75 | */ 76 | public string $viewsPath = SYSTEMPATH . 'Debug/Toolbar/Views/'; 77 | 78 | /** 79 | * -------------------------------------------------------------------------- 80 | * Max Queries 81 | * -------------------------------------------------------------------------- 82 | * 83 | * If the Database Collector is enabled, it will log every query that the 84 | * the system generates so they can be displayed on the toolbar's timeline 85 | * and in the query log. This can lead to memory issues in some instances 86 | * with hundreds of queries. 87 | * 88 | * `$maxQueries` defines the maximum amount of queries that will be stored. 89 | */ 90 | public int $maxQueries = 100; 91 | 92 | /** 93 | * -------------------------------------------------------------------------- 94 | * Watched Directories 95 | * -------------------------------------------------------------------------- 96 | * 97 | * Contains an array of directories that will be watched for changes and 98 | * used to determine if the hot-reload feature should reload the page or not. 99 | * We restrict the values to keep performance as high as possible. 100 | * 101 | * NOTE: The ROOTPATH will be prepended to all values. 102 | * 103 | * @var list 104 | */ 105 | public array $watchedDirectories = [ 106 | 'app', 107 | ]; 108 | 109 | /** 110 | * -------------------------------------------------------------------------- 111 | * Watched File Extensions 112 | * -------------------------------------------------------------------------- 113 | * 114 | * Contains an array of file extensions that will be watched for changes and 115 | * used to determine if the hot-reload feature should reload the page or not. 116 | * 117 | * @var list 118 | */ 119 | public array $watchedExtensions = [ 120 | 'php', 'css', 'js', 'html', 'svg', 'json', 'env', 121 | ]; 122 | } 123 | -------------------------------------------------------------------------------- /app/Config/ContentSecurityPolicy.php: -------------------------------------------------------------------------------- 1 | |string|null 49 | */ 50 | public $defaultSrc; 51 | 52 | /** 53 | * Lists allowed scripts' URLs. 54 | * 55 | * @var list|string 56 | */ 57 | public $scriptSrc = 'self'; 58 | 59 | /** 60 | * Lists allowed stylesheets' URLs. 61 | * 62 | * @var list|string 63 | */ 64 | public $styleSrc = 'self'; 65 | 66 | /** 67 | * Defines the origins from which images can be loaded. 68 | * 69 | * @var list|string 70 | */ 71 | public $imageSrc = 'self'; 72 | 73 | /** 74 | * Restricts the URLs that can appear in a page's `` element. 75 | * 76 | * Will default to self if not overridden 77 | * 78 | * @var list|string|null 79 | */ 80 | public $baseURI; 81 | 82 | /** 83 | * Lists the URLs for workers and embedded frame contents 84 | * 85 | * @var list|string 86 | */ 87 | public $childSrc = 'self'; 88 | 89 | /** 90 | * Limits the origins that you can connect to (via XHR, 91 | * WebSockets, and EventSource). 92 | * 93 | * @var list|string 94 | */ 95 | public $connectSrc = 'self'; 96 | 97 | /** 98 | * Specifies the origins that can serve web fonts. 99 | * 100 | * @var list|string 101 | */ 102 | public $fontSrc; 103 | 104 | /** 105 | * Lists valid endpoints for submission from `
` tags. 106 | * 107 | * @var list|string 108 | */ 109 | public $formAction = 'self'; 110 | 111 | /** 112 | * Specifies the sources that can embed the current page. 113 | * This directive applies to ``, `