1
0

ndex route works again

This commit is contained in:
2020-01-15 02:50:23 +01:00
parent f9a692e635
commit 588e9b089a
30 changed files with 427 additions and 258 deletions

View File

@@ -0,0 +1,214 @@
<?php
class AdventOfCode
{
const YEARS =
[
'2017' => [ 'url-aoc'=>'https://adventofcode.com/2017/day/', 'blog-id' => 25, 'github' => 'https://github.com/Mikescher/AdventOfCode2017' ],
'2018' => [ 'url-aoc'=>'https://adventofcode.com/2018/day/', 'blog-id' => 23, 'github' => 'https://github.com/Mikescher/AdventOfCode2018' ],
'2019' => [ 'url-aoc'=>'https://adventofcode.com/2019/day/', 'blog-id' => 24, 'github' => 'https://github.com/Mikescher/AdventOfCode2019' ],
];
const LANGUAGES =
[
'cs' => ['ext'=>'linq', 'css'=>'language-csharp', 'name'=>'C#'],
'java' => ['ext'=>'java', 'css'=>'language-java', 'name'=>'Java'],
'bef' => ['ext'=>'b93', 'css'=>'language-befungerunner', 'name'=>'Befunge-93+'],
'cpp' => ['ext'=>'cpp', 'css'=>'language-cpp', 'name'=>'C++'],
'pyth' => ['ext'=>'py', 'css'=>'language-python', 'name'=>'Python'],
'rust' => ['ext'=>'rs', 'css'=>'language-rust', 'name'=>'Rust'],
'go' => ['ext'=>'go', 'css'=>'language-go', 'name'=>'Go'],
'js' => ['ext'=>'js', 'css'=>'language-javascript', 'name'=>'Javascript'],
'pas' => ['ext'=>'pas', 'css'=>'language-pascal', 'name'=>'Pascal/Delphi'],
'ts' => ['ext'=>'ts', 'css'=>'language-typescript', 'name'=>'Typescript'],
];
/** @var array */
private $staticData;
public function __construct()
{
$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); }); });
$this->staticData = $all;
}
public function listAllFromAllYears()
{
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;
}
return $result;
}
public function listYears()
{
return array_keys($this->staticData);
}
private static function readSingle($year, $a)
{
$yeardata = self::YEARS[$year];
$n2p = str_pad($a['day'], 2, '0', STR_PAD_LEFT);
$a['day-padded'] = $n2p;
$a['url'] = '/blog/' . $yeardata['blog-id'] . '/Advent_of_Code_' . $year . '/day-' . $n2p;
$a['canonical'] = "https://www.mikescher.com" . $a['url'];
$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['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']);
}
$a['file_solutions'] = $solutionfiles;
return $a;
}
public function getDayFromStrIdent($year, $ident)
{
$e = explode('-', $ident, 2); // day-xxx
if (count($e)!==2) return null;
$i = intval($e[1], 10);
if ($i == 0) return null;
return self::getSingleDay($year, $i);
}
public function getSingleDay($year, $day)
{
foreach ($this->listSingleYear($year) as $aocd) {
if ($aocd['day'] == $day) return $aocd;
}
return null;
}
public function getGithubLink($year)
{
return self::YEARS['' . $year]['github'];
}
public function getURLForYear($year)
{
return '/blog/' . self::YEARS[''.$year]['blog-id'] . '/Advent_of_Code_' . $year . '/';
}
public function getPrevYear($year)
{
$last = null;
foreach (self::YEARS as $y => $d)
{
if ($y == $year) return $last;
$last = $y;
}
return null;
}
public function getNextYear($year)
{
$found = false;
foreach (self::YEARS as $y => $d)
{
if ($found) return $y;
if ($y == $year) $found = true;
}
return null;
}
public function getLanguageCSS($data)
{
return self::LANGUAGES[$data['language']]['css'];
}
public function getSolutionCode($data, $i)
{
$raw = file_get_contents($data['file_solutions'][$i]);
if ($data['language'] === 'cs')
{
$raw = trim($raw);
if (startsWith($raw, '<Query Kind="Program" />')) $raw = substr($raw, strlen('<Query Kind="Program" />'));
if (startsWith($raw, '<Query Kind="Expression" />')) $raw = substr($raw, strlen('<Query Kind="Expression" />'));
if (startsWith($raw, '<Query Kind="Statements" />')) $raw = substr($raw, strlen('<Query Kind="Statements" />'));
$raw = trim($raw);
}
return $raw;
}
public function checkConsistency()
{
$warn = null;
$this->load();
foreach ($this->listAllFromAllYears() as $year => $yd)
{
$daylist = [];
$titlelist = [];
if (!array_key_exists($year, self::YEARS)) return ['result'=>'err', 'message' => 'Invalid Year: ' . $year];
foreach ($yd as $aocdata)
{
if (in_array($aocdata['day'], $daylist)) return ['result'=>'err', 'message' => 'Duplicate day ' . $aocdata['day']];
$daylist []= $aocdata['day'];
if (in_array($aocdata['title'], $titlelist)) return ['result'=>'err', 'message' => 'Duplicate title ' . $aocdata['title']];
$titlelist []= $aocdata['title'];
if ($aocdata['day'] < 1 || $aocdata['day'] > 25) return ['result'=>'err', 'message' => 'Invali [day]-value title ' . $aocdata['day']];
if (count($aocdata['solutions']) !== $aocdata['parts']) return ['result'=>'err', 'message' => 'Not enough solution-values in day' . $aocdata['day']];
if (count($aocdata['file_solutions']) !== $aocdata['parts']) return ['result'=>'err', 'message' => 'Not enough solution-files in day' . $aocdata['day']];
if (!file_exists($aocdata['file_challenge'])) return ['result'=>'err', 'message' => 'file_challenge not found ' . $aocdata['file_challenge']];
if (!file_exists($aocdata['file_input'])) return ['result'=>'err', 'message' => 'file_input not found ' . $aocdata['file_input']];
foreach ($aocdata['file_solutions'] as $sfile)
{
if (!file_exists($sfile)) return ['result'=>'err', 'message' => 'file_solution[?] not found ' . $sfile];
}
if (!array_key_exists($aocdata['language'], self::LANGUAGES)) return ['result'=>'err', 'message' => 'Unknown language ' . $aocdata['language']];
}
}
if ($warn != null) return $warn;
return ['result'=>'ok', 'message' => ''];
}
}

