Webbserverprogrammering 1

Show sourcecode

The following files exists in this folder. Click to view.

webbserverprogrammering/submissions/projekt-matkort-handler/classes/

CardBalance.php
FoodLog.php
Restaurant.php
User.php

User.php

191 lines UTF-8 Windows (CRLF)
<?php
class User {
  private 
$conn// Database connection

  
private $id;
  private 
$name;
  private 
$email;
  private 
$created_at;

  function 
__construct($conn){
    
$this->conn $conn;
  }

  static function 
register($pdo$name$email$password) {
    try {
      
$stmt $pdo->prepare("SELECT * FROM students WHERE email = ?");
      
$stmt->execute([$email]);
      
$user_found $stmt->fetch();
      if (
$user_found) { throw new Exception("Ett konto har redan skapats med denna mejl"); }
    } catch (
Exception $e) {
      throw 
$e;
    }

    
// Generate Verification Token (64 char hex) + Expiration (15 mins)
    
$token bin2hex(random_bytes(32));
    
$expires date('Y-m-d H:i:s'strtotime('+15 minutes'));

    try {
      
$stmt $pdo->prepare("INSERT INTO students (name, email, password, is_verified, verification_token, token_expires_at) VALUES (?, ?, ?, 0, ?, ?)");
      
$success $stmt->execute([$name$emailpassword_hash($passwordPASSWORD_DEFAULT), $token$expires]);
      
      if (!
$success) throw new Exception("Konto kunde inte skapas");

      return 
$token// Return token so we can send it in the email
    
} catch (Exception $e) {
      throw new 
Exception("Konto kunde inte skapas");
    }
  }
  
  static function 
login($pdo$email$password) {
    try {
      
$stmt $pdo->prepare("SELECT * FROM students WHERE email = :email");
      
$stmt->execute([':email' => $email]);
      
$user $stmt->fetch(PDO::FETCH_ASSOC);
      
      if (
$user && password_verify($password$user['password'])) {
          
        
// 1. Is user verified?
        
if ($user['is_verified'] == 0) {
            throw new 
Exception("vänligen verifiera din e-post innan du loggar in.");
        }

        
$stmt $pdo->prepare("UPDATE students SET last_login = NOW() WHERE id = :id");
        
$stmt->execute([':id' => $user['id']]);
        
        
session_regenerate_id(true);
        
$_SESSION['user_id'] = $user['id'];
        
$_SESSION['name'] = $user['name'];
        
$_SESSION['email'] = $user['email'];
        
$_SESSION['is_admin'] = isset($user['is_admin']) && $user['is_admin'] == true false;
        
$_SESSION['logged_in'] = true;
        
      } else {
        throw new 
Exception("Felaktigt användarnamn eller lösenord");
      }
    } catch (
Exception $e) {
      throw 
$e// Pass literal exception up
    
}
  }

  static function 
verifyEmail($pdo$token) {
    try {
      
$stmt $pdo->prepare("SELECT id, token_expires_at FROM students WHERE verification_token = ? AND is_verified = 0");
      
$stmt->execute([$token]);
      
$user $stmt->fetch(PDO::FETCH_ASSOC);

      if (!
$user) throw new Exception("Ogiltig eller redan använd länk.");
      if (
strtotime($user['token_expires_at']) < time()) throw new Exception("Din verifieringslänk har gått ut (15 minuter gräns).");

      
// Success! Verify and wipe the token
      
$stmt $pdo->prepare("UPDATE students SET is_verified = 1, verification_token = NULL, token_expires_at = NULL WHERE id = ?");
      
$stmt->execute([$user['id']]);
      return 
$user['id'];
    } catch (
PDOException $e) {
      throw new 
Exception("Databasfel vid verifiering: " $e->getMessage());
    }
  }

