diff --git a/README.md b/README.md index e69de29..7e35bf8 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,50 @@ +<<<<<<< HEAD +# kvazar-network webapp +Web-oriented content exploring platform for Kevacoin Blockchain + +### requirements +``` +php-8^ +php-curl +php-mbstring +php-sqlite3 +php-pdo +php-bcmath +php-gd +``` +#### database + +https://github.com/kvazar-network/database + +##### MySQL + +https://github.com/kvazar-network/webapp/tree/master + +##### SQLite + +https://github.com/kvazar-network/webapp/tree/sqlite + +#### crontab + +``` +0 0 * * * /path-to/php /path-to/crontab/sitemap.php > /dev/null 2>&1 +``` + +### nginx sef_mode example + +``` +location / { + try_files $uri $uri/ =404 @sef; +} + +location @sef { + rewrite ^(/.*)$ /?$1 last; +} +``` + +### examples + +#### yggdrasil +[http://[203:9fd0:95df:54d7:29db:5ee1:fe2d:95c7]](http://[203:9fd0:95df:54d7:29db:5ee1:fe2d:95c7]) +======= +>>>>>>> master diff --git a/config-default.php b/config-default.php index a527d31..e6bb98d 100644 --- a/config-default.php +++ b/config-default.php @@ -6,14 +6,16 @@ ini_set('display_startup_errors', '1'); error_reporting(E_ALL); // Application -define('BASE_URL', 'https://kvazar.today'); +define('BASE_URL', 'https://kvazar.today/'); define('PAGE_LIMIT', 10); -define('SEF_MODE', true); define('CACHE_ENABLED', false); +define('TRENDS_ENABLED', false); // alpha +define('TRENDS_SECONDS_OFFSET', 2592000); +define('TRENDS_MIN_LENGHT', 4); +define('TRENDS_LIMIT', 40); + // Database -define('DB_HOST', 'localhost'); -define('DB_PORT', '3306'); -define('DB_NAME', ''); +define('DB_NAME', '../kvazar.sqlite'); define('DB_USERNAME', ''); define('DB_PASSWORD', ''); diff --git a/crontab/sitemap.php b/crontab/sitemap.php index 5991e8b..5058d43 100644 --- a/crontab/sitemap.php +++ b/crontab/sitemap.php @@ -1,9 +1,9 @@ '; @@ -18,12 +18,12 @@ $transactions = []; foreach ($db->getData(false, false, false, 0, 1000000) as $value) { if (!in_array($value['namehash'], $namespaces)) { - $namespace .= '' . BASE_URL . '/' . $value['namehash'] . ''; + $namespace .= '' . BASE_URL . $value['namehash'] . ''; } if (!in_array($value['namehash'], $transactions)) { - $transaction .= '' . BASE_URL . '/' . $value['txid'] . ''; + $transaction .= '' . BASE_URL . $value['txid'] . ''; } $namespaces[] = $value['namehash']; @@ -47,10 +47,10 @@ fclose($handle); $sitemap = ''; $sitemap .= ''; $sitemap .= ' '; -$sitemap .= ' ' . BASE_URL . '/sitemap.namespace.xml'; +$sitemap .= ' ' . BASE_URL . 'sitemap.namespace.xml'; $sitemap .= ' '; $sitemap .= ' '; -$sitemap .= ' ' . BASE_URL . '/sitemap.transaction.xml'; +$sitemap .= ' ' . BASE_URL . 'sitemap.transaction.xml'; $sitemap .= ' '; $sitemap .= ''; diff --git a/library/icon.php b/library/icon.php index 3daeddc..4df6a58 100755 --- a/library/icon.php +++ b/library/icon.php @@ -165,7 +165,7 @@ final class Icon { for ($i = 0; $i < count($shape); $i++) $shape[$i] = $shape[$i] * $this->_spriteZ; - imagefilledpolygon($sprite, $shape, count($shape) / 2, $fg); + imagefilledpolygon($sprite, $shape, $fg); for ($i = 0; $i < $rotation; $i++) $sprite = imagerotate($sprite, 90, $bg); @@ -215,7 +215,7 @@ final class Icon { for ($i = 0; $i < count($shape); $i++) $shape[$i] = $shape[$i] * $this->_spriteZ; if (count($shape) > 0) - imagefilledpolygon($sprite, $shape, count($shape) / 2, $fg); + imagefilledpolygon($sprite, $shape, $fg); return $sprite; } diff --git a/library/sqlite.php b/library/sqlite.php new file mode 100644 index 0000000..fa4aaf1 --- /dev/null +++ b/library/sqlite.php @@ -0,0 +1,268 @@ +_db = new PDO('sqlite:' . $database, $username, $password); + $this->_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $this->_db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); + $this->_db->setAttribute(PDO::ATTR_TIMEOUT, 600); + + $this->_db->query(' + CREATE TABLE IF NOT EXISTS "namespace"( + "nameSpaceId" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("nameSpaceId">=0), + "timeIndexed" INTEGER NOT NULL CHECK("timeIndexed">=0), + "hash" CHAR(34) NOT NULL, + CONSTRAINT "hash_UNIQUE" + UNIQUE("hash") + ) + '); + + $this->_db->query(' + CREATE TABLE IF NOT EXISTS "block"( + "blockId" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("blockId">=0), + "timeIndexed" INTEGER NOT NULL CHECK("timeIndexed">=0), + "lostTransactions" INTEGER NOT NULL CHECK("lostTransactions">=0) + ) + '); + + $this->_db->query(' + CREATE TABLE IF NOT EXISTS "data"( + "dataId" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL CHECK("dataId">=0), + "nameSpaceId" INTEGER NOT NULL CHECK("nameSpaceId">=0), + "blockId" INTEGER NOT NULL CHECK("blockId">=0), + "time" INTEGER NOT NULL CHECK("time">=0), + "timeIndexed" INTEGER NOT NULL CHECK("timeIndexed">=0), + "size" INTEGER NOT NULL, + "ns" TEXT NOT NULL CHECK("ns" IN(\'0\', \'1\')), + "deleted" TEXT NOT NULL CHECK("deleted" IN(\'0\', \'1\')), + "txid" CHAR(64) NOT NULL, + "key" TEXT NOT NULL, + "value" TEXT NOT NULL, + CONSTRAINT "txid_UNIQUE" + UNIQUE("txid"), + CONSTRAINT "fk_data_namespace" + FOREIGN KEY("nameSpaceId") + REFERENCES "namespace"("nameSpaceId"), + CONSTRAINT "fk_data_block" + FOREIGN KEY("blockId") + REFERENCES "block"("blockId") + ) + + '); + + $this->_db->query('CREATE INDEX IF NOT EXISTS "data.fk_data_namespase_idx" ON "data" ("nameSpaceId")'); + $this->_db->query('CREATE INDEX IF NOT EXISTS "data.fk_data_block_idx" ON "data" ("blockId")'); + $this->_db->query('CREATE INDEX IF NOT EXISTS "data.deleted_INDEX" ON "data" ("deleted")'); + $this->_db->query('CREATE INDEX IF NOT EXISTS "data.ns_INDEX" ON "data" ("ns")'); + + } catch(PDOException $e) { + trigger_error($e->getMessage()); + } + } + + public function getNamespaceValueByNS(string $ns) { + + try { + + $query = $this->_db->prepare('SELECT `data`.`value` AS `value` + + FROM `data` + JOIN `namespace` ON (`namespace`.`nameSpaceId` = `data`.`nameSpaceId`) + + WHERE `namespace`.`hash` = ? + AND `data`.`ns` = "1" + -- AND `data`.`deleted` = "0" -- + + ORDER BY `data`.`blockId` DESC + + LIMIT 1'); + + $query->execute([$ns]); + + $result = $query->fetch(); + + return $result ? $result['value'] : ''; + + } catch(PDOException $e) { + + trigger_error($e->getMessage()); + return false; + } + } + + public function getNamespaceHashByTX(string $txid) { + + try { + + $query = $this->_db->prepare('SELECT `namespace`.`hash` + + FROM `namespace` + JOIN `data` ON (`data`.`nameSpaceId` = `namespace`.`nameSpaceId`) + + WHERE `data`.`txid` = ?'); + + $query->execute([$txid]); + + return $query->rowCount() ? $query->fetch()['hash'] : ''; + + } catch(PDOException $e) { + + trigger_error($e->getMessage()); + return false; + } + } + + public function getData(string $namehash = '', string $txid = '', string $search = '', int $start = 0, int $limit = 10) { + + try { + + if ($txid) { + + $query = $this->_db->prepare('SELECT `block`.`blockId` AS `block`, + `namespace`.`hash` AS `namehash`, + `data`.`time` AS `time`, + `data`.`key` AS `key`, + `data`.`value` AS `value`, + `data`.`txid` AS `txid` + + FROM `data` + JOIN `block` ON (`block`.`blockId` = `data`.`blockId`) + JOIN `namespace` ON (`namespace`.`nameSpaceId` = `data`.`nameSpaceId`) + + WHERE `data`.`txid` = ? + AND `data`.`ns` = "0" + -- AND `data`.`deleted` = "0" -- + + ORDER BY `block`.`blockId` DESC + + LIMIT ' . (int) $start . ',' . (int) $limit); + + $query->execute([$txid]); + + } else if ($namehash) { + + $query = $this->_db->prepare('SELECT `block`.`blockId` AS `block`, + `namespace`.`hash` AS `namehash`, + `data`.`time` AS `time`, + `data`.`key` AS `key`, + `data`.`value` AS `value`, + `data`.`txid` AS `txid` + + FROM `data` + JOIN `block` ON (`block`.`blockId` = `data`.`blockId`) + JOIN `namespace` ON (`namespace`.`nameSpaceId` = `data`.`nameSpaceId`) + + WHERE `namespace`.`hash` = ? + AND `data`.`ns` = "0" + -- AND `data`.`deleted` = "0" -- + + ORDER BY `block`.`blockId` DESC + + LIMIT ' . (int) $start . ',' . (int) $limit); + + $query->execute([$namehash]); + + } else if ($search) { + + $query = $this->_db->prepare('SELECT `block`.`blockId` AS `block`, + `namespace`.`hash` AS `namehash`, + `data`.`time` AS `time`, + `data`.`key` AS `key`, + `data`.`value` AS `value`, + `data`.`txid` AS `txid` + + FROM `data` + JOIN `block` ON (`block`.`blockId` = `data`.`blockId`) + JOIN `namespace` ON (`namespace`.`nameSpaceId` = `data`.`nameSpaceId`) + + WHERE (`data`.`key` LIKE :search + OR `data`.`value` LIKE :search + OR `block`.`blockId` LIKE :search + OR `namespace`.`hash` LIKE :search + OR `data`.`txid` LIKE :search) + + AND `data`.`ns` = "0" + -- AND `data`.`deleted` = "0" -- + + ORDER BY `block`.`blockId` DESC + + LIMIT ' . (int) $start . ',' . (int) $limit); + + $query->bindValue(':search', '%' . $search . '%', PDO::PARAM_STR); + + $query->execute(); + + } else { + + $query = $this->_db->prepare('SELECT `block`.`blockId` AS `block`, + `namespace`.`hash` AS `namehash`, + `data`.`time` AS `time`, + `data`.`key` AS `key`, + `data`.`value` AS `value`, + `data`.`txid` AS `txid` + + FROM `data` + JOIN `block` ON (`block`.`blockId` = `data`.`blockId`) + JOIN `namespace` ON (`namespace`.`nameSpaceId` = `data`.`nameSpaceId`) + + WHERE `data`.`ns` = "0" + -- AND `data`.`deleted` = "0" -- + + ORDER BY `block`.`blockId` DESC + + LIMIT ' . (int) $start . ',' . (int) $limit); + + $query->execute(); + } + + $result = $query->fetchAll(); + + return $result ? $result : []; + + } catch(PDOException $e) { + + trigger_error($e->getMessage()); + return false; + } + } + + public function getTrends(int $offset = 0) { + + try { + + $query = $this->_db->prepare('SELECT `block`.`blockId` AS `block`, + `namespace`.`hash` AS `namehash`, + `data`.`time` AS `time`, + `data`.`key` AS `key`, + `data`.`value` AS `value`, + `data`.`txid` AS `txid` + + FROM `data` + JOIN `block` ON (`block`.`blockId` = `data`.`blockId`) + JOIN `namespace` ON (`namespace`.`nameSpaceId` = `data`.`nameSpaceId`) + + WHERE `data`.`ns` = "0" + AND `data`.`time` >= ' . (int) $offset . ' + -- AND `data`.`deleted` = "0" -- + + ORDER BY `block`.`blockId` DESC'); + + $query->execute(); + + $result = $query->fetchAll(); + + return $result ? $result : []; + + } catch(PDOException $e) { + + trigger_error($e->getMessage()); + return false; + } + } +} diff --git a/public/css/app.css b/public/css/app.css index 7ba85cf..f67d71b 100755 --- a/public/css/app.css +++ b/public/css/app.css @@ -12,8 +12,8 @@ button::-moz-focus-inner { input, button { opacity: 0.8; - color: #18102d; - background: #BFBACC; + color: #000; + background: #ABA6B7; border: 0; border-radius: 3px; height: 18px; @@ -23,8 +23,8 @@ input, button { } body { - color: #E8E8E8; - background-color: #18102d; + color: #BFBACC; + background-color: #000; font-family: Sans-Serif, Arial; font-size: 14px; font-weight: normal; @@ -32,12 +32,7 @@ body { } a { - color: #BFBACC; - text-decoration: none; -} - -a { - color: #BFBACC; + color: #ABA6B7; text-decoration: none; -moz-transition: all .5s ease-in; -o-transition: all .5s ease-in; @@ -47,7 +42,7 @@ a { } a:hover { - color: #E8E8E8; + color: #BFBACC; -webkit-transition: all .5s ease-in; /* issue #2 */ } @@ -96,7 +91,7 @@ img:hover { .b-g::before { content: ""; - background-image: linear-gradient(to left, #9B94BF, #18102d); + background-image: linear-gradient(to left, #9B94BF, #000); height: 1px; width: 50%; max-width: 360px; @@ -105,7 +100,7 @@ img:hover { .b-g::after { content: ""; - background-image: linear-gradient(to right, #9B94BF, #18102d); + background-image: linear-gradient(to right, #9B94BF, #000); height: 1px; width: 50%; max-width: 360px; @@ -127,7 +122,7 @@ img:hover { .c-1:active, .c-1:visited, .c-1:hover { - color: #ABA6B7; + color: #BFBACC; } .c-2, diff --git a/public/index.php b/public/index.php index e69de29..3970c11 100644 --- a/public/index.php +++ b/public/index.php @@ -0,0 +1,174 @@ +<<<<<<< HEAD + 0) { + $limit = PAGE_LIMIT * $page - PAGE_LIMIT; +} else { + $limit = PAGE_LIMIT * $page; +} + +$db = new SQLite(DB_NAME, DB_USERNAME, DB_PASSWORD); + +if ($ns) { + + $namespaceHash = $ns; + $namespaceValue = $db->getNamespaceValueByNS($ns); + +} else if ($tx) { + + $namespaceHash = $db->getNamespaceHashByTX($tx); + $namespaceValue = $db->getNamespaceValueByNS($namespaceHash); + +} else { + + $namespaceHash = false; + $namespaceValue = false; +} + +$trends = []; + +if (TRENDS_ENABLED) { + + foreach ($db->getTrends(time() - TRENDS_SECONDS_OFFSET) as $value) { + + foreach ((array) explode(' ', strip_tags(html_entity_decode(nl2br(trim($value['key']))))) as $trend) { + + if (strlen($trend) >= TRENDS_MIN_LENGHT) { + + $trend = strtolower($trend); + + if (isset($trends[$trend])) { + $trends[$trend]++; + } else { + $trends[$trend] = 1; + } + } + } + + foreach ((array) explode(' ', strip_tags(html_entity_decode(nl2br(trim($value['value']))))) as $trend) { + + if (strlen($trend) >= TRENDS_MIN_LENGHT) { + + $trend = strtolower($trend); + + if (isset($trends[$trend])) { + $trends[$trend]++; + } else { + $trends[$trend] = 1; + } + } + } + } + + arsort($trends); + + $trends = array_slice($trends, 0, TRENDS_LIMIT); + + $trends = array_flip($trends); +} + +$data = []; +foreach ($db->getData($ns, $tx, $query, $limit, PAGE_LIMIT) as $value) { + $data[] = [ + 'namehash' => $value['namehash'], + 'block' => $value['block'], + 'txid' => $value['txid'], + 'time' => date(($rss ? 'r' : 'd-m-Y H:i'), $value['time']), + 'key' => $rss ? htmlentities(strip_tags(trim($value['key'])), ENT_XML1) : nl2br(trim($value['key'])), + 'value' => $rss ? htmlentities(strip_tags(trim($value['value'])), ENT_XML1): nl2br(trim($value['value'])), + ]; +} + +$older = false; +$newer = false; + +if (!in_array($page, [0, 1])) { + if ($page == 2) { + $newer = ($ns ? $ns : ''); + } else { + $newer = ($ns ? $ns . '/' . ($page - 1) : ($page - 1)); + } + + if ($query) { + $newer = $newer . '?q=' . $query; + } +} + +if ($data) { + if (in_array($page, [0, 1])) { + $older = ($ns ? $ns . '/2' : '2'); + } else { + $older = ($ns ? $ns . '/' . ($page + 1) : ($page + 1)); + } + + if ($query) { + $older = $older . '?q=' . $query; + } +} + +if ($ns) { + if ($page) { + $hrefThisPage = $ns . '/' . $page; + } else { + $hrefThisPage = $ns; + } +} else { + if ($page) { + $hrefThisPage = $page; + } else { + $hrefThisPage = ''; + } +} + +if ($rss) { + + header('Content-type: application/xml'); + require_once('rss.phtml'); + +} else { + + require_once('index.phtml'); + +} +======= +>>>>>>> master diff --git a/public/index.phtml b/public/index.phtml index 0b80271..5bdd177 100755 --- a/public/index.phtml +++ b/public/index.phtml @@ -1,11 +1,11 @@ - + - + @@ -20,6 +20,8 @@ <?php echo $tx && isset($data[0]['key']) ? $data[0]['key'] : $tx; ?> | <?php echo ($namespaceValue ? $namespaceValue : ($namespaceHash ? $namespaceHash : false)); ?> | KVAZAR + + KVAZAR | SEARCH | <?php echo $query; ?> KVAZAR | TODAY @@ -29,11 +31,11 @@
- <?php echo $ns; ?> + <?php echo $ns; ?>
@@ -42,24 +44,30 @@
+ +
+
+ + # + +
+
+
+
+
+
- - - <?php echo $item['namehash']; ?> - - - - <?php echo $item['namehash']; ?> - - + + <?php echo $item['namehash']; ?> +
- +
@@ -80,23 +88,26 @@
-
+
+ + +
KVAZAR Webapp is the content exploring platform for Kevacoin Blockchain.
Sources distributed under the MIT License. Ownership of all content belongs to the authors.
diff --git a/public/rss.phtml b/public/rss.phtml new file mode 100644 index 0000000..9a6b565 --- /dev/null +++ b/public/rss.phtml @@ -0,0 +1,21 @@ + + + + + KVAZAR - <?php echo ($namespaceValue ? $namespaceValue : + ($namespaceHash ? $namespaceHash : + ($query ? 'SEARCH - ' . $query : 'TODAY'))); ?> + Observe Kevacoin Universe + + + + <?php echo $item['key']; ?> + + + + + + + + \ No newline at end of file