LOTTE CHEMICAL PAKISTAN

Administrator & HR Guide · system overview & security
CONFIDENTIAL · IT & HR USE ONLY
1. How This Guide was prepared

This guide is based on a full read of the application's source code, now including the admin-side files: default.php, form_employment.php, employee_dashboard.php, form_bank.php, index.php, logout.php, register.php, setup_admin.php, submit_hr.php, db.php, footer.php, functions.php, header.php and — added in this revision — admin/dashboard.php, admin/invite.php, admin/view_application.php, admin/delete_user.php. With these four files, every admin-facing workflow referenced by index.php's login redirect is now documented directly from working code rather than inferred from the database structure. The previous edition of this guide flagged the admin dashboard as an unknown; that gap is now closed, and reading these files also surfaced two new issues that need attention (Sections 3.6 and 3.7).

2. System Overview

The portal is a PHP + MySQL web application (built for Hostinger hosting) that lets new employees complete their own onboarding paperwork online instead of on paper. There are two roles:

EmployeeActivates their account via an emailed link, fills in the Employment Application Form and Bank & Tax Details, uploads supporting documents, and submits to HR.
Admin (HR)Manages employee accounts and (based on the login redirect) reviews submitted applications through a separate admin dashboard not included in this handover.

Core files and what they do

index.phpLogin page for both employees and admins. Redirects by role after successful login.
register.phpAccount activation page reached via a one-time emailed link containing a token.
employee_dashboard.phpEmployee's home page — shows status and links to the Employment Form and the Submit-to-HR action.
form_employment.phpThe full, seven-section Employment Application Form.
form_bank.phpSeparate "Confidential Salaries Section" form for bank/tax details and salary certificate.
submit_hr.phpHandles the one-way "Submit to HR" action, changing the employee's status.
setup_admin.phpOne-time script that creates (or resets) the master HR/admin account.
logout.phpEnds the session and returns to the login page.
db.php, functions.php, header.php, footer.phpShared includes: database connection, CSRF/login helpers, and page layout.
admin/dashboard.phpAdmin home screen: candidate stats, full employee list, status badges, and links to view/delete/invite.
admin/invite.phpGenerates a one-time registration link for a new candidate's email address.
admin/view_application.phpRead-only, printable view of one employee's full submitted application.
admin/delete_user.phpPermanently deletes a non-admin user and their related records.
3. Urgent Security Findings (Action Required)

While reading the code to write this guide, several issues came up that IT/HR leadership should address quickly, since this system stores highly sensitive personal data (CNIC numbers, bank details, scanned ID documents).