View File

@@ -0,0 +1,32 @@
<?php
class AlephNoteStatistics
{
/** @var Website */
private $site;
public function __construct(Website $site)
{
$this->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');
}
}

View File

@@ -0,0 +1,140 @@
<?php
class Blog
{
/** @var array */
private $staticData;
public function __construct()
{
$this->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)
{
if ($d['cat']==='blog')
$d['url'] = "/blog/" . $d['id'] . "/" . destructiveUrlEncode($d['title']);
else if ($d['cat']==='log')
$d['url'] = "/log/" . $d['id'] . "/" . destructiveUrlEncode($d['title']);
$d['canonical'] = "https://www.mikescher.com" . $d['url'];
$d['file_fragment'] = __DIR__ . '/../statics/blog/' . $d['fragment'];
if (!array_key_exists('extras', $d)) $d['extras'] = [];
return $d;
}
public function listAll()
{
return $this->staticData;
}
public function listAllNewestFirst()
{
$data = $this->staticData;
usort($data, function($a, $b) { return strcasecmp($b['date'], $a['date']); });
return $data;
}
public function getBlogpost($id)
{
foreach ($this->staticData as $post) {
if ($post['id'] == $id) return $post;
}
return null;
}
public function getFullBlogpost($id, $subview, &$error)
{
$post = $this->getBlogpost($id);
if ($post === null) { $error="Blogpost not found"; return null; }
$post['issubview'] = false;
$isSubEuler = ($post['type'] === 'euler' && $subview !== '');
$eulerproblem = null;
if ($isSubEuler)
{
$eulerproblem = Website::inst()->modules->Euler()->getEulerProblemFromStrIdent($subview);
if ($eulerproblem === null) { $error="Project Euler entry not found"; return null; }
$post['submodel'] = $eulerproblem;
$post['issubview'] = true;
}
$isSubAdventOfCode = ($post['type'] === 'aoc' && $subview !== '');
$adventofcodeday = null;
if ($isSubAdventOfCode)
{
$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;
}
if ($isSubEuler) $post['title'] = $eulerproblem['title'];
if ($isSubAdventOfCode) $post['title'] = $adventofcodeday['title'];
if ($isSubEuler) $post['canonical'] = $eulerproblem['canonical'];
if ($isSubAdventOfCode) $post['canonical'] = $adventofcodeday['canonical'];
return $post;
}
public function getPostFragment($post)
{
return file_get_contents($post['file_fragment']);
}
public function checkConsistency()
{
$keys = [];
$this->load();
foreach ($this->staticData as $post)
{
if (in_array($post['id'], $keys)) return ['result'=>'err', 'message' => 'Duplicate key ' . $post['id']];
$keys []= $post['id'];
if ($post['cat'] !== 'log' && $post['cat'] !== 'blog') return ['result'=>'err', 'message' => 'Unknown cat ' . $post['cat']];
if ($post['type'] === 'markdown') {
if (!file_exists($post['file_fragment'])) return ['result'=>'err', 'message' => 'Fragment not found ' . $post['fragment']];
} else if ($post['type'] === 'plain') {
if (!file_exists($post['file_fragment'])) return ['result'=>'err', 'message' => 'Fragment not found ' . $post['fragment']];
} else if ($post['type'] === 'euler') {
// aok
} else if ($post['type'] === 'aoc') {
if (!array_key_exists('aoc:year', $post['extras'])) return ['result'=>'err', 'message' => 'AdventOfCode metadata [aoc:year] missing: ' . $post['title']];
// aok
} else {
return ['result'=>'err', 'message' => 'Unknown type ' . $post['type']];
}
}
return ['result'=>'ok', 'message' => ''];
}
}

