diff --git a/.gitignore b/.gitignore index 6ed4df6..54562f9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,8 @@ runtime/ **/.idea/workspace.xml **/.idea/tasks.xml -**/.idea/dataSources* \ No newline at end of file +**/.idea/dataSources* + +config.php + +www/dtest.php \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index c66df00..f5f15f4 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -1,7 +1,13 @@ \ No newline at end of file diff --git a/data/css_compress/compress.py b/data/css_compress/compress.py index 6072e02..0dd97db 100644 --- a/data/css_compress/compress.py +++ b/data/css_compress/compress.py @@ -2,78 +2,83 @@ import sys import os -from subprocess import call import re import subprocess -def findnext(str, start, chr): - depth = 0 - for i in range(start, len(str)): - if (str[i] == chr): return i; -def findclose(str, start): +def findnext(strdata, start, searchchr): depth = 0 - for i in range(start, len(str)): - if (str[i] == '{'): depth = depth+1; - if (str[i] == '}'): depth = depth-1; - if (depth == 0): return i; + for i in range(start, len(strdata)): + if strdata[i] == searchchr: return i; -def countnl(str, start, end): + +def findclose(strdata, start): + depth = 0 + for i in range(start, len(strdata)): + if strdata[i] == '{': depth = depth + 1; + if strdata[i] == '}': depth = depth - 1; + if depth == 0: return i; + + +def countnl(strdata, start, end): cnt = 0 - for i in range(start, end+1): - if (str[i] == '\n'): cnt = cnt+1; - return cnt; + for i in range(start, end + 1): + if strdata[i] == '\n': cnt = cnt + 1; + return cnt + def comment_remover(text): def replacer(match): s = match.group(0) if s.startswith('/'): - return " " # note: a space and not an empty string + return " " # note: a space and not an empty string else: return s + pattern = re.compile( r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', re.DOTALL | re.MULTILINE ) return re.sub(pattern, replacer, text) + fsource = str.replace(sys.argv[1], '\\', '/') # scss -finput = str.replace(sys.argv[2], '\\', '/') # css +finput = str.replace(sys.argv[2], '\\', '/') # css foutput = str.replace(sys.argv[3], '\\', '/') # min.css -ftemp1 = '__temp_compresss_py_1.tmp.css'; -ftemp2 = '__temp_compresss_py_2.tmp.css'; +ftemp1 = '__temp_compresss_py_1.tmp.css' +ftemp2 = '__temp_compresss_py_2.tmp.css' -print('======== INPUT ========'); -print(); -print(fsource); -print(finput); -print(foutput); -print(); -print(); +print('======== INPUT ========') +print() +print(fsource) +print(finput) +print(foutput) +print() +print() -print('======== DELETE OLD DATA ========'); +print('======== DELETE OLD DATA ========') if os.path.isfile(finput): - try: - os.remove(finput); - print(finput + ' deleted') - except: - print(sys.exc_info()[0]) + try: + os.remove(finput) + print(finput + ' deleted') + except: + print(sys.exc_info()[0]) else: - print(finput + ' does not exist') + print(finput + ' does not exist') if os.path.isfile(foutput): - try: - os.remove(foutput); - print(foutput + ' deleted') - except: - print(sys.exc_info()[0]) + try: + os.remove(foutput) + print(foutput + ' deleted') + except: + print(sys.exc_info()[0]) else: - print(foutput + ' does not exist') -print(); -print(); + print(foutput + ' does not exist') +print() +print() - -print('======== CALL SCSS ========'); -out = subprocess.run(['ruby', 'scss', '--style=expanded', '--no-cache', '--update', fsource + ':' + finput], stdout=subprocess.PIPE, stderr=subprocess.PIPE) +print('======== CALL SCSS ========') +out = subprocess.run(['ruby', 'scss', '--style=expanded', '--no-cache', '--update', fsource + ':' + finput], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) print('> scss.bat --style=expanded --no-cache --update ' + fsource + ':' + finput) print('STDOUT:') print(out.stdout.decode('utf-8')) @@ -83,13 +88,13 @@ print(out.stderr.decode('utf-8')) print('') print('') -print('======== CLEANUP COMMENTS ========'); +print('======== CLEANUP COMMENTS ========') with open(finput, 'r') as tf: data1 = tf.read() print(str(len(data1)) + ' characters read from ' + os.path.basename(finput)) data1 = comment_remover(data1) -print('Comments in css removed'); +print('Comments in css removed') with open(ftemp1, "w") as tf: tf.write(data1) @@ -98,19 +103,19 @@ with open(ftemp1, "w") as tf: print('') print('') - -print('======== CALL YUI ========'); -out = subprocess.run(['java', '-jar', 'yuicompressor.jar', '--verbose', ftemp1, '-o', ftemp2], stdout=subprocess.PIPE, stderr=subprocess.PIPE) -print('> java -jar yuicompressor.jar --verbose "'+finput+'" -o "'+ftemp2+'"') -print('STDOUT:'); +print('======== CALL YUI ========') +out = subprocess.run(['java', '-jar', 'yuicompressor.jar', '--verbose', ftemp1, '-o', ftemp2], stdout=subprocess.PIPE, + stderr=subprocess.PIPE) +print('> java -jar yuicompressor.jar --verbose "' + finput + '" -o "' + ftemp2 + '"') +print('STDOUT:') print(out.stdout.decode('utf-8')) -print('STDERR:'); +print('STDERR:') print(out.stderr.decode('utf-8')) print('') print('') -print('======== READ ========'); +print('======== READ ========') with open(ftemp2, 'r') as tf: data = tf.read() print(str(len(data)) + ' characters read from ' + ftemp2) @@ -118,11 +123,11 @@ with open(ftemp2, 'r') as tf: print('') print('') -print('======== REM ========'); +print('======== REM ========') try: - os.remove(ftemp1); + os.remove(ftemp1) print(ftemp1 + ' deleted') - os.remove(ftemp2); + os.remove(ftemp2) print(ftemp2 + ' deleted') except: print(sys.exc_info()[0]) @@ -130,30 +135,29 @@ except: print('') print('') -print('======== REGEX ========'); -data = re.sub(r'(\}*\})', '\g<1>\n', data); +print('======== REGEX ========') +data = re.sub(r'(\}*\})', '\g<1>\n', data) print('css data modified (1)') print('') print('') -print('======== MEDIA ========'); +print('======== MEDIA ========') ins = [] for i in range(len(data)): if data[i:].startswith('@media'): - copen = findnext(data, i, '{') cclose = findclose(data, copen) - if (countnl(data, copen, cclose) == 0): continue; + if countnl(data, copen, cclose) == 0: continue; - ins.append( (copen+1, '\n\t') ) - for i in range(copen+1, cclose): - if data[i] == '\n': - tp =(i+1, '\t') - ins.append( tp ) + ins.append((copen + 1, '\n\t')) + for i2 in range(copen + 1, cclose): + if data[i2] == '\n': + tp = (i2 + 1, '\t') + ins.append(tp) ins.append((cclose, '\n')) print('media query at idx:' + str(i) + ' formatted') @@ -163,7 +167,7 @@ for (l, c) in reversed(ins): print('') print('') -print('======== WRITE ========'); +print('======== WRITE ========') with open(foutput, "w") as tf: tf.write(data) print(str(len(data)) + ' characters written to ' + foutput) @@ -171,18 +175,17 @@ with open(foutput, "w") as tf: print('') print('') -print('======== REMOVE MAP ========'); +print('======== REMOVE MAP ========') if os.path.isfile(finput + '.map'): - try: - os.remove(finput + '.map'); - print(finput + '.map' + ' deleted') - except e: - print(e) + try: + os.remove(finput + '.map') + print(finput + '.map' + ' deleted') + except Exception as e: + print(e) else: - print(finput + '.map' + ' does not exist') + print(finput + '.map' + ' does not exist') print('') print('') - print('Finished.') diff --git a/www/commands/alephnote_show.php b/www/commands/alephnote_show.php index ee98d25..aa2c36d 100644 --- a/www/commands/alephnote_show.php +++ b/www/commands/alephnote_show.php @@ -1,9 +1,9 @@
@@ -20,7 +20,7 @@ Database::connect(); - + modules->AlephNoteStatistics()->getAllActiveEntriesOrdered() as $entry): ?> diff --git a/www/commands/alephnote_statsping.php b/www/commands/alephnote_statsping.php index dcbf878..98e3f99 100644 --- a/www/commands/alephnote_statsping.php +++ b/www/commands/alephnote_statsping.php @@ -1,16 +1,17 @@ forceResult(400, "Wrong parameters."); return; } +if (!isset($API_OPTIONS['clientid'])) { $FRAME_OPTIONS->forceResult(400, "Wrong parameters."); return; } +if (!isset($API_OPTIONS['version'])) { $FRAME_OPTIONS->forceResult(400, "Wrong parameters."); return; } +if (!isset($API_OPTIONS['providerstr'])) { $FRAME_OPTIONS->forceResult(400, "Wrong parameters."); return; } +if (!isset($API_OPTIONS['providerid'])) { $FRAME_OPTIONS->forceResult(400, "Wrong parameters."); return; } +if (!isset($API_OPTIONS['notecount'])) { $FRAME_OPTIONS->forceResult(400, "Wrong parameters."); return; } $nam = $API_OPTIONS['name']; $cid = $API_OPTIONS['clientid']; @@ -22,9 +23,7 @@ $tnc = $API_OPTIONS['notecount']; if ($nam !== 'AlephNote') print('{"success":false, "message":"Unknown AppName"}'); -Database::connect(); - -Database::sql_exec_prep('INSERT INTO an_statslog (ClientID, Version, ProviderStr, ProviderID, NoteCount) VALUES (:cid1, :ver1, :prv1, :pid1, :tnc1) ON DUPLICATE KEY UPDATE Version=:ver2,ProviderStr=:prv2,ProviderID=:pid2,NoteCount=:tnc2', +$SITE->modules->Database()->sql_exec_prep('INSERT INTO an_statslog (ClientID, Version, ProviderStr, ProviderID, NoteCount) VALUES (:cid1, :ver1, :prv1, :pid1, :tnc1) ON DUPLICATE KEY UPDATE Version=:ver2,ProviderStr=:prv2,ProviderID=:pid2,NoteCount=:tnc2', [ [':cid1', $cid, PDO::PARAM_STR], [':ver1', $ver, PDO::PARAM_STR], diff --git a/www/commands/base_test.php b/www/commands/base_test.php index 1c467f6..4a1b139 100644 --- a/www/commands/base_test.php +++ b/www/commands/base_test.php @@ -1,3 +1,9 @@ updateCache(); - +$v = $SITE->modules->ExtendedGitGraph()->updateCache(); diff --git a/www/commands/extendedgitgraph_refresh.php b/www/commands/extendedgitgraph_refresh.php index f2f3bf1..a65c9fe 100644 --- a/www/commands/extendedgitgraph_refresh.php +++ b/www/commands/extendedgitgraph_refresh.php @@ -1,12 +1,12 @@ update(); -$v->updateCache(); +$SITE->modules->ExtendedGitGraph()->update(); +$SITE->modules->ExtendedGitGraph()->updateCache(); diff --git a/www/commands/extendedgitgraph_status.php b/www/commands/extendedgitgraph_status.php index e39ee5e..9a56ba6 100644 --- a/www/commands/extendedgitgraph_status.php +++ b/www/commands/extendedgitgraph_status.php @@ -1,10 +1,14 @@ config['extendedgitgraph']['output_file']) { - $lfile = $CONFIG['extendedgitgraph']['output_filepath']; + $lfile = $SITE->config['extendedgitgraph']['output_filepath']; if (file_exists($lfile)) { @@ -18,11 +22,11 @@ if ($CONFIG['extendedgitgraph']['output_file']) echo '[[ FILE NOT FOUND ]]'; } } -else if ($CONFIG['extendedgitgraph']['output_file']) +else if ($SITE->config['extendedgitgraph']['output_file']) { if (session_status() !== PHP_SESSION_ACTIVE) session_start(); - $svar = $CONFIG['extendedgitgraph']['session_var']; + $svar = $SITE->config['extendedgitgraph']['session_var']; if (isset($_GET['clear'])) if (key_exists($svar, $_SESSION)) $_SESSION[$svar] = ''; diff --git a/www/commands/html_panel-aoc-calendar.php b/www/commands/html_panel-aoc-calendar.php index fd42fcc..185a81b 100644 --- a/www/commands/html_panel-aoc-calendar.php +++ b/www/commands/html_panel-aoc-calendar.php @@ -1,16 +1,21 @@ intval($_GET['year']), - 'nav' => boolval($_GET['nav']), - 'linkheader' => boolval($_GET['linkheader']), - 'ajax' => boolval($_GET['ajax']), - 'frame' => false, - 'frameid' => strval($_GET['frameid']), -]; -require (__DIR__ . '/../fragments/panel_aoc_calendar.php'); + + +if (!isset($API_OPTIONS['year'])) { $FRAME_OPTIONS->forceResult(400, "Wrong parameters."); return; } +if (!isset($API_OPTIONS['nav'])) { $FRAME_OPTIONS->forceResult(400, "Wrong parameters."); return; } +if (!isset($API_OPTIONS['linkheader'])) { $FRAME_OPTIONS->forceResult(400, "Wrong parameters."); return; } +if (!isset($API_OPTIONS['ajax'])) { $FRAME_OPTIONS->forceResult(400, "Wrong parameters."); return; } + +$year = intval($API_OPTIONS['year']); +$shownav = boolval($API_OPTIONS['nav']); +$linkheader = boolval($API_OPTIONS['linkheader']); +$ajax = boolval($API_OPTIONS['ajax']); +$frameid = strval($API_OPTIONS['frameid']); + +echo $SITE->fragments->PanelAdventOfCodeCalendar($year, $shownav, $linkheader, $ajax, false, $frameid); diff --git a/www/commands/progs_updatecheck.php b/www/commands/progs_updatecheck.php index 93108a8..602549e 100644 --- a/www/commands/progs_updatecheck.php +++ b/www/commands/progs_updatecheck.php @@ -1,21 +1,21 @@ forceResult(400, "Wrong parameters."); return; } $name = $API_OPTIONS['name']; -$updatedata = Programs::listUpdateData(); +$updatedata = $SITE->modules->UpdatesLog()->listUpdateData(); -if (!array_key_exists($name, $updatedata)) httpError(404, 'Invalid Request - [Name] not found'); +if (!array_key_exists($name, $updatedata)) { $FRAME_OPTIONS->forceResult(404, 'Invalid Request - [Name] not found'); return; } $data = $updatedata[$name]; -UpdatesLog::insert($name, $data['version']); +$SITE->modules->UpdatesLog()->insert($name, $data['version']); print($name."
".$data['version']."
".$data['url']); diff --git a/www/commands/server_backupupload.php b/www/commands/server_backupupload.php index 02740ef..cf26e3e 100644 --- a/www/commands/server_backupupload.php +++ b/www/commands/server_backupupload.php @@ -1,17 +1,17 @@ forceResult(400, "Wrong parameters."); return; } +if (!isset($API_OPTIONS['filename'])) { $FRAME_OPTIONS->forceResult(400, "Wrong parameters."); return; } $folder = $API_OPTIONS['folder']; $filename = $API_OPTIONS['filename']; -$uri = $OPTIONS['uri']; +$uri = $ROUTE->full_url; $reltarget = "Backup/$folder/$filename"; diff --git a/www/commands/server_gitwebhook.php b/www/commands/server_gitwebhook.php index 1876fd8..c7f7b6e 100644 --- a/www/commands/server_gitwebhook.php +++ b/www/commands/server_gitwebhook.php @@ -1,21 +1,27 @@ forceResult(400, "Wrong parameters."); return; } $hook = $API_OPTIONS['target']; -$uri = $OPTIONS['uri']; +$uri = $ROUTE->full_url; $cmd = ""; -if ($hook == 'website_mikescher') $cmd = 'git pull'; -else if ($hook == 'griddominance') $cmd = 'update-gdapi'; -else httpDie(400, "Unknown webhook: $hook"); +if ($hook == 'website_mikescher') + $cmd = 'git pull'; +else if ($hook == 'griddominance') + $cmd = 'update-gdapi'; +else +{ + $FRAME_OPTIONS->forceResult(400, "Unknown webhook: $hook"); + return; +} $std = shell_exec($cmd); diff --git a/www/commands/server_setselfaddress.php b/www/commands/server_setselfaddress.php index 0b2db70..f9e0f3e 100644 --- a/www/commands/server_setselfaddress.php +++ b/www/commands/server_setselfaddress.php @@ -1,4 +1,9 @@ '; echo ''; @@ -17,10 +17,10 @@ echo ''; echo ''; echo ''; -foreach (Books::listAll() as $book) +foreach ($SITE->modules->Books()->listAll() as $book) { echo 'Create preview for ' . $book['title'] . '
' . "\n"; - Books::createPreview($book); + $SITE->modules->Books()->createPreview($book); } echo 'Finished.' . '
' . "\n"; diff --git a/www/commands/site_createProgramThumbnails.php b/www/commands/site_createProgramThumbnails.php index 8b5cd6a..7c5b00d 100644 --- a/www/commands/site_createProgramThumbnails.php +++ b/www/commands/site_createProgramThumbnails.php @@ -1,10 +1,10 @@ '; echo ''; @@ -17,10 +17,10 @@ echo ''; echo ''; echo ''; -foreach (Programs::listAll() as $prog) +foreach ($SITE->modules->Programs()->listAll() as $prog) { echo 'Create preview for ' . $prog['name'] . '
' . "\n"; - Programs::createPreview($prog); + $SITE->modules->Programs()->createPreview($prog); } echo 'Finished.' . '
' . "\n"; diff --git a/www/commands/site_selftest.php b/www/commands/site_selftest.php new file mode 100644 index 0000000..27c38da --- /dev/null +++ b/www/commands/site_selftest.php @@ -0,0 +1,14 @@ +forceResult(400, "Wrong parameters."); return; } + + +$json = $SITE->modules->SelfTest()->run($API_OPTIONS['filter']); + +echo json_encode($json); \ No newline at end of file diff --git a/www/commands/updates_show.php b/www/commands/updates_show.php index 7f35a4b..021f7b3 100644 --- a/www/commands/updates_show.php +++ b/www/commands/updates_show.php @@ -1,10 +1,9 @@
@@ -16,7 +15,7 @@ Database::connect(); - + modules->UpdatesLog()->getEntries($_GET['ulname'], 512) as $entry): ?> diff --git a/www/data/css/styles.css b/www/data/css/styles.css index 61cd5e7..fd3e460 100644 --- a/www/data/css/styles.css +++ b/www/data/css/styles.css @@ -1,3 +1,4 @@ +@charset "UTF-8"; /* 400px */ body { background-color: #EEEEEE; @@ -782,12 +783,6 @@ html, body { text-align: left; } -.boxedcontent.alertbox { - background-color: #F52; - font-weight: bold; - text-align: center; -} - .egg_col_x5_0 { fill: #eeeeee; } @@ -858,7 +853,7 @@ html, body { min-width: 300px; } -.consistency_result_ok, .consistency_result_warn, .consistency_result_err { +.consistency_result { min-width: 400px; color: #222222; border: 1px solid #888; @@ -866,6 +861,10 @@ html, body { margin: 1px 0; } +.consistency_result:after { + content: " "; +} + .consistency_result_ok { background: #00FF00; } @@ -878,6 +877,15 @@ html, body { background: #FF0000; } +.consistency_result_intermed { + background: #EEEEEE; +} + +.consistency_result_running { + background: #DDDDDD; + border: 1px solid #000; +} + .admincontent .boxedcontent hr { width: 95%; height: 1px; @@ -887,6 +895,58 @@ html, body { background: -webkit-radial-gradient(circle, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0) 100%); } +.admindberr { + color: #BB2222; +} + +.boxedcontent.alertbox { + background-color: #FF4444; + color: #222222; + border: 1px solid #AA4444; + font-weight: bold; + text-align: center; +} +.boxedcontent.alertbox .bc_data { + padding-top: 2px; + padding-bottom: 2px; +} + +.boxedcontent.warnbox { + background-color: #FFA726; + color: #333333; + border: 1px solid #444444; + font-weight: bold; + text-align: center; +} +.boxedcontent.warnbox .bc_data { + padding-top: 2px; + padding-bottom: 2px; +} + +.boxedcontent.graybox { + background-color: #888888; + color: #222222; + border: 1px solid #444444; + font-weight: bold; + text-align: center; +} +.boxedcontent.graybox .bc_data { + padding-top: 2px; + padding-bottom: 2px; +} + +.boxedcontent.successbox { + background-color: #168B00; + color: #222222; + border: 1px solid #444444; + font-weight: bold; + text-align: center; +} +.boxedcontent.successbox .bc_data { + padding-top: 2px; + padding-bottom: 2px; +} + /* 400px */ #loginform div { display: flex; @@ -1900,6 +1960,7 @@ html, body { /* 400px */ .ev_master { align-self: center; + width: 100%; } @media (min-width: 851px) { .ev_master { @@ -1918,6 +1979,17 @@ html, body { text-align: center; font-size: 25pt; } +.ev_master .ev_statusmore { + color: #333333; + background-color: #BBBBBB; + text-align: left; + padding: 4px; + font-family: Consolas, Monaco, "Courier New", Menlo, monospace; + font-size: small; + overflow-x: auto; + white-space: nowrap; + width: 100%; +} @media (max-width: 767px) { .ev_master .ev_code { font-size: 75pt; diff --git a/www/data/css/styles.min.css b/www/data/css/styles.min.css index e2e9758..5ee24b8 100644 --- a/www/data/css/styles.min.css +++ b/www/data/css/styles.min.css @@ -1,4 +1,4 @@ -body{background-color:#eee;color:#333;font-family:"Times New Roman",serif} +@charset "UTF-8";body{background-color:#eee;color:#333;font-family:"Times New Roman",serif} #content{padding-top:64px;display:flex;justify-content:center;line-height:1.4;flex-direction:column;align-items:center} .content-responsive{margin-left:auto;margin-right:auto} @media(max-width:767px){.content-responsive{width:95%;width:calc(100% - 20px);margin-left:auto;margin-right:auto}} @@ -152,7 +152,6 @@ html,body{margin:0;padding:0;height:100%} .about_circles{display:flex;flex-direction:column} .about_circles a{margin:5px 0} .about_circles .iconbutton_light span{text-align:left} -.boxedcontent.alertbox{background-color:#F52;font-weight:bold;text-align:center} .egg_col_x5_0{fill:#eee} .egg_col_x5_1{fill:#6bcdff} .egg_col_x5_2{fill:#00a1f3} @@ -168,11 +167,23 @@ html,body{margin:0;padding:0;height:100%} .kvl_100 div span:first-child{min-width:100px} .kvl_200 div span:first-child{min-width:200px} .kvl_300 div span:first-child{min-width:300px} -.consistency_result_ok,.consistency_result_warn,.consistency_result_err{min-width:400px;color:#222;border:1px solid #888;padding:0 5px;margin:1px 0} +.consistency_result{min-width:400px;color:#222;border:1px solid #888;padding:0 5px;margin:1px 0} +.consistency_result:after{content:" "} .consistency_result_ok{background:#0f0} .consistency_result_warn{background:#ff0} .consistency_result_err{background:red} +.consistency_result_intermed{background:#eee} +.consistency_result_running{background:#ddd;border:1px solid #000} .admincontent .boxedcontent hr{width:95%;height:1px;border:0;color:#FFFFFF00;background:-moz-radial-gradient(circle,rgba(0,0,0,0.1),rgba(0,0,0,0));background:-webkit-radial-gradient(circle,rgba(0,0,0,0.1) 0,rgba(0,0,0,0) 100%)} +.admindberr{color:#b22} +.boxedcontent.alertbox{background-color:#f44;color:#222;border:1px solid #a44;font-weight:bold;text-align:center} +.boxedcontent.alertbox .bc_data{padding-top:2px;padding-bottom:2px} +.boxedcontent.warnbox{background-color:#ffa726;color:#333;border:1px solid #444;font-weight:bold;text-align:center} +.boxedcontent.warnbox .bc_data{padding-top:2px;padding-bottom:2px} +.boxedcontent.graybox{background-color:#888;color:#222;border:1px solid #444;font-weight:bold;text-align:center} +.boxedcontent.graybox .bc_data{padding-top:2px;padding-bottom:2px} +.boxedcontent.successbox{background-color:#168b00;color:#222;border:1px solid #444;font-weight:bold;text-align:center} +.boxedcontent.successbox .bc_data{padding-top:2px;padding-bottom:2px} #loginform div{display:flex;flex-direction:column} #loginform div button{margin:10px 0;padding:0} .loginerror{display:flex;background:#f44;color:#222;border:1px solid #a44;border-radius:2px;font-weight:bold;padding:0 5px;margin:5px 0 20px 0} @@ -360,10 +371,11 @@ html,body{margin:0;padding:0;height:100%} .wle_date{border-bottom:1px solid transparent;padding:2px;font-size:.8em;font-style:italic} .wle_title{font-weight:bold;font-size:1.2em;text-align:left;margin:2px 0 2px 10px} @media(max-width:767px){.wle_title{font-size:1.25em}} -.ev_master{align-self:center} +.ev_master{align-self:center;width:100%} @media(min-width:851px){.ev_master{padding-bottom:80px}} .ev_master .ev_code{color:#333;text-align:center;font-size:150pt;font-weight:500;font-family:Consolas,Monaco,"Courier New",Menlo,monospace} .ev_master .ev_msg{color:#888;text-align:center;font-size:25pt} +.ev_master .ev_statusmore{color:#333;background-color:#bbb;text-align:left;padding:4px;font-family:Consolas,Monaco,"Courier New",Menlo,monospace;font-size:small;overflow-x:auto;white-space:nowrap;width:100%} @media(max-width:767px){ .ev_master .ev_code{font-size:75pt} .ev_master .ev_msg{font-size:15pt} diff --git a/www/data/css/styles_about.scss b/www/data/css/styles_about.scss index 24a1bdb..6c6acbc 100644 --- a/www/data/css/styles_about.scss +++ b/www/data/css/styles_about.scss @@ -112,12 +112,6 @@ } -.boxedcontent.alertbox { - background-color: #F52; - font-weight: bold; - text-align: center; -} - @if $CFG_EGG_THEME == 'standard' { // ==== STANDARD ==== diff --git a/www/data/css/styles_admin.scss b/www/data/css/styles_admin.scss index 43495f4..cdc741b 100644 --- a/www/data/css/styles_admin.scss +++ b/www/data/css/styles_admin.scss @@ -41,7 +41,7 @@ .kvl_200 div span:first-child { min-width: 200px; } .kvl_300 div span:first-child { min-width: 300px; } -.consistency_result_ok, .consistency_result_warn, .consistency_result_err { +.consistency_result { min-width: 400px; color: $COL_ADMIN_STATUS_FG; border: $COL_ADMIN_STATUS_BORDER; @@ -49,9 +49,13 @@ margin: 1px 0; } -.consistency_result_ok { background: $COL_ADMIN_OK; } -.consistency_result_warn { background: $COL_ADMIN_WARN; } -.consistency_result_err { background: $COL_ADMIN_ERROR; } +.consistency_result:after { content: '\00a0' } + +.consistency_result_ok { background: $COL_ADMIN_OK; } +.consistency_result_warn { background: $COL_ADMIN_WARN; } +.consistency_result_err { background: $COL_ADMIN_ERROR; } +.consistency_result_intermed { background: $COL_ADMIN_INTERMED; } +.consistency_result_running { background: $COL_ADMIN_RUNNING; border: $COL_ADMIN_STATUS_BORDER_ACTIVE; } .admincontent .boxedcontent hr { @@ -61,4 +65,54 @@ color: $COL_TRANSPARENT; background: -moz-radial-gradient( circle, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.0)); background: -webkit-radial-gradient(circle, rgba(0, 0, 0, 0.1) 0%,rgba(0, 0, 0, 0.0) 100%); -} \ No newline at end of file +} + +.admindberr { color: $COL_ADMIN_STATUS_DB_ERROR; } + +.boxedcontent.alertbox { + background-color: $COL_TOAST_ERROR_BG; + color: $COL_TOAST_ERROR_FG; + border: $COL_TOAST_ERROR_BORDER; + font-weight: bold; + text-align: center; + .bc_data { + padding-top: 2px; + padding-bottom: 2px; + } +} + +.boxedcontent.warnbox { + background-color: $COL_TOAST_WARN_BG; + color: $COL_TOAST_WARN_FG; + border: $COL_TOAST_WARN_BORDER; + font-weight: bold; + text-align: center; + .bc_data { + padding-top: 2px; + padding-bottom: 2px; + } +} + +.boxedcontent.graybox { + background-color: $COL_TOAST_GRAY_BG; + color: $COL_TOAST_GRAY_FG; + border: $COL_TOAST_GRAY_BORDER; + font-weight: bold; + text-align: center; + .bc_data { + padding-top: 2px; + padding-bottom: 2px; + } +} + +.boxedcontent.successbox { + background-color: $COL_TOAST_SUCCESS_BG; + color: $COL_TOAST_SUCCESS_FG; + border: $COL_TOAST_SUCCESS_BORDER; + font-weight: bold; + text-align: center; + .bc_data { + padding-top: 2px; + padding-bottom: 2px; + } +} diff --git a/www/data/css/styles_config.scss b/www/data/css/styles_config.scss index 21e7ffd..8276b5e 100644 --- a/www/data/css/styles_config.scss +++ b/www/data/css/styles_config.scss @@ -115,9 +115,21 @@ $COL_FOOTER_FG: #CCCCCC; // ------------------------------------ -$COL_TOAST_ERROR_FG: #222222; -$COL_TOAST_ERROR_BG: #FF4444; -$COL_TOAST_ERROR_BORDER: 1px solid #AA4444; +$COL_TOAST_ERROR_FG: #222222; +$COL_TOAST_ERROR_BG: #FF4444; +$COL_TOAST_ERROR_BORDER: 1px solid #AA4444; + +$COL_TOAST_WARN_FG: #333333; +$COL_TOAST_WARN_BG: #FFA726; +$COL_TOAST_WARN_BORDER: $LAYER1_BORDER; + +$COL_TOAST_GRAY_FG: #222222; +$COL_TOAST_GRAY_BG: #888888; +$COL_TOAST_GRAY_BORDER: $LAYER1_BORDER; + +$COL_TOAST_SUCCESS_FG: #222222; +$COL_TOAST_SUCCESS_BG: #168B00; +$COL_TOAST_SUCCESS_BORDER: $LAYER1_BORDER; // ------------------------------------ @@ -149,12 +161,17 @@ $AOC_DESCRIPTION_BG: #333333; // ------------------------------------ -$COL_ADMIN_OK: #00FF00; -$COL_ADMIN_WARN: #FFFF00; -$COL_ADMIN_ERROR: #FF0000; +$COL_ADMIN_OK: #00FF00; +$COL_ADMIN_WARN: #FFFF00; +$COL_ADMIN_ERROR: #FF0000; +$COL_ADMIN_INTERMED: #EEEEEE; +$COL_ADMIN_RUNNING: #DDDDDD; $COL_ADMIN_STATUS_FG: #222222; $COL_ADMIN_STATUS_BORDER: 1px solid #888; +$COL_ADMIN_STATUS_BORDER_ACTIVE: 1px solid #000; + +$COL_ADMIN_STATUS_DB_ERROR: #BB2222; // ------------------------------------ ------------------------------------ diff --git a/www/data/css/styles_errorview.scss b/www/data/css/styles_errorview.scss index cf45298..38cb153 100644 --- a/www/data/css/styles_errorview.scss +++ b/www/data/css/styles_errorview.scss @@ -3,6 +3,7 @@ .ev_master { align-self: center; + width: 100%; @include rdmedia_range(2,4) {padding-bottom: 80px;} @@ -20,6 +21,20 @@ font-size: 25pt; } + .ev_statusmore { + color: $LAYER1_FG; + background-color: $LAYER1_BG_DARKER; + text-align: left; + padding: 4px; + font-family: $FONT_CODE; + font-size: small; + + overflow-x: auto; + white-space: nowrap; + + width: 100%; + } + @include rdmedia(0) { .ev_code { font-size: 75pt; } .ev_msg { font-size: 15pt; } diff --git a/www/data/javascript/admin.js b/www/data/javascript/admin.js index 0a54c76..47c5fdd 100644 --- a/www/data/javascript/admin.js +++ b/www/data/javascript/admin.js @@ -69,4 +69,51 @@ function startAjaxReplace(target, url) }, async: true }); -} \ No newline at end of file +} + +function refreshConsistencyDisplay(skip) +{ + let i = 0; + for (let apibutton of $('.consistence_ajax_handler').toArray()) + { + if (i++ !== skip) continue; + + const filter = $(apibutton).data('filter'); + + $(apibutton).removeClass('consistency_result_intermed'); + $(apibutton).addClass('consistency_result_running'); + + $.ajax('/api/site::selftest?filter=' + filter) + .done((data, status, xhr) => + { + let json = JSON.parse(data); + $(apibutton).removeClass('consistency_result_intermed'); + $(apibutton).removeClass('consistency_result_running'); + + if (json.result === 0) $(apibutton).addClass('consistency_result_ok'); + if (json.result === 1) $(apibutton).addClass('consistency_result_warn'); + if (json.result === 2) $(apibutton).addClass('consistency_result_err'); + + $(apibutton).text(json.message); + $(apibutton).attr('title', json.long); + + setTimeout(() => refreshConsistencyDisplay(skip+1), 10); + }) + .fail((xhr, status, err) => + { + $(apibutton).removeClass('consistency_result_intermed'); + $(apibutton).removeClass('consistency_result_running'); + + $(apibutton).addClass('consistency_result_err'); + $(apibutton).text(err); + + setTimeout(() => refreshConsistencyDisplay(skip+1), 10); + }); + + } +} + +$(function() +{ + setTimeout(() => refreshConsistencyDisplay(0), 200); +}); \ No newline at end of file diff --git a/www/extern/Parsedown.php b/www/extern/Parsedown.php index 757666e..1b9d6d5 100644 --- a/www/extern/Parsedown.php +++ b/www/extern/Parsedown.php @@ -17,7 +17,7 @@ class Parsedown { # ~ - const version = '1.6.0'; + const version = '1.7.4'; # ~ @@ -75,6 +75,32 @@ class Parsedown protected $urlsLinked = true; + function setSafeMode($safeMode) + { + $this->safeMode = (bool) $safeMode; + + return $this; + } + + protected $safeMode; + + protected $safeLinksWhitelist = array( + 'http://', + 'https://', + 'ftp://', + 'ftps://', + 'mailto:', + 'data:image/png;base64,', + 'data:image/gif;base64,', + 'data:image/jpeg;base64,', + 'irc:', + 'ircs:', + 'git:', + 'ssh:', + 'news:', + 'steam:', + ); + # # Lines # @@ -342,8 +368,6 @@ class Parsedown { $text = $Block['element']['text']['text']; - $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8'); - $Block['element']['text']['text'] = $text; return $Block; @@ -354,7 +378,7 @@ class Parsedown protected function blockComment($Line) { - if ($this->markupEscaped) + if ($this->markupEscaped or $this->safeMode) { return; } @@ -396,7 +420,7 @@ class Parsedown protected function blockFencedCode($Line) { - if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([\w-]+)?[ ]*$/', $Line['text'], $matches)) + if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([^`]+)?[ ]*$/', $Line['text'], $matches)) { $Element = array( 'name' => 'code', @@ -405,7 +429,21 @@ class Parsedown if (isset($matches[1])) { - $class = 'language-'.$matches[1]; + /** + * https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes + * Every HTML element may have a class attribute specified. + * The attribute, if specified, must have a value that is a set + * of space-separated tokens representing the various classes + * that the element belongs to. + * [...] + * The space characters, for the purposes of this specification, + * are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab), + * U+000A LINE FEED (LF), U+000C FORM FEED (FF), and + * U+000D CARRIAGE RETURN (CR). + */ + $language = substr($matches[1], 0, strcspn($matches[1], " \t\n\f\r")); + + $class = 'language-'.$language; $Element['attributes'] = array( 'class' => $class, @@ -457,8 +495,6 @@ class Parsedown { $text = $Block['element']['text']['text']; - $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8'); - $Block['element']['text']['text'] = $text; return $Block; @@ -515,10 +551,10 @@ class Parsedown ), ); - if($name === 'ol') + if($name === 'ol') { $listStart = stristr($matches[0], '.', true); - + if($listStart !== '1') { $Block['element']['attributes'] = array('start' => $listStart); @@ -547,6 +583,8 @@ class Parsedown { $Block['li']['text'] []= ''; + $Block['loose'] = true; + unset($Block['interrupted']); } @@ -595,6 +633,22 @@ class Parsedown } } + protected function blockListComplete(array $Block) + { + if (isset($Block['loose'])) + { + foreach ($Block['element']['text'] as &$li) + { + if (end($li['text']) !== '') + { + $li['text'] []= ''; + } + } + } + + return $Block; + } + # # Quote @@ -678,7 +732,7 @@ class Parsedown protected function blockMarkup($Line) { - if ($this->markupEscaped) + if ($this->markupEscaped or $this->safeMode) { return; } @@ -997,7 +1051,7 @@ class Parsedown # ~ # - public function line($text) + public function line($text, $nonNestables=array()) { $markup = ''; @@ -1013,6 +1067,13 @@ class Parsedown foreach ($this->InlineTypes[$marker] as $inlineType) { + # check to see if the current inline type is nestable in the current context + + if ( ! empty($nonNestables) and in_array($inlineType, $nonNestables)) + { + continue; + } + $Inline = $this->{'inline'.$inlineType}($Excerpt); if ( ! isset($Inline)) @@ -1034,6 +1095,13 @@ class Parsedown $Inline['position'] = $markerPosition; } + # cause the new element to 'inherit' our non nestables + + foreach ($nonNestables as $non_nestable) + { + $Inline['element']['nonNestables'][] = $non_nestable; + } + # the text that comes before the inline $unmarkedText = substr($text, 0, $Inline['position']); @@ -1074,7 +1142,6 @@ class Parsedown if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(? 'a', 'handler' => 'line', + 'nonNestables' => array('Url', 'Link'), 'text' => null, 'attributes' => array( 'href' => null, @@ -1253,8 +1321,6 @@ class Parsedown $Element['attributes']['title'] = $Definition['title']; } - $Element['attributes']['href'] = str_replace(array('&', '<'), array('&', '<'), $Element['attributes']['href']); - return array( 'extent' => $extent, 'element' => $Element, @@ -1263,7 +1329,7 @@ class Parsedown protected function inlineMarkup($Excerpt) { - if ($this->markupEscaped or strpos($Excerpt['text'], '>') === false) + if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false) { return; } @@ -1343,14 +1409,16 @@ class Parsedown if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE)) { + $url = $matches[0][0]; + $Inline = array( 'extent' => strlen($matches[0][0]), 'position' => $matches[0][1], 'element' => array( 'name' => 'a', - 'text' => $matches[0][0], + 'text' => $url, 'attributes' => array( - 'href' => $matches[0][0], + 'href' => $url, ), ), ); @@ -1363,7 +1431,7 @@ class Parsedown { if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w+:\/{2}[^ >]+)>/i', $Excerpt['text'], $matches)) { - $url = str_replace(array('&', '<'), array('&', '<'), $matches[1]); + $url = $matches[1]; return array( 'extent' => strlen($matches[0]), @@ -1401,6 +1469,11 @@ class Parsedown protected function element(array $Element) { + if ($this->safeMode) + { + $Element = $this->sanitiseElement($Element); + } + $markup = '<'.$Element['name']; if (isset($Element['attributes'])) @@ -1412,21 +1485,45 @@ class Parsedown continue; } - $markup .= ' '.$name.'="'.$value.'"'; + $markup .= ' '.$name.'="'.self::escape($value).'"'; } } + $permitRawHtml = false; + if (isset($Element['text'])) + { + $text = $Element['text']; + } + // very strongly consider an alternative if you're writing an + // extension + elseif (isset($Element['rawHtml'])) + { + $text = $Element['rawHtml']; + $allowRawHtmlInSafeMode = isset($Element['allowRawHtmlInSafeMode']) && $Element['allowRawHtmlInSafeMode']; + $permitRawHtml = !$this->safeMode || $allowRawHtmlInSafeMode; + } + + if (isset($text)) { $markup .= '>'; + if (!isset($Element['nonNestables'])) + { + $Element['nonNestables'] = array(); + } + if (isset($Element['handler'])) { - $markup .= $this->{$Element['handler']}($Element['text']); + $markup .= $this->{$Element['handler']}($text, $Element['nonNestables']); + } + elseif (!$permitRawHtml) + { + $markup .= self::escape($text, true); } else { - $markup .= $Element['text']; + $markup .= $text; } $markup .= ''; @@ -1485,10 +1582,77 @@ class Parsedown return $markup; } + protected function sanitiseElement(array $Element) + { + static $goodAttribute = '/^[a-zA-Z0-9][a-zA-Z0-9-_]*+$/'; + static $safeUrlNameToAtt = array( + 'a' => 'href', + 'img' => 'src', + ); + + if (isset($safeUrlNameToAtt[$Element['name']])) + { + $Element = $this->filterUnsafeUrlInAttribute($Element, $safeUrlNameToAtt[$Element['name']]); + } + + if ( ! empty($Element['attributes'])) + { + foreach ($Element['attributes'] as $att => $val) + { + # filter out badly parsed attribute + if ( ! preg_match($goodAttribute, $att)) + { + unset($Element['attributes'][$att]); + } + # dump onevent attribute + elseif (self::striAtStart($att, 'on')) + { + unset($Element['attributes'][$att]); + } + } + } + + return $Element; + } + + protected function filterUnsafeUrlInAttribute(array $Element, $attribute) + { + foreach ($this->safeLinksWhitelist as $scheme) + { + if (self::striAtStart($Element['attributes'][$attribute], $scheme)) + { + return $Element; + } + } + + $Element['attributes'][$attribute] = str_replace(':', '%3A', $Element['attributes'][$attribute]); + + return $Element; + } + # # Static Methods # + protected static function escape($text, $allowQuotes = false) + { + return htmlspecialchars($text, $allowQuotes ? ENT_NOQUOTES : ENT_QUOTES, 'UTF-8'); + } + + protected static function striAtStart($string, $needle) + { + $len = strlen($needle); + + if ($len > strlen($string)) + { + return false; + } + else + { + return strtolower(substr($string, 0, $len)) === strtolower($needle); + } + } + static function instance($name = 'default') { if (isset(self::$instances[$name])) diff --git a/www/extern/ParsedownExtra.php b/www/extern/ParsedownExtra.php index be6966d..632ba84 100644 --- a/www/extern/ParsedownExtra.php +++ b/www/extern/ParsedownExtra.php @@ -17,13 +17,13 @@ class ParsedownExtra extends Parsedown { # ~ - const version = '0.7.0'; + const version = '0.8.1'; # ~ function __construct() { - if (parent::version < '1.5.0') + if (version_compare(parent::version, '1.7.4') < 0) { throw new Exception('ParsedownExtra requires a later version of Parsedown'); } @@ -206,6 +206,10 @@ class ParsedownExtra extends Parsedown { $Block = parent::blockHeader($Line); + if (! isset($Block)) { + return null; + } + if (preg_match('/[ #]*{('.$this->regexAttribute.'+)}[ ]*$/', $Block['element']['text'], $matches, PREG_OFFSET_CAPTURE)) { $attributeString = $matches[1][0]; @@ -238,6 +242,10 @@ class ParsedownExtra extends Parsedown { $Block = parent::blockSetextHeader($Line, $Block); + if (! isset($Block)) { + return null; + } + if (preg_match('/[ ]*{('.$this->regexAttribute.'+)}[ ]*$/', $Block['element']['text'], $matches, PREG_OFFSET_CAPTURE)) { $attributeString = $matches[1][0]; @@ -302,6 +310,10 @@ class ParsedownExtra extends Parsedown { $Link = parent::inlineLink($Excerpt); + if (! isset($Link)) { + return null; + } + $remainder = substr($Excerpt['text'], $Link['extent']); if (preg_match('/^[ ]*{('.$this->regexAttribute.'+)}/', $remainder, $matches)) @@ -420,7 +432,7 @@ class ParsedownExtra extends Parsedown $Element['text'][1]['text'] []= array( 'name' => 'li', 'attributes' => array('id' => 'fn:'.$definitionId), - 'text' => "\n".$text."\n", + 'rawHtml' => "\n".$text."\n", ); } diff --git a/www/extern/egg/EGGDatabase.php b/www/extern/egg/EGGDatabase.php index 67ec66d..613d172 100644 --- a/www/extern/egg/EGGDatabase.php +++ b/www/extern/egg/EGGDatabase.php @@ -69,9 +69,7 @@ class EGGDatabase public function sql_query_assoc(string $query) { - $r = $this->pdo->query($query)->fetchAll(PDO::FETCH_ASSOC); - - return $r; + return $this->pdo->query($query)->fetchAll(PDO::FETCH_ASSOC); } public function sql_query_assoc_prep(string $query, array $params) @@ -84,9 +82,7 @@ class EGGDatabase } $stmt->execute(); - $r = $stmt->fetchAll(PDO::FETCH_ASSOC); - - return $r; + return $stmt->fetchAll(PDO::FETCH_ASSOC); } public function sql_exec_prep(string $query, array $params) diff --git a/www/extern/egg/RemoteSource.php b/www/extern/egg/RemoteSource.php index 558320d..bd58fa8 100644 --- a/www/extern/egg/RemoteSource.php +++ b/www/extern/egg/RemoteSource.php @@ -227,7 +227,7 @@ abstract class StandardGitConnection implements IRemoteSource $target = $branch->Head; $next_sha = [ $branch->HeadFromAPI ]; - $visited = [ $branch->HeadFromAPI ]; + $visited = [ ]; $json = $this->queryCommits($repo->Name, $branch->Name, $next_sha[0]); @@ -257,6 +257,7 @@ abstract class StandardGitConnection implements IRemoteSource if (count($newcommits) === 0) { $this->logger->proclog("Found no new commits for: [" . $this->name . "|" . $repo->Name . "|" . $branch->Name . "] (HEAD at {" . substr($branch->HeadFromAPI, 0, 8) . "})"); + if ($branch->HeadFromAPI !== $branch->Head) $db->setBranchHead($branch, $branch->HeadFromAPI); return []; } @@ -295,7 +296,11 @@ abstract class StandardGitConnection implements IRemoteSource $db->deleteAllCommits($branch); - if (count($newcommits) === 0) return []; + if (count($newcommits) === 0) + { + if ($branch->HeadFromAPI !== $branch->Head) $db->setBranchHead($branch, $branch->HeadFromAPI); + return []; + } $db->insertNewCommits($this->name, $repo, $branch, $newcommits); $db->setBranchHead($branch, $branch->HeadFromAPI); diff --git a/www/fragments/blogview_aoc_list.php b/www/fragments/blogview_aoc_list.php index ad487af..b5a0eb9 100644 --- a/www/fragments/blogview_aoc_list.php +++ b/www/fragments/blogview_aoc_list.php @@ -1,8 +1,17 @@ + +
- + Fork me on GitHub
@@ -21,16 +30,8 @@ $year = $post['extras']['aoc:year'];
- text(Blog::getPostFragment($post)); - ?> + renderMarkdown($SITE->modules->Blog()->getPostFragment($post)); ?>
- $year, 'nav'=>true, 'linkheader'=>false, 'ajax'=>false]; - require (__DIR__ . '/../fragments/panel_aoc_calendar.php') - ?> - + fragments->PanelAdventOfCodeCalendar($year, true, false, false); ?>
\ No newline at end of file diff --git a/www/fragments/blogview_aoc_single.php b/www/fragments/blogview_aoc_single.php index 179d668..12a37be 100644 --- a/www/fragments/blogview_aoc_single.php +++ b/www/fragments/blogview_aoc_single.php @@ -1,23 +1,28 @@ + +modules->AdventOfCode()->getDayFromStrIdent($year, $subview); +if ($day === NULL) { $FRAME_OPTIONS->forceResult(404, 'AdventOfCode entry not found'); return; } ?>
- + Fork me on GitHub
@@ -43,7 +48,7 @@ $pd = new ParsedownCustom(); Part :
-
+
modules->AdventOfCode()->getSolutionCode($day, $i-1)); ?>
Result:
@@ -51,12 +56,12 @@ $pd = new ParsedownCustom(); - - + addScript("/data/javascript/prism.js", true); ?> + addStylesheet("/data/rawcss/prism.css"); ?>
diff --git a/www/fragments/blogview_markdown.php b/www/fragments/blogview_markdown.php index 75520a2..8bfb621 100644 --- a/www/fragments/blogview_markdown.php +++ b/www/fragments/blogview_markdown.php @@ -1,7 +1,17 @@ + +
@@ -11,10 +21,7 @@ require_once (__DIR__ . '/../internals/ParsedownCustom.php');
- text(Blog::getPostFragment($post)); - ?> + renderMarkdown($SITE->modules->Blog()->getPostFragment($post)); ?>
\ No newline at end of file diff --git a/www/fragments/blogview_plain.php b/www/fragments/blogview_plain.php index 765ecfe..92d8ecb 100644 --- a/www/fragments/blogview_plain.php +++ b/www/fragments/blogview_plain.php @@ -1,6 +1,17 @@ + +
@@ -10,7 +21,7 @@ require_once (__DIR__ . '/../internals/blog.php');
- + modules->Blog()->getPostFragment($post))); ?>
\ No newline at end of file diff --git a/www/fragments/footer.php b/www/fragments/footer.php deleted file mode 100644 index 060bca4..0000000 --- a/www/fragments/footer.php +++ /dev/null @@ -1,4 +0,0 @@ -
-
- made with vanilla PHP and MySQL, no frameworks, no bootstrap, no unnecessary* javascript -
\ No newline at end of file diff --git a/www/fragments/header.php b/www/fragments/header.php deleted file mode 100644 index 98c7909..0000000 --- a/www/fragments/header.php +++ /dev/null @@ -1,19 +0,0 @@ -
-
- -
- - - -
\ No newline at end of file diff --git a/www/fragments/panel_aoc.php b/www/fragments/panel_aoc.php index ce70235..16050e8 100644 --- a/www/fragments/panel_aoc.php +++ b/www/fragments/panel_aoc.php @@ -1,22 +1,28 @@ + +modules->AdventOfCode()->listYears(); +$year = intval(end($years)); ?>
- $year, 'nav'=>true, 'linkheader'=>true, 'ajax'=>true]; - require (__DIR__ . '/../fragments/panel_aoc_calendar.php') - ?> + fragments->PanelAdventOfCodeCalendar($year, true, true, true); ?>
diff --git a/www/fragments/panel_aoc_calendar.php b/www/fragments/panel_aoc_calendar.php index da5f72c..4c1629e 100644 --- a/www/fragments/panel_aoc_calendar.php +++ b/www/fragments/panel_aoc_calendar.php @@ -1,19 +1,28 @@ -$assocdays = AdventOfCode::listSingleYearAssociative($year); -$prev_year = $shownav ? AdventOfCode::getPrevYear($year) : null; -$next_year = $shownav ? AdventOfCode::getNextYear($year) : null; +modules->AdventOfCode()->listSingleYearAssociative($year); +$prev_year = $shownav ? $SITE->modules->AdventOfCode()->getPrevYear($year) : null; +$next_year = $shownav ? $SITE->modules->AdventOfCode()->getNextYear($year) : null; + +if ($ajax) $FRAME_OPTIONS->addScript("/data/javascript/aoc_panel_interactive.js", true); ?> @@ -26,14 +35,14 @@ if ($ajax) includeAdditionalScript("/data/javascript/aoc_panel_interactive.js", if ($ajax) echo '<'; else - echo '<'; + echo '<'; } else { echo '<'; } - if ($linkheader) echo ''.$year.''; + if ($linkheader) echo ''.$year.''; else echo ''.$year.''; if ($next_year !== null) @@ -41,7 +50,7 @@ if ($ajax) includeAdditionalScript("/data/javascript/aoc_panel_interactive.js", if ($ajax) echo '>'; else - echo '>'; + echo '>'; } else { diff --git a/www/fragments/panel_blog.php b/www/fragments/panel_blog.php index a3804d6..2f4d605 100644 --- a/www/fragments/panel_blog.php +++ b/www/fragments/panel_blog.php @@ -1,7 +1,17 @@ + +modules->Blog()->listAllNewestFirst(); ?>
diff --git a/www/fragments/panel_books.php b/www/fragments/panel_books.php index 6f53726..ed3ea9c 100644 --- a/www/fragments/panel_books.php +++ b/www/fragments/panel_books.php @@ -1,7 +1,17 @@ + +modules->Books()->listAllNewestFirst(); ?>
diff --git a/www/fragments/panel_euler.php b/www/fragments/panel_euler.php index 294880d..843be72 100644 --- a/www/fragments/panel_euler.php +++ b/www/fragments/panel_euler.php @@ -1,7 +1,17 @@ + +modules->Euler()->listAll(); $RATING_CLASSES = ['euler_pnl_celltime_perfect', 'euler_pnl_celltime_good', 'euler_pnl_celltime_ok', 'euler_pnl_celltime_bad', 'euler_pnl_celltime_fail']; ?> @@ -18,7 +28,7 @@ $arr = []; $max = 0; - foreach ($euler as $problem) + foreach ($data as $problem) { $max = max($max, $problem['number']); $arr[$problem['number']] = $problem; diff --git a/www/fragments/panel_programs.php b/www/fragments/panel_programs.php index c0b15ce..ad82e36 100644 --- a/www/fragments/panel_programs.php +++ b/www/fragments/panel_programs.php @@ -1,7 +1,17 @@ + +modules->Programs()->listAllNewestFirst(); ?>
diff --git a/www/fragments/widget_befunge93.php b/www/fragments/widget_befunge93.php index 30e30da..ac7b188 100644 --- a/www/fragments/widget_befunge93.php +++ b/www/fragments/widget_befunge93.php @@ -1,15 +1,23 @@ 0) $speed_attr = ' data-b93rnr_initialspeed="'.$initspeed.'" '; $code_attr = ''; @@ -58,7 +67,7 @@ if ($interactive) { $result .= '
' . "\n"; $result .= '
' . "\n"; - includeAdditionalScript("/data/javascript/blogpost_bef93runner.js"); + $FRAME_OPTIONS->addScript("/data/javascript/blogpost_bef93runner.js", false); } else { @@ -72,4 +81,4 @@ else $result .= '
' . "\n"; } -return $result; \ No newline at end of file +echo $result; \ No newline at end of file diff --git a/www/fragments/widget_bfjoust.php b/www/fragments/widget_bfjoust.php index e50e1f3..a77a2b2 100644 --- a/www/fragments/widget_bfjoust.php +++ b/www/fragments/widget_bfjoust.php @@ -1,15 +1,25 @@ ' . "\n"; $result .= '
' . "\n"; -$result .= ' ' . "\n"; -$result .= ' ' . "\n"; +$result .= ' ' . "\n"; +$result .= ' ' . "\n"; $result .= '
' . "\n"; $result .= '
' . "\n"; @@ -35,6 +45,6 @@ $result .= '
' . "\n"; $result .= '' . "\n"; -includeAdditionalScript("/data/javascript/blogpost_BFJoustBot_script.js"); +$FRAME_OPTIONS->addScript('/data/javascript/blogpost_BFJoustBot_script.js', false); -return $result; \ No newline at end of file +echo $result; \ No newline at end of file diff --git a/www/frames/api_frame.php b/www/frames/api_frame.php new file mode 100644 index 0000000..cff59c6 --- /dev/null +++ b/www/frames/api_frame.php @@ -0,0 +1,9 @@ +raw); \ No newline at end of file diff --git a/www/frames/default_frame.php b/www/frames/default_frame.php new file mode 100644 index 0000000..9b16bbe --- /dev/null +++ b/www/frames/default_frame.php @@ -0,0 +1,69 @@ + + + + + + + + title !== '' && $FRAME_OPTIONS->title !== null) + echo '' . htmlspecialchars('Mikescher.com - ' . $FRAME_OPTIONS->title) . ''; + else if ($FRAME_OPTIONS->title === '') + echo 'Mikescher.com'; + else + echo ''; + ?> + + + canonical_url !== null) echo '' . "\n"; + foreach ($FRAME_OPTIONS->stylesheets as $cssfile) echo '' . "\n"; + foreach ($FRAME_OPTIONS->scripts as $scriptfile) + { + if ($scriptfile[1]) echo '' . "\n"; + else echo '' . "\n"; + } + ?> + + +
+ +
+
+ +
+ +
+ Home + Project Euler + Blog + Programs + Tools + isLoggedInByCookie()): ?>Admin + About +
+ isLoggedInByCookie()): ?> + Github +
+ +
+ +
+ raw; ?> +
+ +
+
+ made with vanilla PHP and MySQL, no frameworks, no bootstrap, no unnecessary* javascript +
+ +
+ + \ No newline at end of file diff --git a/www/frames/error_frame.php b/www/frames/error_frame.php new file mode 100644 index 0000000..e6f4058 --- /dev/null +++ b/www/frames/error_frame.php @@ -0,0 +1,52 @@ + + + + + + + + <?php echo ($FRAME_OPTIONS->title !== '') ? htmlspecialchars('Mikescher.com - ' . $FRAME_OPTIONS->title) : 'Mikescher.com'; ?> + + + + + +
+ +
+
+ +
+ + + +
+ +
+ raw; ?> +
+ +
+
+ made with vanilla PHP and MySQL, no frameworks, no bootstrap, no unnecessary* javascript +
+ +
+ + \ No newline at end of file diff --git a/www/frames/nocontent_frame.php b/www/frames/nocontent_frame.php new file mode 100644 index 0000000..6ba0e16 --- /dev/null +++ b/www/frames/nocontent_frame.php @@ -0,0 +1,9 @@ +init(); $URL_RULES = [ - [ 'url' => [], 'target' => 'pages/main.php', 'options' => [], ], - [ 'url' => ['index'], 'target' => 'pages/main.php', 'options' => [], ], - [ 'url' => ['index.php'], 'target' => 'pages/main.php', 'options' => [], ], - [ 'url' => ['msmain', 'index'], 'target' => 'pages/main.php', 'options' => [], ], - [ 'url' => ['about'], 'target' => 'pages/about.php', 'options' => [], ], - [ 'url' => ['msmain', 'about'], 'target' => 'pages/about.php', 'options' => [], ], - [ 'url' => ['login'], 'target' => 'pages/login.php', 'options' => [ 'login_target' => '/' ], ], - [ 'url' => ['logout'], 'target' => 'pages/logout.php', 'options' => [ 'logout_target' => '/' ], ], + [ 'url' => [], 'target' => 'main.php', 'options' => [ 'http' ], 'parameter' => [ ], ], + [ 'url' => ['index'], 'target' => 'main.php', 'options' => [ 'http' ], 'parameter' => [ ], ], + [ 'url' => ['index.php'], 'target' => 'main.php', 'options' => [ 'http' ], 'parameter' => [ ], ], + [ 'url' => ['msmain', 'index'], 'target' => 'main.php', 'options' => [ 'http' ], 'parameter' => [ ], ], + [ 'url' => ['about'], 'target' => 'about.php', 'options' => [ 'http' ], 'parameter' => [ ], ], + [ 'url' => ['msmain', 'about'], 'target' => 'about.php', 'options' => [ 'http' ], 'parameter' => [ ], ], + [ 'url' => ['login'], 'target' => 'login.php', 'options' => [ 'http' ], 'parameter' => [ 'login_target' => '/' ], ], + [ 'url' => ['logout'], 'target' => 'logout.php', 'options' => [ 'http' ], 'parameter' => [ 'logout_target' => '/' ], ], - [ 'url' => ['programs'], 'target' => 'pages/programs_list.php', 'options' => [ 'categoryfilter' => '' ], ], - [ 'url' => ['programs', 'index'], 'target' => 'pages/programs_list.php', 'options' => [ 'categoryfilter' => '%GET%' ], ], - [ 'url' => ['programs', 'index'], 'target' => 'pages/programs_list.php', 'options' => [ 'categoryfilter' => '' ], ], - [ 'url' => ['programs', 'cat', '?{categoryfilter}'], 'target' => 'pages/programs_list.php', 'options' => [ 'categoryfilter' => '%URL%' ], ], - [ 'url' => ['downloads', 'details.php'], 'target' => 'pages/programs_list.php', 'options' => [ 'categoryfilter' => '' ], ], - [ 'url' => ['downloads', 'downloads.php'], 'target' => 'pages/programs_list.php', 'options' => [ 'categoryfilter' => '' ], ], - [ 'url' => ['programs', 'view', '?{id}'], 'target' => 'pages/programs_view.php', 'options' => [ 'id' => '%URL%' ], ], - [ 'url' => ['programs', 'view'], 'target' => 'pages/programs_view.php', 'options' => [ 'id' => '%GET%' ], ], - [ 'url' => ['downloads', '?{id}'], 'target' => 'pages/programs_download.php', 'options' => [ 'id' => '%URL%' ], ], - [ 'url' => ['programs', 'download', '?{id}'], 'target' => 'pages/programs_download.php', 'options' => [ 'id' => '%URL%' ], ], - [ 'url' => ['programs', 'download'], 'target' => 'pages/programs_download.php', 'options' => [ 'id' => '%GET%' ], ], + [ 'url' => ['programs'], 'target' => 'programs_list.php', 'options' => [ 'http' ], 'parameter' => [ 'categoryfilter' => '' ], ], + [ 'url' => ['programs', 'index'], 'target' => 'programs_list.php', 'options' => [ 'http' ], 'parameter' => [ 'categoryfilter' => '%GET%' ], ], + [ 'url' => ['programs', 'index'], 'target' => 'programs_list.php', 'options' => [ 'http' ], 'parameter' => [ 'categoryfilter' => '' ], ], + [ 'url' => ['programs', 'cat', '?{categoryfilter}'], 'target' => 'programs_list.php', 'options' => [ 'http' ], 'parameter' => [ 'categoryfilter' => '%URL%' ], ], + [ 'url' => ['downloads', 'details.php'], 'target' => 'programs_list.php', 'options' => [ 'http' ], 'parameter' => [ 'categoryfilter' => '' ], ], + [ 'url' => ['downloads', 'downloads.php'], 'target' => 'programs_list.php', 'options' => [ 'http' ], 'parameter' => [ 'categoryfilter' => '' ], ], + [ 'url' => ['programs', 'view', '?{id}'], 'target' => 'programs_view.php', 'options' => [ 'http' ], 'parameter' => [ 'id' => '%URL%' ], ], + [ 'url' => ['programs', 'view'], 'target' => 'programs_view.php', 'options' => [ 'http' ], 'parameter' => [ 'id' => '%GET%' ], ], + [ 'url' => ['downloads', '?{id}'], 'target' => 'programs_download.php', 'options' => [ 'http' ], 'parameter' => [ 'id' => '%URL%' ], ], + [ 'url' => ['programs', 'download', '?{id}'], 'target' => 'programs_download.php', 'options' => [ 'http' ], 'parameter' => [ 'id' => '%URL%' ], ], + [ 'url' => ['programs', 'download'], 'target' => 'programs_download.php', 'options' => [ 'http' ], 'parameter' => [ 'id' => '%GET%' ], ], - [ 'url' => ['books'], 'target' => 'pages/books_list.php', 'options' => [], ], - [ 'url' => ['books', 'list'], 'target' => 'pages/books_list.php', 'options' => [], ], - [ 'url' => ['books', 'view', '?{id}'], 'target' => 'pages/books_view.php', 'options' => [ 'id' => '%GET%' ], ], - [ 'url' => ['books', 'view', '?{id}', '*'], 'target' => 'pages/books_view.php', 'options' => [ 'id' => '%URL%' ], ], + [ 'url' => ['books'], 'target' => 'books_list.php', 'options' => [ 'http' ], 'parameter' => [ ], ], + [ 'url' => ['books', 'list'], 'target' => 'books_list.php', 'options' => [ 'http' ], 'parameter' => [ ], ], + [ 'url' => ['books', 'view', '?{id}'], 'target' => 'books_view.php', 'options' => [ 'http' ], 'parameter' => [ 'id' => '%GET%' ], ], + [ 'url' => ['books', 'view', '?{id}', '*'], 'target' => 'books_view.php', 'options' => [ 'http' ], 'parameter' => [ 'id' => '%URL%' ], ], - [ 'url' => ['update.php'], 'target' => 'pages/api.php', 'options' => [ '_opt' => 'http', 'cmd' => 'progs::updatecheck' ], ], - [ 'url' => ['update.php', '?{Name}'], 'target' => 'pages/api.php', 'options' => [ '_opt' => 'http', 'cmd' => 'progs::updatecheck' ], ], - [ 'url' => ['update'], 'target' => 'pages/api.php', 'options' => [ '_opt' => 'http', 'cmd' => 'progs::updatecheck' ], ], - [ 'url' => ['update', '?{Name}'], 'target' => 'pages/api.php', 'options' => [ '_opt' => 'http', 'cmd' => 'progs::updatecheck' ], ], - [ 'url' => ['update2'], 'target' => 'pages/api.php', 'options' => [ '_opt' => 'http', 'cmd' => 'progs::updatecheck' ], ], - [ 'url' => ['api', 'update'], 'target' => 'pages/api.php', 'options' => [ '_opt' => 'http', 'cmd' => 'progs::updatecheck' ], ], - [ 'url' => ['api', 'update', '?{Name}'], 'target' => 'pages/api.php', 'options' => [ '_opt' => 'http', 'cmd' => 'progs::updatecheck' ], ], - [ 'url' => ['api', 'test'], 'target' => 'pages/api.php', 'options' => [ '_opt' => 'http', 'cmd' => 'base::test' ], ], - [ 'url' => ['api', 'setselfadress'], 'target' => 'pages/api.php', 'options' => [ '_opt' => 'http', 'cmd' => 'server::setselfaddress' ], ], - [ 'url' => ['api', 'statsping'], 'target' => 'pages/api.php', 'options' => [ '_opt' => 'http', 'cmd' => 'alephnote::statsping' ], ], - [ 'url' => ['api', 'webhook', '?{target}'], 'target' => 'pages/api.php', 'options' => [ '_opt' => 'http', 'cmd' => 'server::gitwebhook' ], ], - [ 'url' => ['api', 'backupupload'], 'target' => 'pages/api.php', 'options' => [ '_opt' => 'http', 'cmd' => 'server::backupupload' ], ], - [ 'url' => ['api', '?{cmd}'], 'target' => 'pages/api.php', 'options' => [ 'cmd' => '%URL%' ], ], + [ 'url' => ['update.php'], 'target' => 'api.php', 'options' => [ 'http', 'api' ], 'parameter' => [ 'cmd' => 'progs::updatecheck' ], ], + [ 'url' => ['update.php', '?{Name}'], 'target' => 'api.php', 'options' => [ 'http', 'api' ], 'parameter' => [ 'cmd' => 'progs::updatecheck' ], ], + [ 'url' => ['update'], 'target' => 'api.php', 'options' => [ 'http', 'api' ], 'parameter' => [ 'cmd' => 'progs::updatecheck' ], ], + [ 'url' => ['update', '?{Name}'], 'target' => 'api.php', 'options' => [ 'http', 'api' ], 'parameter' => [ 'cmd' => 'progs::updatecheck' ], ], + [ 'url' => ['update2'], 'target' => 'api.php', 'options' => [ 'http', 'api' ], 'parameter' => [ 'cmd' => 'progs::updatecheck' ], ], + [ 'url' => ['api', 'update'], 'target' => 'api.php', 'options' => [ 'http', 'api' ], 'parameter' => [ 'cmd' => 'progs::updatecheck' ], ], + [ 'url' => ['api', 'update', '?{Name}'], 'target' => 'api.php', 'options' => [ 'http', 'api' ], 'parameter' => [ 'cmd' => 'progs::updatecheck' ], ], + [ 'url' => ['api', 'test'], 'target' => 'api.php', 'options' => [ 'http', 'api' ], 'parameter' => [ 'cmd' => 'base::test' ], ], + [ 'url' => ['api', 'setselfadress'], 'target' => 'api.php', 'options' => [ 'http', 'api' ], 'parameter' => [ 'cmd' => 'server::setselfaddress' ], ], + [ 'url' => ['api', 'statsping'], 'target' => 'api.php', 'options' => [ 'http', 'api' ], 'parameter' => [ 'cmd' => 'alephnote::statsping' ], ], + [ 'url' => ['api', 'webhook', '?{target}'], 'target' => 'api.php', 'options' => [ 'http', 'api' ], 'parameter' => [ 'cmd' => 'server::gitwebhook' ], ], + [ 'url' => ['api', 'backupupload'], 'target' => 'api.php', 'options' => [ 'http', 'api' ], 'parameter' => [ 'cmd' => 'server::backupupload' ], ], + [ 'url' => ['api', '?{cmd}'], 'target' => 'api.php', 'options' => [ 'api' ], 'parameter' => [ 'cmd' => '%URL%' ], ], - [ 'url' => ['admin'], 'target' => 'pages/admin.php', 'options' => [ '_opt' => 'password'], ], + [ 'url' => ['admin'], 'target' => 'admin.php', 'options' => [ 'password' ], 'parameter' => [ ] ], - [ 'url' => ['blog'], 'target' => 'pages/blog_list.php', 'options' => [], ], - [ 'url' => ['log'], 'target' => 'pages/blog_list.php', 'options' => [], ], - [ 'url' => ['blogpost', 'index'], 'target' => 'pages/blog_list.php', 'options' => [], ], - [ 'url' => ['blog', '?{id}'], 'target' => 'pages/blog_view.php', 'options' => [ 'id' => '%URL%', 'subview' => '' ], ], - [ 'url' => ['blog', '?{id}'], 'target' => 'pages/blog_view.php', 'options' => [ 'id' => '%URL%', 'subview' => '' ], ], - [ 'url' => ['blog', '?{id}', '?{name}'], 'target' => 'pages/blog_view.php', 'options' => [ 'id' => '%URL%', 'subview' => '' ], ], - [ 'url' => ['blog', '?{id}', '?{name}', '?{subview}'], 'target' => 'pages/blog_view.php', 'options' => [ 'id' => '%URL%', 'subview' => '%URL%' ], ], - [ 'url' => ['log', '?{id}'], 'target' => 'pages/blog_view.php', 'options' => [ 'id' => '%URL%', 'subview' => '' ], ], - [ 'url' => ['log', '?{id}'], 'target' => 'pages/blog_view.php', 'options' => [ 'id' => '%URL%', 'subview' => '' ], ], - [ 'url' => ['log', '?{id}', '?{name}'], 'target' => 'pages/blog_view.php', 'options' => [ 'id' => '%URL%', 'subview' => '' ], ], - [ 'url' => ['log', '?{id}', '?{name}', '?{subview}'], 'target' => 'pages/blog_view.php', 'options' => [ 'id' => '%URL%', 'subview' => '%URL%' ], ], - [ 'url' => ['blogpost', 'view'], 'target' => 'pages/blog_view.php', 'options' => [ 'id' => '%GET%', 'subview' => '' ], ], + [ 'url' => ['blog'], 'target' => 'blog_list.php', 'options' => [ ], 'parameter' => [ ], ], + [ 'url' => ['log'], 'target' => 'blog_list.php', 'options' => [ ], 'parameter' => [ ], ], + [ 'url' => ['blogpost', 'index'], 'target' => 'blog_list.php', 'options' => [ ], 'parameter' => [ ], ], + [ 'url' => ['blog', '?{id}'], 'target' => 'blog_view.php', 'options' => [ ], 'parameter' => [ 'id' => '%URL%', 'subview' => '' ], ], + [ 'url' => ['blog', '?{id}', '?{name}'], 'target' => 'blog_view.php', 'options' => [ ], 'parameter' => [ 'id' => '%URL%', 'subview' => '' ], ], + [ 'url' => ['blog', '?{id}', '?{name}', '?{subview}'], 'target' => 'blog_view.php', 'options' => [ ], 'parameter' => [ 'id' => '%URL%', 'subview' => '%URL%' ], ], + [ 'url' => ['log', '?{id}'], 'target' => 'blog_view.php', 'options' => [ ], 'parameter' => [ 'id' => '%URL%', 'subview' => '' ], ], + [ 'url' => ['log', '?{id}', '?{name}'], 'target' => 'blog_view.php', 'options' => [ ], 'parameter' => [ 'id' => '%URL%', 'subview' => '' ], ], + [ 'url' => ['log', '?{id}', '?{name}', '?{subview}'], 'target' => 'blog_view.php', 'options' => [ ], 'parameter' => [ 'id' => '%URL%', 'subview' => '%URL%' ], ], + [ 'url' => ['blogpost', 'view'], 'target' => 'blog_view.php', 'options' => [ ], 'parameter' => [ 'id' => '%GET%', 'subview' => '' ], ], - [ 'url' => ['webapps'], 'target' => 'pages/webapps_list.php', 'options' => [], ], + [ 'url' => ['webapps'], 'target' => 'webapps_list.php', 'options' => [ ], 'parameter' => [ ], ], - [ 'url' => ['highscores', 'list.php'], 'target' => 'pages/highscores_listentries.php', 'options' => [ '_opt' => 'http', 'gameid' => '%GET%' ], ], - [ 'url' => ['highscores', 'list'], 'target' => 'pages/highscores_listentries.php', 'options' => [ '_opt' => 'http', 'gameid' => '%GET%' ], ], - [ 'url' => ['highscores', 'listentries'], 'target' => 'pages/highscores_listentries.php', 'options' => [ '_opt' => 'http', 'gameid' => '%GET%' ], ], - [ 'url' => ['highscores', 'list.php'], 'target' => 'pages/highscores_listgames.php', 'options' => [ '_opt' => 'http' ], ], - [ 'url' => ['highscores', 'list'], 'target' => 'pages/highscores_listgames.php', 'options' => [ '_opt' => 'http' ], ], - [ 'url' => ['highscores', 'listgames'], 'target' => 'pages/highscores_listgames.php', 'options' => [ '_opt' => 'http' ], ], - [ 'url' => ['highscores', 'insert.php'], 'target' => 'pages/highscores_insert.php', 'options' => [ '_opt' => 'http', 'gameid' => '%GET%', 'check' => '%GET%', 'name' => '%GET%', 'rand' => '%GET%', 'points' => '%GET%' ], ], - [ 'url' => ['highscores', 'insert'], 'target' => 'pages/highscores_insert.php', 'options' => [ '_opt' => 'http', 'gameid' => '%GET%', 'check' => '%GET%', 'name' => '%GET%', 'rand' => '%GET%', 'points' => '%GET%' ], ], - [ 'url' => ['highscores', 'update.php'], 'target' => 'pages/highscores_update.php', 'options' => [ '_opt' => 'http', 'gameid' => '%GET%', 'check' => '%GET%', 'name' => '%GET%', 'rand' => '%GET%', 'points' => '%GET%', 'nameid' => '%GET%' ], ], - [ 'url' => ['highscores', 'update'], 'target' => 'pages/highscores_update.php', 'options' => [ '_opt' => 'http', 'gameid' => '%GET%', 'check' => '%GET%', 'name' => '%GET%', 'rand' => '%GET%', 'points' => '%GET%', 'nameid' => '%GET%' ], ], - [ 'url' => ['highscores', 'list_top50.php'], 'target' => 'pages/highscores_top50.php', 'options' => [ '_opt' => 'http', 'gameid' => '%GET%' ], ], - [ 'url' => ['highscores', 'list_top50'], 'target' => 'pages/highscores_top50.php', 'options' => [ '_opt' => 'http', 'gameid' => '%GET%' ], ], - [ 'url' => ['highscores', 'getNewID.php'], 'target' => 'pages/highscores_newid.php', 'options' => [ '_opt' => 'http', 'gameid' => '%GET%' ], ], - [ 'url' => ['highscores', 'newid'], 'target' => 'pages/highscores_newid.php', 'options' => [ '_opt' => 'http', 'gameid' => '%GET%' ], ], - - [ 'url' => ['404'], 'target' => 'pages/error_404.php', 'options' => [], ], + [ 'url' => ['highscores', 'list.php'], 'target' => 'highscores_listentries.php', 'options' => [ 'http' ], 'parameter' => [ 'gameid' => '%GET%' ], ], + [ 'url' => ['highscores', 'list'], 'target' => 'highscores_listentries.php', 'options' => [ 'http' ], 'parameter' => [ 'gameid' => '%GET%' ], ], + [ 'url' => ['highscores', 'listentries'], 'target' => 'highscores_listentries.php', 'options' => [ 'http' ], 'parameter' => [ 'gameid' => '%GET%' ], ], + [ 'url' => ['highscores', 'list.php'], 'target' => 'highscores_listgames.php', 'options' => [ 'http' ], 'parameter' => [ ], ], + [ 'url' => ['highscores', 'list'], 'target' => 'highscores_listgames.php', 'options' => [ 'http' ], 'parameter' => [ ], ], + [ 'url' => ['highscores', 'listgames'], 'target' => 'highscores_listgames.php', 'options' => [ 'http' ], 'parameter' => [ ], ], + [ 'url' => ['highscores', 'insert.php'], 'target' => 'highscores_insert.php', 'options' => [ 'http' ], 'parameter' => [ 'gameid' => '%GET%', 'check' => '%GET%', 'name' => '%GET%', 'rand' => '%GET%', 'points' => '%GET%' ], ], + [ 'url' => ['highscores', 'insert'], 'target' => 'highscores_insert.php', 'options' => [ 'http' ], 'parameter' => [ 'gameid' => '%GET%', 'check' => '%GET%', 'name' => '%GET%', 'rand' => '%GET%', 'points' => '%GET%' ], ], + [ 'url' => ['highscores', 'update.php'], 'target' => 'highscores_update.php', 'options' => [ 'http' ], 'parameter' => [ 'gameid' => '%GET%', 'check' => '%GET%', 'name' => '%GET%', 'rand' => '%GET%', 'points' => '%GET%', 'nameid' => '%GET%' ], ], + [ 'url' => ['highscores', 'update'], 'target' => 'highscores_update.php', 'options' => [ 'http' ], 'parameter' => [ 'gameid' => '%GET%', 'check' => '%GET%', 'name' => '%GET%', 'rand' => '%GET%', 'points' => '%GET%', 'nameid' => '%GET%' ], ], + [ 'url' => ['highscores', 'list_top50.php'], 'target' => 'highscores_top50.php', 'options' => [ 'http' ], 'parameter' => [ 'gameid' => '%GET%' ], ], + [ 'url' => ['highscores', 'list_top50'], 'target' => 'highscores_top50.php', 'options' => [ 'http' ], 'parameter' => [ 'gameid' => '%GET%' ], ], + [ 'url' => ['highscores', 'getNewID.php'], 'target' => 'highscores_newid.php', 'options' => [ 'http' ], 'parameter' => [ 'gameid' => '%GET%' ], ], + [ 'url' => ['highscores', 'newid'], 'target' => 'highscores_newid.php', 'options' => [ 'http' ], 'parameter' => [ 'gameid' => '%GET%' ], ], ]; -//############################################################################# +$site->serve($URL_RULES); -try { - InitPHP(); - - if (isProd()) - $requri = $_SERVER['REQUEST_URI']; - else - $requri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : 'localhost:80/'; - - $parse = parse_url($requri); - - $path = isset($parse['path']) ? $parse['path'] : ''; - $pathparts = preg_split('@/@', $path, NULL, PREG_SPLIT_NO_EMPTY); - $partcount = count($pathparts); - - global $OPTIONS; - global $HEADER_ACTIVE; - - $HEADER_ACTIVE = 'none'; - - foreach ($URL_RULES as $rule) - { - if ($partcount !== count($rule['url'])) continue; - - $urlparams = []; - $ctrlOpt = key_exists('_opt', $rule['options']) ? explode('|', $rule['options']['_opt']) : []; - $target = $rule['target']; - - $match = true; - for($i = 0; $i < $partcount; $i++) - { - $comp = $rule['url'][$i]; - if (startsWith($comp, '?{') && endsWith($comp, '}')) - { - $ident = substr($comp, 2, strlen($comp)-3); - $urlparams[$ident] = $pathparts[$i]; - } - else if ($comp === '*') - { - // ok - } - else - { - if (strtolower($comp) !== strtolower($pathparts[$i])) { $match = false; break; } - } - } - if (!$match) continue; - - $opt = [ 'controllerOptions' => $ctrlOpt, 'uri' => $requri ]; - foreach($rule['options'] as $optname => $optvalue) - { - $value = $optvalue; - - if ($value === '%GET%') - { - if (!isset($_GET[$optname])) { $match = false; break; } - $value = $_GET[$optname]; - } - else if ($value === '%POST%') - { - if (!isset($_POST[$optname])) { $match = false; break; } - $value = $_POST[$optname]; - } - else if ($value === '%URL%') - { - if (!isset($urlparams[$optname])) { $match = false; break; } - $value = urldecode($urlparams[$optname]); - } - - $opt[strtolower($optname)] = $value; - } - - $opt['_urlparams'] = []; - foreach ($urlparams as $name => $value) $opt['_urlparams'][strtolower($name)] = urldecode($value); - - if (!$match) continue; - - if (in_array('disabled', $ctrlOpt)) continue; - - if (in_array('password', $ctrlOpt)) - { - if (!isLoggedInByCookie()) - { - $opt['login_target'] = $path; - $target = 'pages/login.php'; - } - } - - $is_http = (!isset($_SERVER['HTTPS'])) || empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == "off"; - - if (isProd() && $is_http && !in_array('http', $ctrlOpt)) - { - ob_clean(); - $redirect = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; - header('HTTP/1.1 301 Moved Permanently'); - header('Location: ' . $redirect); - exit(); - } - - $OPTIONS = $opt; - - /** @noinspection PhpIncludeInspection */ - include $target; - return; - - } - - { - // [404] - Page Not Found - $OPTIONS = []; - httpError('404', 'Page not found'); - return; - } - -} catch (Exception $e) { - - if (isProd()) - { - sendExceptionMail($e); - httpError('500 ', 'Internal server error'); - } - else - { - if (isset($e->xdebug_message)) echo '
'.$e->xdebug_message.'
'; - else echo nl2br($e); - } - -} //TODO euler insert+show 32bit | 64bit mode //TODO support for different color schemes diff --git a/www/internals/.gitignore b/www/internals/.gitignore deleted file mode 100644 index 4e9b47a..0000000 --- a/www/internals/.gitignore +++ /dev/null @@ -1 +0,0 @@ -config.php \ No newline at end of file diff --git a/www/internals/alephnoteStatistics.php b/www/internals/alephnoteStatistics.php deleted file mode 100644 index 7fb6749..0000000 --- a/www/internals/alephnoteStatistics.php +++ /dev/null @@ -1,26 +0,0 @@ -0'); - } - - public static function getUserCountFromLastVersion() - { - return Database::sql_query_num('SELECT COUNT(*) FROM an_statslog WHERE NoteCount>0 GROUP BY Version ORDER BY INET_ATON(Version) DESC LIMIT 1'); - } - - public static function getActiveUserCount($days) - { - return Database::sql_query_num('SELECT COUNT(*) FROM an_statslog WHERE NoteCount>0 AND LastChanged > NOW() - INTERVAL '.$days.' DAY'); - } - - public static function getAllActiveEntriesOrdered() - { - return Database::sql_query_assoc('SELECT * FROM an_statslog WHERE NoteCount>0 ORDER BY LastChanged DESC'); - } -} \ No newline at end of file diff --git a/www/internals/base.php b/www/internals/base.php deleted file mode 100644 index 52d2eee..0000000 --- a/www/internals/base.php +++ /dev/null @@ -1,422 +0,0 @@ - $errorcode, 'message' => $message ]; - require (__DIR__ . '/../pages/errorview.php'); - die(); -} - -function httpDie($errorcode, $message) -{ - ob_flush(); - http_response_code($errorcode); - die($message); - -} - -function destructiveUrlEncode($str) { - $str = str_replace(' ', '_', $str); - $str = str_replace('+', '_', $str); - $str = str_replace(':', '_', $str); - $str = str_replace('.', '', $str); - return urlencode($str); -} - -function formatMilliseconds($millis) -{ - if ($millis < 1000) - { - return $millis . 'ms'; - } - else if ($millis < 10 * 1000) - { - return number_format($millis / (1000), 2) . 's'; - } - else if ($millis < 60 * 1000) - { - return floor($millis / (1000)) . 's'; - } - else if ($millis < 10 * 60 * 1000) - { - return floor($millis / (60 * 1000)) . 'min ' . floor(($millis % (60 * 1000)) / 1000) . 's'; - } - else if ($millis < 60 * 60 * 1000) - { - return floor($millis / (60 * 1000)) . 'min'; - } - else if ($millis < 10 * 60 * 60 * 1000) - { - return number_format($millis / (60 * 60 * 1000), 2) . ' hours'; - } - else - { - return floor($millis / (60 * 60 * 1000)) . ' hours'; - } -} - -function includeAdditionalScript($script, $attr='', $printImmediately = false) { - global $ADDITIONAL_SCRIPTS; - - if (in_array($script, $ADDITIONAL_SCRIPTS)) return false; - - if ($printImmediately) { - $ADDITIONAL_SCRIPTS[$script] = ['src' => $script, 'attr' => $attr, 'consumed' => true]; - echo ''; - return true; - } else { - $ADDITIONAL_SCRIPTS[$script] = ['src' => $script, 'attr' => $attr, 'consumed' => false]; - return true; - } -} - -function includeAdditionalStylesheet($sheet, $attr='', $printImmediately = false) { - global $ADDITIONAL_STYLESHEETS; - - if (in_array($sheet, $ADDITIONAL_STYLESHEETS)) return false; - - if ($printImmediately) { - $ADDITIONAL_STYLESHEETS[$sheet] = ['src' => $sheet, 'attr' => $attr, 'consumed' => true]; - echo ''; - return true; - } else { - $ADDITIONAL_STYLESHEETS[$sheet] = ['src' => $sheet, 'attr' => $attr, 'consumed' => false]; - return true; - } -} - -function printHeaderCSS() { - global $CSS_BASE; - includeAdditionalStylesheet($CSS_BASE, '', true); -} - -function printAdditionalScripts() { - global $ADDITIONAL_SCRIPTS; - - foreach ($ADDITIONAL_SCRIPTS as $d) { - if ($d['consumed']) continue; - echo ''; - $d['consumed'] = true; - } -} - -function printAdditionalStylesheets() { - global $ADDITIONAL_STYLESHEETS; - - foreach ($ADDITIONAL_STYLESHEETS as $d) { - if ($d['consumed']) continue; - echo ''; - $d['consumed'] = true; - } -} - -function isProd() { - global $CONFIG; - return $CONFIG['prod']; -} - -function convertCountryToFlag($country) { - $country = trim(strtolower($country)); - - if ($country === 'italy') return '/data/images/flags/013-italy.svg'; - if ($country === 'china') return '/data/images/flags/034-china.svg'; - if ($country === 'japan') return '/data/images/flags/063-japan.svg'; - if ($country === 'un') return '/data/images/flags/082-united-nations.svg'; - if ($country === 'south korea') return '/data/images/flags/094-south-korea.svg'; - if ($country === 'spain') return '/data/images/flags/128-spain.svg'; - if ($country === 'norway') return '/data/images/flags/143-norway.svg'; - if ($country === 'Czech') return '/data/images/flags/149-czech-republic.svg'; - if ($country === 'germany') return '/data/images/flags/162-germany.svg'; - if ($country === 'sweden') return '/data/images/flags/184-sweden.svg'; - if ($country === 'france') return '/data/images/flags/195-france.svg'; - if ($country === 'switzerland') return '/data/images/flags/205-switzerland.svg'; - if ($country === 'england') return '/data/images/flags/216-england.svg'; - if ($country === 'usa') return '/data/images/flags/226-united-states.svg'; - if ($country === 'america') return '/data/images/flags/226-united-states.svg'; - if ($country === 'canada') return '/data/images/flags/243-canada.svg'; - if ($country === 'russia') return '/data/images/flags/248-russia.svg'; - if ($country === 'eu') return '/data/images/flags/259-european-union.svg'; - if ($country === 'uk') return '/data/images/flags/260-united-kingdom.svg'; - - return null; -} - -function convertLanguageToFlag($lang) { - $lang = trim(strtolower($lang)); - - if ($lang === 'italian') return '/data/images/flags/013-italy.svg'; - if ($lang === 'english') return '/data/images/flags/226-united-states.svg'; - if ($lang === 'french') return '/data/images/flags/195-france.svg'; - if ($lang === 'german') return '/data/images/flags/162-germany.svg'; - if ($lang === 'spanish') return '/data/images/flags/128-spain.svg'; - - return null; -} - -function setLoginCookie($user, $pass) -{ - $expires = time() + (24*60*60); // 24h - $hash = hash('sha256', $user . ';' . $pass . ';' . gmdate('Y-m-d')); - setcookie('mikescher_auth', $hash, $expires); -} - -function isLoggedInByCookie() -{ - static $_loginCache = null; - if ($_loginCache !== null) return $_loginCache; - - global $CONFIG; - if (key_exists('mikescher_auth', $_COOKIE)) - { - if (strlen($_COOKIE['mikescher_auth']) !== 64) return $_loginCache = false; - $auth = hash('sha256', $CONFIG['admin_username'] . ';' . $CONFIG['admin_password'] . ';' . gmdate('Y-m-d')); - if ($auth === $_COOKIE['mikescher_auth']) return $_loginCache = true; - } - - return $_loginCache = false; -} - -function clearLoginCookie() -{ - setcookie("mikescher_auth", "", time()+30); -} - -/** - * easy image resize function - * @author http://www.nimrodstech.com/php-image-resize/ - * @param string $file - file name to resize - * @param int $width - new image width - * @param int $height - new image height - * @param boolean $proportional - keep image proportional, default is no - * @param string $output - name of the new file (include path if needed) - * @return boolean|resource - */ -function smart_resize_image($file, $width = 0, $height = 0, $proportional, $output) -{ - if ( $height <= 0 && $width <= 0 ) return false; - if ( $file === null) return false; - - # Setting defaults and meta - $info = getimagesize($file); - $image = ''; - $final_width = 0; - $final_height = 0; - list($width_old, $height_old) = $info; - $cropHeight = $cropWidth = 0; - - # Calculating proportionality - if ($proportional) { - if ($width == 0) $factor = $height/$height_old; - elseif ($height == 0) $factor = $width/$width_old; - else $factor = min( $width / $width_old, $height / $height_old ); - - $final_width = round( $width_old * $factor ); - $final_height = round( $height_old * $factor ); - } - else { - $final_width = ( $width <= 0 ) ? $width_old : $width; - $final_height = ( $height <= 0 ) ? $height_old : $height; - $widthX = $width_old / $width; - $heightX = $height_old / $height; - - $x = min($widthX, $heightX); - $cropWidth = ($width_old - $width * $x) / 2; - $cropHeight = ($height_old - $height * $x) / 2; - } - - # Loading image to memory according to type - switch ( $info[2] ) { - case IMAGETYPE_JPEG: $image = imagecreatefromjpeg($file); break; - case IMAGETYPE_GIF: $image = imagecreatefromgif($file); break; - case IMAGETYPE_PNG: $image = imagecreatefrompng($file); break; - default: return false; - } - - - # This is the resizing/resampling/transparency-preserving magic - $image_resized = imagecreatetruecolor( $final_width, $final_height ); - if ( ($info[2] == IMAGETYPE_GIF) || ($info[2] == IMAGETYPE_PNG) ) { - $transparency = imagecolortransparent($image); - $palletsize = imagecolorstotal($image); - - if ($transparency >= 0 && $transparency < $palletsize) { - $transparent_color = imagecolorsforindex($image, $transparency); - $transparency = imagecolorallocate($image_resized, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']); - imagefill($image_resized, 0, 0, $transparency); - imagecolortransparent($image_resized, $transparency); - } - elseif ($info[2] == IMAGETYPE_PNG) { - imagealphablending($image_resized, false); - $color = imagecolorallocatealpha($image_resized, 0, 0, 0, 127); - imagefill($image_resized, 0, 0, $color); - imagesavealpha($image_resized, true); - } - } - imagecopyresampled($image_resized, $image, 0, 0, $cropWidth, $cropHeight, $final_width, $final_height, $width_old - 2 * $cropWidth, $height_old - 2 * $cropHeight); - - # Preparing a method of providing result - switch ( strtolower($output) ) { - case 'browser': - $mime = image_type_to_mime_type($info[2]); - header("Content-type: $mime"); - $output = NULL; - break; - case 'file': - $output = $file; - break; - case 'return': - return $image_resized; - break; - default: - break; - } - - # Writing image according to type to the output destination and image quality - switch ( $info[2] ) { - case IMAGETYPE_GIF: imagegif($image_resized, $output); break; - case IMAGETYPE_JPEG: imagejpeg($image_resized, $output, 100); break; - case IMAGETYPE_PNG: - $quality = 9 - (int)((0.9*100)/10.0); - imagepng($image_resized, $output, $quality); - break; - default: return false; - } - - return true; -} - -/** - * @param string $file - file name to resize - * @param int $width - new image width - * @param int $height - new image height - * @param string $output - name of the new file (include path if needed) - */ -function magick_resize_image($file, $width, $height, $output) -{ - list($width_old, $height_old) = getimagesize($file); - - if ($width == 0) $factor = $height/$height_old; - elseif ($height == 0) $factor = $width/$width_old; - else $factor = min( $width / $width_old, $height / $height_old ); - - $final_width = round( $width_old * $factor ); - $final_height = round( $height_old * $factor ); - - $cmd = 'convert "' . $file . '" -strip -resize ' . $final_width . 'x' . $final_height . ' "' . $output . '"'; - - shell_exec($cmd); -} - -function sendMail($subject, $content, $to, $from) { - mail($to, $subject, $content, 'From: ' . $from); -} - -function ParamServerOrUndef($idx) { - return isset($_SERVER[$idx]) ? $_SERVER[$idx] : 'NOT_SET'; -} - -/** - * @param Exception $e - */ -function sendExceptionMail($e) -{ - try { - $subject = "Server has encountered an Error at " . date("Y-m-d H:i:s") . "] "; - - $content = ""; - - $content .= 'HTTP_HOST: ' . ParamServerOrUndef('HTTP_HOST') . "\n"; - $content .= 'REQUEST_URI: ' . ParamServerOrUndef('REQUEST_URI') . "\n"; - $content .= 'TIME: ' . date('Y-m-d H:i:s') . "\n"; - $content .= 'REMOTE_ADDR: ' . ParamServerOrUndef('REMOTE_ADDR') . "\n"; - $content .= 'HTTP_X_FORWARDED_FOR: ' . ParamServerOrUndef('HTTP_X_FORWARDED_FOR') . "\n"; - $content .= 'HTTP_USER_AGENT: ' . ParamServerOrUndef('HTTP_USER_AGENT') . "\n"; - $content .= 'MESSAGE:' . "\n" . $e->getMessage() . "\n"; - $content .= 'CODE:' . "\n" . $e->getCode() . "\n"; - $content .= 'TRACE:' . "\n" . $e->getTraceAsString() . "\n"; - $content .= '$_GET:' . "\n" . print_r($_GET, true) . "\n"; - $content .= '$_POST:' . "\n" . print_r($_POST, true) . "\n"; - $content .= '$_FILES:' . "\n" . print_r($_FILES, true) . "\n"; - - sendMail($subject, $content, 'virtualadmin@mikescher.de', 'webserver-error@mikescher.com'); - } - catch (Exception $e) - { - // - } -} - -function get_client_ip() { - if (getenv('HTTP_CLIENT_IP')) return getenv('HTTP_CLIENT_IP'); - else if(getenv('HTTP_X_FORWARDED_FOR')) return getenv('HTTP_X_FORWARDED_FOR'); - else if(getenv('HTTP_X_FORWARDED')) return getenv('HTTP_X_FORWARDED'); - else if(getenv('HTTP_FORWARDED_FOR')) return getenv('HTTP_FORWARDED_FOR'); - else if(getenv('HTTP_FORWARDED')) return getenv('HTTP_FORWARDED'); - else if(getenv('REMOTE_ADDR')) return getenv('REMOTE_ADDR'); - else if (isset($_SERVER['HTTP_CLIENT_IP'])) return $_SERVER['HTTP_CLIENT_IP']; - else if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) return $_SERVER['HTTP_X_FORWARDED_FOR']; - else if(isset($_SERVER['HTTP_X_FORWARDED'])) return $_SERVER['HTTP_X_FORWARDED']; - else if(isset($_SERVER['HTTP_FORWARDED_FOR'])) return $_SERVER['HTTP_FORWARDED_FOR']; - else if(isset($_SERVER['HTTP_FORWARDED'])) return $_SERVER['HTTP_FORWARDED']; - else if(isset($_SERVER['REMOTE_ADDR'])) return $_SERVER['REMOTE_ADDR']; - else return 'UNKNOWN'; -} - -function getRandomToken($length = 32) -{ - try - { - if(!isset($length) || intval($length) <= 8 ) $length = 32; - - if (function_exists('random_bytes')) return bin2hex(random_bytes($length)); - if (function_exists('mcrypt_create_iv')) return bin2hex(mcrypt_create_iv($length, MCRYPT_DEV_URANDOM)); - if (function_exists('openssl_random_pseudo_bytes')) return bin2hex(openssl_random_pseudo_bytes($length)); - } - catch (Exception $e) { throw new InvalidArgumentException($e); } - - throw new InvalidArgumentException("No random"); -} \ No newline at end of file diff --git a/www/internals/database.php b/www/internals/database.php deleted file mode 100644 index ea4e5f9..0000000 --- a/www/internals/database.php +++ /dev/null @@ -1,113 +0,0 @@ - PDO::ERRMODE_EXCEPTION, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_EMULATE_PREPARES => false, - ]; - - self::$PDO = new PDO($dsn, $CONFIG['user'], $CONFIG['password'], $opt); - } - - public static function tryconnect() - { - try { - self::connect(); - return true; - } catch (exception $e) { - return false; - } - } - - public static function sql_query_num($query) - { - $r = self::$PDO->query($query)->fetch(PDO::FETCH_NUM)[0]; - - return $r; - } - - public static function sql_query_num_prep($query, $params) - { - $stmt = self::$PDO->prepare($query); - - foreach ($params as $p) - { - if (strpos($query, $p[0]) !== FALSE) $stmt->bindValue($p[0], $p[1], $p[2]); - } - - $stmt->execute(); - $r = $stmt->fetch(PDO::FETCH_NUM)[0]; - - return $r; - } - - public static function sql_query_assoc($query) - { - $r = self::$PDO->query($query)->fetchAll(PDO::FETCH_ASSOC); - - return $r; - } - - public static function sql_query_assoc_prep($query, $params) - { - $stmt = self::$PDO->prepare($query); - - foreach ($params as $p) - { - if (strpos($query, $p[0]) !== FALSE) $stmt->bindValue($p[0], $p[1], $p[2]); - } - - $stmt->execute(); - $r = $stmt->fetchAll(PDO::FETCH_ASSOC); - - return $r; - } - - public static function sql_query_single($query) - { - $r = self::$PDO->query($query)->fetch(PDO::FETCH_ASSOC); - - return $r; - } - - public static function sql_query_single_prep($query, $params) - { - $stmt = self::$PDO->prepare($query); - - foreach ($params as $p) - { - if (strpos($query, $p[0]) !== FALSE) $stmt->bindValue($p[0], $p[1], $p[2]); - } - - $stmt->execute(); - $r = $stmt->fetch(PDO::FETCH_ASSOC); - - return $r; - } - - public static function sql_exec_prep($query, $params) - { - $stmt = self::$PDO->prepare($query); - - foreach ($params as $p) - { - if (strpos($query, $p[0]) !== FALSE) $stmt->bindValue($p[0], $p[1], $p[2]); - } - - $stmt->execute(); - - return $stmt->rowCount(); - } -} \ No newline at end of file diff --git a/www/internals/fragments.php b/www/internals/fragments.php new file mode 100644 index 0000000..3a1e7ea --- /dev/null +++ b/www/internals/fragments.php @@ -0,0 +1,132 @@ +evalFragment('PanelEuler', 'panel_euler.php', [ ]); + } + + public function PanelPrograms() + { + return $this->evalFragment('PanelPrograms', 'panel_programs.php', [ ]); + } + + public function PanelBlog() + { + return $this->evalFragment('PanelBlog', 'panel_blog.php', [ ]); + } + + public function PanelBooks() + { + return $this->evalFragment('PanelBooks', 'panel_books.php', [ ]); + } + + public function PanelAdventOfCode() + { + return $this->evalFragment('PanelAdventOfCode', 'panel_aoc.php', [ ]); + } + + public function PanelAdventOfCodeCalendar(int $year, bool $shownav, bool $linkheader, bool $ajax, bool $frame=true, $frameid=null) + { + return $this->evalFragment('PanelAdventOfCodeCalendar', 'panel_aoc_calendar.php', + [ + 'year' => $year, + 'nav' => $shownav, + 'linkheader' => $linkheader, + 'ajax' => $ajax, + 'frame' => $frame, + 'frameid' => ($frameid == null) ? ('aoc_frame_' . getRandomToken(16)) : $frameid, + ]); + } + + public function BlogviewPlain(array $blogpost) + { + return $this->evalFragment('BlogviewPlain', 'blogview_plain.php', + [ + 'blogpost' => $blogpost, + ]); + } + + public function BlogviewMarkdown(array $blogpost) + { + return $this->evalFragment('BlogviewMarkdown', 'blogview_markdown.php', + [ + 'blogpost' => $blogpost, + ]); + } + + public function BlogviewEulerList(array $blogpost) + { + return $this->evalFragment('BlogviewEulerList', 'blogview_euler_list.php', + [ + 'blogpost' => $blogpost, + ]); + } + + public function BlogviewEulerSingle(array $blogpost, string $subview) + { + return $this->evalFragment('BlogviewEulerSingle', 'blogview_euler_single.php', + [ + 'blogpost' => $blogpost, + 'subview' => $subview, + ]); + } + + public function BlogviewAdventOfCodeList(array $blogpost) + { + return $this->evalFragment('BlogviewAdventOfCodeList', 'blogview_aoc_list.php', + [ + 'blogpost' => $blogpost, + ]); + } + + public function BlogviewAdventOfCodeSingle(array $blogpost, string $subview) + { + return $this->evalFragment('BlogviewAdventOfCodeSingle', 'blogview_aoc_single.php', + [ + 'blogpost' => $blogpost, + 'subview' => $subview, + ]); + } + + public function WidgetBefunge93(string $code, string $url, bool $interactive, int $speed, bool $editable) + { + return $this->evalFragment('WidgetBefunge93', 'widget_befunge93.php', + [ + 'code' => $code, + 'url' => $url, + 'interactive' => $interactive, + 'speed' => $speed, + 'editable' => $editable, + ]); + } + + public function WidgetBFJoust(string $codeLeft, string $codeRight) + { + return $this->evalFragment('WidgetBFJoust', 'widget_bfjoust.php', + [ + 'code_left' => $codeLeft, + 'code_right' => $codeRight, + ]); + } +} \ No newline at end of file diff --git a/www/internals/highscores.php b/www/internals/highscores.php deleted file mode 100644 index 80e60c9..0000000 --- a/www/internals/highscores.php +++ /dev/null @@ -1,102 +0,0 @@ -= 0) - return md5($rand . $player . $playerid . $points . $gamesalt); - else - return md5($rand . $player . $points . $gamesalt); - } - - public static function insert($gameid, $points, $name, $playerid, $check, $time, $ip) - { - return Database::sql_exec_prep('INSERT INTO highscoreentries (GAME_ID, POINTS, PLAYER, PLAYERID, CHECKSUM, TIMESTAMP, IP) VALUES (:gid, :p, :pn, :pid, :cs, :ts, :ip)', - [ - [':gid', $gameid, PDO::PARAM_INT], - [':p', $points, PDO::PARAM_INT], - [':pn', $name, PDO::PARAM_STR], - [':pid', $playerid, PDO::PARAM_INT], - [':cs', $check, PDO::PARAM_STR], - [':ts', $time, PDO::PARAM_STR], - [':ip', $ip, PDO::PARAM_STR], - ]); - } - - public static function update($gameid, $points, $name, $playerid, $check, $time, $ip) - { - return Database::sql_exec_prep('UPDATE highscoreentries SET POINTS = :p, PLAYER = :pn, CHECKSUM = :cs, IP = :ip, TIMESTAMP = :ts WHERE GAME_ID = :gid AND PLAYERID = :pid', - [ - [':gid', $gameid, PDO::PARAM_INT], - [':p', $points, PDO::PARAM_INT], - [':pn', $name, PDO::PARAM_STR], - [':pid', $playerid, PDO::PARAM_INT], - [':cs', $check, PDO::PARAM_STR], - [':ts', $time, PDO::PARAM_STR], - [':ip', $ip, PDO::PARAM_STR], - ]); - } - - public static function getGameByID($gameid) - { - return Database::sql_query_single_prep('SELECT * FROM highscoregames WHERE ID = :id', - [ - [ ':id', $gameid, PDO::PARAM_INT ], - ]); - } - - public static function getOrderedEntriesFromGame($gameid, $limit = null) - { - $sql = 'SELECT * FROM highscoreentries WHERE GAME_ID = :id ORDER BY POINTS DESC'; - if ($limit !== null) $sql .= " LIMIT $limit"; - - return Database::sql_query_assoc_prep($sql, - [ - [ ':id', $gameid, PDO::PARAM_INT ] - ]); - } - - public static function getNewestEntriesFromGame($gameid, $limit = null) - { - $sql = 'SELECT * FROM highscoreentries WHERE GAME_ID = :id ORDER BY TIMESTAMP DESC'; - if ($limit !== null) $sql .= " LIMIT $limit"; - - return Database::sql_query_assoc_prep($sql, - [ - [ ':id', $gameid, PDO::PARAM_INT ] - ]); - } - - public static function getEntryCountFromGame($gameid) - { - return Database::sql_query_num_prep('SELECT COUNT(*) FROM highscoreentries WHERE GAME_ID = :id', - [ - [ ':id', $gameid, PDO::PARAM_INT ] - ]); - } - - public static function getAllGames() - { - return Database::sql_query_assoc('SELECT * FROM highscoregames'); - } - - public static function getNextPlayerID($gameid) - { - return Database::sql_query_num_prep('SELECT MAX(PLAYERID)+1 AS NID FROM highscoreentries WHERE GAME_ID = :gid', - [ - [ ':id', $gameid, PDO::PARAM_INT ] - ]); - } - - public static function getSpecificScore($gameid, $playerid) - { - return Database::sql_query_single_prep('SELECT * FROM highscoreentries WHERE GAME_ID = :gid AND PLAYERID = :pid', - [ - [ ':gid', $gameid, PDO::PARAM_INT ], - [ ':pid', $playerid, PDO::PARAM_INT ], - ]); - } -} \ No newline at end of file diff --git a/www/internals/iwebsitemodule.php b/www/internals/iwebsitemodule.php new file mode 100644 index 0000000..0fd065f --- /dev/null +++ b/www/internals/iwebsitemodule.php @@ -0,0 +1,6 @@ +loadFromCache(); - if ($d === null) return ""; - return $d; - } - - public static function checkConsistency() - { - $p = self::getPathRenderedData(); - - if (!file_exists($p)) return ['result'=>'err', 'message' => 'Rendered data not found']; - - if (filemtime($p) < time()-(24*60*60)) return ['result'=>'warn', 'message' => 'Rendered data is older than 1 day']; - - return ['result'=>'ok', 'message' => '']; - } -} \ No newline at end of file diff --git a/www/internals/modules.php b/www/internals/modules.php new file mode 100644 index 0000000..df79928 --- /dev/null +++ b/www/internals/modules.php @@ -0,0 +1,99 @@ +site = $site; + } + + public function Database() + { + if ($this->database === null) { require_once 'modules/database.php'; $this->database = new Database($this->site); } + return $this->database; + } + + public function AdventOfCode(): AdventOfCode + { + if ($this->adventOfCode === null) { require_once 'modules/adventofcode.php'; $this->adventOfCode = new AdventOfCode(); } + return $this->adventOfCode; + } + + public function Blog(): Blog + { + if ($this->blog === null) { require_once 'modules/blog.php'; $this->blog = new Blog(); } + return $this->blog; + } + + public function Books(): Books + { + if ($this->books === null) { require_once 'modules/books.php'; $this->books = new Books($this->site); } + return $this->books; + } + + public function Euler(): Euler + { + if ($this->euler === null) { require_once 'modules/euler.php'; $this->euler = new Euler(); } + return $this->euler; + } + + public function Programs(): Programs + { + if ($this->programs === null) { require_once 'modules/programs.php'; $this->programs = new Programs(); } + return $this->programs; + } + + public function AlephNoteStatistics(): AlephNoteStatistics + { + if ($this->anstats === null) { require_once 'modules/alephnoteStatistics.php'; $this->anstats = new AlephNoteStatistics($this->site); } + return $this->anstats; + } + + public function UpdatesLog(): UpdatesLog + { + if ($this->updateslog === null) { require_once 'modules/updateslog.php'; $this->updateslog = new UpdatesLog($this->site); } + return $this->updateslog; + } + + public function WebApps(): WebApps + { + if ($this->webapps === null) { require_once 'modules/webapps.php'; $this->webapps = new WebApps(); } + return $this->webapps; + } + + public function ExtendedGitGraph(): MikescherGitGraph + { + if ($this->extendedgitgraph === null) { require_once 'modules/mikeschergitgraph.php'; $this->extendedgitgraph = new MikescherGitGraph($this->site); } + return $this->extendedgitgraph; + } + + public function Highscores(): Highscores + { + if ($this->highscores === null) { require_once 'modules/highscores.php'; $this->highscores = new Highscores($this->site); } + return $this->highscores; + } + + public function SelfTest(): SelfTest + { + if ($this->selftest === null) { require_once 'modules/selftest.php'; $this->selftest = new SelfTest(); } + return $this->selftest; + } +} \ No newline at end of file diff --git a/www/internals/adventofcode.php b/www/internals/modules/adventofcode.php similarity index 75% rename from www/internals/adventofcode.php rename to www/internals/modules/adventofcode.php index 8fccc9e..0a5b572 100644 --- a/www/internals/adventofcode.php +++ b/www/internals/modules/adventofcode.php @@ -1,6 +1,6 @@ ['ext'=>'ts', 'css'=>'language-typescript', 'name'=>'Typescript'], ]; - public static function listAllFromAllYears() + /** @var array */ + private $staticData; + + public function __construct() { - $all = require (__DIR__ . '/../statics/aoc/__all.php'); + $this->load(); + } + + private function load() + { + $all = require (__DIR__ . '/../../statics/aoc/__all.php'); array_walk($all, function(&$value, $year) { array_walk($value, function (&$innervalue) use ($year) { $innervalue = self::readSingle($year, $innervalue); }); }); - return $all; + $this->staticData = $all; } - public static function listSingleYear($year) + public function listAllFromAllYears() { - $all = require (__DIR__ . '/../statics/aoc/__all.php'); - - $result = $all[$year]; - - array_walk($result, function(&$value) use ($year) { $value = self::readSingle($year, $value); }); - - return $result; + return $this->staticData; } - public static function listSingleYearAssociative($year) + public function listAllDays() { - $all = self::listSingleYear($year); + $r = []; + foreach ($this->staticData as $yeardata) foreach ($yeardata as $year => $daydata) $r []= $daydata; + return $this->staticData; + } + + public function listSingleYear($year) + { + return $this->staticData[$year]; + } + + public function listSingleYearAssociative($year) + { + $all = $this->listSingleYear($year); $result = array_fill(0, 25, null); foreach ($all as $d) { - $result[$d['day']-1] = $d; + $result[$d['day'] - 1] = $d; } return $result; } - public static function listYears() + public function listYears() { - $all = require (__DIR__ . '/../statics/aoc/__all.php'); - - return array_keys($all); + return array_keys($this->staticData); } - public static function readSingle($year, $a) + private static function readSingle($year, $a) { $yeardata = self::YEARS[$year]; @@ -76,16 +88,17 @@ class AdventOfCode $a['url_aoc'] = $yeardata['url-aoc'] . $a['day']; // adventofcode.com/{year}/day/{day} - $a['file_challenge'] = (__DIR__ . '/../statics/aoc/'.$year.'/'.$n2p.'_challenge.txt'); - $a['file_input'] = (__DIR__ . '/../statics/aoc/'.$year.'/'.$n2p.'_input.txt'); + $a['file_challenge'] = (__DIR__ . '/../../statics/aoc/'.$year.'/'.$n2p.'_challenge.txt'); + $a['file_input'] = (__DIR__ . '/../../statics/aoc/'.$year.'/'.$n2p.'_input.txt'); + $a['year'] = $year; $a['date'] = $year . '-' . 12 . '-' . $n2p; $solutionfiles = []; for ($i=1; $i <= $a['parts']; $i++) { - $solutionfiles []= (__DIR__ . '/../statics/aoc/' . $year . '/' . $n2p . '_solution-' . $i . '.' . self::LANGUAGES[$a['language']]['ext']); + $solutionfiles []= (__DIR__ . '/../../statics/aoc/' . $year . '/' . $n2p . '_solution-' . $i . '.' . self::LANGUAGES[$a['language']]['ext']); } $a['file_solutions'] = $solutionfiles; @@ -93,7 +106,7 @@ class AdventOfCode return $a; } - public static function getDayFromStrIdent($year, $ident) + public function getDayFromStrIdent($year, $ident) { $e = explode('-', $ident, 2); // day-xxx if (count($e)!==2) return null; @@ -104,25 +117,25 @@ class AdventOfCode return self::getSingleDay($year, $i); } - public static function getSingleDay($year, $day) + public function getSingleDay($year, $day) { - foreach (self::listSingleYear($year) as $aocd) { + foreach ($this->listSingleYear($year) as $aocd) { if ($aocd['day'] == $day) return $aocd; } return null; } - public static function getGithubLink($year) + public function getGithubLink($year) { return self::YEARS['' . $year]['github']; } - public static function getURLForYear($year) + public function getURLForYear($year) { return '/blog/' . self::YEARS[''.$year]['blog-id'] . '/Advent_of_Code_' . $year . '/'; } - public static function getPrevYear($year) + public function getPrevYear($year) { $last = null; foreach (self::YEARS as $y => $d) @@ -133,7 +146,7 @@ class AdventOfCode return null; } - public static function getNextYear($year) + public function getNextYear($year) { $found = false; foreach (self::YEARS as $y => $d) @@ -144,12 +157,12 @@ class AdventOfCode return null; } - public static function getLanguageCSS($data) + public function getLanguageCSS($data) { return self::LANGUAGES[$data['language']]['css']; } - public static function getSolutionCode($data, $i) + public function getSolutionCode($data, $i) { $raw = file_get_contents($data['file_solutions'][$i]); @@ -165,11 +178,13 @@ class AdventOfCode return $raw; } - public static function checkConsistency() + public function checkConsistency() { $warn = null; - foreach (self::listAllFromAllYears() as $year => $yd) + $this->load(); + + foreach ($this->listAllFromAllYears() as $year => $yd) { $daylist = []; $titlelist = []; diff --git a/www/internals/modules/alephnoteStatistics.php b/www/internals/modules/alephnoteStatistics.php new file mode 100644 index 0000000..d2f59c0 --- /dev/null +++ b/www/internals/modules/alephnoteStatistics.php @@ -0,0 +1,37 @@ +site = $site; + } + + public function getTotalUserCount() + { + return $this->site->modules->Database()->sql_query_num('SELECT COUNT(*) FROM an_statslog WHERE NoteCount>0'); + } + + public function getUserCountFromLastVersion() + { + return $this->site->modules->Database()->sql_query_num('SELECT COUNT(*) FROM an_statslog WHERE NoteCount>0 GROUP BY Version ORDER BY INET_ATON(Version) DESC LIMIT 1'); + } + + public function getActiveUserCount($days) + { + return $this->site->modules->Database()->sql_query_num('SELECT COUNT(*) FROM an_statslog WHERE NoteCount>0 AND LastChanged > NOW() - INTERVAL '.$days.' DAY'); + } + + public function getAllActiveEntriesOrdered() + { + return $this->site->modules->Database()->sql_query_assoc('SELECT * FROM an_statslog WHERE NoteCount>0 ORDER BY LastChanged DESC'); + } + + public function checkConsistency() + { + return ['result'=>'ok', 'message' => '']; + } +} \ No newline at end of file diff --git a/www/internals/blog.php b/www/internals/modules/blog.php similarity index 70% rename from www/internals/blog.php rename to www/internals/modules/blog.php index 12310b4..0f07d6d 100644 --- a/www/internals/blog.php +++ b/www/internals/modules/blog.php @@ -1,12 +1,20 @@ load(); + } + + private function load() + { + $all = require (__DIR__ . '/../../statics/blog/__all.php'); + + $this->staticData = array_map(function($a){return self::readSingle($a);}, $all); } private static function readSingle($d) @@ -18,31 +26,42 @@ class Blog $d['canonical'] = "https://www.mikescher.com" . $d['url']; - $d['file_fragment'] = __DIR__ . '/../statics/blog/' . $d['fragment']; + $d['file_fragment'] = __DIR__ . '/../../statics/blog/' . $d['fragment']; if (!array_key_exists('extras', $d)) $d['extras'] = []; return $d; } - public static function listAllNewestFirst() + public function listAll() { - $data = self::listAll(); + return $this->staticData; + } + + public function listAllNewestFirst() + { + $data = $this->staticData; usort($data, function($a, $b) { return strcasecmp($b['date'], $a['date']); }); return $data; } - public static function getBlogpost($id) + public function getBlogpost($id) { - foreach (self::listAll() as $post) { + foreach ($this->staticData as $post) { if ($post['id'] == $id) return $post; } return null; } - public static function getFullBlogpost($id, $subview, &$error) + /** + * @param string $id + * @param string $subview + * @param string $error + * @return array|null + */ + public function getFullBlogpost($id, $subview, &$error) { - $post = self::getBlogpost($id); + $post = $this->getBlogpost($id); if ($post === null) { $error="Blogpost not found"; return null; } $post['issubview'] = false; @@ -51,8 +70,7 @@ class Blog $eulerproblem = null; if ($isSubEuler) { - require_once(__DIR__ . '/../internals/euler.php'); - $eulerproblem = Euler::getEulerProblemFromStrIdent($subview); + $eulerproblem = Website::inst()->modules->Euler()->getEulerProblemFromStrIdent($subview); if ($eulerproblem === null) { $error="Project Euler entry not found"; return null; } $post['submodel'] = $eulerproblem; $post['issubview'] = true; @@ -62,8 +80,7 @@ class Blog $adventofcodeday = null; if ($isSubAdventOfCode) { - require_once(__DIR__ . '/../internals/adventofcode.php'); - $adventofcodeday = AdventOfCode::getDayFromStrIdent($post['extras']['aoc:year'], $subview); + $adventofcodeday = Website::inst()->modules->AdventOfCode()->getDayFromStrIdent($post['extras']['aoc:year'], $subview); if ($adventofcodeday === null) { $error="AdventOfCode entry not found"; return null; } $post['submodel'] = $adventofcodeday; $post['issubview'] = true; @@ -79,16 +96,18 @@ class Blog } - public static function getPostFragment($post) + public function getPostFragment($post) { return file_get_contents($post['file_fragment']); } - public static function checkConsistency() + public function checkConsistency() { $keys = []; - foreach (self::listAll() as $post) + $this->load(); + + foreach ($this->staticData as $post) { if (in_array($post['id'], $keys)) return ['result'=>'err', 'message' => 'Duplicate key ' . $post['id']]; $keys []= $post['id']; diff --git a/www/internals/books.php b/www/internals/modules/books.php similarity index 78% rename from www/internals/books.php rename to www/internals/modules/books.php index 6e8602a..879419d 100644 --- a/www/internals/books.php +++ b/www/internals/modules/books.php @@ -1,10 +1,27 @@ -site = $site; + $this->load(); + } + + private function load() + { + $all = require (__DIR__ . '/../../statics/books/__all.php'); + + $this->staticData = array_map(function($a){return self::readSingle($a);}, $all); + } + + private static function readSingle($a) { $a['imgfront_url'] = '/data/images/book_img/' . $a['id'] . '_front.png'; $a['imgfront_path'] = __DIR__ . '/../data/images/book_img/' . $a['id'] . '_front.png'; @@ -22,8 +39,8 @@ class Books for ($i=1; $i <= $a['imagecount']; $i++) { - $a['extraimages_urls'] []= '/data/images/book_img/' . $a['id'] . '_img' . $i . '.jpg'; - $a['extraimages_paths'] []= __DIR__ . '/../data/images/book_img/' . $a['id'] . '_img' . $i . '.jpg'; + $a['extraimages_urls'] []= '/data/images/book_img/' . $a['id'] . '_img' . $i . '.jpg'; + $a['extraimages_paths'] []= __DIR__ . '/../../data/images/book_img/' . $a['id'] . '_img' . $i . '.jpg'; } $a['book_count'] = is_array($a['pdf']) ? count($a['pdf']) : 1; @@ -31,27 +48,27 @@ class Books return $a; } - public static function listAll() + public function listAll() { - $all = require (__DIR__ . '/../statics/books/__all.php'); - - return array_map('self::readSingle', $all); + return $this->staticData; } - public static function listAllNewestFirst() + public function listAllNewestFirst() { - $data = self::listAll(); + $data = $this->staticData; usort($data, function($a, $b) { return strcasecmp($b['date'], $a['date']); }); return $data; } - public static function checkConsistency() + public function checkConsistency() { $warn = null; + $this->load(); + $ids = []; - foreach (self::listAll() as $prog) + foreach ($this->staticData as $prog) { if (in_array($prog['id'], $ids)) return ['result'=>'err', 'message' => 'Duplicate id ' . $prog['id']]; $ids []= $prog['id']; @@ -79,7 +96,7 @@ class Books return ['result'=>'ok', 'message' => '']; } - public static function checkThumbnails() + public function checkThumbnails() { foreach (self::listAll() as $book) { @@ -89,21 +106,19 @@ class Books return ['result'=>'ok', 'message' => '']; } - public static function createPreview($prog) + public function createPreview($prog) { - global $CONFIG; - $src = $prog['imgfront_path']; $dst = $prog['preview_path']; - if ($CONFIG['use_magick']) + if ($this->site->config['use_magick']) magick_resize_image($src, 200, 0, $dst); else smart_resize_image($src, 200, 0, true, $dst); } - public static function getBook($id) + public function getBook($id) { foreach (self::listAll() as $book) { if ($book['id'] == $id) return $book; @@ -111,7 +126,7 @@ class Books return null; } - public static function getRepositoryHost($book) + public function getRepositoryHost($book) { $r = $book['repository']; if (startsWith($r, "http://")) $r = substr($r, strlen("http://")); diff --git a/www/internals/modules/database.php b/www/internals/modules/database.php new file mode 100644 index 0000000..719b45c --- /dev/null +++ b/www/internals/modules/database.php @@ -0,0 +1,99 @@ +connect($site->config); + } + + private function connect(array $config) + { + $dsn = "mysql:host=" . $config['host'] . ";dbname=" . $config['database'] . ";charset=utf8"; + $opt = + [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, + ]; + + $this->pdo = new PDO($dsn, $config['user'], $config['password'], $opt); + } + + public function sql_query_num($query) + { + return $this->pdo->query($query)->fetch(PDO::FETCH_NUM)[0]; + } + + public function sql_query_num_prep($query, $params) + { + $stmt = $this->pdo->prepare($query); + + foreach ($params as $p) + { + if (strpos($query, $p[0]) !== FALSE) $stmt->bindValue($p[0], $p[1], $p[2]); + } + + $stmt->execute(); + + return $stmt->fetch(PDO::FETCH_NUM)[0]; + } + + public function sql_query_assoc($query) + { + return $this->pdo->query($query)->fetchAll(PDO::FETCH_ASSOC); + } + + public function sql_query_assoc_prep($query, $params) + { + $stmt = $this->pdo->prepare($query); + + foreach ($params as $p) + { + if (strpos($query, $p[0]) !== FALSE) $stmt->bindValue($p[0], $p[1], $p[2]); + } + + $stmt->execute(); + return $stmt->fetchAll(PDO::FETCH_ASSOC); + } + + public function sql_query_single($query) + { + return $this->pdo->query($query)->fetch(PDO::FETCH_ASSOC); + } + + public function sql_query_single_prep($query, $params) + { + $stmt = $this->pdo->prepare($query); + + foreach ($params as $p) + { + if (strpos($query, $p[0]) !== FALSE) $stmt->bindValue($p[0], $p[1], $p[2]); + } + + $stmt->execute(); + return $stmt->fetch(PDO::FETCH_ASSOC); + } + + public function sql_exec_prep($query, $params) + { + $stmt = $this->pdo->prepare($query); + + foreach ($params as $p) + { + if (strpos($query, $p[0]) !== FALSE) $stmt->bindValue($p[0], $p[1], $p[2]); + } + + $stmt->execute(); + + return $stmt->rowCount(); + } + + public function checkConsistency() + { + return ['result'=>'ok', 'message' => '']; + } +} \ No newline at end of file diff --git a/www/internals/euler.php b/www/internals/modules/euler.php similarity index 68% rename from www/internals/euler.php rename to www/internals/modules/euler.php index c6b3c04..9a03f7b 100644 --- a/www/internals/euler.php +++ b/www/internals/modules/euler.php @@ -1,8 +1,23 @@ -load(); + } + + private function load() + { + $all = require (__DIR__ . '/../../statics/euler/__all.php'); + + $this->staticData = array_map(function($a){return self::readSingle($a);}, $all); + } + + private static function readSingle($a) { $n3p = str_pad($a['number'], 3, '0', STR_PAD_LEFT); $a['number3'] = $n3p; @@ -18,40 +33,14 @@ class Euler $a['url_raw'] = 'https://raw.githubusercontent.com/Mikescher/Project-Euler_Befunge/master/processed/Euler_Problem-' . $n3p . '.b93'; $a['url_github'] = 'https://github.com/Mikescher/Project-Euler_Befunge'; - $a['file_description'] = (__DIR__ . '/../statics/euler/Euler_Problem-'.$n3p.'_description.md'); - $a['file_code'] = (__DIR__ . '/../statics/euler/Euler_Problem-'.$n3p.'.b93'); - $a['file_explanation'] = (__DIR__ . '/../statics/euler/Euler_Problem-'.$n3p.'_explanation.md'); + $a['file_description'] = (__DIR__ . '/../../statics/euler/Euler_Problem-'.$n3p.'_description.md'); + $a['file_code'] = (__DIR__ . '/../../statics/euler/Euler_Problem-'.$n3p.'.b93'); + $a['file_explanation'] = (__DIR__ . '/../../statics/euler/Euler_Problem-'.$n3p.'_explanation.md'); return $a; } - public static function listAll() - { - $all = require (__DIR__ . '/../statics/euler/__all.php'); - - return array_map('self::readSingle', $all); - } - - public static function getEulerProblemFromStrIdent($ident) - { - $e = explode('-', $ident, 2); // problem-xxx - if (count($e)!==2) return null; - - $i = intval($e[1], 10); - if ($i == 0) return null; - - return self::getEulerProblem($i); - } - - public static function getEulerProblem($num) - { - foreach (self::listAll() as $ep) { - if ($ep['number'] == $num) return $ep; - } - return null; - } - - public static function rateTime($problem) + private static function rateTime($problem) { if ($problem['time'] < 100) // < 100ms return 0; @@ -68,14 +57,40 @@ class Euler return 4; } - public static function checkConsistency() + public function listAll() + { + return $this->staticData; + } + + public function getEulerProblemFromStrIdent($ident) + { + $e = explode('-', $ident, 2); // problem-xxx + if (count($e)!==2) return null; + + $i = intval($e[1], 10); + if ($i == 0) return null; + + return self::getEulerProblem($i); + } + + public function getEulerProblem($num) + { + foreach (self::listAll() as $ep) { + if ($ep['number'] == $num) return $ep; + } + return null; + } + + public function checkConsistency() { $warn = null; + $this->load(); + $numbers = []; $realname = []; - foreach (self::listAll() as $ep) + foreach ($this->staticData as $ep) { if (in_array($ep['number'], $numbers)) return ['result'=>'err', 'message' => 'Duplicate number ' . $ep['number']]; $numbers []= $ep['number']; diff --git a/www/internals/modules/highscores.php b/www/internals/modules/highscores.php new file mode 100644 index 0000000..fd11033 --- /dev/null +++ b/www/internals/modules/highscores.php @@ -0,0 +1,113 @@ +site = $site; + } + + public function generateChecksum($rand, $player, $playerid, $points, $gamesalt) + { + if ($playerid >= 0) + return md5($rand . $player . $playerid . $points . $gamesalt); + else + return md5($rand . $player . $points . $gamesalt); + } + + public function insert($gameid, $points, $name, $playerid, $check, $time, $ip) + { + return $this->site->modules->Database()->sql_exec_prep('INSERT INTO highscoreentries (GAME_ID, POINTS, PLAYER, PLAYERID, CHECKSUM, TIMESTAMP, IP) VALUES (:gid, :p, :pn, :pid, :cs, :ts, :ip)', + [ + [':gid', $gameid, PDO::PARAM_INT], + [':p', $points, PDO::PARAM_INT], + [':pn', $name, PDO::PARAM_STR], + [':pid', $playerid, PDO::PARAM_INT], + [':cs', $check, PDO::PARAM_STR], + [':ts', $time, PDO::PARAM_STR], + [':ip', $ip, PDO::PARAM_STR], + ]); + } + + public function update($gameid, $points, $name, $playerid, $check, $time, $ip) + { + return $this->site->modules->Database()->sql_exec_prep('UPDATE highscoreentries SET POINTS = :p, PLAYER = :pn, CHECKSUM = :cs, IP = :ip, TIMESTAMP = :ts WHERE GAME_ID = :gid AND PLAYERID = :pid', + [ + [':gid', $gameid, PDO::PARAM_INT], + [':p', $points, PDO::PARAM_INT], + [':pn', $name, PDO::PARAM_STR], + [':pid', $playerid, PDO::PARAM_INT], + [':cs', $check, PDO::PARAM_STR], + [':ts', $time, PDO::PARAM_STR], + [':ip', $ip, PDO::PARAM_STR], + ]); + } + + public function getGameByID($gameid) + { + return $this->site->modules->Database()->sql_query_single_prep('SELECT * FROM highscoregames WHERE ID = :id', + [ + [ ':id', $gameid, PDO::PARAM_INT ], + ]); + } + + public function getOrderedEntriesFromGame($gameid, $limit = null) + { + $sql = 'SELECT * FROM highscoreentries WHERE GAME_ID = :id ORDER BY POINTS DESC'; + if ($limit !== null) $sql .= " LIMIT $limit"; + + return $this->site->modules->Database()->sql_query_assoc_prep($sql, + [ + [ ':id', $gameid, PDO::PARAM_INT ] + ]); + } + + public function getNewestEntriesFromGame($gameid, $limit = null) + { + $sql = 'SELECT * FROM highscoreentries WHERE GAME_ID = :id ORDER BY TIMESTAMP DESC'; + if ($limit !== null) $sql .= " LIMIT $limit"; + + return $this->site->modules->Database()->sql_query_assoc_prep($sql, + [ + [ ':id', $gameid, PDO::PARAM_INT ] + ]); + } + + public function getEntryCountFromGame($gameid) + { + return $this->site->modules->Database()->sql_query_num_prep('SELECT COUNT(*) FROM highscoreentries WHERE GAME_ID = :id', + [ + [ ':id', $gameid, PDO::PARAM_INT ] + ]); + } + + public function getAllGames() + { + return $this->site->modules->Database()->sql_query_assoc('SELECT * FROM highscoregames'); + } + + public function getNextPlayerID($gameid) + { + return $this->site->modules->Database()->sql_query_num_prep('SELECT MAX(PLAYERID)+1 AS NID FROM highscoreentries WHERE GAME_ID = :gid', + [ + [ ':id', $gameid, PDO::PARAM_INT ] + ]); + } + + public function getSpecificScore($gameid, $playerid) + { + return $this->site->modules->Database()->sql_query_single_prep('SELECT * FROM highscoreentries WHERE GAME_ID = :gid AND PLAYERID = :pid', + [ + [ ':gid', $gameid, PDO::PARAM_INT ], + [ ':pid', $playerid, PDO::PARAM_INT ], + ]); + } + + public function checkConsistency() + { + return ['result'=>'ok', 'message' => '']; + } +} \ No newline at end of file diff --git a/www/internals/modules/mikeschergitgraph.php b/www/internals/modules/mikeschergitgraph.php new file mode 100644 index 0000000..06220c7 --- /dev/null +++ b/www/internals/modules/mikeschergitgraph.php @@ -0,0 +1,51 @@ +extgitgraph = new ExtendedGitGraph2($site->config['extendedgitgraph']); + } + + public function getPathRenderedData() + { + return __DIR__ . '/../../dynamic/egg/cache_fullrenderer.html'; + } + + public function update() + { + return $this->extgitgraph->update(); + } + + public function updateCache() + { + return $this->extgitgraph->updateCache(); + } + + /** + * @return string|null + */ + public function get() + { + $d = $this->extgitgraph->loadFromCache(); + if ($d === null) return ""; + return $d; + } + + public function checkConsistency() + { + $p = $this->getPathRenderedData(); + + if (!file_exists($p)) return ['result'=>'err', 'message' => 'Rendered data not found']; + + if (filemtime($p) < time()-(24*60*60)) return ['result'=>'warn', 'message' => 'Rendered data is older than 1 day']; + + return ['result'=>'ok', 'message' => '']; + } +} \ No newline at end of file diff --git a/www/internals/programs.php b/www/internals/modules/programs.php similarity index 73% rename from www/internals/programs.php rename to www/internals/modules/programs.php index e892bed..ba2e338 100644 --- a/www/internals/programs.php +++ b/www/internals/modules/programs.php @@ -1,8 +1,6 @@ - 'https://choosealicense.com/licenses/mpl-2.0/', ]; - public static function readSingle($a) + /** @var array */ + private $staticData; + + public function __construct() + { + $this->load(); + } + + private function load() + { + $all = require (__DIR__ . '/../../statics/programs/__all.php'); + + $this->staticData = array_map(function($a){return self::readSingle($a);}, $all); + } + + private static function readSingle($a) { $a['mainimage_url'] = '/data/images/program_img/' . $a['internal_name'] . '.png'; - $a['mainimage_path'] = __DIR__ . '/../data/images/program_img/' . $a['internal_name'] . '.png'; + $a['mainimage_path'] = __DIR__ . '/../../data/images/program_img/' . $a['internal_name'] . '.png'; $a['preview_url'] = '/data/dynamic/progprev_' . $a['internal_name'] . '.png'; - $a['preview_path'] = __DIR__ . '/../data/dynamic/progprev_' . $a['internal_name'] . '.png'; + $a['preview_path'] = __DIR__ . '/../../data/dynamic/progprev_' . $a['internal_name'] . '.png'; - $a['file_longdescription'] = (__DIR__ . '/../statics/programs/' . $a['internal_name'] . '_description.md'); + $a['file_longdescription'] = (__DIR__ . '/../../statics/programs/' . $a['internal_name'] . '_description.md'); $a['url'] = '/programs/view/' . $a['internal_name']; @@ -54,50 +67,42 @@ class Programs { foreach ($a['extra_images'] as $fn) { - $a['extraimages_urls'] []= '/data/images/program_img/' . $fn; - $a['extraimages_paths'] []= __DIR__ . '/../data/images/program_img/' . $fn; + $a['extraimages_urls'] []= '/data/images/program_img/' . $fn; + $a['extraimages_paths'] []= __DIR__ . '/../../data/images/program_img/' . $fn; } } return $a; } - public static function listAll() + public function listAll() { - $all = require (__DIR__ . '/../statics/programs/__all.php'); - - return array_map('self::readSingle', $all); + return $this->staticData; } - public static function listAllNewestFirst($filter = '') + public function listAllNewestFirst($filter = '') { - $data = self::listAll(); + $data = $this->staticData; usort($data, function($a, $b) { return strcasecmp($b['add_date'], $a['add_date']); }); if ($filter !== '') $data = array_filter($data, function($a) use($filter) { return strtolower($a['category']) === strtolower($filter); }); return $data; } - public static function listUpdateData() + public function getProgramByInternalName($id) { - $a = require (__DIR__ . '/../statics/updates/_all.php'); - return $a; - } - - public static function getProgramByInternalName($id) - { - foreach (self::listAll() as $prog) { + foreach ($this->staticData as $prog) { if (strcasecmp($prog['internal_name'], $id) === 0) return $prog; if ($prog['internal_name_alt'] !== null && strcasecmp($prog['internal_name_alt'], $id) === 0) return $prog; } return null; } - public static function getProgramDescription($prog) + public function getProgramDescription($prog) { return file_get_contents($prog['file_longdescription']); } - public static function urlComparator($a, $b) + private static function urlComparator($a, $b) { $na = 0; $nb = 0; @@ -118,10 +123,10 @@ class Programs } - public static function getURLs($prog) + public function getURLs($prog) { $urls = $prog['urls']; - uksort($urls, 'self::urlComparator'); + uksort($urls, function($a,$b){return self::urlComparator($a,$b);}); $result = []; foreach ($urls as $fulltype => $urldata) @@ -178,29 +183,31 @@ class Programs return $result; } - public static function getLicenseUrl($license) + public function getLicenseUrl($license) { return self::LICENSES[$license]; } - public static function getDirectDownloadURL($prog) + public function getDirectDownloadURL($prog) { return '/data/binaries/'.$prog['internal_name'].'.zip'; } - public static function getDirectDownloadPath($prog) + public function getDirectDownloadPath($prog) { - return (__DIR__ . '/../data/binaries/'.$prog['internal_name'].'.zip'); + return (__DIR__ . '/../../data/binaries/'.$prog['internal_name'].'.zip'); } - public static function checkConsistency() + public function checkConsistency() { $warn = null; + $this->load(); + $intname = []; $realname = []; - foreach (self::listAll() as $prog) + foreach ($this->staticData as $prog) { if (in_array($prog['internal_name'], $intname)) return ['result'=>'err', 'message' => 'Duplicate internal_name ' . $prog['name']]; $intname []= $prog['internal_name']; @@ -216,7 +223,7 @@ class Programs if (strpos($prog['internal_name'], ' ') !== FALSE) return ['result'=>'err', 'message' => 'Internal name contains spaces ' . $prog['name']]; - foreach (explode('|', $prog['ui_language']) as $lang) if (convertLanguageToFlag($lang) === null) return ['result'=>'err', 'message' => 'Unknown ui-lang ' . $prog['name']];; + foreach (explode('|', $prog['ui_language']) as $lang) if ($this->convertLanguageToFlag($lang) === null) return ['result'=>'err', 'message' => 'Unknown ui-lang ' . $prog['name']]; if (!in_array($prog['prog_language'], self::PROG_LANGS)) return ['result'=>'err', 'message' => 'Unknown prog-lang ' . $prog['name']]; @@ -225,11 +232,11 @@ class Programs if ($prog['license'] !== null && !array_key_exists($prog['license'], self::LICENSES)) return ['result'=>'err', 'message' => 'Unknown license ' . $prog['name']]; $isdl = false; - foreach (self::getURLs($prog) as $xurl) + foreach ($this->getURLs($prog) as $xurl) { if (!in_array($xurl['type'], self::URL_ORDER)) return ['result'=>'err', 'message' => 'Unknown url ' . $xurl['type']]; - if ($xurl['type']==='download' && $xurl['isdirect'] && !file_exists(self::getDirectDownloadPath($prog))) return ['result'=>'err', 'message' => 'Direct download not found ' . $prog['name']]; + if ($xurl['type']==='download' && $xurl['isdirect'] && !file_exists($this->getDirectDownloadPath($prog))) return ['result'=>'err', 'message' => 'Direct download not found ' . $prog['name']]; if ($xurl['type']==='download' || $xurl['type']==='playstore' || $xurl['type']==='itunesstore') $isdl = true; } @@ -242,7 +249,7 @@ class Programs foreach ($prog['extraimages_paths'] as $eipath) { - if (!file_exists($eipath)) return ['result'=>'err', 'message' => 'Extra-Image not found ' . $prog['title_short']]; + if (!file_exists($eipath)) return ['result'=>'err', 'message' => 'Extra-Image not found ' . $prog['name'], 'long' => $eipath]; } } @@ -250,9 +257,9 @@ class Programs return ['result'=>'ok', 'message' => '']; } - public static function checkThumbnails() + public function checkThumbnails() { - foreach (self::listAll() as $prog) + foreach ($this->staticData as $prog) { if (!file_exists($prog['preview_path'])) return ['result'=>'err', 'message' => 'Preview not found ' . $prog['name']]; } @@ -260,16 +267,26 @@ class Programs return ['result'=>'ok', 'message' => '']; } - public static function createPreview($prog) + public function createPreview($prog) { - global $CONFIG; - $src = $prog['mainimage_path']; $dst = $prog['preview_path']; - if ($CONFIG['use_magick']) + if (Website::inst()->config['use_magick']) magick_resize_image($src, 250, 0, $dst); else smart_resize_image($src, 250, 0, true, $dst); } + + public function convertLanguageToFlag($lang) { + $lang = trim(strtolower($lang)); + + if ($lang === 'italian') return '/data/images/flags/013-italy.svg'; + if ($lang === 'english') return '/data/images/flags/226-united-states.svg'; + if ($lang === 'french') return '/data/images/flags/195-france.svg'; + if ($lang === 'german') return '/data/images/flags/162-germany.svg'; + if ($lang === 'spanish') return '/data/images/flags/128-spain.svg'; + + return null; + } } \ No newline at end of file diff --git a/www/internals/modules/selftest.php b/www/internals/modules/selftest.php new file mode 100644 index 0000000..ec6b6ca --- /dev/null +++ b/www/internals/modules/selftest.php @@ -0,0 +1,644 @@ + 'Website (http)', + 'web::programs' => 'Programs (http)', + 'web::books' => 'Books (http)', + 'web::blog' => 'Blog (http)', + 'web::webapps' => 'WebApps (http)', + 'web::euler' => 'Project Euler (http)', + 'web::aoc' => 'Advent of Code (http)', + 'api::default' => 'API', + 'api::highscore' => 'Highscores API', + 'modules::database' => 'Database', + 'modules::blog' => 'Blog (data)', + 'modules::euler' => 'Project Euler (data)', + 'modules::books' => 'Books (data)', + 'modules::extgitgraph' => 'ExtendedGitGraph (data)', + 'modules::programs' => 'Programs (data)', + 'modules::adventofcode' => 'Advent of Code (data)', + 'modules::anstatistics' => 'AlephNote Stats (data)', + 'modules::updateslog' => 'Program Updates (data)', + 'modules::webapps' => 'Webapps (data)', + 'modules::highscores' => 'Highscores (data)', + 'backend::git' => 'Git Repository' + ]; + + private $methods = []; + + public function __construct() + { + $this->init(); + } + + private function init() + { + $this->addMethodPathStatus("web::main::index-1", 200, ''); + $this->addMethodPathStatus("web::main::index-2", 200, '/index'); + $this->addMethodPathStatus("web::main::index-3", 200, '/index.php'); + $this->addMethodPathStatus("web::main::index-4", 200, '/msmain/index'); + $this->addMethodPathStatus("web::main::about-1", 200, '/about'); + $this->addMethodPathStatus("web::main::about-2", 200, '/msmain/about'); + $this->addMethodPathStatus("web::main::login-1", 200, '/login'); + $this->addMethodPathStatus("web::main::404-1", 404, '/asdf'); + $this->addHTTPSRedirect( "web::main::redirect-1", ''); + $this->addHTTPSRedirect( "web::main::redirect-2", '/about'); + $this->addHTTPSRedirect( "web::main::redirect-3", '/about'); + + $this->addMethodPathStatus( "web::programs::programs-list-1", 200, '/programs'); + $this->addMethodPathStatus( "web::programs::programs-list-2", 200, '/programs/index'); + $this->addMethodPathStatus( "web::programs::programs-list-3", 200, '/downloads/details.php'); + $this->addMethodPathStatus( "web::programs::programs-list-4", 200, '/downloads/downloads.php'); + $this->addMethodMultiPathStatus("web::programs::programs-filtered-1", 200, '/programs/index?categoryfilter={0}', function(){ return array_key_map_unique(Website::inst()->modules->Programs()->listAll(), 'category'); }); + $this->addMethodMultiPathStatus("web::programs::programs-filtered-2", 200, '/programs/cat/{0}', function(){ return array_key_map_unique(Website::inst()->modules->Programs()->listAll(), 'category'); }); + $this->addMethodMultiPathStatus("web::programs::programs-show-1", 200, '/programs/view/{0}', function(){ return array_key_map(Website::inst()->modules->Programs()->listAll(), 'internal_name'); }); + $this->addMethodMultiPathStatus("web::programs::programs-show-2", 200, '/programs/view?id={0}', function(){ return array_key_map(Website::inst()->modules->Programs()->listAll(), 'internal_name'); }); + $this->addMethodMultiPathStatus("web::programs::programs-show-3", 200, '{0}', function(){ return array_key_map(Website::inst()->modules->Programs()->listAll(), 'url'); }); + $this->addMethodMultiPathStatus("web::programs::programs-download-1", 301, '/downloads/{0}', function(){ return array_key_map(Website::inst()->modules->Programs()->listAll(), 'internal_name'); }); + $this->addMethodMultiPathStatus("web::programs::programs-download-2", 301, '/programs/download/{0}', function(){ return array_key_map(Website::inst()->modules->Programs()->listAll(), 'internal_name'); }); + $this->addMethodMultiPathStatus("web::programs::programs-download-3", 301, '/programs/download?id={0}', function(){ return array_key_map(Website::inst()->modules->Programs()->listAll(), 'internal_name'); }); + $this->addMethodPathStatus( "web::programs::programs-404-1", 404, '/programs/view/asdf_not_found'); + $this->addMethodPathStatus( "web::programs::programs-404-2", 404, '/programs/download/asdf_not_found'); + $this->addMethodExtProgLinks( "web::programs::programs-ext-links"); + + $this->addMethodPathStatus( "web::books::books-list-1", 200, '/books'); + $this->addMethodPathStatus( "web::books::books-list-2", 200, '/books/list'); + $this->addMethodMultiPathStatus("web::books::books-show-1", 200, '/books/view/{0}', function(){ return array_key_map(Website::inst()->modules->Books()->listAll(), 'id'); }); + $this->addMethodMultiPathStatus("web::books::books-show-2", 200, '{0}', function(){ return array_key_map(Website::inst()->modules->Books()->listAll(), 'url'); }); + $this->addMethodPathStatus( "web::books::books-404-1", 404, '/books/view/asdf/not_found'); + + $this->addMethodPathStatus( "web::blog::blog-list-1", 200, '/blog'); + $this->addMethodPathStatus( "web::blog::blog-list-2", 200, '/log'); + $this->addMethodPathStatus( "web::blog::blog-list-3", 200, '/blogpost/index'); + $this->addMethodMultiPathStatus("web::blog::blog-show-1", 200, '/blog/{0}', function(){ return array_key_map(Website::inst()->modules->Blog()->listAll(), 'id'); }); + $this->addMethodMultiPathStatus("web::blog::blog-show-2", 200, '/log/{0}', function(){ return array_key_map(Website::inst()->modules->Blog()->listAll(), 'id'); }); + $this->addMethodMultiPathStatus("web::blog::blog-show-3", 200, '/blogpost/view?id={0}', function(){ return array_key_map(Website::inst()->modules->Blog()->listAll(), 'id'); }); + $this->addMethodMultiPathStatus("web::blog::blog-show-4", 200, '{0}', function(){ return array_key_map(Website::inst()->modules->Blog()->listAll(), 'url'); }); + $this->addMethodPathStatus( "web::blog::blog-404-1", 404, '/blog/999999'); + $this->addMethodPathStatus( "web::blog::blog-404-2", 404, '/blog/999999/Notfound'); + $this->addMethodPathStatus( "web::blog::blog-404-3", 404, '/blog/asdf'); + + $this->addMethodPathStatus("web::webapps::webapps-list-1", 200, '/webapps'); + + $this->addMethodPathStatus( "web::euler::euler-list-1", 200, '/blog/1/Project_Euler_with_Befunge'); + $this->addMethodMultiPathStatus("web::euler::euler-show-1", 200, '{0}', function(){ return array_key_map(Website::inst()->modules->Euler()->listAll(), 'url'); }); + $this->addMethodPathStatus( "web::euler::euler-404-1", 404, '/blog/1/Project_Euler_with_Befunge/problem-A'); + $this->addMethodPathStatus( "web::euler::euler-404-2", 404, '/blog/1/Project_Euler_with_Befunge/problem-99999'); + $this->addMethodPathStatus( "web::euler::euler-404-3", 404, '/blog/1/Project_Euler_with_Befunge/asdf'); + + $this->addMethodMultiPathStatus("web::aoc::aoc-list-1", 200, '{0}', function(){ return array_map(function($x){return Website::inst()->modules->AdventOfCode()->getURLForYear($x);},Website::inst()->modules->AdventOfCode()->listYears()); }); + $this->addMethodMultiPathStatus("web::aoc::aoc-show-1", 200, '{0}', function(){ return array_key_map(Website::inst()->modules->AdventOfCode()->listAllDays(), 'url'); }); + $this->addMethodPathStatus( "web::aoc::aoc-404-1", 404, '/blog/25/Advent_of_Code_2017/day-26'); + $this->addMethodPathStatus( "web::aoc::aoc-404-2", 404, '/blog/23/Advent_of_Code_2018/day-27'); + $this->addMethodPathStatus( "web::aoc::aoc-404-3", 404, '/blog/24/Advent_of_Code_2019/day-28'); + + $this->addCheckConsistency("modules::database::database-check-consistency", function(){ return Website::inst()->modules->Database(); }); + $this->addCheckConsistency("modules::blog::blog-check-consistency", function(){ return Website::inst()->modules->Blog(); }); + $this->addCheckConsistency("modules::euler::euler-check-consistency", function(){ return Website::inst()->modules->Euler(); }); + $this->addCheckConsistency("modules::books::books-check-consistency", function(){ return Website::inst()->modules->Books(); }); + $this->addCheckConsistency("modules::extgitgraph::extgitgraph-check-consistency", function(){ return Website::inst()->modules->ExtendedGitGraph(); }); + $this->addCheckConsistency("modules::programs::programs-check-consistency", function(){ return Website::inst()->modules->Programs(); }); + $this->addCheckConsistency("modules::books::books-check-consistency", function(){ return Website::inst()->modules->Books(); }); + $this->addCheckConsistency("modules::adventofcode::adventofcode-check-consistency", function(){ return Website::inst()->modules->AdventOfCode(); }); + $this->addCheckConsistency("modules::anstatistics::anstatistics-check-consistency", function(){ return Website::inst()->modules->AlephNoteStatistics(); }); + $this->addCheckConsistency("modules::updateslog::updateslog-check-consistency", function(){ return Website::inst()->modules->UpdatesLog(); }); + $this->addCheckConsistency("modules::webapps::webapps-check-consistency", function(){ return Website::inst()->modules->WebApps(); }); + $this->addCheckConsistency("modules::highscores::highscores-check-consistency", function(){ return Website::inst()->modules->Highscores(); }); + + $ajaxsecret = Website::inst()->config['ajax_secret']; + + $this->addMethodPathResponse( "api::default::base-test-2", 200, '{}', '/api/test'); + $this->addMethodPathResponse( "api::default::base-test-4", 200, '{}', '/api/base::test'); + $this->addMethodMultiPathStatus("api::default::updatecheck-1", 200, '/update.php?name={0}', function(){ return array_keys(Website::inst()->modules->UpdatesLog()->listUpdateData()); }); + $this->addMethodMultiPathStatus("api::default::updatecheck-2", 200, '/update.php/{0}', function(){ return array_keys(Website::inst()->modules->UpdatesLog()->listUpdateData()); }); + $this->addMethodMultiPathStatus("api::default::updatecheck-3", 200, '/update?name={0}', function(){ return array_keys(Website::inst()->modules->UpdatesLog()->listUpdateData()); }); + $this->addMethodMultiPathStatus("api::default::updatecheck-4", 200, '/update/{0}', function(){ return array_keys(Website::inst()->modules->UpdatesLog()->listUpdateData()); }); + $this->addMethodMultiPathStatus("api::default::updatecheck-5", 200, '/update2?name={0}', function(){ return array_keys(Website::inst()->modules->UpdatesLog()->listUpdateData()); }); + $this->addMethodMultiPathStatus("api::default::updatecheck-6", 200, '/api/update?name={0}', function(){ return array_keys(Website::inst()->modules->UpdatesLog()->listUpdateData()); }); + $this->addMethodMultiPathStatus("api::default::updatecheck-7", 200, '/api/update/{0}', function(){ return array_keys(Website::inst()->modules->UpdatesLog()->listUpdateData()); }); + $this->addMethodPathStatus( "api::default::egg-status", 200, "/api/extendedgitgraph::status?ajax_secret=$ajaxsecret"); + $this->addMethodPathStatus( "api::default::an-show", 200, "/api/alephnote::show?ajax_secret=$ajaxsecret"); + $this->addMethodPathStatus( "api::default::updates-show", 200, "/api/updates::show?ajax_secret=$ajaxsecret"); + $this->addMethodPathStatus( "api::default::aoc-ajax", 200, "/api/html::panel_aoc_calendar"); + $this->addMethodPathStatus( "api::default::404-1", 404, '/api/update/no_prog_xx'); + $this->addMethodPathStatus( "api::default::404-2", 404, '/api/asdf::notfound'); + + $this->addMethodPathStatus( "api::highscore::listgames-1", 200, "/highscores/list.php"); + $this->addMethodPathStatus( "api::highscore::listgames-2", 200, "/highscores/list"); + $this->addMethodPathStatus( "api::highscore::listgames-3", 200, "/highscores/listgames"); + $this->addMethodMultiPathStatus("api::highscore::listentries-1", 200, "/highscores/list.php?gameid={0}", function(){ return [1,2,3,4,5,6]; }); + $this->addMethodMultiPathStatus("api::highscore::listentries-2", 200, "/highscores/list?gameid={0}", function(){ return [1,2,3,4,5,6]; }); + $this->addMethodMultiPathStatus("api::highscore::listentries-3", 200, "/highscores/listentries?gameid={0}", function(){ return [1,2,3,4,5,6]; }); + $this->addMethodMultiPathStatus("api::highscore::top50-1", 200, "/highscores/list_top50.php?gameid={0}", function(){ return [1,2,3,4,5,6]; }); + $this->addMethodMultiPathStatus("api::highscore::top50-2", 200, "/highscores/list_top50?gameid={0}", function(){ return [1,2,3,4,5,6]; }); + + $this->addMethodGitStatusCheck("backend::git::git-status"); + } + + /** @noinspection PhpUnhandledExceptionInspection */ + public function listMethodGroups() + { + $data = []; + foreach ($this->methods as $method) + { + $parts = explode('::', $method['name']); + if (count($parts) !== 3) throw new Exception(); + + $data []= ($parts[0] . '::' . $parts[1]); + } + $data = array_unique($data); + + $result = []; + foreach ($data as $d) + { + $result []= + [ + 'name' => key_exists($d, self::DISPLAY_NAMES) ? self::DISPLAY_NAMES[$d] : $d, + 'filter' => $d.'::*', + 'base' => $d + ]; + } + + sort($result); + + return $result; + } + + private function addMethodPathStatus(string $name, int $status, string $path) + { + $this->methods []= + [ + 'name' => $name, + 'func' => function() use ($name, $path, $status) + { + $xname = explode('::', $name)[2]; + + try + { + if (!Website::inst()->isProd()) return + [ + 'result' => self::STATUS_WARN, + 'message' => '{'.$xname.'} not executed: curl requests in dev mode prohibited', + 'long' => null, + 'exception' => null, + ]; + + $r = curl_http_request($_SERVER['HTTP_HOST'] . $path); + if ($r['statuscode'] === $status) return + [ + 'result' => self::STATUS_OK, + 'message' => "{".$xname."} succeeded", + 'long' => null, + 'exception' => null, + ]; + + return + [ + 'result' => self::STATUS_ERROR, + 'message' => '{'.$xname.'} failed: Request returned wrong statuscode', + 'long' => 'Wrong HTTP Statuscode (Expected: ['.$status.']; Found: ['.$r['statuscode'].'])' . "\n" . "Response:\n" . $r['output'] . "\nError [" . $r['errnum'] . "]:\n" . $r['errstr'], + 'exception' => null, + ]; + } + catch (Exception $e) + { + return + [ + 'result' => self::STATUS_ERROR, + 'message' => "{$xname} failed: " . $e->getMessage(), + 'long' => str_max_len($e->getMessage(), 48), + 'exception' => $e, + ]; + } + } + ]; + } + + private function addMethodMultiPathStatus(string $name, int $status, string $path, Closure $supplier) + { + $this->methods []= + [ + 'name' => $name, + 'func' => function() use ($name, $path, $status, $supplier) + { + $xname = explode('::', $name)[2]; + + try + { + if (!Website::inst()->isProd()) return + [ + 'result' => self::STATUS_WARN, + 'message' => '{'.$xname.'} not executed: curl requests in dev mode prohibited', + 'long' => null, + 'exception' => null, + ]; + + $supdata = $supplier(); + + $message = ''; + $count = 0; + foreach ($supdata as $d) + { + $r = curl_http_request($_SERVER['HTTP_HOST'] . str_replace('{0}', $d, $path)); + $count++; + if ($r['statuscode'] === $status) { $message .= "{".$xname."} succeeded" . "\n"; continue; } + + return + [ + 'result' => self::STATUS_ERROR, + 'message' => '{'.$xname.'} failed: Request returned wrong statuscode', + 'long' => 'Wrong HTTP Statuscode (Expected: ['.$status.']; Found: ['.$r['statuscode'].'])' . "\n" . "Response:\n" . $r['output'] . "\nError [" . $r['errnum'] . "]:\n" . $r['errstr'], + 'exception' => null, + ]; + } + + return + [ + 'result' => self::STATUS_OK, + 'message' => "$count requests succeeded\n" . $message, + 'long' => null, + 'exception' => null, + ]; + } + catch (Exception $e) + { + return + [ + 'result' => self::STATUS_ERROR, + 'message' => "{$xname} failed: " . $e->getMessage(), + 'long' => str_max_len($e->getMessage(), 48), + 'exception' => $e, + ]; + } + } + ]; + } + + private function addCheckConsistency(string $name, Closure $moduleSupplier) + { + $this->methods []= + [ + 'name' => $name, + 'func' => function() use ($name, $moduleSupplier) + { + try + { + /** @var IWebsiteModule $module */ + $module = $moduleSupplier(); + + $consistency = $module->checkConsistency(); + + if ($consistency['result'] === 'err') return + [ + 'result' => self::STATUS_ERROR, + 'message' => $consistency['message'], + 'long' => isset($consistency['long']) ? $consistency['long'] : null, + 'exception' => null, + ]; + + if ($consistency['result'] === 'warn') return + [ + 'result' => self::STATUS_WARN, + 'message' => $consistency['message'], + 'long' => isset($consistency['long']) ? $consistency['long'] : null, + 'exception' => null, + ]; + + if ($consistency['result'] === 'ok') return + [ + 'result' => self::STATUS_OK, + 'message' => 'OK', + 'long' => isset($consistency['long']) ? $consistency['long'] : null, + 'exception' => null, + ]; + + throw new Exception("Unknown result: " . print_r($consistency, true)); + } + catch (Exception $e) + { + return + [ + 'result' => self::STATUS_ERROR, + 'message' => str_max_len($e->getMessage(), 48), + 'long' => formatException($e), + 'exception' => $e, + ]; + } + } + ]; + } + + private function addMethodPathResponse(string $name, int $status, string $json_expected, string $path) + { + $this->methods []= + [ + 'name' => $name, + 'func' => function() use ($name, $path, $status, $json_expected) + { + $xname = explode('::', $name)[2]; + + try + { + if (!Website::inst()->isProd()) return + [ + 'result' => self::STATUS_WARN, + 'message' => '{'.$xname.'} not executed: curl requests in dev mode prohibited', + 'long' => null, + 'exception' => null, + ]; + + $r = curl_http_request($_SERVER['HTTP_HOST'] . $path); + if ($r['statuscode'] !== $status) + { + return + [ + 'result' => self::STATUS_ERROR, + 'message' => '{'.$xname.'} failed: Request returned wrong statuscode', + 'long' => 'Wrong HTTP Statuscode (Expected: ['.$status.']; Found: ['.$r['statuscode'].'])' . "\n" . "Response:\n" . $r['output'] . "\nError [" . $r['errnum'] . "]:\n" . $r['errstr'], + 'exception' => null, + ]; + } + if (json_encode(json_decode($r['output'])) == json_encode(json_decode($json_expected))) + { + return + [ + 'result' => self::STATUS_ERROR, + 'message' => '{'.$xname.'} failed: Request returned wrong statuscode', + 'long' => "Wrong HTTP Response\nExpected:\n$json_expected\nFound:\n".$r['output'] . "\n" . "HTTP Statuscode:\n" . $r['statuscode'] . "\nError [" . $r['errnum'] . "]:\n" . $r['errstr'], + 'exception' => null, + ]; + } + return + [ + 'result' => self::STATUS_OK, + 'message' => "{".$xname."} succeeded", + 'long' => null, + 'exception' => null, + ]; + } + catch (Exception $e) + { + return + [ + 'result' => self::STATUS_ERROR, + 'message' => "{$xname} failed: " . $e->getMessage(), + 'long' => str_max_len($e->getMessage(), 48), + 'exception' => $e, + ]; + } + } + ]; + } + + private function addMethodGitStatusCheck(string $name) + { + $this->methods []= + [ + 'name' => $name, + 'func' => function() use ($name) + { + $xname = explode('::', $name)[2]; + + try + { + if (!Website::inst()->isProd()) return + [ + 'result' => self::STATUS_WARN, + 'message' => '{'.$xname.'} not executed in dev mode', + 'long' => null, + 'exception' => null, + ]; + + $r = exec('git rev-parse --abbrev-ref HEAD'); + $ok = (strpos($r, 'Your branch is up to date with') !== false) && (strpos($r, 'nothing to commit, working tree clean') !== false); + + if (!$ok) + { + return + [ + 'result' => self::STATUS_ERROR, + 'message' => "{$xname} failed", + 'long' => $r, + 'exception' => null, + ]; + } + else + { + return + [ + 'result' => self::STATUS_OK, + 'message' => "{".$xname."} succeeded", + 'long' => $r, + 'exception' => null, + ]; + } + + } + catch (Exception $e) + { + return + [ + 'result' => self::STATUS_ERROR, + 'message' => "{$xname} failed: " . $e->getMessage(), + 'long' => str_max_len($e->getMessage(), 48), + 'exception' => $e, + ]; + } + } + ]; + } + + private function addMethodExtProgLinks(string $name) + { + $this->methods []= + [ + 'name' => $name, + 'func' => function() use ($name) + { + $xname = explode('::', $name)[2]; + + if (!Website::inst()->isProd()) return + [ + 'result' => self::STATUS_WARN, + 'message' => '{'.$xname.'} not executed: curl requests in dev mode prohibited', + 'long' => null, + 'exception' => null, + ]; + + try + { + $message = ''; + $count = 0; + foreach (Website::inst()->modules->Programs()->listAll() as $prog) + { + foreach ($prog['urls'] as $urlobj) + { + $url = $urlobj; + if (is_array($urlobj)) $url = $urlobj['url']; + + $r = curl_http_request($url); + $count++; + if ($r['statuscode'] === 200) { $message .= "[".$prog['name']."] Request to '$url' succeeded" . "\n"; continue; } + + return + [ + 'result' => self::STATUS_ERROR, + 'message' => '['.$prog['name'].'] failed: Request to returned wrong statuscode', + 'long' => 'Wrong HTTP Statuscode from "'.$url.'"' . "\nExpected: [200]\nFound: [".$r['statuscode'].']' . "\n" . "Response:\n" . $r['output'] . "\nError [" . $r['errnum'] . "]:\n" . $r['errstr'], + 'exception' => null, + ]; + } + } + + return + [ + 'result' => self::STATUS_OK, + 'message' => "$count requests succeeded\n" . $message, + 'long' => null, + 'exception' => null, + ]; + } + catch (Exception $e) + { + return + [ + 'result' => self::STATUS_ERROR, + 'message' => "{$xname} failed: " . $e->getMessage(), + 'long' => str_max_len($e->getMessage(), 48), + 'exception' => $e, + ]; + } + } + ]; + } + + private function addHTTPSRedirect(string $name, string $path) + { + $this->methods []= + [ + 'name' => $name, + 'func' => function() use ($name, $path) + { + $xname = explode('::', $name)[2]; + + try + { + if (!Website::inst()->isProd()) return + [ + 'result' => self::STATUS_WARN, + 'message' => '{'.$xname.'} not executed: curl requests in dev mode prohibited', + 'long' => null, + 'exception' => null, + ]; + + $host = parse_url($_SERVER['HTTP_HOST'], PHP_URL_HOST); + $port = parse_url($_SERVER['HTTP_HOST'], PHP_URL_PORT); + + $url1 = 'http://' . $host . ':' . $port . $path; + $url2 = 'https://' . $host . ':' . $port . $path; + + $r = curl_http_request($url1); + if ($r['statuscode'] !== 310) + { + return + [ + 'result' => self::STATUS_ERROR, + 'message' => '{'.$xname.'} failed: Request returned wrong statuscode', + 'long' => 'Wrong HTTP Statuscode (Expected: [200]; Found: ['.$r['statuscode'].'])' . "\n" . "Response:\n" . $r['output'] . "\n" . "Redirect:\n" . $r['redirect'] . "\nError [" . $r['errnum'] . "]:\n" . $r['errstr'], + 'exception' => null, + ]; + } + if ($r['redirect'] !== $url2) + { + return + [ + 'result' => self::STATUS_ERROR, + 'message' => '{'.$xname.'} failed: Request returned wrong redirect', + 'long' => 'Wrong Redirect URL (Expected: ['.$url2.']; Found: ['.$r['redirect'].'])' . "\n" . "Response:\n" . $r['output'] . "\n" . "Redirect:\n" . $r['redirect'] . "\nError [" . $r['errnum'] . "]:\n" . $r['errstr'], + 'exception' => null, + ]; + } + + return + [ + 'result' => self::STATUS_OK, + 'message' => "{".$xname."} succeeded", + 'long' => null, + 'exception' => null, + ]; + } + catch (Exception $e) + { + return + [ + 'result' => self::STATUS_ERROR, + 'message' => "{$xname} failed: " . $e->getMessage(), + 'long' => str_max_len($e->getMessage(), 48), + 'exception' => $e, + ]; + } + } + ]; + } + + public function run($filter) + { + $rex = '/^' . str_replace('*', '([^:]*)', $filter) . '$/'; + + $fullmessage = ''; + $fullwarnmessage = ''; + + $warnings = 0; + $count = 0; + foreach ($this->methods as $method) + { + if (!preg_match($rex, $method['name'])) continue; + + $r = $method['func'](); + if ($r['result'] === self::STATUS_ERROR) return $r; + if ($r['result'] === self::STATUS_WARN) { $warnings++; $fullwarnmessage .= $r['message'] . "\n"; } + $fullmessage .= $r['message'] . "\n"; + + $count++; + } + + if ($warnings > 0) + { + return + [ + 'result' => self::STATUS_WARN, + 'message' => "$warnings/$count methods had warnings", + 'long' => $fullwarnmessage, + 'exception' => null, + ]; + } + + if ($count === 0) return + [ + 'result' => self::STATUS_WARN, + 'message' => "No methods matched filter", + 'long' => null, + 'exception' => null, + ]; + + return + [ + 'result' => self::STATUS_OK, + 'message' => "OK", + 'long' => "$count methods succeeded\n\n" . $fullmessage, + 'exception' => null, + ]; + } + + public function checkConsistency() + { + return ['result'=>'ok', 'message' => '']; + } +} \ No newline at end of file diff --git a/www/internals/modules/updateslog.php b/www/internals/modules/updateslog.php new file mode 100644 index 0000000..ea720ab --- /dev/null +++ b/www/internals/modules/updateslog.php @@ -0,0 +1,80 @@ +site = $site; + $this->load(); + } + + private function load() + { + $all = require (__DIR__ . '/../../statics/updates/__all.php'); + + $this->staticData = array_map(function($a){return self::readSingle($a);}, $all); + } + + private static function readSingle($d) + { + return $d; + } + + public function listUpdateData() + { + return $this->staticData; + } + + public function insert($name, $version) + { + $ip = get_client_ip(); + + $ippath = (__DIR__ . '/../../dynamic/self_ip_address.auto.cfg'); + $self_ip = file_exists($ippath) ? file_get_contents($ippath) : 'N/A'; + + if ($self_ip === $ip) $ip = "self"; + + $this->site->modules->Database()->sql_exec_prep("INSERT INTO updateslog (programname, ip, version, date) VALUES (:pn, :ip, :vn, NOW())", + [ + [':pn', $name, PDO::PARAM_STR], + [':ip', $ip, PDO::PARAM_STR], + [':vn', $version, PDO::PARAM_STR], + ]); + } + + public function listProgramsInformation() + { + return $this->site->modules->Database()->sql_query_assoc('SELECT programname AS name, Count(*) as count_total, MAX(date) AS last_query, (SELECT COUNT(*) FROM updateslog AS u1 WHERE u1.programname=u0.programname AND NOW() - INTERVAL 7 DAY < u1.date) AS count_week FROM updateslog AS u0 GROUP BY programname'); + } + + public function getEntries($name, $limit) + { + return $this->site->modules->Database()->sql_query_assoc_prep('SELECT * FROM updateslog WHERE programname = :pn ORDER BY date DESC LIMIT :lt', + [ + [':pn', $name, PDO::PARAM_STR], + [':lt', $limit, PDO::PARAM_INT], + ]); + } + + public function checkConsistency() + { + $warn = null; + + $this->load(); + + foreach ($this->staticData as $name => $data) + { + if (!key_exists('version', $data)) return ['result'=>'err', 'message' => 'Missing value [version]']; + if (!key_exists('url', $data)) return ['result'=>'err', 'message' => 'Missing value [url]']; + } + + if ($warn != null) return $warn; + return ['result'=>'ok', 'message' => '']; + } +} \ No newline at end of file diff --git a/www/internals/modules/webapps.php b/www/internals/modules/webapps.php new file mode 100644 index 0000000..3320cdb --- /dev/null +++ b/www/internals/modules/webapps.php @@ -0,0 +1,49 @@ +load(); + } + + private function load() + { + $all = require (__DIR__ . '/../../statics/webapps/__all.php'); + + $this->staticData = array_map(function($a){return self::readSingle($a);}, $all); + } + + private static function readSingle($a) + { + return $a; + } + + public function listAllNewestFirst() + { + $data = $this->staticData; + usort($data, function($a, $b) { return strcasecmp($b['date'], $a['date']); }); + return $data; + } + + public function checkConsistency() + { + $warn = null; + + $this->load(); + + $ids = []; + + foreach ($this->staticData as $prog) + { + if (in_array($prog['id'], $ids)) return ['result'=>'err', 'message' => 'Duplicate id ' . $prog['id']]; + $ids []= $prog['id']; + } + + if ($warn != null) return $warn; + return ['result'=>'ok', 'message' => '']; + } +} \ No newline at end of file diff --git a/www/internals/pageframeoptions.php b/www/internals/pageframeoptions.php new file mode 100644 index 0000000..c9cc72b --- /dev/null +++ b/www/internals/pageframeoptions.php @@ -0,0 +1,86 @@ +stylesheets as $css) if ($css === $url) return; + $this->stylesheets []= $url; + } + + public function addScript(string $url, bool $defer = false) + { + foreach ($this->scripts as &$script) + { + if ($script[0] === $url) + { + if (!$defer && $script[1]) $script[1] = false; // upgrade from defered to immediate script + return; + } + } + + $this->scripts []= [ $url, $defer ]; + } + + public function setForced404(string $err) + { + $this->force_404 = true; + $this->force_404_message = $err; + } + + public function setForcedRedirect(string $url) + { + $this->force_redirect = true; + $this->force_redirect_url = $url; + } + + public function forceResult(int $statuscode, string $content) + { + $this->statuscode = $statuscode; + ob_clean(); + echo $content; + } +} \ No newline at end of file diff --git a/www/internals/ParsedownCustom.php b/www/internals/parsedowncustom.php similarity index 78% rename from www/internals/ParsedownCustom.php rename to www/internals/parsedowncustom.php index e6304d7..a665f98 100644 --- a/www/internals/ParsedownCustom.php +++ b/www/internals/parsedowncustom.php @@ -1,6 +1,5 @@ fragments->WidgetBFJoust(trim($split[0]), trim($split[1])); } protected function handleBef93(array $Element) { - global $PARAM_BEFUNGE93RUNNER; - $PARAM_BEFUNGE93RUNNER = - [ - 'code' => $Element['text'], - 'url' => '', - 'interactive' => $Element['b93_interactive'], - 'speed' => $Element['b93_speed'], - 'editable' => $Element['b93_editable'], - ]; - return require (__DIR__ . '/../fragments/widget_befunge93.php'); + return Website::inst()->fragments->WidgetBefunge93($Element['text'], '', $Element['b93_interactive'], $Element['b93_speed'], $Element['b93_editable']); } protected function blockTable($Line, array $Block = null) diff --git a/www/internals/ruleengine.php b/www/internals/ruleengine.php new file mode 100644 index 0000000..a7fa119 --- /dev/null +++ b/www/internals/ruleengine.php @@ -0,0 +1,113 @@ +isProd()) + $requri = $_SERVER['REQUEST_URI']; + else + $requri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : 'localhost:80/'; + + $parse = parse_url($requri); + + $path = isset($parse['path']) ? $parse['path'] : ''; + $pathparts = preg_split('@/@', $path, NULL, PREG_SPLIT_NO_EMPTY); + $partcount = count($pathparts); + + foreach ($urlConfig as $rule) + { + $route = self::testRule($site, $rule, $requri, $pathparts, $partcount); + if ($route === null) continue; + + if ($route->needsAdminLogin && !$site->isLoggedInByCookie()) return URLRoute::getLoginRoute($route, $requri); + + return $route; + } + + return URLRoute::getNotFoundRoute($requri); + } + + private static function testRule(Website $site, array $rule, string $requri, array $pathparts, int $partcount) + { + if ($partcount !== count($rule['url'])) return null; + + $urlparams = []; + + $match = true; + for($i = 0; $i < $partcount; $i++) + { + $comp = $rule['url'][$i]; + if (startsWith($comp, '?{') && endsWith($comp, '}')) + { + $ident = substr($comp, 2, strlen($comp)-3); + $urlparams[$ident] = $pathparts[$i]; + } + else if ($comp === '*') + { + if (!isset($urlparams['*'])) $urlparams['*'] = []; + $urlparams['*'] []= $pathparts[$i]; + } + else + { + if (strtolower($comp) !== strtolower($pathparts[$i])) { $match = false; break; } + } + } + if (!$match) return null; + + $route = new URLRoute($rule['target'], $requri); + + foreach($rule['parameter'] as $optname => $optvalue) + { + $value = $optvalue; + + if ($value === '%GET%') + { + if (!isset($_GET[$optname])) { $match = false; break; } + $value = $_GET[$optname]; + } + else if ($value === '%POST%') + { + if (!isset($_POST[$optname])) { $match = false; break; } + $value = $_POST[$optname]; + } + else if ($value === '%URL%') + { + if (!isset($urlparams[$optname])) { $match = false; break; } + $value = urldecode($urlparams[$optname]); + } + + $route->parameter[strtolower($optname)] = $value; + } + if (!$match) return null; + + $route->urlParameter = $urlparams; + + $ctrlOpt = $rule['options']; + + if (in_array('disabled', $ctrlOpt)) return null; + if (in_array('api', $ctrlOpt)) $route->isAPI = true; + + if (isset($ctrlOpt['method']) && $_SERVER["REQUEST_METHOD"] !== $ctrlOpt['method']) return null; + + $route->needsAdminLogin = isset($ctrlOpt['password']); + + if ($site->isProd() && isHTTPRequest() && !in_array('http', $ctrlOpt)) + { + // enforce https + $redirect = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; + header('HTTP/1.1 301 Moved Permanently'); + header('Location: ' . $redirect); + exit(); + } + + return $route; + } +} diff --git a/www/internals/updateslog.php b/www/internals/updateslog.php deleted file mode 100644 index 184068b..0000000 --- a/www/internals/updateslog.php +++ /dev/null @@ -1,40 +0,0 @@ -targetpath = (__DIR__ . '/../pages/' . $target); + $this->full_url = $url; + $this->parameter = []; + $this->needsAdminLogin = false; + $this->urlParameter = []; + $this->isAPI = false; + } + + /** + * @param Website $site + * @return PageFrameOptions + */ + public function get(Website $site): PageFrameOptions + { + $pfo = new PageFrameOptions(); + + $pfo->addStylesheet($site->isProd() ? ('/data/css/styles.min.css') : ('/data/css/styles.css')); + + return $this->getDirect($site, $pfo); + } + + /** + * @param Website $site + * @param PageFrameOptions $pfo + * @return PageFrameOptions + */ + public function getDirect(Website $site, PageFrameOptions $pfo): PageFrameOptions + { + try + { + ob_start(); + + global $ROUTE; + global $FRAME_OPTIONS; + global $SITE; + $ROUTE = $this; + $FRAME_OPTIONS = $pfo; + $SITE = $site; + + /** @noinspection PhpIncludeInspection */ + require $this->targetpath; + + $FRAME_OPTIONS->raw = ob_get_contents(); + + return $FRAME_OPTIONS; + } + finally + { + ob_end_clean(); + } + } + + /** + * @param URLRoute $route + * @param string $requri + * @return URLRoute + */ + public static function getLoginRoute(URLRoute $route, string $requri): URLRoute + { + $r = new URLRoute('login.php', $requri); + $r->parameter = [ 'login_target' => $route->full_url ]; + return $r; + } + + /** + * @param string $requri + * @return URLRoute + */ + public static function getNotFoundRoute(string $requri): URLRoute + { + $r = new URLRoute('error_notfound.php', $requri); + $r->parameter = []; + return $r; + } + + /** + * @param string $requri + * @return URLRoute + */ + public static function getServerErrorRoute(string $requri): URLRoute + { + $r = new URLRoute('error_servererror.php', $requri); + $r->parameter = []; + return $r; + } +} \ No newline at end of file diff --git a/www/internals/utils.php b/www/internals/utils.php new file mode 100644 index 0000000..ee2a0be --- /dev/null +++ b/www/internals/utils.php @@ -0,0 +1,287 @@ += 0 && $transparency < $palletsize) { + $transparent_color = imagecolorsforindex($image, $transparency); + $transparency = imagecolorallocate($image_resized, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']); + imagefill($image_resized, 0, 0, $transparency); + imagecolortransparent($image_resized, $transparency); + } + elseif ($info[2] == IMAGETYPE_PNG) { + imagealphablending($image_resized, false); + $color = imagecolorallocatealpha($image_resized, 0, 0, 0, 127); + imagefill($image_resized, 0, 0, $color); + imagesavealpha($image_resized, true); + } + } + imagecopyresampled($image_resized, $image, 0, 0, $cropWidth, $cropHeight, $final_width, $final_height, $width_old - 2 * $cropWidth, $height_old - 2 * $cropHeight); + + # Preparing a method of providing result + switch ( strtolower($output) ) { + case 'browser': + $mime = image_type_to_mime_type($info[2]); + header("Content-type: $mime"); + $output = NULL; + break; + case 'file': + $output = $file; + break; + case 'return': + return $image_resized; + break; + default: + break; + } + + # Writing image according to type to the output destination and image quality + switch ( $info[2] ) { + case IMAGETYPE_GIF: imagegif($image_resized, $output); break; + case IMAGETYPE_JPEG: imagejpeg($image_resized, $output, 100); break; + case IMAGETYPE_PNG: + $quality = 9 - (int)((0.9*100)/10.0); + imagepng($image_resized, $output, $quality); + break; + default: return false; + } + + return true; +} + +/** + * @param string $file - file name to resize + * @param int $width - new image width + * @param int $height - new image height + * @param string $output - name of the new file (include path if needed) + */ +function magick_resize_image($file, $width, $height, $output) +{ + list($width_old, $height_old) = getimagesize($file); + + if ($width == 0) $factor = $height/$height_old; + elseif ($height == 0) $factor = $width/$width_old; + else $factor = min( $width / $width_old, $height / $height_old ); + + $final_width = round( $width_old * $factor ); + $final_height = round( $height_old * $factor ); + + $cmd = 'convert "' . $file . '" -strip -resize ' . $final_width . 'x' . $final_height . ' "' . $output . '"'; + + shell_exec($cmd); +} + +function sendMail($subject, $content, $to, $from) +{ + mail($to, $subject, $content, 'From: ' . $from); +} + +function get_client_ip() { + if (getenv('HTTP_CLIENT_IP')) return getenv('HTTP_CLIENT_IP'); + else if(getenv('HTTP_X_FORWARDED_FOR')) return getenv('HTTP_X_FORWARDED_FOR'); + else if(getenv('HTTP_X_FORWARDED')) return getenv('HTTP_X_FORWARDED'); + else if(getenv('HTTP_FORWARDED_FOR')) return getenv('HTTP_FORWARDED_FOR'); + else if(getenv('HTTP_FORWARDED')) return getenv('HTTP_FORWARDED'); + else if(getenv('REMOTE_ADDR')) return getenv('REMOTE_ADDR'); + else if (isset($_SERVER['HTTP_CLIENT_IP'])) return $_SERVER['HTTP_CLIENT_IP']; + else if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) return $_SERVER['HTTP_X_FORWARDED_FOR']; + else if(isset($_SERVER['HTTP_X_FORWARDED'])) return $_SERVER['HTTP_X_FORWARDED']; + else if(isset($_SERVER['HTTP_FORWARDED_FOR'])) return $_SERVER['HTTP_FORWARDED_FOR']; + else if(isset($_SERVER['HTTP_FORWARDED'])) return $_SERVER['HTTP_FORWARDED']; + else if(isset($_SERVER['REMOTE_ADDR'])) return $_SERVER['REMOTE_ADDR']; + else return 'UNKNOWN'; +} + +function getRandomToken($length = 32) +{ + try + { + if(!isset($length) || intval($length) <= 8 ) $length = 32; + + if (function_exists('random_bytes')) return bin2hex(random_bytes($length)); + if (function_exists('mcrypt_create_iv')) return bin2hex(mcrypt_create_iv($length, MCRYPT_DEV_URANDOM)); + if (function_exists('openssl_random_pseudo_bytes')) return bin2hex(openssl_random_pseudo_bytes($length)); + } + catch (Exception $e) { throw new InvalidArgumentException($e); } + + throw new InvalidArgumentException("No random"); +} + +function isHTTPRequest() +{ + return (!isset($_SERVER['HTTPS'])) || empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == "off"; +} + +function str_max_len(string $str, int $max) +{ + if (strlen($str) < $max) return $str; + + return substr($str, 0, $max-3)."..."; +} + +function formatException($e) +{ + if ($e === null) return "NULL"; + + if ($e instanceof Exception) + { + $r = ''; + $r .= $e->getMessage() . "\n\n"; + $r .= $e->getFile() . "\n\n"; + $r .= str_replace(dirname(__DIR__), '.', $e->getTraceAsString()) . "\n\n"; + if (isset($e->xdebug_message)) + { + $xdbg = $e->xdebug_message; + $xdbg = str_replace('
', "\n", $xdbg); + $xdbg = str_replace('
', "\n", $xdbg); + $xdbg = str_replace('
', "\n", $xdbg); + $xdbg = str_replace('><', "> <", $xdbg); + $xdbg = strip_tags($xdbg); + $xdbg = htmlspecialchars($xdbg); + $r .= $xdbg . "\n"; + } + return $r; + } + + return 'object'; +} + +function array_key_map_unique(array $array, string $key) +{ + $r = []; + foreach ($array as $d) if (!in_array($d[$key], $r)) $r []= $d[$key]; + return $r; +} + +function array_key_map(array $array, string $key) +{ + $r = []; + foreach ($array as $d) $r []= $d[$key]; + return $r; +} + +function curl_http_request($url) +{ + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); + + $output = curl_exec($ch); + $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $redirect = curl_getinfo($ch, CURLINFO_REDIRECT_URL); + $errnum = curl_errno( $ch ); + $errmsg = curl_error( $ch ); + curl_close($ch); + + return [ 'output'=>$output, 'statuscode'=>$httpcode, 'redirect'=>$redirect, 'erronum'=>$errnum, 'errorstr'=>$errmsg ]; +} + + diff --git a/www/internals/webapp.php b/www/internals/webapp.php deleted file mode 100644 index e5b8754..0000000 --- a/www/internals/webapp.php +++ /dev/null @@ -1,25 +0,0 @@ -config = require (__DIR__ . "/../config.php"); + + if (!$this->config['prod']) + { + ini_set('display_errors', 1); + ini_set('display_startup_errors', 1); + error_reporting(E_ALL); + } + + $this->modules = new Modules($this); + + $this->fragments = new Fragments(); + + self::$instance = $this; + } + catch (exception $e) + { + $this->serveServerError("Initialization failed", formatException($e), null); + } + } + + public static function inst() + { + return self::$instance; + } + + public function serve($rules) + { + try + { + $route = RuleEngine::findRoute($this, $rules); + + $result = $route->get($this); + + if ($result->force_redirect) + { + header('Location: ' . $result->force_redirect_url); + exit(); + } + + if ($result->force_404) + { + $this->serveCustom404($route->full_url, $result, $result->force_404_message); + exit(); + } + + $this->output($result, $route); + } + catch (Exception $e) + { + $this->serveServerError("Internal Server Error", formatException($e), null); + } + } + + private function serveCustom404(string $uri, PageFrameOptions $frameOpt, string $message) + { + try + { + $frameOpt->statuscode = 404; + $frameOpt->title = 'Page not found'; + + $route = URLRoute::getNotFoundRoute($uri); + + $route->parameter['message'] = $message; + + $result = $route->getDirect($this, $frameOpt); + + $this->output($result, $route); + } + catch (Exception $e) + { + $this->serveServerError("Internal Server Error", formatException($e), null); + } + + exit(); + } + + /** + * @param string $message + * @param string|null $debugInfo + * @param PageFrameOptions|null $frameOpt + */ + private function serveServerError(string $message, $debugInfo, $frameOpt) + { + try + { + if ($frameOpt === null) $frameOpt = new PageFrameOptions(); + + $frameOpt->statuscode = 500; + $frameOpt->title = 'Internal Server Error'; + $frameOpt->frame = 'error_frame.php'; + + $route = URLRoute::getServerErrorRoute($_SERVER['REQUEST_URI']); + + $route->parameter['message'] = $message; + $route->parameter['debuginfo'] = $debugInfo; + + $result = $route->getDirect($this, $frameOpt); + + $this->output($result, $route); + } + catch (Exception $e) + { + http_response_code(500); + die('Internal Server Error'); + } + + exit(); + } + + private function output(PageFrameOptions $pfo, URLRoute $route) + { + if ($pfo->contentType !== null) header('Content-Type: ' . $pfo->contentType); + http_response_code($pfo->statuscode); + + global $ROUTE; + global $FRAME_OPTIONS; + global $SITE; + $ROUTE = $route; + $FRAME_OPTIONS = $pfo; + $SITE = $this; + + /** @noinspection PhpIncludeInspection */ + require __DIR__ . '/../frames/' . $FRAME_OPTIONS->frame; + } + + /** + * @return bool + */ + public function isProd() + { + if ($this->config == null) return true; + return $this->config['prod']; + } + + public function isLoggedInByCookie() + { + if ($this->isLoggedIn !== null) return $this->isLoggedIn; + + if (key_exists('mikescher_auth', $_COOKIE)) + { + if (strlen($_COOKIE['mikescher_auth']) !== 64) return ($this->isLoggedIn = false); + $auth = hash('sha256', $this->config['admin_username'] . ';' . $this->config['admin_password'] . ';' . gmdate('Y-m-d')); + if ($auth === $_COOKIE['mikescher_auth']) return ($this->isLoggedIn = true); + } + + return ($this->isLoggedIn = false); + } + + function setLoginCookie($user, $pass) + { + $expires = time() + (24*60*60); // 24h + $hash = hash('sha256', $user . ';' . $pass . ';' . gmdate('Y-m-d')); + setcookie('mikescher_auth', $hash, $expires); + } + + function clearLoginCookie() + { + setcookie("mikescher_auth", "", time()+30); + } + + public function renderMarkdown(string $txt) + { + require_once 'parsedowncustom.php'; + $pd = new ParsedownCustom(); + return $pd->text($txt); + } + +} + +/** + * @param $severity + * @param $message + * @param $file + * @param $line + * @throws ErrorException + */ +function exception_error_handler($severity, $message, $file, $line) { + // This error code is not included in error_reporting + if (!(error_reporting() & $severity)) return; + throw new ErrorException($message, 0, $severity, $file, $line); +} \ No newline at end of file diff --git a/www/pages/about.php b/www/pages/about.php index 3eea2d9..19cffb6 100644 --- a/www/pages/about.php +++ b/www/pages/about.php @@ -1,114 +1,98 @@ - - - - - Mikescher.com - About - - - - - - -
- +title = 'About'; +$FRAME_OPTIONS->canonical_url = 'https://www.mikescher.com/about'; +$FRAME_OPTIONS->activeHeader = 'about'; +?> -
+
-
+

About mikescher.com


-

About mikescher.com


+ - +
+
About me
-
-
About me
+
-
+

Welcome to my Mikescher.com

+

This is my personal homepage, I use it to upload programs I have written, web serials I have style-setted and sometimes for a little bit of blogging.

+

Its mostly just a collection of stuff I wanted to put only, but I guess thats the core of most personal homepages

-

Welcome to my Mikescher.com

-

This is my personal homepage, I use it to upload programs I have written, web serials I have style-setted and sometimes for a little bit of blogging.

-

Its mostly just a collection of stuff I wanted to put only, but I guess thats the core of most personal homepages

+
+
-
+ -
+
+
My git timeline
- +
-
-
My git timeline
+ addScript('/data/javascript/extendedgitgraph.js', true); + echo $SITE->modules->ExtendedGitGraph()->get(); + ?> -
+
- +
-
+ -
+ - -
- - +
- - - - \ No newline at end of file diff --git a/www/pages/admin.php b/www/pages/admin.php index 2736487..a9d9d92 100644 --- a/www/pages/admin.php +++ b/www/pages/admin.php @@ -1,261 +1,220 @@ - - -$consistency_blog = Blog::checkConsistency(); -$consistency_prog = Programs::checkConsistency(); -$consistency_euler = Euler::checkConsistency(); -$consistency_books = Books::checkConsistency(); -$consistency_egg = MikescherGitGraph::checkConsistency(); -$consistency_progimg = Programs::checkThumbnails(); -$consistency_bookimg = Books::checkThumbnails(); -$consistency_aoc = AdventOfCode::checkConsistency(); +title = 'Admin'; +$FRAME_OPTIONS->canonical_url = 'https://www.mikescher.com/admin'; +$FRAME_OPTIONS->activeHeader = 'admin'; + +$FRAME_OPTIONS->addScript('https://code.jquery.com/jquery-latest.min.js', true); +$FRAME_OPTIONS->addScript('/data/javascript/admin.js', true); + + +$connected = true; try { $SITE->modules->Database(); } catch (Exception $e) { $connected = false; } ?> -OK"; - else if ($c['result']==='warn') echo "".$c['message'].""; - else echo "".$c['message'].""; -} +
-?> - - - Mikescher.com - Admin - - - - - - - -
+

Admin


- + +
+
Could not connect to database
+
+ -
+ isProd()): ?> +
+
Website runs in /dev/ mode
+
+ -
+ -

