« Back to History
profile.php
|
20260722_120325.php
Initial Domain Snapshot
Copy Code
<?php /* ============================================= File: /erp/profile.php Purpose: User Profile + DP (avatar) change Auth: login required (no ACL) ============================================= */ error_reporting(E_ALL); ini_set('display_errors',1); /* 1) Login + $pdo */ require __DIR__ . '/modules/auth/auth.php'; require_login(); $u = auth_user(); $company_id = (int)($u['company_id'] ?? 0); $user_id = (int)($u['id'] ?? 0); if (!isset($pdo) || !($pdo instanceof PDO)) { die('DB not ready'); } require __DIR__ . '/partials/header.php'; /* 2) Helpers */ function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES,'UTF-8'); } function cols_of(PDO $pdo,$table){ $s=$pdo->query('SHOW COLUMNS FROM `'.$table.'`'); $c=[]; foreach($s as $r){ $c[$r['Field']]=true; } return $c; } /* 3) Dashboard target (redirect after save) */ $DASH_DEFAULT = '/erp/public/index.php'; $DASH_OWNER = '/erp/public/main_dashboard.php'; $dash_url = (in_array($u['role'] ?? '', ['Owner','Admin'], true) && is_file(__DIR__.'/public/main_dashboard.php')) ? $DASH_OWNER : $DASH_DEFAULT; /* 4) Avatar paths - Using dp directory structure */ $PUBLIC_PREFIX = '/erp/public'; $DP_BASE_DIR = __DIR__ . '/public/uploads/dp'; // Get current year/month for directory structure $year = date('Y'); $month = date('m'); $DP_DIR_FS = $DP_BASE_DIR . '/' . $year . '/' . $month; $DP_DIR_URLBASE = $PUBLIC_PREFIX . '/uploads/dp/' . $year . '/' . $month; // Create directory if not exists if (!is_dir($DP_DIR_FS)) { @mkdir($DP_DIR_FS, 0775, true); } $allowed_exts = ['jpg','jpeg','png','webp']; $allowed_mime = ['image/jpeg','image/png','image/webp']; /* 5) Function to get user's avatar from dp_url column */ function get_user_avatar($pdo, $user_id, $company_id) { $q = $pdo->prepare("SELECT dp_url FROM users WHERE id=? AND company_id=?"); $q->execute([$user_id, $company_id]); $row = $q->fetch(PDO::FETCH_ASSOC); if ($row && !empty($row['dp_url'])) { $dp_url = $row['dp_url']; $file_path = __DIR__ . str_replace('/erp', '', $dp_url); $file_path = preg_replace('/\?v=.*/', '', $file_path); if (file_exists($file_path)) { return $dp_url . '?v=' . filemtime($file_path); } } return null; } // Get avatar URL from database $avatar_url = get_user_avatar($pdo, $user_id, $company_id); /* 6) CSRF */ if (empty($_SESSION['csrf'])) { $_SESSION['csrf']=bin2hex(random_bytes(16)); } $csrf = $_SESSION['csrf']; /* 7) POST handlers */ $msg = null; $err = null; if ($_SERVER['REQUEST_METHOD']==='POST' && hash_equals($csrf, $_POST['csrf'] ?? '')) { try { $action = $_POST['action'] ?? ''; if ($action==='save_profile') { $name = trim((string)($_POST['name'] ?? $u['name'])); $email = trim((string)($_POST['email'] ?? $u['email'])); $new_pass = (string)($_POST['new_password'] ?? ''); $confirm = (string)($_POST['confirm_password'] ?? ''); $set=[]; $vals=[]; if ($name !== ($u['name'] ?? '')) { $set[]='name=?'; $vals[]=$name; $u['name']=$name; } if ($email!== ($u['email']?? '')) { $set[]='email=?'; $vals[]=$email; $u['email']=$email; } if ($new_pass!=='') { if (strlen($new_pass)<6) throw new Exception('Password must be at least 6 chars.'); if ($new_pass!==$confirm) throw new Exception('Passwords do not match.'); $set[]='password_hash=?'; $vals[]=password_hash($new_pass, PASSWORD_DEFAULT); } if ($set) { $sql="UPDATE users SET ".implode(',', $set)." WHERE id=? AND company_id=?"; $vals[]=$user_id; $vals[]=$company_id; $st=$pdo->prepare($sql); $st->execute($vals); } $_SESSION['flash_ok'] = 'Profile updated.'; header('Location: '.$dash_url.'?profile=updated'); exit; } if ($action==='upload_avatar') { if (!isset($_FILES['avatar']) || $_FILES['avatar']['error']!==UPLOAD_ERR_OK) { throw new Exception('Upload failed.'); } $tmp = $_FILES['avatar']['tmp_name']; $size = (int)$_FILES['avatar']['size']; $type = null; if (function_exists('mime_content_type')) $type = mime_content_type($tmp); if (!$type && class_exists('finfo')) { $f = new finfo(FILEINFO_MIME_TYPE); $type = $f->file($tmp); } if (!$type) $type = $_FILES['avatar']['type'] ?? ''; if ($size > 2*1024*1024) throw new Exception('Max 2 MB allowed.'); if (!in_array($type,$allowed_mime,true)) throw new Exception('Only JPG/PNG/WEBP allowed.'); $ext = ($type==='image/png') ? 'png' : (($type==='image/webp') ? 'webp' : 'jpg'); $username = preg_replace('/[^a-zA-Z0-9]/', '', $u['username'] ?? 'user'); $timestamp = date('Ymd_His'); $new_filename = $timestamp . '_' . $user_id . '_' . $username . '.' . $ext; if (!is_dir($DP_DIR_FS)) { @mkdir($DP_DIR_FS, 0775, true); } if ($avatar_url) { $old_url = preg_replace('/\?v=.*/', '', $avatar_url); $old_file = __DIR__ . str_replace('/erp', '', $old_url); if (file_exists($old_file)) { @unlink($old_file); } } for ($y = date('Y'); $y >= 2020; $y--) { for ($m = 12; $m >= 1; $m--) { $month_pad = str_pad($m, 2, '0', STR_PAD_LEFT); $check_dir = $DP_BASE_DIR . '/' . $y . '/' . $month_pad; if (is_dir($check_dir)) { $old_files = glob($check_dir . '/' . $user_id . '_*'); foreach ($old_files as $old_file) { @unlink($old_file); } } } } $dest = $DP_DIR_FS . '/' . $new_filename; if (!@move_uploaded_file($tmp, $dest)) { throw new Exception('Could not save file.'); } $new_dp_url = $DP_DIR_URLBASE . '/' . $new_filename; $st = $pdo->prepare("UPDATE users SET dp_url = ? WHERE id = ? AND company_id = ?"); $st->execute([$new_dp_url, $user_id, $company_id]); $avatar_url = $new_dp_url . '?v=' . time(); $msg = 'Photo updated successfully!'; } } catch (Throwable $e) { $err=$e->getMessage(); } } if ($_SERVER['REQUEST_METHOD'] === 'POST' && $action === 'upload_avatar' && !$err) { $avatar_url = get_user_avatar($pdo, $user_id, $company_id); } ?> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>My Profile • Mister Manager</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> :root{--primary:#34A853;--bg:#F5FFF7;--text:#202124;--muted:#5F6368;--card:#fff;--shadow:0 8px 20px rgba(0,0,0,.06);--radius:16px} body{margin:0;background:var(--bg);color:var(--text);font-family:Inter,system-ui,Arial} .wrap{max-width:980px;margin:24px auto;padding:0 16px} .grid{display:grid;grid-template-columns:280px 1fr;gap:16px} @media(max-width:768px){ .grid{grid-template-columns:1fr} } .card{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);padding:16px} .title{font-weight:700;font-size:20px;margin:0 0 12px} .avatar{width:160px;height:160px;border-radius:50%;object-fit:cover;border:3px solid #eee} .avatar-placeholder{width:160px;height:160px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:#E6F4EA;color:#1e8e3e;font-weight:700;font-size:48px} label{display:block;font-size:12px;color:var(--muted);margin:10px 0 4px} input[type=text],input[type=email],input[type=password]{width:100%;padding:10px 12px;border:1px solid #ddd;border-radius:10px;font-size:14px;box-sizing:border-box} .row{display:flex;gap:10px} @media(max-width:480px){ .row{flex-direction:column;gap:0} } .btn{background:var(--primary);color:#fff;border:none;padding:12px 16px;border-radius:12px;font-weight:600;cursor:pointer;width:100%;display:inline-block;text-align:center;box-sizing:border-box} /* Styled File Input for Mobile */ .custom-file-upload { display: block; border: 2px dashed #34A853; background: #F5FFF7; color: #34A853; padding: 14px; text-align: center; border-radius: 12px; cursor: pointer; font-weight: 600; margin-top: 8px; font-size: 14px; transition: all 0.2s ease; } .custom-file-upload:active { background: #E6F4EA; } .file-name-preview { font-size: 12px; color: #5F6368; margin-top: 6px; font-style: italic; word-break: break-all; } .note{margin:8px 0;padding:10px 12px;border-radius:10px} .ok{background:#E3FCEF} .err{background:#FDECEA;color:#b00020} .meta{color:var(--muted);font-size:13px;margin-top:8px} .small{font-size:11px;color:#999} </style> </head> <body> <div class="wrap"> <?php if($msg): ?><div class="note ok"><?=h($msg)?></div><?php endif; ?> <?php if($err): ?><div class="note err"><?=h($err)?></div><?php endif; ?> <div class="grid"> <!-- Left: Avatar --> <div class="card" style="text-align: center;"> <div class="title" style="text-align: left;">Profile Photo</div> <div style="display:flex; justify-content:center; margin-bottom:10px;"> <?php if($avatar_url): ?> <img class="avatar" src="<?=h($avatar_url)?>" alt="Avatar"> <?php else: ?> <div class="avatar-placeholder"><?=h(strtoupper(mb_substr($u['name']??'U',0,1)))?></div> <?php endif; ?> </div> <div class="meta small"><?= $avatar_url ? 'Current photo' : 'No photo uploaded' ?></div> <form method="post" enctype="multipart/form-data" style="margin-top:16px; text-align: left;"> <input type="hidden" name="csrf" value="<?=h($csrf)?>"> <input type="hidden" name="action" value="upload_avatar"> <label>Select Photo (JPG/PNG/WEBP, max 2MB)</label> <!-- छिपा हुआ असली इनपुट और उसकी जगह बड़ा टच-फ्रेंडली लेबल बटन --> <input type="file" name="avatar" id="avatar-input" accept="image/jpeg,image/png,image/webp" style="display: none;" required onchange="document.getElementById('file-chosen').textContent = this.files[0] ? this.files[0].name : 'No file chosen'"> <label for="avatar-input" class="custom-file-upload"> 📱 Choose Image From Gallery </label> <div id="file-chosen" class="file-name-preview">No file chosen</div> <div style="margin-top:14px"> <button type="submit" class="btn">Save Photo</button> </div> </form> </div> <!-- Right: Profile form --> <div class="card"> <div class="title">My Profile</div> <form method="post"> <input type="hidden" name="csrf" value="<?=h($csrf)?>"> <input type="hidden" name="action" value="save_profile"> <label>Name</label> <input type="text" name="name" value="<?=h($u['name'] ?? '')?>" required> <label style="margin-top:10px">Email</label> <input type="email" name="email" value="<?=h($u['email'] ?? '')?>" required> <div class="meta">Role: <b><?=h($u['role'] ?? '')?></b> • Company ID: <b><?=h($company_id)?></b></div> <hr style="border:none;height:1px;background:#eee;margin:16px 0"> <div class="row"> <div style="flex:1"> <label>New Password (optional)</label> <input type="password" name="new_password" placeholder="Leave blank to keep same"> </div> <div style="flex:1"> <label>Confirm Password</label> <input type="password" name="confirm_password"> </div> </div> <div style="margin-top:16px"> <button type="submit" class="btn">Save Changes</button> </div> </form> </div> </div> </div> </body> </html>