View File

@@ -0,0 +1,140 @@
<?php
class Books
{
/** @var array */
private $staticData;
public function __construct()
{
$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';
$a['imgfull_url'] = '/data/images/book_img/' . $a['id'] . '_full.png';
$a['imgfull_path'] = __DIR__ . '/../data/images/book_img/' . $a['id'] . '_full.png';
$a['preview_url'] = '/data/dynamic/bookprev_' . $a['id'] . '.png';
$a['preview_path'] = __DIR__ . '/../data/dynamic/bookprev_' . $a['id'] . '.png';
$a['url'] = '/books/view/' . $a['id'] . '/' . destructiveUrlEncode($a['title']);
$a['extraimages_urls'] = [];
$a['extraimages_paths'] = [];
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['book_count'] = is_array($a['pdf']) ? count($a['pdf']) : 1;
return $a;
}
public function listAll()
{
return $this->staticData;
}
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 (!file_exists($prog['imgfront_path'])) return ['result'=>'err', 'message' => 'Image not found ' . $prog['title_short']];
if (!file_exists($prog['imgfull_path'])) return ['result'=>'err', 'message' => 'Image not found ' . $prog['title_short']];
foreach ($prog['extraimages_paths'] as $eipath)
{
if (!file_exists($eipath)) return ['result'=>'err', 'message' => 'Extra-Image not found ' . $prog['title_short']];
}
if ($prog['book_count'] <= 0) return ['result'=>'err', 'message' => 'BookCount must be greater than zero ' . $prog['title_short']];
if ($prog['book_count'] > 1 && !is_array($prog['pdf'])) return ['result'=>'err', 'message' => 'Attribute [pdf] must be an array ' . $prog['title_short']];
if ($prog['book_count'] > 1 && count($prog['pdf']) !== $prog['book_count']) return ['result'=>'err', 'message' => 'Attribute [pdf] must be the correct size ' . $prog['title_short']];
if ($prog['book_count'] === 1 && !is_string($prog['pdf'])) return ['result'=>'err', 'message' => 'Attribute [pdf] must be an string ' . $prog['title_short']];
if ($prog['book_count'] > 1 && !is_array($prog['pages'])) return ['result'=>'err', 'message' => 'Attribute [pages] must be an array ' . $prog['title_short']];
if ($prog['book_count'] > 1 && count($prog['pages']) !== $prog['book_count']) return ['result'=>'err', 'message' => 'Attribute [pages] must be the correct size ' . $prog['title_short']];
if ($prog['book_count'] === 1 && !is_string($prog['pages'])) return ['result'=>'err', 'message' => 'Attribute [pages] must be an string ' . $prog['title_short']];
}
if ($warn != null) return $warn;
return ['result'=>'ok', 'message' => ''];
}
public function checkThumbnails()
{
foreach (self::listAll() as $book)
{
if (!file_exists($book['preview_path'])) return ['result'=>'err', 'message' => 'Preview not found ' . $book['title_short']];
}
return ['result'=>'ok', 'message' => ''];
}
public function createPreview($prog)
{
global $CONFIG;
$src = $prog['imgfront_path'];
$dst = $prog['preview_path'];
if ($CONFIG['use_magick'])
magick_resize_image($src, 200, 0, $dst);
else
smart_resize_image($src, 200, 0, true, $dst);
}
public function getBook($id)
{
foreach (self::listAll() as $book) {
if ($book['id'] == $id) return $book;
}
return null;
}
public function getRepositoryHost($book)
{
$r = $book['repository'];
if (startsWith($r, "http://")) $r = substr($r, strlen("http://"));
if (startsWith($r, "https://")) $r = substr($r, strlen("https://"));
if (startsWith($r, "www.")) $r = substr($r, strlen("www."));
if (startsWith(strtolower($r), "gitlab")) return "Gitlab";
if (startsWith(strtolower($r), "github")) return "Github";
if (startsWith(strtolower($r), "bitbucket")) return "Bitbucket";
return "Online";
}
}

