---
# Goal

Create an admin panel that uses PHP as the scripting language and MySQL as the database.

---
# Specification

In this section, we will discuss the specification of the admin panel.

---
## Directory Structure

The root directory of this application is designated as {admin-panel}.
The acutall value of {admin-panel} is "obfus-express".

The root directory contains the following folders:

### FOLDER: info

The path of this folder is '{admin-panel}/info'.
The info folder stores information regarding this project.

### FOLDER: config

The path of this folder is '{admin-panel}/config'.
The config folder contains configuration files which define settings, parameters, or environment-specific variables needed to configure the application.
The file name format for configuration files in this folder is "config.{name}.inc.php".
The {name} part varies depending on which category of settings the file contains.
For example:

- the file name for a configuration file that defines settings for accessing a database is config.db.inc.php. The path will be '{admin-panel}/config/config.db.inc.php'.
- The file name for a configuration file that defines settings related to logging is config.log.inc.php. The path will be '{admin-panel}/config/config.log.inc.php'.
- The file name for a configuration file that defines uncategorized settings is config.main.inc.php. The path will be '{admin-panel}/config/config.main.inc.php'.

Define configuration items in configuration files in the format shown below:

```php
//-- {Comment the configuration item}
$cfg[{key}]={value};
```

### FOLDER: locale

The path of this folder is '{admin-panel}/locale'.
The locale folder contains locale files which are related to internationalization (i18n) and localization (l10n),

The file path of a locale file is '{admin-panel}/locale/{language}/locale.{name}.inc.php'
In this project, {language} is always 'en' and {name} is 'main'.

Define locale items in locale files in the format shown below:

```php
//-- {Comment the locale item}
$lca[{key}]={value};
```

### FOLDER: include

The path of this folder is '{admin-panel}/include'.
The include folder contains PHP class files and a PHP function file.

The path format of PHP class files is '{admin-panel}/include/{class-name}.class.php',
where {class-name} is the name of the PHP class contained in the file.
The path of the PHP function file is '{admin-panel}/include/functions.inc.php', which
includes useful PHP functions used in this application.

---
## DATABASE

The default name of the database is "my-admin-panel".
Save the file that defines the database in SQL statements as
"{admin-panel}/info/sql.txt". 

The database has two tables:

- user
- accesslog

### TABLE: user

The name of this table is 'user' but when we access to the acutal table, you must prefix it with the table prefix. You can obtain the table prefix from the configuration file, config.db.inc.php. $cfg["db-tbl-prefix"] in the configuration file gives you the value of the table prefix. Let's assume that $cfg["db-tbl-prefix"] is "tbl_", then the definition of the user table is as follows:

