0
0
Fork 0
easterhegg-2009-website/orga.php

589 lines
21 KiB
PHP

<?php
// diese Seite stellt Orga-Funktionen für die eh1005-Seite zur Verfügung
// (Topics: ~ heißt geplant, - heißt im Bau, + heißt implementiert.)
// + diese Seite liegt im öffentlichen Serverbereich, dieser darf *.php nicht als plain/text ausliefern ;)
// + diese Seite verlangt zwingend https
// + diese Seite fragt ein Authentifikationspasswort ab
// + die Authentifikation läuft nach einer gewissen Zeitspanne (Konstante) ab
// + es dürfen von dieser Seite aus keine anderen orga-spezifischen Seiten aufgerufen werden,
// da dies eventuell eine Umgehungsmöglichkeit der Authentifizierung zur Folge haben könnte
/*
Struktur dieser Seite:
+ write HTTP header
+ recall session
+ check, defuse and shorten input variables
+ Prüfung auf https
= OK => continue
= FAIL => Session-Zwangslogout, Abbruchmeldung und Schlußverarbeitung
+ Prüfung auf gültigen Loginstatus, inkl. Timeout
= OK => continue
= FAIL => Authentifizierungsformular, Abbruchmeldung und Schlußverarbeitung
+ Prüfung auf Wartungsstatus
= OK => continue
= FAIL => Abbruchmeldung und Schlußverarbeitung
+ Login
= OK => continue
= FAIL => Authentifizierungsformular, Abbruchmeldung und Schlußverarbeitung
+ Verarbeitung der Submit-Aktionen (POST), Anzeige der einzelnen Orga-Formulare
*/
/*
known bugs / todo
- Script rennt in einen Loop-of-Death, wenn man auf einen Button klickt, während die Seite (z.B. wegen dem Fahrplan-Editor) noch nicht fertig aufgebaut war
-> Session hängt sich auf.
Dieses Problem taucht auf webtest.hamburg.ccc.de auf, ist aber lokal (auf Rainers Notebook) nicht reproduzierbar.
-> php-Version oder "nur" Config-Problem? (deadlock-timeout?)
*/
// this script needs following additional server modules for PHP
// - Database: (e.g. pgsql)
// write HTTP header (anti-cache)
header('Expires: Sun, 31 Dec 1989 23:59:59 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0');
header('Pragma: no-cache');
// recall session
session_cache_limiter('nocache');
session_cache_expire(1);
session_start();
// define general server constants
define( "SERVER_SITE_MAINTENANCE", false ); // maintenance state, set to TRUE to lock this page temporarily
define( "SERVER_LOCALHOST_IP", "127.0.0.1" ); // localhost IP, which does not need authentication
define( "SERVER_PROTOCOL_HTTPS", "HTTPS" ); // HTTPS protocol name
// define server file constants
define( "SERVER_FILE_TEMPLATE", "template.shtml" ); // template file
define( "SERVER_FILE_HEADER", "ssi_site_header.html" ); // SSI file for site header
define( "SERVER_FILE_INTRO", "ssi_site_intro.html" ); // SSI file for site intro
define( "SERVER_FILE_EXTRO", "ssi_site_extro.html" ); // SSI file for site extro
define( "SERVER_FILE_AUTOGEN", "ssi_site_autogen.html" ); // SSI file for site autogeneration warning
define( "SERVER_FILE_ANMELDUNGSLISTE", "anmeldung-data/anmeldung.csv" ); // path and file for registered participants
// pages of Kassenliste will be printed and can be arranged horizontally
// each column contains as much rows as defined by KASSENLISTE_COLUMN_ROWS, after each column of KASSENLISTE_PAGE_COLUMNS a page break will be initiated
define( "KASSENLISTE_COLUMN_ROWS", 61 ); // number of rows per page in kassenliste, pages will be printed horizontally
define( "KASSENLISTE_PAGE_COLUMNS", 3 ); // number of columns per page in kassenliste, pages will contain those number printed horizontally
// define server file constants
define( "ORGA_DAYS_BREAKFAST", 3 ); //
// define display constants
define( "DISPLAY_TEXT_NONE", " " );
define( "DISPLAY_VALUE_SEPARATOR", chr(9));
// define auth constants
define( "AUTH_TIMEOUT_MINUTES", 20 ); // idle timeout for login session
define( "AUTH_SERVER_PASS", "[Attrakt.Chaos]*9" ); // login password, [todo:] should be outsourced to an external, secured data file
// init references to $_SESSION variables ($sxxx)
$sbolauthloggedin = & $_SESSION['bolauthloginok'];
$sintauthprevtime = & $_SESSION['intauthprevtime'];
// init session variables
if ( !isset($sbolauthloggedin) ) $sbolauthloggedin = false;
if ( !isset($sintauthprevtime) ) $sintauthprevtime = time();
// init references to $_POST variables ($pxxx)
$pstrauth = & $_POST['txtauth'];
$pbollogin = & $_POST['cmdlogin'];
$pbollogout = & $_POST['cmdlogout'];
$pbolshowanmeldungen = & $_POST['cmdshowanmeldungen'];
$pbolshowkassenliste = & $_POST['cmdshowkassenliste'];
// init post variables (only for mandatory variables, ignore variables submitted by special forms!)
if ( !isset($pstrauth) ) $pstrauth = '';
// init instance variables
$eintritt = array ( 'Normal' => 42,
'Mitglied' => 35,
'Engel' => 35,
'Ermaeszigt' => 35 );
$intnow = time();
$strmsg = ''; // (status/error/etc.) message to user
$bolauthabort = false; // auth check will be aborted: show authentication page
$bolauthlogoutnow = false; // user will be logged out
$strdbfields = array();
$strdbsql = '';
$strdbsql2 = '';
$strdbrow = '';
$strweekdayname = array (1 => 'Sonntag',
2 => 'Montag',
3 => 'Dienstag',
4 => 'Mittwoch',
5 => 'Donnerstag',
6 => 'Freitag',
7 => 'Samstag');
$strvalue = '';
$intindex = 0;
$intcolrotate = 1;
$strinput = '';
$stroutput = '';
$intfileid = 0;
$intcount = 0;
$strauth = '';
$bollogin = false;
$bollogout = false;
$bolshowanmeldungen = false;
$bolshowkassenliste = false;
$strtablehead = '';
$intcolrot = 0;
$boleof = false;
$strdbfields = '';
$bolok = false; // action feedback, triggers confirmation if true or warning if false
// function library
function addmsg ($straddmsg)
{
// adds $straddmsg to $strmsg
global $strmsg;
if ( $straddmsg != '' )
{
$strmsg = $strmsg . '<li>' . $straddmsg . '</li>';
}
}
function showmsg ()
{
// shows messages in $strmsg if available
global $strmsg, $bolok;
if ( $strmsg != '' )
{
echo'
<div class="announcement">
<h1 class="';
if ( $bolok )
{
echo 'confirmation';
}
else
{
echo 'warning';
}
echo '">Feedback</h1>
<ul>' . $strmsg . '</ul>
</div>';
$strmsg = '';
$bolok = false;
}
}
// check input variables
//$bollogin = isset( $pbollogin ); // does not work in IE when submitted from within a text field by pressing Return key, reason unknown
$bollogin = ( isset( $pbollogin ) || $pstrauth != '' ); //workaround for IE problem, see line above
$bollogout = ( isset( $pbollogout ) || $bollogin ); //also fire a logout before (re-)login
$bolshowanmeldungen = ( isset( $pbolshowanmeldungen ) );
$bolshowkassenliste = ( isset( $pbolshowkassenliste ) );
// defuse input variables
$strauth = trim( htmlentities( $pstrauth, ENT_QUOTES ));
// shorten input variables
if ( strlen( $strauth ) > 255 ) $strauth = substr( $strauth, 0, 255 ); //cut it, do not modify
$strserverremoteaddr = htmlspecialchars( $_SERVER['REMOTE_ADDR'], ENT_QUOTES );
if ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] )) $strserverremoteaddr = htmlspecialchars( $_SERVER['HTTP_X_FORWARDED_FOR'], ENT_QUOTES );
$strserverprotohttps = htmlspecialchars( $_SERVER['HTTPS'], ENT_QUOTES );
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] )) $strserverprotohttps = htmlspecialchars( $_SERVER['HTTP_X_FORWARDED_PROTO'], ENT_QUOTES );
// localhost darf immer
if ( $strserverremoteaddr != constant("SERVER_LOCALHOST_IP") )
{
// check protocol
// check secure connection
// possible results:
// - secure => continue
// - insecure => abort processing and show error message ($strmsg)
if ( strtolower( $strserverprotohttps ) != 'https' && strtolower( $strserverprotohttps ) != 'on' )
{
// insecure connection -> abort
if ( !$bolauthlogoutnow && $sbolauthloggedin )
{
// active login over insecure connection -> force logout
$bolauthlogoutnow = true;
addmsg ( 'Du wirst ausgeloggt, da Deine Verbindung unsicher (unverschl&uuml;sselt) geworden ist.' );
}
addmsg ( '<a href="https://' . $_SERVER['HTTP_HOST'] . $_SERVER["PHP_SELF"] . '">Dein Verbindungsprotokoll ist HTTP. Bitte verwende f&uuml;r den Orga-Foo Verschl&uuml;sselung mittels HTTPS.</a>' );
$bolauthabort = true;
$bolok = false;
}
// check auth timeout
// possible results:
// - auth active => continue
// - auth timeout => force logout ($bolauthlogoutnow), prepare message ($strmsg) and continue
if ( $sbolauthloggedin && !$bolauthlogoutnow && ( $intnow > ( $sintauthprevtime + 60 * constant("AUTH_TIMEOUT_MINUTES") )))
{
// write message on user authentication expired -> also fire a logout ($bolauthlogoutnow)
// echo '<div class="warning">Du wurdest ausgeloggt wegen mehr als ' . constant("AUTH_TIMEOUT_MINUTES") . ' Minuten Inaktivit&auml;t.</div><br>';
$bolauthlogoutnow = true;
addmsg ( 'Du wirst ausgeloggt wegen mehr als ' . constant("AUTH_TIMEOUT_MINUTES") . ' Minuten Inaktivit&auml;t.' );
}
// restart timeout
$sintauthprevtime = $intnow;
}
else
{
// localhost ist immer eingeloggt
$sbolauthloggedin = true;
}
if ( $bolauthlogoutnow || $bollogout )
{
// logout
if ( $bolauthlogoutnow )
{
addmsg ( 'Du wurdest automatisch ausgeloggt. Bitte gegebenenfalls erneut einloggen.' );
}
$sbolauthloggedin = false;
}
// check maintenance state
if ( constant("SERVER_SITE_MAINTENANCE") )
{
// cancel because of maintenance
addmsg ( 'Die Orga-Seite ist zurzeit wegen Wartungsarbeiten deaktiviert. Bitte sp&auml;ter wiederkommen. Danke.' );
$bolauthabort = true;
}
// Well, Checkpoint.
// Now a defined and normal state of checking has been reached.
// Possible states are now:
// - $sbolauthloggedin = true: user has successfully authenticated and is still logged in
// - $sbolauthloggedin = false: user is either not (yet) authenticated or authentication has been expired
// If there were any messages on the way up to here, they are stored as list items (<li>) in variable $strmsg.
// check auth phrase if user tries to login
if ( !$bolauthabort && $bollogin && $strauth > '' )
{
if ( $strauth == constant("AUTH_SERVER_PASS") )
{
// login accepted
$sbolauthloggedin = true;
}
else
{
// login failed
$sbolauthloggedin = false;
addmsg ( 'Das klappt so nicht. Vermutlich hast Du Dich vertippt.' );
}
}
// prepare orga page
// assume that all ssi files are there. No, I won't check _that_ explicitely.
// If they ain't there, the user gets a partial page. ...so what? ;o)
readfile( constant("SERVER_FILE_HEADER") );
echo'
<!-- begin of specific page header -->
<title>Easterhegg - Orga</title>
<!-- end of specific page header -->';
readfile( constant("SERVER_FILE_INTRO") );
echo'
<!-- begin of specific page content -->
';
echo
'
<div id="main">
<h1>interne Orga</h1>
';
// show msg, if available
if ( $strmsg != '' )
{
echo'
<div class="announcement">
<h1 class="warning">Authentifizierungshinweis:</h1>
<ul>' . $strmsg . '</ul>
</div>';
$strmsg = '';
}
if ( !$sbolauthloggedin )
{
// show authentication page and then die
if ( !$bolauthabort )
{
// show login form
echo'
<div class="chapter">
<h1>*knock-knock*</h1>
<form id="loginform" name="loginform" action="' . $_SERVER["PHP_SELF"] . '" method="post">
<input name="txtauth" type="password">
<input name="cmdlogin" type="submit" value="Lass mich rein!">
</form>
</div>';
}
// close page and stoprun.
echo'
<!-- end of specific page content -->
';
readfile( constant("SERVER_FILE_EXTRO") );
die();
}
// Well, Checkpoint.
// Now the user is proofed to be successfully logged in. (All others are wiped out.)
// From here on the user is authorized to enjoy all the following features.
// default sequence within each chapter:
// 1. headline
// 2. submit action
// 3. showmsg();
// 4. user forms
// 5. showmsg();
// 6. five empty rows to separate from next chapter ;)
// show logout chapter
echo'
<div class="chapter">
<h1>Logout</h1>
</div>';
showmsg();
echo '
<div>
<form id="logoutform" name="logoutform" action="' . $_SERVER["PHP_SELF"] . '" method="post">
<p>
<input name="cmdlogout" type="submit" value="Habe fertig!" />
</p>
</form>
</div>';
showmsg();
// show anmeldungen
echo'
<a name="anmeldungen"></a>
<div class="chapter">
<h1>Anmeldungen anzeigen</h1>
<form id="showanmeldungenform" name="showanmeldungen" action="' . $_SERVER["PHP_SELF"] . '#anmeldungen" method="post">
<p>
<input name="cmdshowanmeldungen" type="submit" value="Anmeldungen anzeigen" />
</p>
</form>
</div>';
if ( $bolshowanmeldungen )
{
// Anmeldungen anzeigen
// hmm, das hier musste jetzt mal schnell gehen, schöner oder gar effizienter Code ist das natürlich absolut nicht ;-)
$strinput = file_get_contents( constant("SERVER_FILE_ANMELDUNGSLISTE") );
$strinput = htmlentities( $strinput, ENT_QUOTES );
$strinput = str_replace( chr(13), '', $strinput );
$strinput = str_replace( chr(10), '</td></tr><tr><td class="db">', $strinput );
$strinput = str_replace( chr(9), '</td><td class="db">', $strinput );
$stroutput = '<table class="db"><tr class="dbhead"><td class="db">' . $strinput . '</td></tr></table>';
$stroutput = str_replace( '<tr><td class="db"></td></tr>', '', $stroutput );
$strinput = file( constant("SERVER_FILE_ANMELDUNGSLISTE") );
$intsumanmeldungen = 0;
$intsumeinnahmen = 0;
$intsumwurst = 0;
$intsumkaese = 0;
$intsummarmelade = 0;
$intsumobst = 0;
$intsummuesli = 0;
$strangelswithoutgarmentsize = '';
$intsumgarmentsize = array ( '?' => 0,
'4XS' => 0,
'3XS' => 0,
'XXS' => 0,
'XS' => 0,
'S' => 0,
'M' => 0,
'L' => 0,
'XL' => 0,
'XXL' => 0,
'3XL' => 0,
'4XL' => 0);
foreach ($strinput as $intlinenum => $strline) {
if ( $intlinenum != 0 && strlen( $strline ) > 0)
{
list($strnick, $strstatus, $stremail, $intwurst, $intkaese, $intmarmelade, $intobst, $intmuesli, $strtimestamp, $strgarmentsize) = explode(chr(9), $strline);
$intsumanmeldungen = $intsumanmeldungen + 1;
$intsumeinnahmen = $intsumeinnahmen + $eintritt[$strstatus];
$intsumwurst = $intsumwurst + $intwurst;
$intsumkaese = $intsumkaese + $intkaese;
$intsummarmelade = $intsummarmelade + $intmarmelade;
$intsumobst = $intsumobst + $intobst;
$intsummuesli = $intsummuesli + $intmuesli;
$strgarmentsize = trim( $strgarmentsize );
if ( $strgarmentsize != '' )
{
if ( array_key_exists( $strgarmentsize, $intsumgarmentsize )) { $intsumgarmentsize[$strgarmentsize] = $intsumgarmentsize[$strgarmentsize] + 1; }
elseif( $strgarmentsize > '' ) { $intsumgarmentsize['?'] = $intsumgarmentsize['?'] + 1; }
}
elseif ( $strstatus == 'Engel' )
{
$strangelswithoutgarmentsize = $strangelswithoutgarmentsize . ', &quot;' . $strnick . '&quot;';
}
}
}
$strangelswithoutgarmentsize = substr( $strangelswithoutgarmentsize, 2 );
echo '<div class="box">';
echo '<span class="topic">nach Status:</span>';
echo '<span class="line">Normal: ' . substr_count( $stroutput, '>Normal<' ) . '</span>';
echo '<span class="line">Mitglieder: ' . substr_count( $stroutput, '>Mitglied<' ) . '</span>';
echo '<span class="line">Engel: ' . substr_count( $stroutput, '>Engel<' ) . '</span>';
echo '<span class="line">Erm&auml;&szlig;igt: ' . substr_count( $stroutput, '>Ermaeszigt<' ) . '</span>';
echo '<hr />';
echo '<span class="line important">Gesamt: ' . $intsumanmeldungen . '</span>';
echo '<span class="line important">Einnahmen: ' . $intsumeinnahmen . ' Euro</span>';
echo '</div>';
echo '<div class="box">';
echo '<span class="topic">nach Futter: pro Tag (' . constant("ORGA_DAYS_BREAKFAST") . ' Tage)</span>';
echo '<span class="line">Wurst: ' . $intsumwurst . ' (' . ( constant("ORGA_DAYS_BREAKFAST") * $intsumwurst ) . ')' . '</span>';
echo '<span class="line">K&auml;se: ' . $intsumkaese . ' (' . ( constant("ORGA_DAYS_BREAKFAST") * $intsumkaese ) . ')' . '</span>';
echo '<span class="line">Marmelade: ' . $intsummarmelade . ' (' . ( constant("ORGA_DAYS_BREAKFAST") * $intsummarmelade ) . ')' . '</span>';
echo '<span class="line">Obst: ' . $intsumobst . ' (' . ( constant("ORGA_DAYS_BREAKFAST") * $intsumobst ) . ')' . '</span>';
echo '<span class="line">M&uuml;sli: ' . $intsummuesli . ' (' . ( constant("ORGA_DAYS_BREAKFAST") * $intsummuesli ) . ')' . '</span>';
echo '<hr />';
echo '<span class="line important">Br&ouml;tchen gesamt: ' . ( $intsumwurst + $intsumkaese + $intsummarmelade ) . ' (' . ( 4 * ( $intsumwurst + $intsumkaese + $intsummarmelade ) ) . ')' . '</span>';
echo '</div>';
echo '<div class="box">';
echo '<span class="topic">nach Konfektionsgr&ouml;&szlig;e:</span>';
foreach ($intsumgarmentsize as $strgarmentsize => $intgarmentsize)
{
if ( $intgarmentsize > 0 ) echo '<span class="line">' . $strgarmentsize . ': ' . $intgarmentsize . '</span>';
}
echo '<hr />';
echo '<span class="line important">T-Shirts gesamt: ' . ( array_sum( $intsumgarmentsize ) ) . '</span>';
echo '<span class="line important">Engel ohne T-Shirt-Gr&ouml;&szlig;e: ' . (( $strangelswithoutgarmentsize != '') ? $strangelswithoutgarmentsize : '(keine)' ) . '</span>';
echo '</div>';
echo '<div class="box">' . $stroutput . '</div>';
}
showmsg();
// show kassenliste
echo'
<a name="kassenliste"></a>
<div class="chapter">
<h1>Kassenliste anzeigen</h1>
<form id="showkassenlisteform" name="showkassenliste" action="' . $_SERVER["PHP_SELF"] . '#kassenliste" method="post">
<p>
<input name="cmdshowkassenliste" type="submit" value="Kassenliste anzeigen" />
</p>
</form>
</div>';
if ( $bolshowkassenliste )
{
// Kassenliste anzeigen
// hmm, das hier musste jetzt mal schnell gehen, schöner oder gar effizienter Code ist das natürlich absolut nicht ;-)
$strinput = file( constant("SERVER_FILE_ANMELDUNGSLISTE") );
array_splice( $strinput, 0, 1 ); // remove first line (header)
natcasesort( $strinput ); // sort by nick (first column)
$stroutput = '';
$intinputnum = 0;
foreach ($strinput as $intlinenum => $strline)
{
if ( strlen( $strline ) > 0)
{
$intinputnum = $intinputnum + 1;
$bolendofpage = ((($intinputnum % ( constant( "KASSENLISTE_PAGE_COLUMNS" ) * constant( "KASSENLISTE_COLUMN_ROWS" ))) == 0) or ($intinputnum == count($strinput)) );
$bolendofcolumn = ((($intinputnum % constant( "KASSENLISTE_COLUMN_ROWS" )) == 0) or $bolendofpage );
$bolbeginofpage = (($intinputnum % ( constant( "KASSENLISTE_PAGE_COLUMNS" ) * constant( "KASSENLISTE_COLUMN_ROWS" ))) == 1 );
$bolbeginofcolumn = (( $intinputnum % ( constant( "KASSENLISTE_COLUMN_ROWS" )) == 1) or $bolbeginofpage );
list($strnick, $strstatus, $stremail, $intwurst, $intkaese, $intmarmelade, $intobst, $intmuesli, $strtimestamp) = explode(chr(9), $strline);
$strnick = htmlentities( $strnick, ENT_QUOTES );
//addmsg($strnick.': '.$intlinenum.'/'.$intinputnum.'='.($bolendofcolumn?'-C':'').($bolendofpage?'-P':'').($bolbeginofpage?'+P':'').($bolbeginofcolumn?'+C':''));
if ( $bolbeginofpage )
{
$stroutput = $stroutput . '<div class="box">';
}
if ( $bolbeginofcolumn )
{
$stroutput = $stroutput . '<table class="db column"><tr class="dbhead"><td class="db">Status</td><td class="db">Eintritt</td><td class="db">Nick</td>';
}
$stroutput = $stroutput . chr(13) . '<tr><td class="db">' . $strstatus . ' &nbsp;</td><td class="db ';
switch ( $strstatus )
{
case 'Ermaeszigt':
case 'Engel':
$stroutput = $stroutput . 'left';
break;
case 'Mitglied':
$stroutput = $stroutput . 'center';
break;
case 'Normal':
$stroutput = $stroutput . 'right';
break;
}
$stroutput = $stroutput . '">' . $eintritt[$strstatus] . '</td><td class="db">' . $strnick . '</td></tr>';
if ( $bolendofcolumn )
{
$stroutput = $stroutput . '</table>';
}
if ( $bolendofpage )
{
$stroutput = $stroutput . '<div class="line"></div></div>';
}
}
}
echo $stroutput;
}
showmsg();
// close page and stoprun.
echo
'
<!-- end of specific page content -->
';
readfile( constant("SERVER_FILE_EXTRO") );
die();
?>