View File

@@ -0,0 +1,94 @@
<?php
class Database
{
/* @var PDO $pdo */
private $pdo = NULL;
public function __construct(Website $site)
{
$this->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();
}
}

View File

@@ -0,0 +1,110 @@
<?php
class Euler
{
/** @var array */
private $staticData;
public function __construct()
{
$this->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;
$a['rating'] = self::rateTime($a);
$a['url'] = '/blog/1/Project_Euler_with_Befunge/problem-' . $n3p;
$a['canonical'] = "https://www.mikescher.com" . $a['url'];
$a['is93'] = ($a['width'] <= 80 AND $a['height'] <= 25);
$a['url_euler'] = 'https://projecteuler.net/problem=' . $n3p;
$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');
return $a;
}
private static function rateTime($problem)
{
if ($problem['time'] < 100) // < 100ms
return 0;
if ($problem['time'] < 15 * 1000) // < 5s
return 1;
if ($problem['time'] < 60 * 1000) // < 1min
return 2;
if ($problem['time'] < 5 * 60 * 1000) // < 5min
return 3;
return 4;
}
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 ($this->staticData as $ep)
{
if (in_array($ep['number'], $numbers)) return ['result'=>'err', 'message' => 'Duplicate number ' . $ep['number']];
$numbers []= $ep['number'];
if (in_array($ep['title'], $realname)) return ['result'=>'err', 'message' => 'Duplicate title ' . $ep['title']];
$realname []= $ep['title'];
if (!file_exists($ep['file_description'])) return ['result'=>'err', 'message' => 'file_description not found ' . $ep['file_description']];
if (!file_exists($ep['file_code'])) return ['result'=>'err', 'message' => 'file_code not found ' . $ep['file_code']];
if (!file_exists($ep['file_explanation'])) return ['result'=>'err', 'message' => 'file_explanation not found ' . $ep['file_explanation']];
}
if ($warn != null) return $warn;
return ['result'=>'ok', 'message' => ''];
}
}

View File

@@ -0,0 +1,42 @@
<?php
require_once (__DIR__ . '/../../extern/egg/ExtendedGitGraph2.php');
class MikescherGitGraph
{
/** @var ExtendedGitGraph2 */
private $extgitgraph;
/** @noinspection PhpUnhandledExceptionInspection */
public function __construct(Website $site)
{
$this->extgitgraph = new ExtendedGitGraph2($site->config['extendedgitgraph']);
}
public function getPathRenderedData()
{
return __DIR__ . '/../../dynamic/egg/cache_fullrenderer.html';
}
/**
* @return string|null
* @throws Exception
*/
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' => ''];
}
}

