<commit_before><?php
//======================================================================================================================
// This file is part of the Mudpuppy PHP framework, released under the MIT License. See LICENSE for full details.
//======================================================================================================================

namespace Mudpuppy;

use App\Config;

defined('MUDPUPPY') or die('Restricted');

class App {
	private static $instance = null;
	private static $dbo = null;
	private static $exited = false;
	private static $completionHandlers = array();
	/** @var Controller|PageController */
	private static $pageController = null;
	/** @var Security */
	private static $security = null;

	public function __construct() {
		if (self::$instance) {
			throw new MudpuppyException('App is a static class; cannot instantiate.');
		}
		self::$instance = $this;
	}

	public function __destruct() {
		if (!self::$exited) {
			App::cleanExit();
		}
	}

	/**
	 * Called by Mudpuppy when the application starts up.
	 */
	public static function start() {
		// Setup the random number generators
		function _createSeed() {
			list($uSec, $sec) = explode(' ', microtime());
			return (((int)$sec * 100000) + ((float)$uSec * 100000)) ^ Config::$randomSeedOffset;
		}

		srand(_createSeed());
		mt_srand(_createSeed());

		// Construct the single instance, which is necessary to automatically call App::cleanExit() on destruction
		new App();

		// Buffer the output (see App::cleanExit() for the reason)
		ob_start();

		// Start the session
		Session::start();

		// Setup the database if desired
		if (Config::$dbHost) {
			// Create database object
			self::$dbo = new Database();

			// Connect to database
			$connectSuccess = self::$dbo->connect(Config::$dbHost, Config::$dbPort, Config::$dbDatabase, Config::$dbUser, Config::$dbPass);

			// Display log on failed connection
			if (!$connectSuccess) {
				if (Config::$debug) {
					Log::displayFullLog();
				} else {
					print 'Database Connection Error. Please contact your administrator or try again later.';
					die();
				}
			}
		} else {
			Config::$logToDatabase = false;
		}

		// Do any application-specific startup tasks
		forward_static_call(array('App\\' . Config::$appClass, 'initialize'));

		/** @var Security $security */
		$security = self::$security = forward_static_call(array('App\\' . Config::$appClass, 'getSecurity'));

		// Refresh login, check for session expiration
		$security->refreshLogin();

		// Handle HTTP Basic Auth if needed
		foreach (json_decode(file_get_contents('App/BasicAuth.json'), true) as $realm => $authInfo) {
			$pathPattern = $authInfo['pathPattern'];
			if (preg_match($pathPattern, $_SERVER['PATH_INFO'])) {
				if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($authInfo['credentials'][$_SERVER['PHP_AUTH_USER']])
					|| !$security->verifyPassword($_SERVER['PHP_AUTH_PW'], $authInfo['credentials'][$_SERVER['PHP_AUTH_USER']])) {
					header("WWW-Authenticate: Basic realm=\"$realm\"");
					header('HTTP/1.0 401 Unauthorized');
					Log::dontWrite();
					App::cleanExit(true);
				}
				break;
			}
		}

		// Get the page controller and verify the user has permission to proceed
		self::$pageController = Controller::getController();
		if (!$security->hasPermissions(self::$pageController->getRequiredPermissions())) {
			$reflectionApp = new \ReflectionClass('App\\' . Config::$appClass);
			if ($reflectionApp->hasMethod('permissionDenied')) {
				forward_static_call(array('App\\' . Config::$appClass, 'permissionDenied'));
			}
			throw new PermissionDeniedException();
		}

		// Process the request
		self::$pageController->processRequest();

		// If we got here, there is no request to process. Continue to load the page.
		if (!self::$pageController->validatePathOptions()) {
			throw new PageNotFoundException("PathOptions are not valid");
		}
	}

	/**
	 * @return Controller|PageController
	 */<commit_msg>Keep track of authorized realms in the session to speed up Basic Auth handling.<commit_after><?php
//======================================================================================================================
// This file is part of the Mudpuppy PHP framework, released under the MIT License. See LICENSE for full details.
//======================================================================================================================

namespace Mudpuppy;

use App\Config;

defined('MUDPUPPY') or die('Restricted');

