diff --git a/.gitignore b/.gitignore index 1d74e21965c4f858f5f818a270e64e1bfad7d843..40078b4b377cd4b5d38c6063eab49785219208e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .vscode/ +mysql/* \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 61d3d5ab1126631949953b0adac659b689632da1..79b927ae796702fa7f19cd72e6f14c914723f9e4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,6 +38,9 @@ RUN make # Add config template COPY config_local.php /var/www/studip/config/config_local.inc.php.dist.docker +# Fix bootstrap.php +COPY bootstrap.php /var/www/studip/lib/bootstrap.php + # Add custom entrypoint COPY docker-entrypoint.sh /usr/local/bin/ RUN chmod u+x /usr/local/bin/docker-entrypoint.sh diff --git a/bootstrap.php b/bootstrap.php new file mode 100644 index 0000000000000000000000000000000000000000..962cff67a1daceb992ad7e3b0a2ef307c4c09403 --- /dev/null +++ b/bootstrap.php @@ -0,0 +1,331 @@ +<?php +# Lifter010: TODO +/* + * Copyright (c) 2009 Stud.IP CoreGroup + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +// Default environment, do not change. Change in config/config_local.inc.php. +const DEFAULT_ENV = 'production'; + +//software version - please leave it as it is! +$SOFTWARE_VERSION = explode(' ', trim(file_get_contents(__DIR__ . '/../VERSION')), 2)[1]; + +// Store startup time +$STUDIP_STARTUP_TIME = microtime(true); + +global $PHP_SELF, $STUDIP_BASE_PATH; + +$PHP_SELF = $_SERVER['PHP_SELF'] = $_SERVER['SCRIPT_NAME']; +$STUDIP_BASE_PATH = realpath(dirname(__FILE__) . '/..'); + +set_include_path( + $STUDIP_BASE_PATH + . PATH_SEPARATOR . $STUDIP_BASE_PATH . DIRECTORY_SEPARATOR . 'config' + . PATH_SEPARATOR . get_include_path() +); + +$ABSOLUTE_PATH_STUDIP = $STUDIP_BASE_PATH . '/public/'; + +$CANONICAL_RELATIVE_PATH_STUDIP = dirname($_SERVER['PHP_SELF']); +if (DIRECTORY_SEPARATOR != '/') { + $CANONICAL_RELATIVE_PATH_STUDIP = str_replace(DIRECTORY_SEPARATOR, '/', $CANONICAL_RELATIVE_PATH_STUDIP); +} +// CANONICAL_RELATIVE_PATH_STUDIP should end with a '/' +if (substr($CANONICAL_RELATIVE_PATH_STUDIP,-1) != "/"){ + $CANONICAL_RELATIVE_PATH_STUDIP .= "/"; +} + +$ABSOLUTE_URI_STUDIP = ""; + +// automagically compute ABSOLUTE_URI_STUDIP if $_SERVER['SERVER_NAME'] is set +if (isset($_SERVER['SERVER_NAME'])) { + // work around possible bug in lighttpd + if (mb_strpos($_SERVER['SERVER_NAME'], ':') !== false) { + list($_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT']) = + explode(':', $_SERVER['SERVER_NAME']); + } + + $ABSOLUTE_URI_STUDIP = $_SERVER['HTTPS'] == 'on' ? 'https' : 'http'; + $ABSOLUTE_URI_STUDIP .= '://'.$_SERVER['SERVER_NAME']; + + if ($_SERVER['HTTPS'] == 'on' && $_SERVER['SERVER_PORT'] != 443 || + $_SERVER['HTTPS'] != 'on' && $_SERVER['SERVER_PORT'] != 80) { + $ABSOLUTE_URI_STUDIP .= ':'.$_SERVER['SERVER_PORT']; + } + + $ABSOLUTE_URI_STUDIP .= $CANONICAL_RELATIVE_PATH_STUDIP; +} + +// default ASSETS_URL, customize if required +$GLOBALS['ASSETS_URL'] = $ABSOLUTE_URI_STUDIP . 'assets/'; + +require __DIR__ . '/classes/StudipFileloader.php'; +$added = StudipFileloader::load('config_defaults.inc.php config_local.inc.php', $GLOBALS, compact('STUDIP_BASE_PATH', 'ABSOLUTE_URI_STUDIP', 'ASSETS_URL', 'CANONICAL_RELATIVE_PATH_STUDIP'), true); + +// If no ENV setting was found in the config files, assume ENV=production +if (!defined('Studip\ENV')) { + define('Studip\ENV', DEFAULT_ENV); +} + +// if in dev mode and webpack dev server is running, adjust assets url +if (Studip\ENV === 'development' && !in_array('ASSETS_URL', $added) && function_exists('socket_create')) { + $wds_config = json_decode( + file_get_contents("{$STUDIP_BASE_PATH}/config/webpack.dev-server.config.json") + ); + + $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + if (@socket_connect($socket, $wds_config->host, $wds_config->port)) { + socket_close($socket); + + $assets_url = sprintf( + "%s://%s:%u/%s/", + $wds_config->protocol, + $wds_config->host, + $wds_config->port, + basename(realpath(__DIR__ . '/..')) + ); + + $probe_headers = get_headers("{$assets_url}images/logos/studip-logo.svg"); + if (strpos($probe_headers[0], '200') !== false) { + $GLOBALS['ASSETS_URL'] = $assets_url; + } + } +} + +if (!file_exists($GLOBALS['STUDIP_BASE_PATH'] . '/config/config_local.inc.php')) { + require_once __DIR__ . '/classes/URLHelper.php'; + + URLHelper::setBaseUrl($GLOBALS['ABSOLUTE_URI_STUDIP']); + header('Location: ' . URLHelper::getURL('install.php')); + + page_close(); + die; +} + +require __DIR__ . '/bootstrap-autoload.php'; + +// construct absolute URL for ASSETS_URL +if ($GLOBALS['ASSETS_URL'][0] === '/') { + $host = preg_replace('%^([a-z]+:/*[^/]*).*%', '$1', $GLOBALS['ABSOLUTE_URI_STUDIP']); + $GLOBALS['ASSETS_URL'] = $host . $GLOBALS['ASSETS_URL']; +} else if (!preg_match('/^[a-z]+:/', $GLOBALS['ASSETS_URL'])) { + $GLOBALS['ASSETS_URL'] = $GLOBALS['ABSOLUTE_URI_STUDIP'] . $GLOBALS['ASSETS_URL']; +} + +require 'config.inc.php'; + +require 'lib/phplib/page_open.php'; +require_once 'lib/functions.php'; +require_once 'lib/language.inc.php'; +require_once 'lib/visual.inc.php'; + +//setup default logger +Log::get()->setHandler($GLOBALS['TMP_PATH'] . '/studip.log'); +if (Studip\ENV == 'development') { + Log::get()->setLogLevel(Log::DEBUG); +} else { + Log::get()->setLogLevel(Log::ERROR); +} + +// set assets url +Assets::set_assets_url($GLOBALS['ASSETS_URL']); + +// globale template factory anlegen +require_once 'vendor/flexi/lib/flexi.php'; +$GLOBALS['template_factory'] = new Flexi_TemplateFactory("{$STUDIP_BASE_PATH}/templates"); + +// set default pdo connection +if (isset($GLOBALS['DB_STUDIP_HOST'])) { + try { + DBManager::getInstance() + ->setConnection('studip', + 'mysql:host=' . $GLOBALS['DB_STUDIP_HOST'] . + ';dbname=' . $GLOBALS['DB_STUDIP_DATABASE'] . + ';charset=utf8mb4', + $GLOBALS['DB_STUDIP_USER'], + $GLOBALS['DB_STUDIP_PASSWORD']); + } catch (PDOException $exception) { + header('HTTP/1.1 500 Internal Server Error'); + die(sprintf('database connection %s failed', 'mysql:host=' . $GLOBALS['DB_STUDIP_HOST'] . + ';dbname=' . $GLOBALS['DB_STUDIP_DATABASE'])); + } +} + +// set default pdo socket connection +if (isset($GLOBALS['DB_STUDIP_SOCKET'])) { + try { + DBManager::getInstance() + ->setConnection('studip', + 'mysql:unix_socket=' . $GLOBALS['DB_STUDIP_SOCKET'] . + ';dbname=' . $GLOBALS['DB_STUDIP_DATABASE'] . + ';charset=utf8mb4', + $GLOBALS['DB_STUDIP_USER'], + $GLOBALS['DB_STUDIP_PASSWORD']); + } catch (PDOException $exception) { + header('HTTP/1.1 500 Internal Server Error'); + die(sprintf('database connection %s failed', 'mysql:unix_socket=' . $GLOBALS['DB_STUDIP_SOCKET'] . + ';dbname=' . $GLOBALS['DB_STUDIP_DATABASE'])); + } +} + +// set slave connection +if (isset($GLOBALS['DB_STUDIP_SLAVE_HOST'])) { + try { + DBManager::getInstance() + ->setConnection('studip-slave', + 'mysql:host=' . $GLOBALS['DB_STUDIP_SLAVE_HOST'] . + ';dbname=' . $GLOBALS['DB_STUDIP_SLAVE_DATABASE'] . + ';charset=utf8mb4', + $GLOBALS['DB_STUDIP_SLAVE_USER'], + $GLOBALS['DB_STUDIP_SLAVE_PASSWORD']); + } catch (PDOException $exception) { + // if connection to slave fails, fall back to master instead + DBManager::getInstance()->aliasConnection('studip', 'studip-slave'); + } +} else { + DBManager::getInstance()->aliasConnection('studip', 'studip-slave'); +} + +// set default exception handler +// command line or http request? +if (isset($_SERVER['REQUEST_METHOD'])) { + set_exception_handler('studip_default_exception_handler'); +} + +// Prime autoloader if cache is enabled (this cannot be in autoloader's +// bootstrap because the stud.ip cache needs to have a db conenction) +if ($GLOBALS['CACHING_ENABLE']) { + $cached = StudipCacheFactory::getCache()->read('STUDIP#autoloader-classes'); + if ($cached) { + $class_lookup = json_decode($cached, true); + if (is_array($class_lookup)) { + $lookup_hash = md5($cached); + StudipAutoloader::addClassLookups($class_lookup); + } + } + + register_shutdown_function(function () use ($lookup_hash) { + $cached = json_encode(StudipAutoloader::$class_lookup, JSON_UNESCAPED_UNICODE); + if (md5($cached) !== $lookup_hash) { + StudipCacheFactory::getCache()->write( + 'STUDIP#autoloader-classes', + $cached, + 7 * 24 * 60 * 60 + ); + } + }); +} + +// set default time zone +date_default_timezone_set(Config::get()->DEFAULT_TIMEZONE ? : @date_default_timezone_get()); + +// sample the request time and number of db queries every tenth time +register_shutdown_function(function ($timer) { + $timer('core.request_time', 0.1); + + $query_count = DBManager::get()->query_count; + Metrics::gauge('core.database.queries', $query_count, 0.1); +}, Metrics::startTimer()); + +//include 'tools/debug/StudipDebugPDO.class.php'; + +/** + * @deprecated + */ +class DB_Seminar extends DB_Sql +{ + public function __construct($query = false) + { + $this->Host = $GLOBALS['DB_STUDIP_HOST']; + $this->Database = $GLOBALS['DB_STUDIP_DATABASE']; + $this->User = $GLOBALS['DB_STUDIP_USER']; + $this->Password = $GLOBALS['DB_STUDIP_PASSWORD']; + parent::__construct($query); + } +} + +if (Config::get()->EXTERN_ENABLE) { + require_once $GLOBALS['STUDIP_BASE_PATH'] . '/lib/extern/extern_config.inc.php'; + require_once $GLOBALS['STUDIP_BASE_PATH'] . '/lib/extern/lib/extern_functions.inc.php'; +} + +if (Config::get()->CALENDAR_ENABLE) { + require_once 'lib/calendar_functions.inc.php'; +} + +if (Config::get()->SOAP_ENABLE) { + require_once 'lib/soap/StudipSoapClient' . (Config::get()->SOAP_USE_PHP5 ? '_PHP5' : '' ) . '.class.php'; +} + +if (Config::Get()->ILIAS_INTERFACE_ENABLE) { + require_once 'lib/ilias_interface/IliasUserObserver.php'; + require_once 'lib/ilias_interface/IliasCourseObserver.php'; +} + +// set dummy navigation until db is ready +Navigation::setRootNavigation(new Navigation('')); + +// set up default page layout +PageLayout::initialize(); + +// init notification observers +Studip\Activity\ActivityObserver::initialize(); +FilesSearch\NotificationObserver::initialize(); +if (Config::Get()->ILIAS_INTERFACE_ENABLE) { + IliasUserObserver::initialize(); + IliasCourseObserver::initialize(); +} + +//Besser hier globale Variablen definieren... +$GLOBALS['_fullname_sql'] = []; +$GLOBALS['_fullname_sql']['full'] = "TRIM(CONCAT(title_front,' ',Vorname,' ',Nachname,IF(title_rear!='',CONCAT(', ',title_rear),'')))"; +$GLOBALS['_fullname_sql']['full_rev'] = "TRIM(CONCAT(Nachname,', ',Vorname,IF(title_front!='',CONCAT(', ',title_front),''),IF(title_rear!='',CONCAT(', ',title_rear),'')))"; +$GLOBALS['_fullname_sql']['no_title'] = "CONCAT(Vorname ,' ', Nachname)"; +$GLOBALS['_fullname_sql']['no_title_rev'] = "CONCAT(Nachname ,', ', Vorname)"; +$GLOBALS['_fullname_sql']['no_title_short'] = "CONCAT(Nachname,', ',UCASE(LEFT(TRIM(Vorname),1)),'.')"; +$GLOBALS['_fullname_sql']['no_title_motto'] = "CONCAT(Vorname ,' ', Nachname,IF(motto!='',CONCAT(', ',motto),''))"; +$GLOBALS['_fullname_sql']['full_rev_username'] = "TRIM(CONCAT(Nachname,', ',Vorname,IF(title_front!='',CONCAT(', ',title_front),''),IF(title_rear!='',CONCAT(', ',title_rear),''),' (',username,')'))"; + +//Initialize $SEM_TYPE and $SEM_CLASS arrays +$GLOBALS['SEM_CLASS'] = SemClass::getClasses(); +$GLOBALS['SEM_TYPE'] = SemType::getTypes(); + +// set up global navigation +Navigation::setRootNavigation(new StudipNavigation('')); + +/* set default umask to a sane value */ +umask(022); + +/*mail settings +----------------------------------------------------------------*/ +if ($GLOBALS['MAIL_TRANSPORT']) { + $mail_transporter_name = mb_strtolower($GLOBALS['MAIL_TRANSPORT']) . '_message'; +} else { + $mail_transporter_name = 'smtp_message'; +} +include 'vendor/email_message/email_message.php'; +include 'vendor/email_message/' . $mail_transporter_name . '.php'; +$mail_transporter_class = $mail_transporter_name . '_class'; +$mail_transporter = new $mail_transporter_class; +if ($mail_transporter_name == 'smtp_message') { + include 'vendor/email_message/smtp.php'; + $mail_transporter->localhost = ($GLOBALS['MAIL_LOCALHOST'] == "") ? $_SERVER["SERVER_NAME"] : $GLOBALS['MAIL_LOCALHOST']; + $mail_transporter->smtp_host = ($GLOBALS['MAIL_HOST_NAME'] == "") ? $_SERVER["SERVER_NAME"] : $GLOBALS['MAIL_HOST_NAME']; + if (is_array($GLOBALS['MAIL_SMTP_OPTIONS'])) { + foreach ($GLOBALS['MAIL_SMTP_OPTIONS'] as $key => $value) { + $mail_transporter->{"smtp_$key"} = $value; + } + if ($mail_transporter->smtp_user !== '') { + include 'vendor/sasl/sasl.php'; + } + } +} +$mail_transporter->default_charset = 'UTF-8'; +$mail_transporter->SetBulkMail((int)$GLOBALS['MAIL_BULK_DELIVERY']); +StudipMail::setDefaultTransporter($mail_transporter); +unset($mail_transporter); diff --git a/config_local.php b/config_local.php index 2e3fd292f7990bc6c012497a37642d44736e339d..dccff2fc1ec97349e46f1e083bf4876a3b7a70fc 100644 --- a/config_local.php +++ b/config_local.php @@ -17,10 +17,15 @@ namespace { // default Stud.IP database (DB_Seminar) $DB_STUDIP_HOST = getenv('MYSQL_HOST'); + $DB_STUDIP_SOCKET = getenv('MYSQL_SOCKET'); $DB_STUDIP_USER = getenv('MYSQL_USER'); $DB_STUDIP_PASSWORD = getenv('MYSQL_PASSWORD'); $DB_STUDIP_DATABASE = getenv('MYSQL_DATABASE'); + // Unset unused variables + if (!$DB_STUDIP_HOST) unset($DB_STUDIP_HOST); + if (!$DB_STUDIP_SOCKET) unset($DB_STUDIP_SOCKET); + /*URL ---------------------------------------------------------------- customize if automatic detection fails, e.g. when installation is hidden diff --git a/docker-compose.yml b/docker-compose.yml index 7a2e81f33005c6747c481c0bdc47c3d01c7f87e4..dd66db4593551c019bb5f7d475689b61f9dd696a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,8 @@ services: image: mariadb:10.4 # The mysql volume has been deactivated to ensure that the database gets reinitialized every time - # volumes: + volumes: + - ./mysql:/var/run/mysqld # - db_data:/var/lib/mysql restart: always environment: @@ -20,6 +21,9 @@ services: # Modify branch to the svn branch you want to check out BRANCH: dev-branches/tic10856-tiled-courses + volumes: + - ./mysql:/var/run/mysqld + # Redirect port to something (hopefully) unused ports: - 8032:80 @@ -30,7 +34,8 @@ services: MYSQL_DATABASE: studip_db MYSQL_USER: studip_user MYSQL_PASSWORD: studip_password - MYSQL_HOST: db + # MYSQL_HOST: localhost + MYSQL_SOCKET: /var/run/mysqld/mysqld.sock # Use automigrate to migrate your instance on startup # AUTO_MIGRATE: 1 diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 47f3c8bb48b5f0eb755ca864334ee7b610853f0d..887cf4c725f298c655b7eb8f4797ab2a4c40ca3d 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -13,7 +13,12 @@ if [ ! -f $CONFIGFILE ]; then cp "$CONF.dist" "$CONF" # Setup mysql database - echo "INSTALL DB" + echo "Waiting for db to come up" + + # If we deal with a socket and mysql host is not set overwrite the host to make MYSQL work + if [ -z $MYSQL_HOST ]; then + MYSQL_HOST='localhost' + fi; # wait until MySQL is really available maxcounter=45 @@ -28,6 +33,9 @@ if [ ! -f $CONFIGFILE ]; then fi; done + echo "Database answered" + + echo "INSTALL DB" mysql -f -u $MYSQL_USER -h $MYSQL_HOST -p$MYSQL_PASSWORD $MYSQL_DATABASE < ${STUDIP}/db/studip.sql echo "INSTALL DEFAULT DATA" mysql -f -u $MYSQL_USER -h $MYSQL_HOST -p$MYSQL_PASSWORD $MYSQL_DATABASE < ${STUDIP}/db/studip_default_data.sql