|
Server : LiteSpeed System : Linux terra.hostitbro.com 5.14.0-611.54.3.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Thu May 7 16:31:24 EDT 2026 x86_64 User : outerorb ( 1091) PHP Version : 8.1.34 Disable Function : mail Directory : /home2/outerorb/emp.outerorbittech.in/ | |
|
Path: /home2/outerorb/emp.outerorbittech.in/submit.php
Size: 16.44 KB
Permissions: 0666
<?php
require __DIR__ . '/includes/helpers.php';
// Determine which page submitted the form so we can redirect back on error.
$fromOnboarding = (($_GET['from'] ?? '') === 'onboarding');
$backUrl = $fromOnboarding ? 'onboarding.php' : 'index.php';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Location: ' . $backUrl);
exit;
}
if (!isset($_POST['csrf_token']) || !verify_csrf($_POST['csrf_token'])) {
// Preserve entered data so the user does not need to retype on session timeout.
// 'docs' is a multi-value checkbox array — handle it separately to avoid TypeError.
$docsRaw = $_POST['docs'] ?? [];
$postScalars = array_filter($_POST, 'is_string');
$old = array_map('sanitize_text', $postScalars);
$old['docs'] = array_map('sanitize_text', (array) $docsRaw);
redirect_with_message($backUrl, 'Invalid session token. Please retry.', 'error', [
'old' => $old,
]);
}
ensure_employees_table();
ensure_designations_table();
$input = [];
foreach ([
'first_name',
'last_name',
'mother_name',
'email',
'phone',
'emergency_contact_name',
'emergency_contact_number',
'emergency_contact_relation',
'dob',
'date_of_joining',
'address',
'permanent_address',
'zip',
'aadhaar_number',
'pan_number',
'highest_qualification',
'department',
'marital_status',
'gender',
'identity_mark',
'blood_group',
'referred_by',
'referral_name',
'designation_id',
'account_number',
'ifsc_code',
'bank_name',
] as $field) {
$input[$field] = sanitize_text($_POST[$field] ?? '');
}
$maritalStatusOptions = ['Single', 'Married', 'Divorced', 'Widowed', 'Separated'];
$genderOptions = ['Male', 'Female', 'Other', 'Prefer not to say'];
$bloodGroupOptions = ['A+', 'A-', 'B+', 'B-', 'AB+', 'AB-', 'O+', 'O-'];
$qualificationOptions = ['10th Pass', '12th Pass', 'Diploma', "Bachelor's Degree", "Master's Degree", 'PhD', 'Other'];
// Normalize date inputs to YYYY-MM-DD for MySQL
$dateFields = ['dob' => 'Date of birth', 'date_of_joining' => 'Date of joining'];
foreach ($dateFields as $field => $label) {
$normalized = normalize_date($input[$field]);
if ($normalized === null) {
$input[$field] = '';
} else {
$input[$field] = $normalized;
}
}
$errors = validate_required([
'first_name' => 'Full name',
'last_name' => "Father's name",
'email' => 'Email',
'phone' => 'Contact number',
'mother_name' => "Mother's name",
'emergency_contact_name' => 'Emergency contact name',
'emergency_contact_number' => 'Emergency contact number',
'emergency_contact_relation' => 'Emergency contact relation',
'dob' => 'Date of birth',
'date_of_joining' => 'Date of joining',
'address' => 'Present address',
'permanent_address' => 'Permanent address',
'zip' => 'Present ZIP / PIN',
'aadhaar_number' => 'Aadhaar number',
'pan_number' => 'PAN number',
'highest_qualification' => 'Highest qualification',
'department' => 'Department / Process',
'designation_id' => 'Designation',
'marital_status' => 'Marital status',
'gender' => 'Gender',
'identity_mark' => 'Identity mark',
'blood_group' => 'Blood group',
'referred_by' => 'Referred by',
'account_number' => 'Account number',
'ifsc_code' => 'IFSC code',
'bank_name' => 'Bank name',
], $input);
$departments = list_departments();
if (empty($departments)) {
$errors['department'] = 'No departments configured. Please contact an admin.';
} elseif (!in_array($input['department'], $departments, true)) {
$errors['department'] = 'Please select a valid department';
}
$designationRows = list_designations(true);
$designationIds = array_map(fn($row) => (int) $row['id'], $designationRows);
$designationId = (int) $input['designation_id'];
if (empty($designationRows)) {
$errors['designation_id'] = 'No designations configured. Please contact an admin.';
} elseif (!$designationId || !in_array($designationId, $designationIds, true)) {
$errors['designation_id'] = 'Please select a valid designation';
}
$validReferrers = ['consultancy', 'person', 'walkin'];
if (!in_array($input['referred_by'], $validReferrers, true)) {
$errors['referred_by'] = 'Please select how you were referred';
}
if (in_array($input['referred_by'], ['consultancy', 'person'], true) && $input['referral_name'] === '') {
$errors['referral_name'] = $input['referred_by'] === 'consultancy' ? 'Consultancy name is required' : 'Person name is required';
}
if (!preg_match('/^[A-Za-z ]+$/', $input['mother_name'])) {
$errors['mother_name'] = "Mother's name should contain only letters and spaces";
}
if (!preg_match('/^[A-Za-z ]+$/', $input['first_name'])) {
$errors['first_name'] = 'Full name should contain only letters and spaces';
}
if (!preg_match('/^[A-Za-z ]+$/', $input['last_name'])) {
$errors['last_name'] = "Father's name should contain only letters and spaces";
}
if (!preg_match('/^\d{10}$/', $input['phone'])) {
$errors['phone'] = 'Contact number must be 10 digits';
}
if (!preg_match('/^[A-Za-z ]+$/', $input['emergency_contact_name'])) {
$errors['emergency_contact_name'] = 'Emergency contact name should contain only letters and spaces';
}
if (!preg_match('/^\d{10}$/', $input['emergency_contact_number'])) {
$errors['emergency_contact_number'] = 'Emergency contact number must be 10 digits';
}
if (!in_array($input['marital_status'], $maritalStatusOptions, true)) {
$errors['marital_status'] = 'Select a valid marital status';
}
if (!in_array($input['gender'], $genderOptions, true)) {
$errors['gender'] = 'Select a valid gender';
}
if (!in_array($input['blood_group'], $bloodGroupOptions, true)) {
$errors['blood_group'] = 'Select a valid blood group';
}
if (!in_array($input['highest_qualification'], $qualificationOptions, true)) {
$errors['highest_qualification'] = 'Select a valid qualification';
}
$emergencyRelations = ['Father', 'Mother', 'Brother', 'Sister', 'Spouse', 'Relative', 'Friend', 'Other'];
if (!in_array($input['emergency_contact_relation'], $emergencyRelations, true)) {
$errors['emergency_contact_relation'] = 'Select a valid emergency contact relation';
}
if ($input['email'] && !filter_var($input['email'], FILTER_VALIDATE_EMAIL)) {
$errors['email'] = 'Invalid email format';
}
if ($input['aadhaar_number'] !== '' && !preg_match('/^\d{12}$/', $input['aadhaar_number'])) {
$errors['aadhaar_number'] = 'Aadhaar number must be exactly 12 digits';
}
if ($input['pan_number'] !== '' && !preg_match('/^[A-Z]{5}[0-9]{4}[A-Z]$/i', $input['pan_number'])) {
$errors['pan_number'] = 'PAN number must be in format ABCDE1234F';
}
if ($input['zip'] !== '' && !preg_match('/^\d{6}$/', $input['zip'])) {
$errors['zip'] = 'Present ZIP / PIN must be exactly 6 digits';
}
if ($input['ifsc_code'] !== '' && !preg_match('/^[A-Z]{4}0[A-Z0-9]{6}$/i', $input['ifsc_code'])) {
$errors['ifsc_code'] = 'IFSC code must be in format ABCD0123456';
}
if ($input['account_number'] !== '' && !preg_match('/^\d{9,18}$/', $input['account_number'])) {
$errors['account_number'] = 'Account number must be 9 to 18 digits';
}
foreach ($dateFields as $field => $label) {
if ($input[$field] === '') {
$errors[$field] = $label . ' must be a valid date (YYYY-MM-DD)';
}
}
if ($input['dob'] !== '') {
$dobTs = strtotime($input['dob']);
if ($dobTs === false) {
$errors['dob'] = 'Date of birth must be a valid date';
} else {
$todayTs = strtotime(date('Y-m-d'));
if ($dobTs > $todayTs) {
$errors['dob'] = 'Date of birth cannot be in the future';
} else {
$age = (int) date('Y') - (int) date('Y', $dobTs);
$birthdayPassed = date('md') >= date('md', $dobTs);
if (!$birthdayPassed) {
$age--;
}
if ($age < 18) {
$errors['dob'] = 'Employee must be at least 18 years old';
}
}
}
}
if ($input['date_of_joining'] !== '') {
$dojTs = strtotime($input['date_of_joining']);
if ($dojTs === false) {
$errors['date_of_joining'] = 'Date of joining must be a valid date';
} elseif ($dojTs > strtotime(date('Y-m-d'))) {
$errors['date_of_joining'] = 'Date of joining cannot be in the future';
}
}
// City and state columns are unused; populate with empty strings
$input['city'] = '';
$input['state'] = '';
if (!empty($errors)) {
redirect_with_message($backUrl, 'Please fix the highlighted errors and try again.', 'error', [
'errors' => $errors,
'old' => array_merge($input, ['docs' => (array)($_POST['docs'] ?? [])]),
]);
}
$config = app_config();
$docMimes = $config['security']['allowed_doc_mimes'];
$photoMimes = $config['security']['allowed_photo_mimes'];
$stagedUploads = staged_uploads();
$documentRules = [
'aadhaar' => ['label' => 'Aadhaar Document', 'mimes' => $docMimes, 'size' => $config['uploads']['max_size']],
'aadhaar_front' => ['label' => 'Aadhaar Front', 'mimes' => $docMimes, 'size' => $config['uploads']['max_size']],
'aadhaar_back' => ['label' => 'Aadhaar Back', 'mimes' => $docMimes, 'size' => $config['uploads']['max_size']],
'pan' => ['label' => 'PAN Document', 'mimes' => $docMimes, 'size' => $config['uploads']['max_size']],
'qualification' => ['label' => 'Graduation', 'mimes' => $docMimes, 'size' => $config['uploads']['max_size']],
'tenth_marksheet' => ['label' => '10th Marksheet', 'mimes' => $docMimes, 'size' => $config['uploads']['max_size']],
'twelfth_marksheet' => ['label' => '12th Marksheet', 'mimes' => $docMimes, 'size' => $config['uploads']['max_size']],
'bank_proof' => ['label' => 'Bank Proof', 'mimes' => $docMimes, 'size' => $config['uploads']['max_size']],
'photo' => ['label' => 'Passport Photo', 'mimes' => $photoMimes, 'size' => $config['uploads']['photo_max_size']],
];
$selectedDocs = array_values(array_intersect(array_keys($documentRules), (array)($_POST['docs'] ?? [])));
$mandatoryDocs = ['tenth_marksheet', 'twelfth_marksheet'];
$selectedDocs = array_values(array_unique(array_merge($selectedDocs, $mandatoryDocs)));
$uploads = $stagedUploads;
$docErrors = [];
$uploadErrors = [];
// Build an identifier prefix for uploaded filenames so files can be traced back to this candidate.
$uploadPrefix = make_upload_prefix($input['first_name'] ?? '', $input['last_name'] ?? '', $input['phone'] ?? '');
foreach ($documentRules as $field => $rule) {
$fileError = isset($_FILES[$field]) ? ($_FILES[$field]['error'] ?? UPLOAD_ERR_NO_FILE) : UPLOAD_ERR_NO_FILE;
$hasFile = $fileError !== UPLOAD_ERR_NO_FILE;
$isSelected = in_array($field, $selectedDocs, true);
$isRequired = in_array($field, $mandatoryDocs, true);
$existing = $stagedUploads[$field] ?? '';
if ($isRequired && !$hasFile && !$existing) {
$docErrors[$field] = $rule['label'] . ' is mandatory';
$uploads[$field] = '';
continue;
}
if ($isSelected && !$hasFile && !$existing) {
$docErrors[$field] = $rule['label'] . ' was selected but no file was uploaded';
$uploads[$field] = '';
continue;
}
if (!$hasFile) {
// Reuse staged upload if present; otherwise leave empty.
$uploads[$field] = $existing ?: '';
continue;
}
$result = handle_upload($field, $rule['mimes'], $rule['size'], $uploadPrefix);
if (!empty($result['error'])) {
$uploadErrors[$field] = $rule['label'] . ': ' . $result['error'];
$uploads[$field] = $existing ?: '';
continue;
}
if ($existing && $existing !== $result['path']) {
@unlink($existing);
}
remember_upload($field, $result['path']);
$uploads[$field] = $result['path'];
}
if (!empty($docErrors)) {
redirect_with_message($backUrl, 'Please fix the highlighted errors and try again.', 'error', [
'errors' => $docErrors,
'old' => array_merge($input, ['docs' => $selectedDocs]),
]);
}
if (!empty($uploadErrors)) {
redirect_with_message($backUrl, 'Please fix the highlighted errors and try again.', 'error', [
'errors' => $uploadErrors,
'old' => array_merge($input, ['docs' => $selectedDocs]),
]);
}
try {
$pdo = db();
$data = [
'first_name' => $input['first_name'],
'last_name' => $input['last_name'],
'email' => $input['email'],
'phone' => $input['phone'],
'emergency_contact' => $input['emergency_contact_number'],
'mother_name' => $input['mother_name'],
'emergency_contact_name' => $input['emergency_contact_name'],
'emergency_contact_number' => $input['emergency_contact_number'],
'emergency_contact_relation' => $input['emergency_contact_relation'],
'dob' => $input['dob'],
'date_of_joining' => $input['date_of_joining'],
'address' => $input['address'],
'permanent_address' => $input['permanent_address'],
'city' => $input['city'],
'state' => $input['state'],
'zip' => $input['zip'],
'aadhaar_number' => $input['aadhaar_number'],
'pan_number' => $input['pan_number'],
'highest_qualification' => $input['highest_qualification'],
'department' => $input['department'],
'employee_status' => 'Active',
'approval_status' => $fromOnboarding ? 'pending' : 'approved',
'last_working_date' => null,
'reason_for_leaving' => null,
'marital_status' => $input['marital_status'],
'gender' => $input['gender'],
'identity_mark' => $input['identity_mark'],
'blood_group' => $input['blood_group'],
'referred_by' => $input['referred_by'],
'referral_name' => $input['referral_name'] ?: null,
'designation_id' => $designationId ?: null,
'account_number' => $input['account_number'],
'ifsc_code' => $input['ifsc_code'],
'bank_name' => $input['bank_name'],
'aadhaar_path' => compose_aadhaar_value([
'front' => $uploads['aadhaar_front'] ?? null,
'back' => $uploads['aadhaar_back'] ?? null,
'single' => $uploads['aadhaar'] ?? null,
]),
'pan_path' => $uploads['pan'],
'qualification_path' => $uploads['qualification'],
'tenth_marksheet_path' => $uploads['tenth_marksheet'],
'twelfth_marksheet_path' => $uploads['twelfth_marksheet'],
'bank_proof_path' => $uploads['bank_proof'],
'photo_path' => $uploads['photo'],
];
$placeholders = array_map(fn($key) => ':' . $key, array_keys($data));
$sql = 'INSERT INTO employees (' . implode(', ', array_keys($data)) . ') VALUES (' . implode(', ', $placeholders) . ')';
$stmt = $pdo->prepare($sql);
$stmt->execute($data);
} catch (Throwable $e) {
error_log('Employee insert failed: ' . $e->getMessage());
$dbFieldErrors = [];
$dbMessage = $e->getMessage();
if ($e instanceof PDOException && (string) $e->getCode() === '23000') {
$lower = strtolower($dbMessage);
if (strpos($lower, 'email') !== false) {
$dbFieldErrors['email'] = 'This email is already registered';
}
if (strpos($lower, 'phone') !== false) {
$dbFieldErrors['phone'] = 'This contact number is already registered';
}
if (strpos($lower, 'aadhaar') !== false) {
$dbFieldErrors['aadhaar_number'] = 'This Aadhaar number is already registered';
}
if (strpos($lower, 'pan') !== false) {
$dbFieldErrors['pan_number'] = 'This PAN number is already registered';
}
}
if (!empty($dbFieldErrors)) {
redirect_with_message($backUrl, 'Please fix the highlighted errors and try again.', 'error', [
'errors' => $dbFieldErrors,
'old' => array_merge($input, ['docs' => $selectedDocs]),
]);
}
$msg = 'Could not save your submission. Please try again.';
redirect_with_message($backUrl, $msg, 'error', [
'old' => array_merge($input, ['docs' => $selectedDocs]),
]);
}
clear_staged_uploads();
if ($fromOnboarding) {
redirect_with_message('onboarding.php', 'Your details have been submitted. HR will review and activate your account. You will be able to log in once approved.');
}
redirect_with_message('index.php', 'Onboarding submitted successfully.');