  static function 
generateResetToken($pdo$email) {
    try {
      
$stmt $pdo->prepare("SELECT id, is_verified FROM students WHERE email = ?");
      
$stmt->execute([$email]);
      
$user $stmt->fetch(PDO::FETCH_ASSOC);

      
// Don't leak if email exists or not for security, just silently return false
      
if (!$user || $user['is_verified'] == 0) return false;

      
$token bin2hex(random_bytes(32));
      
$expires date('Y-m-d H:i:s'strtotime('+15 minutes'));

      
$stmt $pdo->prepare("UPDATE students SET reset_token = ?, reset_token_expires_at = ? WHERE id = ?");
      
$stmt->execute([$token$expires$user['id']]);
      return 
$token;
    } catch (
PDOException $e) {
      throw new 
Exception("Databasfel: " $e->getMessage());
    }
  }

  static function 
resetPassword($pdo$token$new_password) {
    try {
      
$stmt $pdo->prepare("SELECT id, reset_token_expires_at FROM students WHERE reset_token = ?");
      
$stmt->execute([$token]);
      
$user $stmt->fetch(PDO::FETCH_ASSOC);

      if (!
$user) throw new Exception("Ogiltig återställningslänk.");
      if (
strtotime($user['reset_token_expires_at']) < time()) throw new Exception("Länken har gått ut (15 minuter gräns).");

      
// Valid: Update password and wipe tokens
      
$stmt $pdo->prepare("UPDATE students SET password = ?, reset_token = NULL, reset_token_expires_at = NULL WHERE id = ?");
      
$stmt->execute([password_hash($new_passwordPASSWORD_DEFAULT), $user['id']]);
      return 
true;
    } catch (
PDOException $e) {
      throw new 
Exception("Databasfel vid återställning: " $e->getMessage());
    }
  }

  function 
delete() {

  }

  
// Admin funktion
  
static function getAll($pdo) {
    try {
      
$stmt $pdo->prepare("SELECT id, name, email, is_admin, created_at FROM students");
      
$success $stmt->execute();

      if(!
$success){
        throw new 
Exception;
      } else {
        return 
$stmt->fetchAll(PDO::FETCH_ASSOC);
      }
    } catch (
Exception $e) {
      throw new 
Exception("Kunde inte hämta all användardata");
    }
  }

  static function 
getAdminUserStats($pdo) {
      try {
          
$sql "
              SELECT 
                  s.id,
                  s.name,
                  s.email,
                  MAX(coalesce(cb.amount, 0)) as current_balance,
                  COUNT(fl.id) as total_logs,
                  COALESCE(SUM(fl.money_spent), 0) as total_spent,
                  AVG(fl.happy_rating) as avg_happy,
                  AVG(fl.healthy_rating) as avg_healthy,
                  (
                      SELECT r.restaurant_name
                      FROM food_logs fl2
                      JOIN restaurants r ON fl2.restaurant_id = r.id
                      WHERE fl2.user_id = s.id
                      GROUP BY r.id, r.restaurant_name
                      ORDER BY COUNT(fl2.id) DESC, r.restaurant_name ASC
                      LIMIT 1
                  ) as most_visited_restaurant
              FROM students s
              LEFT JOIN food_logs fl ON s.id = fl.user_id
              LEFT JOIN card_balance cb ON s.id = cb.user_id
              WHERE s.is_admin = 0 OR s.is_admin IS NULL
              GROUP BY s.id
              ORDER BY s.created_at DESC
          "
;
          
$stmt $pdo->query($sql);
          return 
$stmt->fetchAll(PDO::FETCH_ASSOC);
      } catch (
PDOException $e) {
          throw new 
Exception("Kunde inte hämta användarstatistik: " $e->getMessage());
      }
  }

  static function 
deleteUser($pdo$id) {
      try {
          
$stmt $pdo->prepare("DELETE FROM students WHERE id = ?");
          return 
$stmt->execute([$id]);
      } catch (
PDOException $e) {
          throw new 
Exception("Kunde inte ta bort användare: " $e->getMessage());
      }
  }

}