447 lines
16 KiB
PHP
447 lines
16 KiB
PHP
<?php
|
|
if (file_exists('config/config.ini')) die('HTMLy already installed!');
|
|
error_reporting(E_ALL);
|
|
ini_set("display_errors", 1);
|
|
|
|
function is__writable($path) {
|
|
|
|
if ($path[strlen($path) - 1] == '/') // recursively return a temporary file path
|
|
return is__writable($path . uniqid(mt_rand()) . '.tmp');
|
|
else if (is_dir($path))
|
|
return is__writable($path . '/' . uniqid(mt_rand()) . '.tmp');
|
|
// check tmp file for read/write capabilities
|
|
$rm = file_exists($path);
|
|
$f = @fopen($path, 'a');
|
|
if ($f === false)
|
|
return false;
|
|
fclose($f);
|
|
if (!$rm)
|
|
unlink($path);
|
|
return true;
|
|
}
|
|
|
|
function from($source, $name) {
|
|
if (is_array($name)) {
|
|
$data = array();
|
|
foreach ($name as $k)
|
|
$data[$k] = isset($source[$k]) ? $source[$k] : null;
|
|
return $data;
|
|
}
|
|
return isset($source[$name]) ? $source[$name] : null;
|
|
}
|
|
|
|
class Message {
|
|
|
|
protected $errors = array();
|
|
|
|
public function error($message) {
|
|
$this->errors[] = $message;
|
|
}
|
|
|
|
protected $warnings = array();
|
|
|
|
public function warning($message) {
|
|
$this->warnings[] = $message;
|
|
}
|
|
|
|
public function run() {
|
|
$string = "";
|
|
if (!empty($this->errors)) {
|
|
foreach ($this->errors as $error) {
|
|
$string .= '<p class="error">' . $error . "</p>";
|
|
}
|
|
}
|
|
if (!empty($this->warnings)) {
|
|
foreach ($this->warnings as $warning) {
|
|
$string .= '<p class="warning">' . $warning . "</p>";
|
|
}
|
|
}
|
|
return $string;
|
|
}
|
|
|
|
}
|
|
|
|
class Settings
|
|
{
|
|
|
|
protected $user = "";
|
|
protected $userPassword = "";
|
|
protected $siteUrl = "";
|
|
|
|
protected $overwriteEmptyForm = array(
|
|
"social.twitter" => "",
|
|
"social.facebook" => "",
|
|
);
|
|
|
|
protected function extractUser()
|
|
{
|
|
$this->user = (string)$_REQUEST["user_name"];
|
|
unset($_REQUEST["user_name"]);
|
|
$this->userPassword = (string)$_REQUEST["user_password"];
|
|
unset($_REQUEST["user_password"]);
|
|
}
|
|
|
|
protected function convertRequestToConfig()
|
|
{
|
|
$array = array();
|
|
foreach ($_REQUEST as $name => $value) {
|
|
if (!is_string($value) || empty($value))
|
|
continue;
|
|
$name = str_replace("_", ".", $name);
|
|
$array[$name] = $value;
|
|
}
|
|
foreach ($this->overwriteEmptyForm as $name => $value) {
|
|
if (!isset($array[$name])) {
|
|
$array[$name] = $value;
|
|
}
|
|
}
|
|
return $array;
|
|
}
|
|
|
|
protected function generateSiteUrl()
|
|
{
|
|
$dir = trim(dirname(substr($_SERVER["SCRIPT_FILENAME"], strlen($_SERVER["DOCUMENT_ROOT"]))), '/');
|
|
if ($dir == '.' || $dir == '..') {
|
|
$dir = '';
|
|
}
|
|
$port = '';
|
|
if ($_SERVER["SERVER_PORT"] != "80" && $_SERVER["SERVER_PORT"] != "443") {
|
|
$port = ':' . $_SERVER["SERVER_PORT"];
|
|
}
|
|
$scheme = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https' : 'http';
|
|
if ($dir === '') {
|
|
$this->siteUrl = $scheme . '://' . trim($_SERVER['SERVER_NAME'], "/") . $port . "/";
|
|
return;
|
|
}
|
|
$this->siteUrl = $scheme . '://' . trim($_SERVER['SERVER_NAME'], "/") . $port . "/" . $dir . '/';
|
|
}
|
|
|
|
protected function overwriteINI($data, $string)
|
|
{
|
|
foreach ($data as $word => $value) {
|
|
$string = preg_replace("/^" . $word . " = .+$/m", $word . ' = "' . $value . '"', $string);
|
|
}
|
|
return $string;
|
|
}
|
|
|
|
protected function saveConfigs()
|
|
{
|
|
$this->extractUser();
|
|
//save config.ini
|
|
$config = array(
|
|
"site.url" => $this->siteUrl,
|
|
"timezone" => $this->getTimeZone(),
|
|
);
|
|
$config += $this->convertRequestToConfig();
|
|
$configFile = file_get_contents("config/config.ini.example");
|
|
$configFile = $this->overwriteINI($config, $configFile);
|
|
file_put_contents("config/config.ini", $configFile, LOCK_EX);
|
|
|
|
//save users/[Username].ini
|
|
$userFile = file_get_contents("config/users/username.ini.example");
|
|
$parsed = parse_ini_string($userFile);
|
|
if (isset($parsed['encryption'])) {
|
|
$userFile = $this->overwriteINI(array(
|
|
'encryption' => 'sha512',
|
|
'password' => hash('sha512', $this->userPassword),
|
|
'role' => 'admin',
|
|
'mfa_secret' => 'disabled',
|
|
), $userFile);
|
|
} else {
|
|
$userFile = $this->overwriteINI(array(
|
|
"password" => $this->userPassword,
|
|
'role' => 'admin',
|
|
'mfa_secret' => 'disabled',
|
|
), $userFile);
|
|
}
|
|
file_put_contents("config/users/" . $this->user . ".ini", $userFile, LOCK_EX);
|
|
}
|
|
|
|
protected function testTheEnvironment()
|
|
{
|
|
$message = new Message;
|
|
|
|
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50300) {
|
|
$message->error('HTMLy requires at least PHP 5.3 to run.');
|
|
}
|
|
if (!in_array('https', stream_get_wrappers())) {
|
|
$message->error('Installer needs the https wrapper, please install openssl.');
|
|
}
|
|
if (function_exists('apache_get_modules') && !in_array('mod_rewrite', apache_get_modules())) {
|
|
$message->warning('mod_rewrite must be enabled if you use Apache.');
|
|
}
|
|
if (!is__writable("./")) {
|
|
$message->error('no permission to write in the Directory.');
|
|
}
|
|
return $message->run();
|
|
}
|
|
|
|
public function __construct()
|
|
{
|
|
$message = $this->testTheEnvironment();
|
|
|
|
$this->generateSiteUrl();
|
|
if (!empty($message)) {
|
|
echo $message;
|
|
} elseif ($this->runForm()) {
|
|
unlink(__FILE__);
|
|
header("Location:" . $this->siteUrl . "add/content?type=post");
|
|
exit();
|
|
}
|
|
}
|
|
|
|
protected function getTimeZone()
|
|
{
|
|
static $ip;
|
|
if (empty($ip)) {
|
|
$ip = @file_get_contents("http://ipecho.net/plain");
|
|
if (!is_string($ip)) {
|
|
$ip = $_SERVER['REMOTE_ADDR'];
|
|
}
|
|
}
|
|
$json = @json_decode(@file_get_contents("http://ip-api.com/json/" . $ip), true);
|
|
if (isset($json['timezone']))
|
|
return $json['timezone'];
|
|
return 'Europe/Berlin';
|
|
}
|
|
|
|
protected function runForm()
|
|
{
|
|
if (from($_REQUEST, 'user_name') && from($_REQUEST, 'user_password')) {
|
|
$this->saveConfigs();
|
|
$_SESSION[$this->siteUrl]["user"] = $this->user;
|
|
return true;
|
|
} else {
|
|
unset($_SESSION[$this->siteUrl]["user"]);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if(from($_SERVER,'QUERY_STRING') == "rewriteRule.html")
|
|
{
|
|
echo "YES!";
|
|
die();
|
|
}
|
|
|
|
$samesite = 'strict';
|
|
if(PHP_VERSION_ID < 70300) {
|
|
session_set_cookie_params('samesite='.$samesite);
|
|
} else {
|
|
session_set_cookie_params(['samesite' => $samesite]);
|
|
}
|
|
|
|
session_start();
|
|
new Settings;
|
|
|
|
?>
|
|
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
*, *:before, *:after {
|
|
-moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
|
|
}
|
|
.responsive {
|
|
min-width: 512px;
|
|
width: 100%;
|
|
max-width: 730px;
|
|
}
|
|
section, footer, header, aside, nav {
|
|
display: block;
|
|
}
|
|
.error:before {
|
|
content: "Error: ";
|
|
color: red;
|
|
font-weight: bold;
|
|
font-size: 120%;
|
|
}
|
|
|
|
.warning:before {
|
|
content: "Warning: ";
|
|
color: gold;
|
|
font-weight: bold;
|
|
font-size: 120%;
|
|
}
|
|
body {
|
|
font-size: 17px;
|
|
line-height: 1.6em;
|
|
font-family: Georgia, sans-serif;
|
|
background: #F7F7F7;
|
|
color: #444444;
|
|
}
|
|
#cover {
|
|
padding: 0 0 20px 0;
|
|
float: left;
|
|
width: 100%;
|
|
}
|
|
#header-wrapper {
|
|
float: left;
|
|
width: 100%;
|
|
position: relative;
|
|
}
|
|
#header {
|
|
position: relative;
|
|
padding: 0 15px;
|
|
margin: 0 auto;
|
|
}
|
|
#branding {
|
|
text-align: left;
|
|
position: relative;
|
|
width: 100%;
|
|
float: left;
|
|
margin: 1em 0;
|
|
text-shadow: 0 1px 0 #ffffff;
|
|
}
|
|
#branding h1{
|
|
font-size: 36px;
|
|
font-family: Georgia,sans-serif;
|
|
margin: 0;
|
|
}
|
|
#branding h1 a{
|
|
color: inherit;
|
|
text-decoration: inherit;
|
|
}
|
|
#branding h1 a:hover{
|
|
color: black;
|
|
}
|
|
#branding p {
|
|
margin: 0;
|
|
font-style: italic;
|
|
margin-top: 5px;
|
|
}
|
|
#main-wrapper {
|
|
float: left;
|
|
width: 100%;
|
|
background: #ffffff;
|
|
position: relative;
|
|
border-top: 1px solid #DFDFDF;
|
|
border-bottom: 1px solid #DFDFDF;
|
|
}
|
|
#main {
|
|
position: relative;
|
|
padding: 0;
|
|
margin: 0 auto;
|
|
background: #ffffff;
|
|
overflow: hidden;
|
|
padding: 30px 15px;
|
|
}
|
|
label{
|
|
width: 100%;
|
|
max-width: 180px;
|
|
float:left;
|
|
}
|
|
input:not([type=submit]), select{
|
|
float:left;
|
|
width: 100%;
|
|
max-width: 520px;
|
|
font-size: 80%;
|
|
}
|
|
input{
|
|
padding: 2px;
|
|
}
|
|
input[type=submit]{
|
|
margin-top: 10px;
|
|
padding: 5px;
|
|
width: 100%;
|
|
}
|
|
span.required {
|
|
color: red;
|
|
}
|
|
</style>
|
|
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAMAAABiM0N1AAACVVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACfnJ28vLzKxsfJycmrqKm/vLykoqKLiYlZWFjDw8Pg4ODQzc26t7jOy8vGwsPa2NiYlpYkJCSdnZ3S0tKppqd8enpCQULQzs/Pzc21s7O0tLTl5eWtra3a2trw8PCwra7KyMjW09Rqamrt7e3u7u729vby8vLy8vLh39/29vbX09TU0tL/VAD////19PTX09Tv7e3t6+vW0tPc2Nn/TgDz8fLw7u7Y1NX/UADx8PDd2tv/UgD/SwD/UwDa19fZ1dbq6Oj08vLm5OTn5eXr6erl4uPf29zj4OHh3t/g3d3x7+//RgDz8PH/PQD/QgD/LgH/KgD49/j/OwD/OADk4eL/RAD/PwD/SAD8/Pz/JwL/+PXo5ubi39///fvp5uf/IwD/Wwz/NQD/mmz/gkf/8u7/MA//MgD/ZyL/5dz/r5H/TQ/839j/3c/8qp78pJX/VgT/WhL/upn/Yxn/vKH/vqX07ev/rof/x6v/yq//Zkz/djX+wbT/koD/ci3/8Or/cFH/f0H/iFH36ef/yrX6uK3/TjL/XEL/6+L+nYj/VDT/Nw7/QAv/cDr/18r/k2H/jGf/aD//zr//SAb/ekPW0tP9fmv15eT/PBv519H/oob/RB79tqf/gmH/lHX/1cL/eEn/pnv/XDH/sZ7/VyT/n4H/wqj7vLL/g0719PT29fXBSHwPAAAASXRSTlMADREZCQMHAQIEHwYWEyUcKCsiPQw3Czo0MT9ALY+Q4p2fwZN0WZjB+bbuyeuESHapmW9Sx9GdiMmCteSmwNxf3OD07OjP9/7pibsSEAAAB91JREFUWMOdmHdXE0EUxU0VUkjZbBqx9957r+c4CrpidDf2SgRCYiBggYig2Hvvvddj7/3wuXzzZpPNGkjQ+8/umZ357X337QylS051BRWg6F2X/xMgCi0mu9fLFRcXe70Op84NuP+guJ2+4SP6T54yJUEImTtlwMhJ/Tx267+xwIvN26/nTMK0cOFCgpo9eYTHaQRW5zGeCbMYQRHDtfXk7PqCrp0qymDhu89JUbJZiZGcsxBQee3oAyMmErKmQyXI/P681gD15bZj9fRkmFyoAZzJAKZy2DGY/AMAk09kdveAGUgdp1wE6SxVdOrmy3O3Ig0Ndbduv7x5KuNBNenvhcw75Ni7J9rSk18dOtcMjEikChSBy7nDrxQU6cnrDV074Ji6k60pnbrbDJCqZLSmMgyqrIkmqyLNF6+nJ5CePjOSsjkWbm562qHXDXVVsZqwJATF0IIFITEoSOGaWNXrw+VpUnd7e59B10INN3G5rAP3ABONS0FgKAoFpXi06tab1KzEBFs2qatBz49sK2f61dwQicUlcUGWRCEeu/++XNYszookFcfs6Enk54fq6lpqpOCCdhWUKpOHU6QBHgxcHVBfUsZ0qCGSjAuqotQFhmOH5akL+9shcFVARn6A/PBCXSRWq7KTZao2elOenOC0WJxSmGlSCdOBZuBAOrkk1j54I0+fHDBmWCoo1PMz2YOtt+uSYeDkI309xeYv9VNLiiHbiFKmww0t8VRdZOfBs6ebGtutLny3hC0Y6TAWpkGFet9ENny9OVIjpGYTVP2ZpvZI+w+UMnEatIQtM2u51ThYcrEuJoXUINCn89m9kz6WMdAEE6bEWubsvh51qrklrgREFJ3ZmxXT/utszTyfvrAgFbVvLI6VHqqLYmFZILLn6t8kobUUF+3ya8ASRm3UcGtxbOntKjQkS9r/9cq3yzJp5+7QX5YermGW+uogblaZbsZq1J6qmJT5zspoLJZ8+kxGtf5FkvaxVf3tUBvrmXPSLqrVFyI1mZ/0+aNSbbiyInblACP95Sl4ohSXjfW5zBRUYHbZx+NI2cWqcOZc2q8vx+EYevCeVfdCfarsLsdlQz0sJIjIN2071ZorSaxMHfax40K44iNLfK+K1NSGy9b6tXoIiWbtHbeOqu1eVMgGkfrHcHQ8wdsbqs28t3odajiCICItPx0HEu8wouz2n4bcW/HuWuY2bEww0BiLG9KmIM/QtVSJ+5Uq0KODKVKrKDzHxA9mnlMiWYvqp3OZU6ANVOR+XFT1N/rgwz5GeiwKn/HmRcarjpANqBTIDaUx0LuwKkwhXhGN3mUN2ytK+D2dzLB0XAaN0WkAVEBB47ZRJe6pQaIgSPGKD0j6GQw+xOT3B5WwE9tQwy0aIwN5p+FA9RVWmvLKx1ehYW+ZpaCAZX4WlPYz0A4/gFhpgfGbqNouqsO+Wg/bHmJGwA8hiI17qxwzu6tx2VCPRSOHbR+2g6r8grr92LQmUcBv6FGt+JteLygH8cmluGwsb011zTkDR9bXV6g+yD0E9EQQj+6ktT0P7iWgA4rrO6W4bHwgDdJxKzaDdpCnqi1ygob7vVYMorXvQgi3SfooPk82bKYaXWSFDxK3iIUfsoWq+puqbUdPXH50LhYOhm4AAF4i1lNnadet1bhoo9+GW6QLBTn64Nh6aK7qPIolkxUQrlCRbGmJ1oakaAtcZdeNl0tx0TheR0F4jFhN/hUbQZvJj8zaRKmyoqYW0EI8Go3WSCGhEq6VgtwzsmMj1TCHBY8RDMnGD8HBsj37RfUXKQTpb0eCJElwJ+JVZIbuLMclS/wmzBqPWo3O0XcF1WbSyt6XX6fJJlwyyEsjAhBL2+TpgcMlOx+KneJc2lmGC5b47TqN/LO2gNYWGLYCRe4cDXWC07iPbGSGeJsVI5Jrszg9vZdQbSfPOgE6cpasxumrwBBWhiDaN5tj9BJUCTkZzAs6RkrY7FFekyVlCPum0Zn4UexZGTl5JI+fY6SczR3COXVa+KxTIAO1VMT1XokqJzcac+ZzhpSzmYuKA2BIjlqOGxrn8A9mz8vIvvM5+rWPlK1k6uN1YkIIki25tTqnr9tiNqGU/jRrH3P82E5SkuJ4ipSWobBxUJy327JVqHXVpP50YztVfYF9u2sVUy+PHQpDQwqIFVfEd1ssz1oPB8bPayrWkWsnLhNSujLF4ewmSNrMDKmLo6TBy5hofaT+7O6mSxhM0+6z9QQwS5bJ6sPBH/BWFxamJhldlOQt7p2aumTtUqLS0nVpzMBuHruTBqQUphRndFmB5ON6LUpr1baSNdWUUb2wZNsqZbx3sRc4qYCySRpKcnj6DlmUKepANTCwDxfokIMkVp3dx3UbvKhDLZ5azDuKTDorcDCgDkgWm9Pu8HLdeixuVwN7FXvATi4OI7m1FjBFUf169ciiDBrt5wP2IihL62I5d0QymPUaagpQPp4b3nfUoB6IG9yj99RhYziPzwEYaseNnFz/QABTkLkNXNkdAS/v4bhiEMd5eK/PwTAWrUZvNuTisPLMepeWopxFFKbITik2xBghHsbJY0rv0lgtwDI5gSbLiRQrYvLYUZICV26NVmux6HQ2G/BMNhtAKMWlYDqLMgILYForCm40GrfeaKYY5HQSRVkUpte7XSC3W683IiXl5p9YFAY4EL0a8nvJ/+9DMJIH8gettE5FHu6NcQAAAABJRU5ErkJggg==" type="image/ico" />
|
|
<title>HTMLy Installer</title>
|
|
</head>
|
|
<body>
|
|
<div id="cover">
|
|
<div id="header-wrapper">
|
|
<header id="header" class="responsive">
|
|
<div id="branding">
|
|
<h1>
|
|
HTMLy
|
|
</h1>
|
|
<div id="blog-tagline">
|
|
<p>the HTMLy Installer Tool</p>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
</div>
|
|
</div>
|
|
<div id="main-wrapper">
|
|
<div id="main" class="responsive">
|
|
|
|
<form method="POST">
|
|
<label for="user_name">Username:<span class="required">*</span></label>
|
|
<input name="user_name" value="" placeholder="Your User Name" required>
|
|
<br/>
|
|
<label for="user_password">Password:<span class="required">*</span></label>
|
|
<input name="user_password" value="" type="password" placeholder="Password" required>
|
|
<br/>
|
|
<br/>
|
|
<label for="blog_title">Blog Title:</label>
|
|
<input name="blog_title" value="" placeholder="HTMLy">
|
|
<br/>
|
|
<label for="blog_tagline">Blog Tagline:</label>
|
|
<input name="blog_tagline" value="" placeholder="Just another HTMLy blog">
|
|
<br/>
|
|
<label for="blog_description">Blog Description:</label>
|
|
<input name="blog_description" value="" placeholder="Proudly powered by HTMLy, a databaseless blogging platform.">
|
|
<br/>
|
|
<label for="blog_copyright">Blog Copyright:</label>
|
|
<input name="blog_copyright" value="" placeholder="(c) Your name.">
|
|
<br/>
|
|
<br/>
|
|
<label for="social_bluesky">Bluesky Link:</label>
|
|
<input name="social_bluesky" type="url" value="" placeholder="https://bsky.app/profile/username.bsky.social">
|
|
<br/>
|
|
<label for="social_twitter">Twitter Link:</label>
|
|
<input name="social_twitter" type="url" value="" placeholder="https://twitter.com/gohtmly">
|
|
<br/>
|
|
<label for="social_facebook">Facebook Link:</label>
|
|
<input name="social_facebook" type="url" value="" placeholder="https://www.facebook.com/gohtmly">
|
|
<br/>
|
|
<label for="comment_system">Comment System:</label>
|
|
<select name="comment_system" onchange="checkCommentSystemSelection();" id="comment.system">
|
|
<option value="disable">disable</option>
|
|
<option value="facebook">facebook</option>
|
|
<option value="disqus">disqus</option>
|
|
</select>
|
|
<div id="facebook" style="display:none">
|
|
<br/>
|
|
<label for="fb_appid">Facebook AppId:</label>
|
|
<input name="fb_appid" value="" placeholder="facebook AppId">
|
|
</div>
|
|
<div id="disqus" style="display:none">
|
|
<br/>
|
|
<label for="disqus_shortname">Disqus Shortname:</label>
|
|
<input name="disqus_shortname" value="" placeholder="disqus shortname">
|
|
</div>
|
|
<br/><input type="submit" value="Install via Tool">
|
|
</form>
|
|
<br><br>
|
|
<div><small><em>Based on HTMLy installer (https://github.com/Kanti/htmly-installer) by <a href="https://github.com/Kanti" target="_blank">Matthias Vogel</a></em></small></div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
function checkCommentSystemSelection(){
|
|
a = document.getElementById("comment.system");
|
|
if(a.value == "facebook")
|
|
document.getElementById("facebook").setAttribute("style","display:inline");
|
|
else
|
|
document.getElementById("facebook").setAttribute("style","display:none");
|
|
if(a.value == "disqus")
|
|
document.getElementById("disqus").setAttribute("style","display:inline");
|
|
else
|
|
document.getElementById("disqus").setAttribute("style","display:none");
|
|
return a.value;
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|