<?php

namespace FOP;

class Session {
  
  

    // --- Statische Eigenschaften ---
  
  static private $sesid = null;
  static private $user = null;
  static private $csrf = null;
  static private $payload = null;
  static private $payload2 = null;

    // --- Statische Methoden ---
  
  public static function getPrefix() { 
    
    
    // --- BLOCK: main ---
    return substr(sha1(dirname(__FILE__)), 0, 8);
    
  }

  public static function getUser() { 
    
    
    // --- BLOCK: main ---
    
		self::setUser(false);
		return self::$user;
	
    
  }

  public static function destroy() { 
    
    
    // --- BLOCK: main ---
    
		self::setUser(false);
		\FOP\Database::query('DELETE FROM fop_session WHERE id = ' . \FOP\Database::quote(self::$sesid));
	
    
  }

  public static function cron() { 
    
    
    // --- BLOCK: main ---
    
		\FOP\Database::query('DELETE FROM fop_session WHERE expires < ' . time());
	
    
  }

  public static function getCSRFToken() { 
    
    
    // --- BLOCK: main ---
    
		self::setUser(false);
		return self::$csrf;
	
    
  }

  public static function validateCSRFToken() { 
    
    
    // --- BLOCK: main ---
    
		if($_POST['csrftoken'] != \FOP\Session::getCSRFToken()){
			throw new \FOP\AccessDeniedException('invalidcsrf');
		}
	
    
  }

  public static function getPayload($key) { 
    
    
    // --- BLOCK: main ---
    
		self::setUser(false);
		return self::$payload[$key] ?? null;
	
    
  }

  public static function setUser($userid, $writeSession = true ) { 
    
    
    // --- BLOCK: main ---
    
		if (!$writeSession) {
			// fake login for crons
			self::$user = $userid;
			return;
		}

		// helper function that initializes session storage and eventually sets user
		if (self::$sesid == null) {
			if (isset($_COOKIE[self::getPrefix()])) {
				// read from session table
				$data = \FOP\Database::query('SELECT * FROM fop_session WHERE id = ' . \FOP\Database::quote($_COOKIE[self::getPrefix()]))->fetch(\PDO::FETCH_ASSOC);
				if ($data) {
					// session recognized
					if ($userid !== false && $userid != $data['user']) {
						\FOP\Database::query('UPDATE fop_session SET '.qi('user').' = '.\FOP\Database::quote($userid).' WHERE id = ' . \FOP\Database::quote($_COOKIE[self::getPrefix()]));
					}
					self::$sesid = $data['id'];
					self::$user = $userid === false ? $data['user'] : $userid;
					self::$payload2 = $data['payload'];
					self::$payload = json_decode(self::$payload2, true, 512, JSON_INVALID_UTF8_IGNORE);
					self::$csrf = $data['csrf'];
					$timeout = self::$user ? 24 * 3600 : 3600; // default: guests 1h, users 24h;
					if ($data['expires'] < time() + $timeout / 2) { // after half the expiration time: prolong
						$data = \FOP\Database::query('UPDATE fop_session SET expires = '.intval(time() + $timeout).' WHERE id = ' . \FOP\Database::quote($_COOKIE[self::getPrefix()]));
						setcookie(self::getPrefix(), self::$sesid, time() + $timeout, '/'); // prolong the cookie
					}
					return true;
				} else {
					// session invalid -> create new one
				}
			}
			// otherwise: set new session
			self::$sesid = base64_encode((openssl_random_pseudo_bytes(36))); // 48 bytes, 288 bits of entropy
			self::$csrf = base64_encode((openssl_random_pseudo_bytes(36))); // 48 bytes, 288 bits of entropy
			self::$user = $userid ?: null;
			self::$payload = [];
			self::$payload2 = '{}';
			$timeout = self::$user ? 24 * 3600 : 3600; // default: guests 1h, users 24h;
			\FOP\Database::query('INSERT INTO fop_session(id, '.qi('user').', payload, csrf, expires) VALUES ('.\FOP\Database::quote(self::$sesid).', '.\FOP\Database::quote($userid ?: null).', '.\FOP\Database::quote('{}').', '.\FOP\Database::quote(self::$csrf).', '.intval(time() + $timeout).')');
			setcookie(self::getPrefix(), self::$sesid, time() + $timeout, '/'); // the user is saving the cookie a bit longer
			return true;
		}
		if ($userid !== false) {
			$data = \FOP\Database::query('UPDATE fop_session SET '.qi('user').' = '.\FOP\Database::quote($userid).' WHERE id = ' . \FOP\Database::quote(self::$sesid));
		}
	
    
  }

  public static function setPayload($key, $value) { 
    
    
    // --- BLOCK: main ---
    
		self::setUser(false);
		while (true) { // loop until transaction does not fail
			// set single value in payload
			if ((self::$payload[$key] ?? null) === $value) {
				return true;
			}
			self::$payload[$key] = $value;

			// only replace if we find the same data as when we have loaded the session
			$q = \FOP\Database::prepare('UPDATE fop_session SET payload = '.\FOP\Database::quote(json_encode(self::$payload)).' WHERE payload = '.\FOP\Database::quote(self::$payload2).' AND id = ' . \FOP\Database::quote($_COOKIE[self::getPrefix()]));
			$q->execute();
			if ($q->rowCount() > 0) {
				// success
				self::$payload2 = json_encode(self::$payload);
				return true;
			}
			// reload from session table and retry
			self::$payload2 = \FOP\Database::query('SELECT payload FROM fop_session WHERE id = ' . \FOP\Database::quote($_COOKIE[self::getPrefix()]))->fetchColumn();
			if (!self::$payload2) {
				return false; // something went wrong with getting the payload (session deleted?)
			}
			self::$payload = json_decode(self::$payload2, true, 512, JSON_INVALID_UTF8_IGNORE);

			// retry
		}
	
    
  }


  
  

  
  
}