class App {
	private static $instance = null;
	private static $dbo = null;
	private static $exited = false;
	private static $completionHandlers = array();
	/** @var Controller|PageController */
	private static $pageController = null;
	/** @var Security */
	private static $security = null;

	public function __construct() {
		if (self::$instance) {
			throw new MudpuppyException('App is a static class; cannot instantiate.');
		}
		self::$instance = $this;
	}

	public function __destruct() {
		if (!self::$exited) {
			App::cleanExit();
		}
	}

	/**
	 * Called by Mudpuppy when the application starts up.
	 */
	public static function start() {
		// Setup the random number generators
		function _createSeed() {
			list($uSec, $sec) = explode(' ', microtime());
			return (((int)$sec * 100000) + ((float)$uSec * 100000)) ^ Config::$randomSeedOffset;
		}

		srand(_createSeed());
		mt_srand(_createSeed());

		// Construct the single instance, which is necessary to automatically call App::cleanExit() on destruction
		new App();

		// Buffer the output (see App::cleanExit() for the reason)
		ob_start();

		// Start the session
		Session::start();

		// Setup the database if desired
		if (Config::$dbHost) {
			// Create database object
			self::$dbo = new Database();

			// Connect to database
			$connectSuccess = self::$dbo->connect(Config::$dbHost, Config::$dbPort, Config::$dbDatabase, Config::$dbUser, Config::$dbPass);

			// Display log on failed connection
			if (!$connectSuccess) {
				if (Config::$debug) {
					Log::displayFullLog();
				} else {
					print 'Database Connection Error. Please contact your administrator or try again later.';
					die();
				}
			}
		} else {
			Config::$logToDatabase = false;
		}

		// Do any application-specific startup tasks
		forward_static_call(array('App\\' . Config::$appClass, 'initialize'));

		/** @var Security $security */
		$security = self::$security = forward_static_call(array('App\\' . Config::$appClass, 'getSecurity'));

		// Refresh login, check for session expiration
		$security->refreshLogin();

		// Handle HTTP Basic Auth if needed
		$authorizedRealms = Session::get('authorizedRealms', []);
		foreach (json_decode(file_get_contents('App/BasicAuth.json'), true) as $realm => $authInfo) {
			$pathPattern = $authInfo['pathPattern'];
			if (preg_match($pathPattern, $_SERVER['PATH_INFO'])) {
				if (!in_array($realm, $authorizedRealms) &&
					(!isset($_SERVER['PHP_AUTH_USER']) || !isset($authInfo['credentials'][$_SERVER['PHP_AUTH_USER']])
						|| !$security->verifyPassword($_SERVER['PHP_AUTH_PW'], $authInfo['credentials'][$_SERVER['PHP_AUTH_USER']]))
				) {
					header("WWW-Authenticate: Basic realm=\"$realm\"");
					header('HTTP/1.0 401 Unauthorized');
					Log::dontWrite();
					App::cleanExit(true);
				}
				$authorizedRealms[] = $realm;
				Session::set('authorizedRealms', $authorizedRealms);
				break;
			}
		}

		// Get the page controller and verify the user has permission to proceed
		self::$pageController = Controller::getController();
		if (!$security->hasPermissions(self::$pageController->getRequiredPermissions())) {
			$reflectionApp = new \ReflectionClass('App\\' . Config::$appClass);
			if ($reflectionApp->hasMethod('permissionDenied')) {
				forward_static_call(array('App\\' . Config::$appClass, 'permissionDenied'));
			}
			throw new PermissionDeniedException();
		}

		// Process the request
		self::$pageController->processRequest();

		// If we got here, there is no request to process. Continue to load the page.
		if (!self::$pageController->validatePathOptions()) {
			throw new PageNotFoundException("PathOptions are not valid");
		}
	}

	/**
	 * @return Controller|PageController
	 */
{'fraction_non_alphanumeric': 0.2010221465076661, 'fraction_numerical': 0.0041372596738865905, 'mean_word_length': 4.516107382550335, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '312592', 'n_tokens_mistral': 2643, 'n_tokens_neox': 2303, 'n_words': 619}