View File

@@ -0,0 +1,280 @@
<?php
class Programs
{
const PROG_LANGS = [ 'Java', 'C#', 'Delphi', 'PHP', 'C++' ];
const URL_ORDER =
[
'github',
'sourceforge',
'download',
'playstore',
'amazonappstore',
'windowsstore',
'itunesstore',
'homepage',
'wiki',
'alternativeto',
'changelog',
];
const LICENSES =
[
'MIT' => 'https://choosealicense.com/licenses/mit/',
'Unlicense' => 'https://choosealicense.com/licenses/unlicense/',
'GPL-3.0' => 'https://choosealicense.com/licenses/gpl-3.0/',
'Apache-2.0' => 'https://choosealicense.com/licenses/apache-2.0/',
'Mozilla-2.0' => 'https://choosealicense.com/licenses/mpl-2.0/',
];
/** @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['preview_url'] = '/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['url'] = '/programs/view/' . $a['internal_name'];
$a['has_extra_images'] = array_key_exists('extra_images', $a) && count($a['extra_images'])>0;
$a['extraimages_urls'] = [];
$a['extraimages_paths'] = [];
if ($a['has_extra_images'])
{
foreach ($a['extra_images'] as $fn)
{
$a['extraimages_urls'] []= '/data/images/program_img/' . $fn;
$a['extraimages_paths'] []= __DIR__ . '/../data/images/program_img/' . $fn;
}
}
return $a;
}
public function listAll()
{
return $this->staticData;
}
public function listAllNewestFirst($filter = '')
{
$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 function getProgramByInternalName($id)
{
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 function getProgramDescription($prog)
{
return file_get_contents($prog['file_longdescription']);
}
private static function urlComparator($a, $b)
{
$na = 0;
$nb = 0;
if (strpos($a, '#') !== FALSE) { $na = intval(explode('#', $a)[1]); $a=explode('#', $a)[0]; }
if (strpos($b, '#') !== FALSE) { $nb = intval(explode('#', $b)[1]); $b=explode('#', $b)[0]; }
$ia = array_search($a, Programs::URL_ORDER);
$ib = array_search($b, Programs::URL_ORDER);
if ($ia === false && $ib === false) return strcasecmp($a, $b);
if ($ia === false && $ib !== false) return +1; // sort [IA | IB]
if ($ia !== false && $ib === false) return -1; // sort [IB | IA]
if ($ia === $ib) return ($na < $nb) ? -1 : +1;
return ($ia < $ib) ? -1 : +1;
}
public function getURLs($prog)
{
$urls = $prog['urls'];
uksort($urls, function($a,$b){return self::urlComparator($a,$b);});
$result = [];
foreach ($urls as $fulltype => $urldata)
{
$type = $fulltype;
if (strpos($fulltype, '#') !== FALSE) $type=explode('#', $fulltype)[0];
$caption = '?';
$css = '?';
$svg = '?';
$direct = false;
if ($type === 'download') { $caption = 'Download'; $css = 'prgv_dl_download'; $svg = 'download'; }
if ($type === 'github') { $caption = 'Github'; $css = 'prgv_dl_github'; $svg = 'github'; }
if ($type === 'homepage') { $caption = 'Homepage'; $css = 'prgv_dl_homepage'; $svg = 'home'; }
if ($type === 'wiki') { $caption = 'Wiki'; $css = 'prgv_dl_wiki'; $svg = 'wiki'; }
if ($type === 'playstore') { $caption = 'Google Playstore'; $css = 'prgv_dl_playstore'; $svg = 'playstore'; }
if ($type === 'amazonappstore') { $caption = 'Amazon Appstore'; $css = 'prgv_dl_amznstore'; $svg = 'amazon'; }
if ($type === 'windowsstore') { $caption = 'Microsoft Store'; $css = 'prgv_dl_winstore'; $svg = 'windows'; }
if ($type === 'itunesstore') { $caption = 'App Store'; $css = 'prgv_dl_appstore'; $svg = 'apple'; }
if ($type === 'sourceforge') { $caption = 'Sourceforge'; $css = 'prgv_dl_sourceforge'; $svg = 'sourceforge'; }
if ($type === 'alternativeto') { $caption = 'AlternativeTo'; $css = 'prgv_dl_alternativeto'; $svg = 'alternativeto'; }
if ($type === 'changelog') { $caption = 'Changelog'; $css = 'prgv_dl_changelog'; $svg = 'changelog'; }
if (is_array($urldata))
{
$url = $urldata['url'];
if (isset($urldata['caption'])) $caption = $urldata['caption'];
if (isset($urldata['css'])) $css = $urldata['css'];
if (isset($urldata['svg'])) $svg = $urldata['svg'];
}
else
{
$url = $urldata;
}
if ($url === 'direct')
{
$direct = true;
$url = Programs::getDirectDownloadURL($prog);
}
$result []=
[
'type' => $type,
'caption' => $caption,
'svg' => $svg,
'href' => $url,
'css' => $css,
'isdirect' => $direct,
];
}
return $result;
}
public function getLicenseUrl($license)
{
return self::LICENSES[$license];
}
public function getDirectDownloadURL($prog)
{
return '/data/binaries/'.$prog['internal_name'].'.zip';
}
public function getDirectDownloadPath($prog)
{
return (__DIR__ . '/../../data/binaries/'.$prog['internal_name'].'.zip');
}
public function checkConsistency()
{
$warn = null;
$this->load();
$intname = [];
$realname = [];
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'];
if ($prog['internal_name_alt'] !== null)
{
if (in_array($prog['internal_name_alt'], $intname)) return ['result'=>'err', 'message' => 'Duplicate internal_name ' . $prog['name']];
$intname []= $prog['internal_name_alt'];
}
if (in_array($prog['name'], $realname)) return ['result'=>'err', 'message' => 'Duplicate name ' . $prog['name']];
$realname []= $prog['name'];
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']];;
if (!in_array($prog['prog_language'], self::PROG_LANGS)) return ['result'=>'err', 'message' => 'Unknown prog-lang ' . $prog['name']];
if (strlen($prog['short_description'])> 128) $warn = ['result'=>'warn', 'message' => 'short_description too long ' . $prog['name']];
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)
{
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['type']==='playstore' || $xurl['type']==='itunesstore') $isdl = true;
}
if (!$isdl) return ['result'=>'err', 'message' => 'No download link ' . $prog['name']];
if (!file_exists($prog['mainimage_path'])) return ['result'=>'err', 'message' => 'Image not found ' . $prog['name']];
if (!file_exists($prog['file_longdescription'])) return ['result'=>'err', 'message' => 'Description not found ' . $prog['name']];
foreach ($prog['extraimages_paths'] as $eipath)
{
if (!file_exists($eipath)) return ['result'=>'err', 'message' => 'Extra-Image not found ' . $prog['title_short']];
}
}
if ($warn != null) return $warn;
return ['result'=>'ok', 'message' => ''];
}
public function checkThumbnails()
{
foreach ($this->staticData as $prog)
{
if (!file_exists($prog['preview_path'])) return ['result'=>'err', 'message' => 'Preview not found ' . $prog['name']];
}
return ['result'=>'ok', 'message' => ''];
}
public function createPreview($prog)
{
$src = $prog['mainimage_path'];
$dst = $prog['preview_path'];
if (Website::inst()->config['use_magick'])
magick_resize_image($src, 250, 0, $dst);
else
smart_resize_image($src, 250, 0, true, $dst);
}
}

View File

@@ -0,0 +1,64 @@
<?php
class UpdatesLog
{
/** @var Website */
private $site;
/** @var array */
private $staticData;
public function __construct(Website $site)
{
$this->site = $site;
$this->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)
{
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],
]);
}
}

View File

@@ -0,0 +1,31 @@
<?php
class WebApps
{
/** @var array */
private $staticData;
public function __construct()
{
$this->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;
}
}