Admin


+
+
Version
- -
-
Could not connect to database
-
- - - - -
-
Version
- -
-
Branch:
-
Commit:
-
Date:
-
Message:
+
+
Branch:
+
Commit:
+
Date:
+
Message:
+
+
+ + + +
+
Self test
+ +
+
+ modules->SelfTest()->listMethodGroups() as $group): ?> +
 
+ +
+
+ Update Program Thumbnails + Update Book Thumbnails +
+
+ + + +
+
Self IP Addr
+ + + +
+
Registered IP:
+
Current IP:
+
+
+ + + +
+
ExtendedGitGraph
+ +
+ + + Update + Redraw + +
+ +
+ + + +
+
AlephNote
+ + +
+
+
Total users: modules->AlephNoteStatistics()->getTotalUserCount(); ?>
+
Users on latest version: modules->AlephNoteStatistics()->getUserCountFromLastVersion(); ?>
+
Active users: modules->AlephNoteStatistics()->getActiveUserCount(32); ?>
+
+
+ Show
+ +
Database not connected.
+ - +
-
-
Self test
+ -
-
-
Program thumbnails:
-
ExtendedGitGraph:
-
Book thumbnails:
-
Blog data:
-
Euler data:
-
AdventOfCode data:
-
Programs data:
-
Books data:
-
-
- Update Program Thumbnails - Update Book Thumbnails +
+
Statics
-
+
+
Blog entries: modules->Blog()->listAll()); ?>
+
Book entries: modules->Books()->listAll()); ?>
+
Euler entries: modules->Euler()->listAll()); ?>
+
Program entries: modules->Programs()->listAll()); ?>
+
Update entries: modules->UpdatesLog()->listUpdateData()); ?>
+
+
+ + + +
+
UpdatesLog
+ + +
+ modules->UpdatesLog()->listProgramsInformation() as $info): ?> +
+
+
+
+ +
+
+ +
Database not connected.
+ +
- + -
-
Self IP Addr
+
+
Highscores
- + +
-
-
Registered IP:
-
Current IP:
-
-
+ modules->Highscores()->getAllGames() as $game): ?> - + +
modules->Highscores()->getOrderedEntriesFromGame($game['ID'], 1)[0]; + echo $hs['POINTS'] . ' (' . $hs['PLAYER'] . ') @ ' . $hs['TIMESTAMP']; + ?>
+
modules->Highscores()->getNewestEntriesFromGame($game['ID'], 1)[0]['TIMESTAMP']; ?>
-
-
ExtendedGitGraph
+
-
- - - Update - Redraw - -
+
+ +
Database not connected.
+ - +
-
-
AlephNote
+ - -
-
-
Total users:
-
Users on latest version:
-
Active users:
-
-
-
- Show -
- -
Database not connected.
- +
+
Configuration
+
+ config as $key => $value) + { + if ($key === 'extendedgitgraph') continue; -
+ if (is_array($value)) + echo '
' . $key . ' ' . json_encode($value, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . '
' . "\n"; + else + echo '
' . $key . ' ' . nl2br(var_export($value, true)) . '
' . "\n"; + } + ?> +
+
- - -
-
Statics
- -
-
Blog entries:
-
Book entries:
-
Euler entries:
-
Program entries:
-
Update entries:
-
-
- - - -
-
UpdatesLog
- - -
- -
-
-
-
- -
-
-
- -
Database not connected.
- -
- - - -
-
Highscores
- - -
- - - -
-
-
- -
- - - -
- -
Database not connected.
- - -
- - - -
-
Configuration
-
- $value) - { - if ($key === 'extendedgitgraph') continue; - - if (is_array($value)) - echo '
' . $key . ' ' . json_encode($value, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . '
' . "\n"; - else - echo '
' . $key . ' ' . nl2br(var_export($value, true)) . '
' . "\n"; - } - ?> -
-
- -
-
Configuration['extendedgitgraph']
-
- $value) - { - if (is_array($value)) - echo '
' . $key . ' ' . json_encode($value, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . '
' . "\n"; - else - echo '
' . $key . ' ' . nl2br(var_export($value, true)) . '
' . "\n"; - } - ?> -
-
- -
- -
- - +
+
Configuration['extendedgitgraph']
+
+ config['extendedgitgraph'] as $key => $value) + { + if (is_array($value)) + echo '
' . $key . ' ' . json_encode($value, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . '
' . "\n"; + else + echo '
' . $key . ' ' . nl2br(var_export($value, true)) . '
' . "\n"; + } + ?> +
+
- - - - \ No newline at end of file diff --git a/www/pages/api.php b/www/pages/api.php index 883245b..c25dff6 100644 --- a/www/pages/api.php +++ b/www/pages/api.php @@ -1,8 +1,15 @@ title = null; +$FRAME_OPTIONS->canonical_url = null; +$FRAME_OPTIONS->activeHeader = null; +$FRAME_OPTIONS->frame = 'api_frame.php'; -require_once (__DIR__ . '/../internals/base.php'); $API_COMMANDS = [ @@ -12,6 +19,7 @@ $API_COMMANDS = 'site::createprogramthumbnails' => [ 'src' => __DIR__.'/../commands/site_createProgramThumbnails.php', 'auth' => 'admin' ], 'site::createbookthumbnails' => [ 'src' => __DIR__.'/../commands/site_createBookThumbnails.php', 'auth' => 'admin' ], + 'site::selftest' => [ 'src' => __DIR__.'/../commands/site_selftest.php', 'auth' => 'admin' ], 'server::setselfaddress' => [ 'src' => __DIR__.'/../commands/server_setselfaddress.php', 'auth' => 'none' ], 'server::gitwebhook' => [ 'src' => __DIR__.'/../commands/server_gitwebhook.php', 'auth' => 'webhook_secret' ], @@ -29,7 +37,7 @@ $API_COMMANDS = 'html::panel_aoc_calendar' => [ 'src' => __DIR__.'/../commands/html_panel-aoc-calendar.php', 'auth' => 'none' ], ]; -$cmd = strtolower($OPTIONS['cmd']); +$cmd = strtolower($ROUTE->parameter['cmd']); if (!array_key_exists($cmd, $API_COMMANDS)) { @@ -58,7 +66,9 @@ if (!array_key_exists($cmd, $API_COMMANDS)) print(" ::::::`:::::;' / / `# \n"); print(" \n"); print(" \n"); - httpDie(400, 'Wrong command.'); + + $FRAME_OPTIONS->forceResult(400, 'Wrong command.'); + return; } $config = $API_COMMANDS[$cmd]; @@ -66,17 +76,17 @@ $config = $API_COMMANDS[$cmd]; $secret = isset($_GET['secret']) ? $_GET['secret'] : ''; -if ($config['auth'] === 'webhook_secret' && $secret !== $CONFIG['webhook_secret']) httpDie(401, 'Unauthorized.'); -if ($config['auth'] === 'ajax_secret' && $secret !== $CONFIG['ajax_secret']) httpDie(401, 'Unauthorized.'); -if ($config['auth'] === 'upload_secret' && $secret !== $CONFIG['upload_secret']) httpDie(401, 'Unauthorized.'); -if ($config['auth'] === 'admin' && !isLoggedInByCookie()) httpDie(401, 'Unauthorized.'); +if ($config['auth'] === 'webhook_secret' && $secret !== $SITE->config['webhook_secret']) { $FRAME_OPTIONS->forceResult(401, "Unauthorized."); return; } +if ($config['auth'] === 'ajax_secret' && $secret !== $SITE->config['ajax_secret']) { $FRAME_OPTIONS->forceResult(401, "Unauthorized."); return; } +if ($config['auth'] === 'upload_secret' && $secret !== $SITE->config['upload_secret']) { $FRAME_OPTIONS->forceResult(401, "Unauthorized."); return; } +if ($config['auth'] === 'admin' && !$SITE->isLoggedInByCookie()) { $FRAME_OPTIONS->forceResult(401, "Unauthorized."); return; } global $API_OPTIONS; $API_OPTIONS = []; foreach ($_GET as $k => $v) $API_OPTIONS[strtolower($k)] = $v; -foreach ($OPTIONS['_urlparams'] as $k => $v) $API_OPTIONS[strtolower($k)] = $v; +foreach ($ROUTE->urlParameter as $k => $v) $API_OPTIONS[strtolower($k)] = $v; try { @@ -85,15 +95,16 @@ try } catch (exception $e) { - print("API Command failed with exception"); - print($e); - $content = "REQUEST: " . var_export($_REQUEST) . "\r\n\r\n" . "IP: " . get_client_ip() . "\r\n\r\n" . "ERROR: " . $e . "\r\n\r\n"; - if (isProd()) sendMail("Website API call failed", $content, 'virtualadmin@mikescher.de', 'webserver-info@mikescher.com'); + if ($SITE->isProd()) sendMail("Website API call failed", $content, 'virtualadmin@mikescher.de', 'webserver-info@mikescher.com'); - httpDie(500, 'Error.'); + $msg = "Error."; + if (!$SITE->isProd()) $msg = "Error.\n" . "API Command failed with exception.\n" . $e; + + $FRAME_OPTIONS->forceResult(500, $msg); + return; } diff --git a/www/pages/blog_list.php b/www/pages/blog_list.php index 0c5a494..e97483a 100644 --- a/www/pages/blog_list.php +++ b/www/pages/blog_list.php @@ -1,55 +1,38 @@ - - - - - Mikescher.com - Blog - - - - - -
- +title = 'Blog'; +$FRAME_OPTIONS->canonical_url = 'https://www.mikescher.com/blog'; +$FRAME_OPTIONS->activeHeader = 'blog'; -
+$allposts = $SITE->modules->Blog()->listAllNewestFirst(); +?> -
+
-

Blogposts and other stuff


+

Blogposts and other stuff


- - -
+ ?> +
- - - -
- - - - \ No newline at end of file diff --git a/www/pages/blog_view.php b/www/pages/blog_view.php index 72e9a7b..595c105 100644 --- a/www/pages/blog_view.php +++ b/www/pages/blog_view.php @@ -1,72 +1,55 @@ - - - - - Mikescher.com - <?php echo htmlspecialchars($post['title']); ?> - - - '; ?> - - -
- - -
+parameter['id']; +$subview = $ROUTE->parameter['subview']; -
+$post = $SITE->modules->Blog()->getFullBlogpost($id, $subview, $err); +if ($post === null) { $FRAME_OPTIONS->setForced404($err); return; } -


+$FRAME_OPTIONS->title = $post['title']; +$FRAME_OPTIONS->canonical_url = $post['canonical']; - activeHeader = 'euler'; +else if ($post['type'] == 'euler' && $post['issubview']) + $FRAME_OPTIONS->activeHeader = 'aoc'; +else + $FRAME_OPTIONS->activeHeader = 'blog'; +?> - if ($post['type'] === 'plain') { - include (__DIR__ . '/../fragments/blogview_plain.php'); +
- } elseif ($post['type'] === 'markdown') { +


- include (__DIR__ . '/../fragments/blogview_markdown.php'); + - -
+ if ($post['type'] === 'plain') + { + echo $SITE->fragments->BlogviewPlain($post); + } + elseif ($post['type'] === 'markdown') + { + echo $SITE->fragments->BlogviewMarkdown($post); + } + elseif ($post['type'] === 'euler') + { + if ($subview === '') echo $SITE->fragments->BlogviewEulerList($post); + else echo $SITE->fragments->BlogviewEulerSingle($post, $subview); + } + elseif ($post['type'] === 'aoc') + { + if ($subview === '') echo $SITE->fragments->BlogviewAdventOfCodeList($post); + else echo $SITE->fragments->BlogviewAdventOfCodeSingle($post, $subview); + } + ?>
- - -
- - - - \ No newline at end of file diff --git a/www/pages/books_list.php b/www/pages/books_list.php index fe98383..32688cc 100644 --- a/www/pages/books_list.php +++ b/www/pages/books_list.php @@ -1,64 +1,47 @@ - - - - - Mikescher.com - Converted Books - - - - - -
- +title = 'Converted Books'; +$FRAME_OPTIONS->canonical_url = 'https://www.mikescher.com/books'; +$FRAME_OPTIONS->activeHeader = 'books'; -
+$allbooks = $SITE->modules->Books()->listAllNewestFirst(); +?> -
+
-

Books/Webserials I self-printed


+

Books/Webserials I self-printed


-

- These are some books I read but that do not have an official print version.
- So I type-setted them myself (mostly in LyX) and printed them online.
- I do not own the rights of any of these books.
- The LyX files and generated PDF's are public and everyone who wants can print them on his own. -

+

+ These are some books I read but that do not have an official print version.
+ So I type-setted them myself (mostly in LyX) and printed them online.
+ I do not own the rights of any of these books.
+ The LyX files and generated PDF's are public and everyone who wants can print them on his own. +

- ' . "\n"; - foreach ($allbooks as $book) - { - echo ''; - echo '
'; - echo ' Thumbnail '  . $book['title'] . ''; - echo '
'; - echo '
'; - echo '
' . $book['date'] . '
'; - echo '
' . htmlspecialchars($book['title']) . '
'; - echo '
'; - echo '
' . "\n"; - } - echo '
' . "\n"; + echo '' . "\n"; - ?> - -
- -
- - + ?>
- - - - \ No newline at end of file diff --git a/www/pages/books_view.php b/www/pages/books_view.php index 4df3087..59de11a 100644 --- a/www/pages/books_view.php +++ b/www/pages/books_view.php @@ -1,127 +1,112 @@ - - - - - Mikescher.com - <?php echo $book['title']; ?> - - - '; ?> - - - -
- +parameter['id']; -
+$book = $SITE->modules->Books()->getBook($id); +if ($book === null) { $FRAME_OPTIONS->setForced404("Books not found"); return; } -
+$FRAME_OPTIONS->title = $book['title']; +$FRAME_OPTIONS->canonical_url = $book['url']; +$FRAME_OPTIONS->activeHeader = 'book'; -
+$FRAME_OPTIONS->addScript('/data/javascript/ms_basic.js', true); +?> -


-
-
<?php echo $book['title'] ?>
-
-
Name:
-
+
-
Pages:
-
'; - $pagi++; - } - } - ?>
+ -
- + +
- - - - \ No newline at end of file diff --git a/www/pages/error_notfound.php b/www/pages/error_notfound.php new file mode 100644 index 0000000..d1cc388 --- /dev/null +++ b/www/pages/error_notfound.php @@ -0,0 +1,24 @@ + + +parameter['message']) ? $ROUTE->parameter['message'] : ''; + +$FRAME_OPTIONS->title = $message; +$FRAME_OPTIONS->canonical_url = null; +$FRAME_OPTIONS->activeHeader = null; +$FRAME_OPTIONS->contentCSSClasses []= 'content-fullheight'; +?> + + +
+
404
+ +
+ +
\ No newline at end of file diff --git a/www/pages/error_servererror.php b/www/pages/error_servererror.php new file mode 100644 index 0000000..5a61038 --- /dev/null +++ b/www/pages/error_servererror.php @@ -0,0 +1,26 @@ + + +title = 'Error'; +$FRAME_OPTIONS->canonical_url = null; +$FRAME_OPTIONS->activeHeader = null; +$FRAME_OPTIONS->contentCSSClasses []= 'content-fullheight'; + +$message = $ROUTE->parameter['message']; +$debuginfo = $ROUTE->parameter['debuginfo']; +?> + + +
+
500
+
+ 0 && ($SITE != null && !$SITE->isProd())): ?> +

