You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

229 lines
6.8 KiB
PHP

<?php
$base_path = dirname(__FILE__);
chdir($base_path);
mb_internal_encoding('UTF-8');
date_default_timezone_set('UTC');
set_error_handler('exception_error_handler');
spl_autoload_register('autoload_model');
require('pagesection.php');
$config_file = 'config/config.ini';
if(file_exists($config_file)) {
$config = parse_ini_file($config_file, true);
} else {
throw new Exception("Config file $config_file does not exist.");
}
require('router.php');
require('routes.php');
require('ldap.php');
require('email.php');
$ldap_options = array();
$ldap_options[LDAP_OPT_PROTOCOL_VERSION] = 3;
$ldap_options[LDAP_OPT_REFERRALS] = !empty($config['ldap']['follow_referrals']);
$ldap = new LDAP($config['ldap']['host'], $config['ldap']['starttls'], $config['ldap']['bind_dn'], $config['ldap']['bind_password'], $ldap_options);
setup_database();
$relative_frontend_base_url = (string)parse_url($config['web']['baseurl'], PHP_URL_PATH);
// Convert all non-fatal errors into exceptions
function exception_error_handler($errno, $errstr, $errfile, $errline) {
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
}
// Autoload needed model files
function autoload_model($classname) {
global $base_path;
$classname = preg_replace('/[^a-z]/', '', strtolower($classname)); # Prevent directory traversal and sanitize name
$filename = path_join($base_path, 'model', $classname.'.php');
if(file_exists($filename)) {
include($filename);
} else {
eval("class $classname {}");
throw new InvalidArgumentException("Attempted to load a class $classname that did not exist.");
}
}
// Setup database connection and models
function setup_database() {
global $config, $database, $driver, $pubkey_dir, $user_dir, $group_dir, $server_dir, $server_account_dir, $event_dir, $sync_request_dir;
try {
$database = new mysqli($config['database']['hostname'], $config['database']['username'], $config['database']['password'], $config['database']['database'], $config['database']['port']);
} catch(ErrorException $e) {
throw new DBConnectionFailedException($e->getMessage());
}
$database->set_charset('utf8mb4');
$driver = new mysqli_driver();
$driver->report_mode = MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT;
$migration_dir = new MigrationDirectory;
$pubkey_dir = new PublicKeyDirectory;
$user_dir = new UserDirectory;
$group_dir = new GroupDirectory;
$server_dir = new ServerDirectory;
$server_account_dir = new ServerAccountDirectory;
$event_dir = new EventDirectory;
$sync_request_dir = new SyncRequestDirectory;
}
/**
* Join a sequence of partial paths into a complete path
* e.g. pathJoin("foo", "bar") -> foo/bar
* pathJoin("f/oo", "b/ar") -> f/oo/b/ar
* pathJoin("/foo/b/", "ar") -> "/foo/b/ar"
* @param string part of path
* @return string joined path
*/
function path_join() {
$args = func_get_args();
$parts = array();
foreach($args as $arg) {
$parts = array_merge($parts, explode("/", $arg));
}
$parts = array_filter($parts, function($x) {return (bool)($x);});
$prefix = $args[0][0] == "/" ? "/" : "";
return $prefix . implode("/", $parts);
}
define('ESC_HTML', 1);
define('ESC_URL', 2);
define('ESC_URL_ALL', 3);
define('ESC_NONE', 9);
/**
* Output the given string, HTML-escaped by default
* @param string $string to output
* @param integer $escaping method of escaping to use
*/
function out($string, $escaping = ESC_HTML) {
switch($escaping) {
case ESC_HTML:
echo htmlspecialchars($string);
break;
case ESC_URL:
echo urlencode($string);
break;
case ESC_URL_ALL:
echo rawurlencode($string);
break;
case ESC_NONE:
echo $string;
break;
default:
throw new InvalidArgumentException("Escaping format $escaping not known.");
}
}
/**
* Generate a root-relative URL from the base URL and the given base-relative URL
* @param string $url base-relative URL
* @return string root-relative URL
*/
function rrurl($url) {
global $relative_frontend_base_url;
return $relative_frontend_base_url.$url;
}
/**
* Output a root-relative URL from the base URL and the given base-relative URL
* @param string $url relative URL
*/
function outurl($url) {
out(rrurl($url));
}
/**
* Short-name HTML escape convenience function
* @param string $string string to escape
* @return string HTML-escaped string
*/
function hesc($string) {
return htmlspecialchars($string);
}
function english_list($array) {
if(count($array) == 1) return reset($array);
else return implode(', ', array_slice($array, 0, -1)).' and '.end($array);
}
/**
* Perform an HTTP redirect to the given URL (or the current URL if none given)
* @param string|null $url URL to redirect to
* @param string $type HTTP response code/name to use
*/
function redirect($url = null, $type = '303 See other') {
global $absolute_request_url, $relative_frontend_base_url;
if(is_null($url)) {
// Redirect is to current URL
$url = $absolute_request_url;
} elseif(substr($url, 0, 1) !== '#') {
$url = $relative_frontend_base_url.$url;
}
header("HTTP/1.1 $type");
header("Location: $url");
print("\n");
exit;
}
/**
* Given a set of defaults and an array of querystring data, convert to a simpler
* easy-to-read form and redirect if any conversion was done. Also return array
* combining defaults with any querysting parameters that do not match defaults.
* @param array $defaults associative array of default values
* @param array $values associative array of querystring data
* @return array result of combining defaults and querystring data
*/
function simplify_search($defaults, $values) {
global $relative_request_url;
$simplify = false;
$simplified = array();
foreach($defaults as $key => $default) {
if(!isset($values[$key])) {
// No value provided, use default
$values[$key] = $default;
} elseif(is_array($values[$key])) {
if($values[$key] == $default) {
// Parameter not needed in URL if it matches the default
} else {
// Simplify array to semicolon-separated string in URL
$simplified[] = urlencode($key).'='.implode(';', array_map('urlencode', $values[$key]));
}
$simplify = true;
} elseif($values[$key] == $default) {
// Parameter not needed in URL if it matches the default
$simplify = true;
} else {
// Pass value as-is to simplified array
$simplified[] = urlencode($key).'='.urlencode($values[$key]);
if(is_array($default)) {
// We expect an array; extract array values from semicolon-separated string
$values[$key] = explode(';', $values[$key]);
}
}
}
if($simplify) {
$url = preg_replace('/\?.*$/', '', $relative_request_url);
if(count($simplified) > 0) $url .= '?'.implode('&', $simplified);
redirect($url);
} else {
return $values;
}
}
class OutputFormatter {
public function comment_format($text) {
return hesc($text);
}
}
$output_formatter = new OutputFormatter;
# Include extensions PHP-Files:
foreach(glob("extensions/*.php") as $filename) {
include $filename;
}
class DBConnectionFailedException extends RuntimeException {}