```sql
CREATE TABLE `tbl_user` (
  `user_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,       -- Primary ID
  `username` VARCHAR(50) NOT NULL UNIQUE,                -- Unique login name
  `email` VARCHAR(100) NOT NULL UNIQUE,                  -- User email
  `password_hash` VARCHAR(255) NOT NULL,                 -- Hashed password
  `first_name` VARCHAR(50),                              -- First name
  `last_name` VARCHAR(50),                               -- Last name
  `language` VARCHAR(20) DEFAULT 'en',                   -- Preferred language
  `timezone` VARCHAR(100) DEFAULT 'UTC',                 -- Timezone
  `status` ENUM('active', 'inactive', 'banned') DEFAULT 'active', -- Account status
  `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,       -- Account creation
  `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- Last update
  `last_login_at` DATETIME DEFAULT NULL,                 -- Last login
  `login_ip` VARCHAR(45) DEFAULT NULL,                   -- IP at last login (IPv6 OK)
  `role` ENUM('user', 'admin', 'moderator') DEFAULT 'user', -- User role
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```

---
## Classification of PHP Files

- Entry point page: This file gets called from the outside.
- PHP class file: This file contains a PHP class and gets included in other PHP files. It never directly gets called from the outside.
- PHP include file: This file gets included in other PHP files. It never directly gets called from the outside.
- Admin panel content page: They include start.inc.php at the top of the file. Also they share the same header and footer. The header is stored in header.inc.php. The footer is stored in footer.inc.php.
- Configuration file: This file is located in '{admin-panel}/config'.
- Locale file: This file is located in '{admin-panel}/locale'.

## PHP FILES

### login.php
The path of this file is '{admin-panel}/login.php'.
This is an entry point file.
This is the login page of the admin panel.

It has two input boxes: Username and Password.
Also, it has one submit button labeled as "Enter".

If you enter your username and password in the input boxes and click Enter, login.php will post the information to login.php, itself. Then login.php will access the database and try to find the record where the username and password match the posted username and password. If they match, call CSess::start($user_id) where $user_id is the user_id of the record, then redirect to main.php. If the match fails then it displays an error message in login.php, which informs the user that the inputted username or password is wrong.

### main.php
The path of this file is '{admin-panel}/main.php'.
This is an entry point file.
This is an admin panel content page.

Users get redirected to this page if the authentication of their username and password is successful.

This page displays the username and email of the user.

### user-list.php
The path of this file is '{admin-panel}/user-list.php'.
This is an entry point page.
This is an admin panel content page.

This PHP page paginates and displays user records.

### settings.php
The path of this file is '{admin-panel}/settings.php'.
This is an entry point page.
This is an admin panel content page.

This PHP page displays the text, "This is the settings page."

### accesslog.php
The path of this file is '{admin-panel}/accesslog.php'.
This is an entry point page.
This is an admin panel content page.

This PHP page displays the text, "This is the accesslog.php."

### start.inc.php
The path of this file is '{admin-panel}/start.inc.php'.
This is a PHP Include file.

start.inc.php is included in every admin panel content page.
Here are the steps that start.inc.php takes:

1. Include every PHP class file and PHP function file in the include folder.
2. Call CSess::userID(). If it returns null, it means the user session is expired so redirect to login.php.
3. Call CDB::open() to open the database.

### header.inc.php
The path of this file is '{admin-panel}/header.inc.php'.
This is a PHP Include file.

This file displays the header of the admin panel.
The header contains a title bar that displays the title of the application.
The title of the application is "HObfusAPI".

Below the title, there is the main menu of the admin panel.
If the user is an administrator, the following menu items are available:

- "Users" that links to user-list.php.
- "Settings" that links to settings.php.

If the user is a regular user, the following menu items are available:

- "Access Log" that links to accesslog.php.
- "Settings" that links to settings.php.

### footer.inc.php
The path of this file is '{admin-panel}/footer.inc.php'.
This is a PHP Include file.

This file display the footer of the admin panel.
The footer contains a bar that display the username of the current user.

### config.db.inc.php
The path of this file is '{admin-panel}/config/config.db.inc.php'.
This file is a configration file.
This file contains configurations regarding the database access, as shown below.

- $cfg["db-hostname"]: the hostname that hosts the database
- $cfg["db-database"]: the name of the database
- $cfg["db-username"]: the username to access the database
- $cfg["db-password"]: the password to access the database
- $cfg["db-tbl-prefix"]: the table prefix

- The initial value of $cfg["db-hostname"] is "localhost".
- The initial value of $cfg["db-database"] is "my-database".
- The initial value of $cfg["db-username"] is "root".
- The initial value of $cfg["db-password"] is "password".
- The initial value of $cfg["db-tbl-prefix"] "tbl_".

### locale.main.inc.php
The path of this file is '{admin-panel}/locale/en/locale.main.inc.php'.
This file is a locale file.
This file contains locale string used in this application.

### CConfig.class.php
The path of this file is '{admin-panel}/include/CConfig.class.php'.
This is a PHP class file.
This file contains a PHP class that accesses configulation files.
The PHP class has the following methods.

#### CConfig::get($name)
This method opens the file located at '{admin-panel}/config/config.{$name}.inc.php'.
Then it returns $cfg.

### CLocale.class.php
The path of this file is '{admin-panel}/include/CLocale.class.php'.
This is a PHP class file.
This file contains a PHP class that accesses locale files.
The PHP class has the following methods.

#### CLocale::get($name)
This method opens the file located at '{admin-panel}/locale/locale.{$name}.inc.php'.
Then it returns $lca.

### CDB.class.php
The path of this file is '{admin-panel}/include/CDB.class.php'.
This is a PHP class file.
This file contains a PHP class that accesses the database.
The PHP class has the following methods.

#### CDB::open()
This method loads the database configurations from config.db.inc.php using CConfig, and then it opens the database and makes it ready for the UTF-8 access.
If it cannot open the database, displays the error message and immediately terminate the script.

#### CDB::close()
This method closes the connection to the database if it's already open. If it's not open, do nothing.

#### CDB::query($sql)
This method accepts a sql and executes it on the database. Before executing it on the database, replace the placeholder %t~p% with the table prefix. You can obtain the value of table prefix from the configuration file, config.db.inc.php.

### CSess.class.php
The path of this file is '{admin-panel}/include/CSess.class.php'.
This is a PHP class file.
This file contains a PHP class that handles the session of an user logging in the admin panel.
The PHP class has the following methods:

#### CSess::start($user_id)
This method accepts the user_id of the current user and stores it in PHP $_SESSION.
 
#### CSess::userID()
This method returns the user_id stored in PHP $_SESSION. If there is no user_id, then return null.

#### CSess::terminate()
This method deletes the user_id stored in PHP $_SESSION.

## Programming Requirements

### Always use locale files to store texts
All the texts that will be displayed in a browser must be defined in one of locale files.
Use CLocale::get($name) to load the $lca array to obtain the text to display.

### Always use CLocale to load locale files
Always use the CLocale class to load locale files. Do not directly include locale files without using CLocale.

### Always use CConfig to load configuration files
Always use the CConfig class to load configuration files. Do not directly include configuration files without using CConfig.

### Always use CDB::query($sql) to run a SQL statement
Always use CDB::query($sql) to run a SQL statement. Before sending it to CDB::query($sql), you must not forget to add %t~p% to the front of every table name. For example, consider the following SQL statement:

```SQL
SELECT * FROM `user`;
```

Before sending the sql statement using CDB::query($sql), make sure you add %t~p% to the front of a table name 'user' like

```SQL
SELECT * FROM `%t~p%user`;
```

---
# Output

Zip all the files you create. If you cannot make a zip file, create a HTML file that produces the zip file. Here's how:

First, assign the contents of each file to a JavaScript variable as shown below:

```javascript
const some_variable_name = `
................
................
................
`;
```

Next, create a JSZip instance:

```javascript
const zip = new JSZip();
```

JSZip can be loaded onto the page using the following tag:

```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
```

Save the data of each file into the zip file as shown in the example below:

```javascript
zip.file("path/to/file", some_variable_name);
```

Finally, make the zip file downloadable when a button is clicked.

---
# Closing Notes

If you have any questions regarding the specification, feel free to ask me. Thank you.