3.1 Database password is hardcoded in plain text
db.php contains a live-looking database password in plain text. Because this file was shared as part of a handover, treat that password as compromised and rotate (change) the database password immediately, then update db.php with the new one.
Recommendation: move all credentials out of the PHP source into environment variables or a config file stored outside the public web root.
3.2 Default admin account has a weak, hardcoded password
setup_admin.php always creates admin@lotte.com with the password "admin123". This script has no login check of its own — anyone who can reach its URL can run it, which deletes the existing admin account and recreates it with the same weak password.
Recommendation: after first use, delete setup_admin.php from the live server entirely. Change the admin password to a strong, unique one immediately.
3.3 Uploaded personal documents are stored in a public, unprotected folder
CNIC scans, education certificates, salary certificates, and photos are saved under assets/uploads/ with no access control. There is no .htaccess or authentication check on this folder.
Recommendation: store uploads outside the public web root and serve them only through an authenticated PHP script.
3.4 "Submitted" applications are not actually locked on the server
The read-only state after submission is only a front-end label. form_employment.php does not check the employee's status before accepting new POST data — a submitted employee could still directly reopen and resave the form.
Recommendation: add a server-side check at the top of form_employment.php that blocks edits once status = 'submitted'.
3.5 File upload validation is extension-only
Uploads are validated only by file extension, not actual file content/MIME type, and have no size limit. A file renamed to end in .pdf but containing different content would currently be accepted.
Recommendation: validate MIME type server-side (e.g. with PHP's fileinfo) and add a maximum file size check.
3.6 The Admin application viewer does not escape employee-entered data (stored XSS risk)
view_application.php prints 32 database fields directly with no escaping. An employee entering a <script> tag in, say, the Career Description would have it executed in the admin's browser — a classic stored XSS vulnerability.
Recommendation: wrap every echoed database value in view_application.php with htmlspecialchars().
3.7 Deleting a user is a destructive GET request with no confirmation-token protection, and cleanup is incomplete
delete_user.php deletes permanently via a plain link (GET), and misses two tables: user_children and user_nominations. Orphaned family data remains.
Recommendation: convert deletion to a POST request protected by a CSRF token, and add the two missing DELETE statements.
4. Initial Admin account setup

The very first admin/HR account is created by visiting setup_admin.php once in a browser. As currently written, it creates this account:

  1. Visit the setup_admin.php URL once, in a trusted/internal context only.
  2. Confirm the on-screen "Admin Created Successfully!" message.
  3. Immediately log in and change the password to something strong (see the recommendation in Section 3.2 — there is currently no in-app "change password" feature described in the files provided, so this may need to be done directly in the database or via a feature that should be added).
  4. Delete or relocate setup_admin.php from the live server so it cannot be run again by anyone who finds the URL.
5. Logging In & the Admin Dashboard

Admins use the same login page as employees (index.php) with their admin email and password. The system checks the account's role in the database: accounts with role = 'admin' are redirected to admin/dashboard.php after login, while all other accounts go to employee_dashboard.php.

5.1 Stat cards — three cards at the top summarize all candidates (users with role = 'employee'):

5.2 The candidate table — list of every candidate, newest-invited first, showing name (or "Not Registered" if they haven't activated their account yet), email, a status badge, and the date they were invited.

Invite SentGrey badge. Account created, activation link not yet used.
In ProgressAmber badge. Account activated; candidate is filling in or has partially saved the Employment Form.
SubmittedGreen badge. Candidate has clicked "Submit to HR"; their application is ready to review.

5.3 Row actions — View (eye icon) only active once status is "Submitted." Delete (trash icon) available for every non-admin row. An "Invite Candidate" button in the top-right corner opens the invite screen.

6. Inviting a new employee

From the Admin Dashboard, click "Invite Candidate."

  1. Enter the candidate's email address and click "Generate Link."
  2. The system checks that the email isn't already registered. If it's new, it creates a database record for that candidate with role = 'employee' and status = 'registered', along with a random, one-time activation token.
  3. A registration link is displayed on screen, e.g. https://<yourdomain>/register.php?token=..., along with a "Copy" button.
  4. Copy this link and send it to the candidate yourself — by email, WhatsApp, or however your team normally reaches new hires.
  5. Click "Invite Another Person" to repeat the process for additional candidates.
No email is sent automatically
Generating a link does not send anything to the candidate — HR must copy the link and deliver it manually. Keep this in mind when coordinating onboarding timelines, and treat the link itself as sensitive since anyone who has it can activate that account.
7. Reviewing a submitted application

Once a candidate's status is "Submitted," click the eye icon next to their name on the Dashboard (or open view_application.php?id=<their user ID> directly) to see their full application in a clean, read-only, printable layout. It mirrors the seven sections of the Employment Form, plus a document-links section:

Treat this screen with care
This page displays a candidate's CNIC, their spouse's and children's identifying details, and links to scanned ID documents on a single screen — exactly the kind of data that should never be left open on an unattended, unlocked computer. See Section 3.6 for a code-level issue on this same page that should be fixed soon.
8. Deleting a user

Click the trash icon next to a candidate's row on the Dashboard. A browser confirmation pop-up appears ("Are you sure you want to remove this user completely?"); confirming permanently deletes:

Admin accounts cannot be deleted this way — the script checks the target's role first and refuses ("Cannot delete Admin accounts") if it's an admin.

This action is permanent, and currently incomplete — see Section 3.7
There is no undo and no archive. Once deleted, an employee's information — and any documents referenced by it — cannot be recovered from within the app.
As currently written, the delete process does not remove that user's children or nomination records, so some of their family members' CNIC/B-Form and nominee details remain in the database even after "deleting" the user. This should be fixed at the code level (Section 3.7) — don't rely on the Delete button alone to fully purge a person's data today.
9. The Employee Lifecycle & status flow
registeredAccount created by HR with an invite token; employee has not yet activated it.
in_progressEmployee has activated their account (set a password) and can freely edit their Employment Application.
submittedEmployee has clicked "Submit to HR." The Dashboard now shows the form as view-only.
activeUsed for the admin/HR account itself (not part of the employee onboarding flow).

submit_hr.php will only allow the transition to "submitted" if the employee has at least saved a record in the Employment Application (employment_details table). If they haven't filled anything in yet, the system blocks submission and asks them to complete the form first.

10. Data Collected — Full Field Reference

This is a complete reference of every field the portal collects, grouped by the database table it's saved to.

employment_details (one record per employee)

Related tables (multiple rows per employee)

education_historyCertificate/level, institution name, grade, year completed.
work_historyEmployer name, position, start date, end date, reason for leaving.
user_childrenName, gender, date of birth, CNIC/B-Form number.
user_nominationsType (Natural Death / Accidental Death / Provident Fund), nominee name, CNIC, address, age, relationship, share %.
user_referencesReference name, designation, address, contact.
bank_detailsStaff number, account number, IBAN, bank name, branch & code, bank address, tax filing location, NTN, salary certificate file path.
11. Where Uploaded Files are stored

All uploaded files — passport photos, CNIC PDFs, education certificate PDFs, and salary certificates — are saved on the server's disk under the assets/uploads/ folder, with filenames generated automatically:

The file path returned by the upload is what's stored in the database (e.g. in employment_details.cnic_self_path). See Section 3.3 for the access-control risk this currently creates.

12. Known Functional Gaps
13. Recommendations summary
  1. Rotate the database password now, and move all credentials into environment variables outside the web root.
  2. Delete or relocate setup_admin.php after first use, and change the default admin password immediately.
  3. Move uploaded documents outside the public web root and serve them through an authenticated script.
  4. Add a server-side lock on the Employment Form once an application has been submitted.
  5. Add real MIME-type and file-size validation to all upload handlers.
  6. Escape every field echoed in view_application.php with htmlspecialchars() to close the stored-XSS gap.
  7. Convert delete_user.php to a CSRF-protected POST request, and add the missing DELETE statements for user_children and user_nominations.
  8. Consider adding: a password-reset flow, an audit log (especially around deletion and application viewing), a visible Dashboard link to the Bank & Tax Details page, and search/export on the candidate list.