<?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üsselt) geworden ist.' ); } addmsg ( '<a href="https://' . $_SERVER['HTTP_HOST'] . $_SERVER["PHP_SELF"] . '">Dein Verbindungsprotokoll ist HTTP. Bitte verwende für den Orga-Foo Verschlü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ät.</div><br>'; $bolauthlogoutnow = true; addmsg ( 'Du wirst ausgeloggt wegen mehr als ' . constant("AUTH_TIMEOUT_MINUTES") . ' Minuten Inaktivitä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ä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 . ', "' . $strnick . '"'; } } } $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äß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ä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üsli: ' . $intsummuesli . ' (' . ( constant("ORGA_DAYS_BREAKFAST") * $intsummuesli ) . ')' . '</span>'; echo '<hr />'; echo '<span class="line important">Brötchen gesamt: ' . ( $intsumwurst + $intsumkaese + $intsummarmelade ) . ' (' . ( 4 * ( $intsumwurst + $intsumkaese + $intsummarmelade ) ) . ')' . '</span>'; echo '</div>'; echo '<div class="box">'; echo '<span class="topic">nach Konfektionsgröß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öß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 . ' </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(); ?>