+ +
\ No newline at end of file diff --git a/www/pages/errorview.php b/www/pages/errorview.php deleted file mode 100644 index 72e4527..0000000 --- a/www/pages/errorview.php +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - Mikescher.com - <?php echo $errormsg; ?> - - - - -
- - - -
- -
-
-
-
- -
- -
- - - - \ No newline at end of file diff --git a/www/pages/highscores_insert.php b/www/pages/highscores_insert.php index a0eb4ad..66a785d 100644 --- a/www/pages/highscores_insert.php +++ b/www/pages/highscores_insert.php @@ -1,26 +1,30 @@ title = null; +$FRAME_OPTIONS->canonical_url = null; +$FRAME_OPTIONS->activeHeader = null; +$FRAME_OPTIONS->frame = 'api_frame.php'; - $gameid = $OPTIONS['gameid']; - $check = $OPTIONS['check']; - $name = $OPTIONS['name']; - $rand = $OPTIONS['rand']; - $points = $OPTIONS['points']; - if (! is_numeric($gameid)) httpError(400, 'Invalid Request'); - if (! is_numeric($points)) httpError(400, 'Invalid Request'); +$gameid = $ROUTE->parameter['gameid']; +$check = $ROUTE->parameter['check']; +$name = $ROUTE->parameter['name']; +$rand = $ROUTE->parameter['rand']; +$points = $ROUTE->parameter['points']; - $game = Highscores::getGameByID($gameid); - if ($game == NULL) httpError(400, 'Invalid Request'); +if (! is_numeric($gameid)) { $FRAME_OPTIONS->forceResult(400, 'Invalid Request'); return; } +if (! is_numeric($points)) { $FRAME_OPTIONS->forceResult(400, 'Invalid Request'); return; } - $checksum_generated = Highscores::generateChecksum($rand, $name, -1, $points, $game['SALT']); - if ($checksum_generated != $check) die('Nice try !'); +$game = $SITE->modules->Highscores()->getGameByID($gameid); +if ($game == NULL) { $FRAME_OPTIONS->forceResult(400, 'Invalid Request'); return; } - Highscores::insert($gameid, $points, $name, -1, $check, date("Y-m-d H:m:s", time()), $_SERVER['REMOTE_ADDR']); - echo 'ok.'; \ No newline at end of file +$checksum_generated = $SITE->modules->Highscores()->generateChecksum($rand, $name, -1, $points, $game['SALT']); +if ($checksum_generated != $check) die('Nice try !'); + +$SITE->modules->Highscores()->insert($gameid, $points, $name, -1, $check, date("Y-m-d H:m:s", time()), $_SERVER['REMOTE_ADDR']); +echo 'ok.'; \ No newline at end of file diff --git a/www/pages/highscores_listentries.php b/www/pages/highscores_listentries.php index 51adbed..01e0f25 100644 --- a/www/pages/highscores_listentries.php +++ b/www/pages/highscores_listentries.php @@ -1,30 +1,35 @@ title = null; +$FRAME_OPTIONS->canonical_url = null; +$FRAME_OPTIONS->activeHeader = null; +$FRAME_OPTIONS->frame = 'api_frame.php'; - $pagesize = 20; - $start = 0; - $highlight = 0; - if (isset($_GET["start"])) - { - $start = intval(htmlspecialchars($_GET["start"])) - 1; - if ($start < 0) $start = 0; - } - if (isset($_GET["highlight"])) - { - $highlight= intval(htmlspecialchars($_GET["highlight"])); - } +$pagesize = 20; +$start = 0; +$highlight = 0; - $game = Highscores::getGameByID($OPTIONS['gameid']); +if (isset($_GET["start"])) +{ + $start = intval(htmlspecialchars($_GET["start"])) - 1; + if ($start < 0) $start = 0; +} - $entries = Highscores::getOrderedEntriesFromGame($OPTIONS['gameid']); +if (isset($_GET["highlight"])) +{ + $highlight= intval(htmlspecialchars($_GET["highlight"])); +} + +$game = $SITE->modules->Highscores()->getGameByID($ROUTE->parameter['gameid']); + +$entries = $SITE->modules->Highscores()->getOrderedEntriesFromGame($ROUTE->parameter['gameid']); ?> diff --git a/www/pages/highscores_listgames.php b/www/pages/highscores_listgames.php index 959b38a..b5b2f59 100644 --- a/www/pages/highscores_listgames.php +++ b/www/pages/highscores_listgames.php @@ -1,14 +1,16 @@ title = null; +$FRAME_OPTIONS->canonical_url = null; +$FRAME_OPTIONS->activeHeader = null; +$FRAME_OPTIONS->frame = 'api_frame.php'; +$games = $SITE->modules->Highscores()->getAllGames(); ?> diff --git a/www/pages/highscores_newid.php b/www/pages/highscores_newid.php index 4e903c4..e0a4c64 100644 --- a/www/pages/highscores_newid.php +++ b/www/pages/highscores_newid.php @@ -1,14 +1,18 @@ title = null; +$FRAME_OPTIONS->canonical_url = null; +$FRAME_OPTIONS->activeHeader = null; +$FRAME_OPTIONS->frame = 'api_frame.php'; - $newid = Highscores::getNextPlayerID($OPTIONS['gameid']); - - if ($newid < 1024) $newid = 1024; - print $newid; \ No newline at end of file +$newid = $SITE->modules->Highscores()->getNextPlayerID($ROUTE->parameter['gameid']); + +if ($newid < 1024) $newid = 1024; + +print $newid; \ No newline at end of file diff --git a/www/pages/highscores_top50.php b/www/pages/highscores_top50.php index ec2aa6c..6510352 100644 --- a/www/pages/highscores_top50.php +++ b/www/pages/highscores_top50.php @@ -1,13 +1,17 @@ title = null; +$FRAME_OPTIONS->canonical_url = null; +$FRAME_OPTIONS->activeHeader = null; +$FRAME_OPTIONS->frame = 'api_frame.php'; - $entries = Highscores::getOrderedEntriesFromGame($OPTIONS['gameid'], 50); + +$entries = $SITE->modules->Highscores()->getOrderedEntriesFromGame($ROUTE->parameter['gameid'], 50); for ($i = 0; $i < count($entries); $i++) { diff --git a/www/pages/highscores_update.php b/www/pages/highscores_update.php index 62b4275..fd5121e 100644 --- a/www/pages/highscores_update.php +++ b/www/pages/highscores_update.php @@ -1,38 +1,42 @@ title = null; +$FRAME_OPTIONS->canonical_url = null; +$FRAME_OPTIONS->activeHeader = null; +$FRAME_OPTIONS->frame = 'api_frame.php'; - $gameid = $OPTIONS['gameid']; - $check = $OPTIONS['check']; - $name = $OPTIONS['name']; - $nameid = $OPTIONS['nameid']; - $rand = $OPTIONS['rand']; - $points = $OPTIONS['points']; - if (! is_numeric($gameid)) httpError(400, 'Invalid Request'); - if (! is_numeric($nameid)) httpError(400, 'Invalid Request'); - if (! is_numeric($points)) httpError(400, 'Invalid Request'); +$gameid = $ROUTE->parameter['gameid']; +$check = $ROUTE->parameter['check']; +$name = $ROUTE->parameter['name']; +$nameid = $ROUTE->parameter['nameid']; +$rand = $ROUTE->parameter['rand']; +$points = $ROUTE->parameter['points']; - $game = Highscores::getGameByID($OPTIONS['gameid']); - if ($game == NULL) httpError(400, 'Invalid Request'); +if (! is_numeric($gameid)) { $FRAME_OPTIONS->forceResult(400, 'Invalid Request'); return; } +if (! is_numeric($nameid)) { $FRAME_OPTIONS->forceResult(400, 'Invalid Request'); return; } +if (! is_numeric($points)) { $FRAME_OPTIONS->forceResult(400, 'Invalid Request'); return; } - $checksum_generated = Highscores::generateChecksum($rand, $name, $nameid, $points, $game['SALT']); - if ($checksum_generated != $check) die('Nice try !'); +$game = $SITE->modules->Highscores()->getGameByID($ROUTE->parameter['gameid']); +if ($game == NULL) { $FRAME_OPTIONS->forceResult(400, 'Invalid Request'); return; } - $old = Highscores::getSpecificScore($gameid, $nameid); +$checksum_generated = $SITE->modules->Highscores()->generateChecksum($rand, $name, $nameid, $points, $game['SALT']); +if ($checksum_generated != $check) die('Nice try !'); - if ($old == null) - { - Highscores::insert($gameid, $points, $name, $nameid, $check, date("Y-m-d H:m:s", time()), $_SERVER['REMOTE_ADDR']); - echo 'ok.'; - } - else - { - Highscores::update($gameid, $points, $name, $nameid, $check, date("Y-m-d H:m:s", time()), $_SERVER['REMOTE_ADDR']); - echo 'ok.'; - } +$old = $SITE->modules->Highscores()->getSpecificScore($gameid, $nameid); + +if ($old == null) +{ + $SITE->modules->Highscores()->insert($gameid, $points, $name, $nameid, $check, date("Y-m-d H:m:s", time()), $_SERVER['REMOTE_ADDR']); + echo 'ok.'; +} +else +{ + $SITE->modules->Highscores()->update($gameid, $points, $name, $nameid, $check, date("Y-m-d H:m:s", time()), $_SERVER['REMOTE_ADDR']); + echo 'ok.'; +} diff --git a/www/pages/login.php b/www/pages/login.php index 8f6e94c..2c39ace 100644 --- a/www/pages/login.php +++ b/www/pages/login.php @@ -1,18 +1,29 @@ - - + +title = 'Login'; +$FRAME_OPTIONS->canonical_url = 'https://www.mikescher.com/login'; +$FRAME_OPTIONS->activeHeader = 'login'; + +$FRAME_OPTIONS->addScript('/data/javascript/ms_basic.js', true); +?> + +config['admin_username'] && $_GET['password'] === $SITE->config['admin_password']) + { + $SITE->setLoginCookie($_GET['username'], $_GET['password']); + $FRAME_OPTIONS->setForcedRedirect($_GET['redirect']); + return; } else { @@ -20,73 +31,49 @@ if (key_exists('username', $_GET) && key_exists('password', $_GET) && key_exists } } -$redirect = $OPTIONS['login_target']; +$redirect = $ROUTE->parameter['login_target']; if (($redirect === '/' || $redirect === '') && isset($_GET['redirect'])) $redirect = $_GET['redirect']; - +if (($redirect === '/' || $redirect === '')) $redirect = '/admin'; ?> - - - Mikescher.com - Login - - - - - -
- +
-
+
+
Mikescher.com - Login
-
+
-
-
Mikescher.com - Login
+
+
-
+ + Wrong username or password + -
- +
+ + +
- - Wrong username or password - +
+ + +
-
- - -
+
+ + +
-
- - -
+
+ +
-
- - -
+ +
-
- -
+
- -
- - -
- -
- -
- -
- - +
- - - - \ No newline at end of file diff --git a/www/pages/logout.php b/www/pages/logout.php index 116e98e..92826ac 100644 --- a/www/pages/logout.php +++ b/www/pages/logout.php @@ -1,27 +1,16 @@ - - - - - Mikescher.com - Logout - - - - - + + +parameter['logout_target']; +$SITE->clearLoginCookie(); +?> + You have been logged out - - - - - + diff --git a/www/pages/main.php b/www/pages/main.php index 1cd4b33..7a8942b 100644 --- a/www/pages/main.php +++ b/www/pages/main.php @@ -1,37 +1,23 @@ - - - - - - Mikescher.com - - - - - - -
+ +/** @var PageFrameOptions $FRAME_OPTIONS */ global $FRAME_OPTIONS; +/** @var URLRoute $ROUTE */ global $ROUTE; +/** @var Website $SITE */ global $SITE; +?> -
+title = ''; +$FRAME_OPTIONS->canonical_url = 'https://www.mikescher.com'; +$FRAME_OPTIONS->activeHeader = 'home'; +?> - +fragments->PanelEuler(); ?> - +fragments->PanelPrograms(); ?> - +fragments->PanelBlog(); ?> - +fragments->PanelBooks(); ?> - - -
- - - -
- - - - \ No newline at end of file +fragments->PanelAdventOfCode(); ?> diff --git a/www/pages/programs_download.php b/www/pages/programs_download.php index 9a41f91..aaf93c9 100644 --- a/www/pages/programs_download.php +++ b/www/pages/programs_download.php @@ -1,21 +1,29 @@ -$prog = Programs::getProgramByInternalName($internalname); -if ($prog === NULL) httpError(404, 'Program not found'); +parameter['id']; -// This page is only for old links. -// Current version does use direct links +$prog = $SITE->modules->Programs()->getProgramByInternalName($progid); +if ($prog === null) { $FRAME_OPTIONS->setForced404("Program not found"); return; } -foreach (Programs::getURLs($prog) as $xurl) +$FRAME_OPTIONS->title = null; +$FRAME_OPTIONS->canonical_url = null; +$FRAME_OPTIONS->activeHeader = null; + +$FRAME_OPTIONS->frame = 'nocontent_frame.php'; + +foreach ($SITE->modules->Programs()->getURLs($prog) as $xurl) { - if ($xurl['type'] === 'download') { header('Location: ' . $xurl['href']); exit; } - if ($xurl['type'] === 'playstore') { header('Location: ' . $xurl['href']); exit; } - if ($xurl['type'] === 'amazonappstore') { header('Location: ' . $xurl['href']); exit; } - if ($xurl['type'] === 'windowsstore') { header('Location: ' . $xurl['href']); exit; } - if ($xurl['type'] === 'itunesstore') { header('Location: ' . $xurl['href']); exit; } -} \ No newline at end of file + if ($xurl['type'] === 'download') { $FRAME_OPTIONS->setForcedRedirect($xurl['href']); return; } + if ($xurl['type'] === 'playstore') { $FRAME_OPTIONS->setForcedRedirect($xurl['href']); return; } + if ($xurl['type'] === 'amazonappstore') { $FRAME_OPTIONS->setForcedRedirect($xurl['href']); return; } + if ($xurl['type'] === 'windowsstore') { $FRAME_OPTIONS->setForcedRedirect($xurl['href']); return; } + if ($xurl['type'] === 'itunesstore') { $FRAME_OPTIONS->setForcedRedirect($xurl['href']); return; } +} +?> diff --git a/www/pages/programs_list.php b/www/pages/programs_list.php index e836906..e337c78 100644 --- a/www/pages/programs_list.php +++ b/www/pages/programs_list.php @@ -1,69 +1,53 @@ - - - - - Mikescher.com - Programs - - - - - -
- +parameter['categoryfilter']; -
- -
- -

My programs


+$FRAME_OPTIONS->title = 'Programs'; +$FRAME_OPTIONS->canonical_url = ($filter === '') ? ('https://www.mikescher.com/programs') : ('https://www.mikescher.com/programs/cat/' . $filter); +$FRAME_OPTIONS->activeHeader = 'programs'; - modules->Programs()->listAllNewestFirst($filter); +?> - echo '' . "\n"; + + ?>
- - - - \ No newline at end of file diff --git a/www/pages/programs_view.php b/www/pages/programs_view.php index a5e1a44..20f3820 100644 --- a/www/pages/programs_view.php +++ b/www/pages/programs_view.php @@ -1,123 +1,101 @@ - - - - - Mikescher.com - <?php echo $prog['name']; ?> - - - - - - -
- +parameter['id']; -
+$prog = $SITE->modules->Programs()->getProgramByInternalName($id); +if ($prog === null) { $FRAME_OPTIONS->setForced404("Program not found"); return; } -
+$FRAME_OPTIONS->title = $prog['name']; +$FRAME_OPTIONS->canonical_url =$prog['url']; +$FRAME_OPTIONS->activeHeader = 'programs'; +?> -
+
-


+
-
+


-
Thumbnail (<?php echo $prog['name'] ?>)
+
-
-
Name:
-
+
Thumbnail (<?php echo $prog['name'] ?>)
-
Language:
-
+
+
Name:
+
- -
License:
-
'.$prog['license'].'' ?>
- - -
Category:
-
- -
Date:
-
- -
- '; - echo ''; - echo ''; - echo ''; - echo ''.$xurl['caption'].''; - echo ''; - } - ?> -
- -
- ' . "\n"; - } - ?> -
-
-
- - - - +
Language:
+
+ +
License:
+
modules->Programs()->getLicenseUrl($prog['license']).'">'.$prog['license'].'' ?>
-
+
Category:
+
-
+
Date:
+
+ +
text(Programs::getProgramDescription($prog)); + foreach ($SITE->modules->Programs()->getURLs($prog) as $xurl) + { + echo ''; + echo ''; + echo ''; + echo ''; + echo ''.$xurl['caption'].''; + echo ''; + } ?> -
+
-
+
+ modules->Programs()->convertLanguageToFlag($lang).'" title="'.$lang.'" alt="'.$lang[0].'" />' . "\n"; + } + ?> +
+
+
-
+ -
+ addScript('/data/javascript/ms_basic.js', true); ?> - + + + + +
+ +
+ renderMarkdown($SITE->modules->Programs()->getProgramDescription($prog)); ?> +
+ +
- - - - \ No newline at end of file diff --git a/www/pages/webapps_list.php b/www/pages/webapps_list.php index 52183c7..c0cf0bf 100644 --- a/www/pages/webapps_list.php +++ b/www/pages/webapps_list.php @@ -1,52 +1,35 @@ - - - - - Mikescher.com - Tools - - - - - -
- +title = 'External tools, apps and more'; +$FRAME_OPTIONS->canonical_url = 'https://www.mikescher.com/webapps'; +$FRAME_OPTIONS->activeHeader = 'webapps'; -
+$allapps = $SITE->modules->WebApps()->listAllNewestFirst(); +?> -
+
-

Online tools, web apps and more


+

Online tools, web apps and more


-
- + \n"; - echo "
" . $post['date'] . "
\n"; - echo "
" . $post['title'] . "
\n"; - echo "\n"; - } + foreach ($allapps as $post) + { + echo "\n"; + echo "
" . $post['date'] . "
\n"; + echo "
" . $post['title'] . "
\n"; + echo "
\n"; + } - ?> -
- -
+ ?> +
- - - -
- - - - \ No newline at end of file diff --git a/www/statics/updates/_all.php b/www/statics/updates/__all.php similarity index 100% rename from www/statics/updates/_all.php rename to www/statics/updates/__all.php