Уважаемые пользователи Голос!
Сайт доступен в режиме «чтение» до сентября 2020 года. Операции с токенами Golos, Cyber можно проводить, используя альтернативные клиенты или через эксплорер Cyberway. Подробности здесь: https://golos.io/@goloscore/operacii-s-tokenami-golos-cyber-1594822432061
С уважением, команда “Голос”
GOLOS
RU
EN
UA
denis-skripnik
5 лет назад

Пояснительная записка к электронному журналу с использованием технологии Блокчейн, практическая часть: часть 3

Продолжаем.

2.2.3 PHP, часть 1

Эта часть находится в подпапке web директории проекта и имеет структуру:

add (папка с html файлами форм добавления):

1.1. assessment.html – добавление оценки

1.2. disciple.html — ученика

1.3. lactor.html — преподавателя

1.4. lesson.html — предмета

1.5. lesson_topics.html — тем предмета.

Будет рассматриваться код одного файла, т. к. он везде идентичен
(отличаются только поля).

Js

2.1. helper.js — JS код веб-части;

2.2. jquery.min.js — jQuery (стандартная библиотека — рассматривать не
будем);

2.3. sjcl.min.js — jQuery библиотека шифрования и расшифровки данных.
Также код файла рассматривать не будем (её методы используются в
helper.js).

Add.php – файл добавления данных в блокчейн;

db.php — подключение к базе данных и функции работы с ней;

functions.php — файл функций (функция главной страницы, функция базы
данных и пр.)

index.php — основной файл: вызов функции homePage из functions.php и
вывод данных в html коде, вызов по Ajax op.php с контентом;

op.php — файл, вызываемый по Ajax. Получает данные: пользователя и
значение page, после чего производит проверку на соответствие
авторизовавшегося одному из пользователей и выводит данные в
зависимости от значения page;

style.css — файл стилей;

1. Папка add

Формы сгенерированы при помощи моего сервиса
https://viz.dpos.space/custom.

Код формы из файла assessment.html

<form id="istr-i52" class="generated-form">

<p style="display: none;">

<label>

Таблица<br>

<input type="text" name="table" value="assessments"> <br>

</label>

</p>

<fieldset>

<legend>Данные</legend>

<p>

<label>

Дата (формат: 20191605(<br>

<input type="text" name="date" value=""> <br>

</label>

</p>

<p>

<label>

Предмет<br>

<input type="text" name="lesson" value=""> <br>

</label>

</p>

<p>

<label>

Ученик<br>

<input type="text" name="disciple" value=""> <br>

</label>

</p>

<p>

<label>

Оценка<br>

<input type="text" name="data[assessment]" value=""> <br>

</label>

</p>

</fieldset>

<p><button>Отправить</button></p>

</form>

<script>!function(){function
e(e){if(localStorage.getItem("login")&&localStorage.getItem("PostingKey"))viz_login=localStorage.getItem("login"),posting_key=sjcl.decrypt(viz_login+"_postingKey",localStorage.getItem("PostingKey"));else
if(sessionStorage.getItem("login")&&sessionStorage.getItem("PostingKey"))viz_login=sessionStorage.getItem("login"),posting_key=sjcl.decrypt(viz_login+"_postingKey",sessionStorage.getItem("PostingKey"));else{document.getElementById(e)&&(document.getElementById(e).style.display="none");var
t=document.createElement("div");t.innerHTML='<form id="auth_form"
action="index.html" method="GET"><p
class="auth_title"><strong>Пожалуйста
авторизируйтесь</strong></p><p><input type="text"
id="this_login" name="viz_login" placeholder="Ваш
логин"></p><p><input type="password" name="posting"
id="this_posting" placeholder="Приватный постинг
ключ"></p><p><input type="submit"
value="Войти"></p></form>',document.getElementById(e).parentNode.insertAdjacentElement("beforeend",t),found"):(t=e[o],viz.config.set("websocket",t),viz.api.getDynamicGlobalPropertiesAsync().then(e=>{console.log("found
working
node",t),localStorage.setItem("node",t)}).catch(e=>{console.log("connection
error",t,e),n(o+1)}))};n(o)}(),e(t),document.querySelector(".generated-form").querySelector("button").disabled=!1):(console.log("wait"),setTimeout(o,50))},0);document.querySelector(".generated-form").onsubmit=function(e){e.preventDefault(),this.querySelector("button").disabled=!0;var
t=new
XMLHttpRequest;t.open("POST","https://viz.dpos.space/custom/json_encode.php"),t.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),t.onload=function(){200===t.status?(console.log(t.responseText),viz.broadcast.custom(posting_key,[],[viz_login],document.querySelector(".generated-form").id,t.responseText,function(e,t){e?alert("Ошибка:
"+e):(alert("Ок. custom
отправлен"),console.log(t)),docum

ent.querySelector(".generated-form").querySelector("button").disabled=!1})):alert("Request
failed. Returned status of "+t.status)},t.send(function(e){for(var
t=[],o=0;o<e.elements.length;o++){ return
t.join("&")}(document.querySelector(".generated-form")))}}()</script>

Поля добавления оценки: первое в скрытом абзаце — название таблицы,
дата, предмет, ученик, оценка.

Далее идёт js код, который вызывает форму авторизации, если не
авторизован, который обращается к ajax скрипту на
viz.dpos.space/custom, который принимает данные и вызывает скрипт
отправки данных в блокчейн.

Функция checkWorkingNode

Выбирает паблик-Ноду блокчейна, к которой подключиться:

function checkWorkingNode() {
const NODES = [
"wss://solox.world/ws",
"wss://vizlite.lexai.host/",
];
let node = localStorage.getItem("node") || NODES[0];
const idx = Math.max(NODES.indexOf(node), 0);
let checked = 0;
const find = (idx) 😕> {
if (idx >= NODES.length) {
idx = 0;
}
if (checked >= NODES.length) {
alert("no working nodes found");
return;
}
node = NODES[idx];
console.log("check", idx, node);
viz.config.set("websocket", node);
try {
viz.api.stop();
} catch(e) {
}

let timeout = false;
let timer = setTimeout(() 😕> {
console.log("timeout", NODES[idx])
timeout = true;
find(idx + 1);
}, 3000);
viz.api.getDynamicGlobalPropertiesAsync()
.then(props 😕> {
if(!timeout) {
check = props.head_block_number;
console.log("found working node", node);
localStorage.setItem("node", node);
clearTimeout(timer);
}
})
.catch(e 😕> {
console.log("connection error", node, e);
find(idx + 1);
});
}
find(idx);
}
checkWorkingNode();

Проверяет работоспособность текущей паблик-Ноды, беря её из
localStorage, используя getDynamicGlobalPropertiesAsync (Если возвращает
ошибку или пустое значение, значит не всё ок). Если ошибка, проверяет
паблик-Ноды из списка массива nodes. Когда находится работающая,
выбирается и добавляется в localStorage.

Ниже создаются переменные

var viz_login = ''; // Логин
var posting_key = ''; // Регулярный (ранее постинг) ключ

Функция getUrlVars

Берёт из url get запросы, позволяет с ними работать.
function getUrlVars() {
var vars = {};
var parts =
window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi,
function(m,key,value) {
vars[key] = value;
});
return vars;
}

Async функция ajaxSend

Отправляет ajax запрос:

async function ajaxSend(login) {
if (getUrlVars()) { // Проверка наличия get параметров

var data = getUrlVars(); // Назначение массива параметров переменной
data

page = data['page'].toLowerCase(); // Назначение переменной page GET
параметра соответствующего с переводом в нижний регистр
action = (data['action'] !== undefined) ? "&action=" +
data["action"] : ''; // Проверка на наличие GET action и добавление
значения или, если его нет, создание пустой переменной.
lactor = (data['lactor'] !== undefined) ? "&lactor=" +
data["lactor"] : ''; // Проверка наличия значения GET lactor.
Используется при удалении.
disciple = (data['disciple'] !== undefined) ? "&disciple=" +
data["disciple"] : ''; // Проверка disciple с возвратом значения, если
есть.
lesson = (data['lesson'] !== undefined) ? "&lesson=" +
data["lesson"] : '';// Также с lesson .
$(document).ready(function() { // jQuery: Вызывается при готовности
документа.
$(".content").load("op.php", "user=" + login + "&page=" + page + action

  • lactor + disciple + lesson); // Отправка ajax запроса со всеми
    возможными переменными.
    });
    }
    }

Функция async userAuth

async function userAuth() {
let login = $('#this_login').val(); // Получаем логин из поля

let posting = $('#this_posting').val(); // Также и ключ

if (localStorage.getItem('PostingKey')) { // Если есть ключ в
localStorage

var isPostingKey = sjcl.decrypt(login + '_postingKey',
localStorage.getItem('PostingKey')); // Расшифровываем ключ, используя
логин, слово _postingKey и зашифрованный ключ из localStorage.

} else if (sessionStorage.getItem('PostingKey')) { // Если кл

юч в
sessionStorage

var isPostingKey = sjcl.decrypt(login + '_postingKey',
sessionStorage.getItem('PostingKey')); // Также расшифровываем, но берём
из сессий.

} else { // Иначе

var isPostingKey = posting; // Берём значение из переменной

}

var resultIsPostingWif = viz.auth.isWif(isPostingKey); // Проверяем, что
ключ валиден.

if (resultIsPostingWif === true) { // Если это так

const account_approve = await viz.api.getAccountsAsync([login]); //
вызываем информацию о пользователе

const public_wif = viz.auth.wifToPublic(isPostingKey); // Приобразуем
полученный приватный ключ в публичный

let posting_public_keys = []; // Создаём массив публичных ключей

if (account_approve.length > 0) { // Если данные аккаунта есть

for (key of account_approve[0].regular_authority.key_auths) { //
Проходим по массиву ключей публичных

posting_public_keys.push(key[0]); // Добавляем их в массив
posting_public_keys.

}

} else {

window.alert('Вероятно, аккаунт не существует. Просьба проверить
введённый логин.'); // Иначе, если данных аккаунта нет, вывести
это сообщение.

}

if (posting_public_keys.includes(public_wif)) { // Далее проверяем,
есть ли наш публичный ключ в массиве posting_public_keys. Если
находит, делаются дальнейшие действия.

var isSavePosting = document.getElementById('isSavePosting'); // Смотрит
элемент с чекбоксом в форме авторизации

if (isSavePosting.checked) { // Если отмечен

localStorage.setItem('login', login); // Добавляем логин в localStorage

localStorage.setItem('PostingKey', sjcl.encrypt(login + '_postingKey',
posting)); // и в зашифрованном виде постинг ключ.

} else { // Если не отмечен.

sessionStorage.setItem('login', login); // добавляется логин в Сессии

sessionStorage.setItem('PostingKey', sjcl.encrypt(login +
'_postingKey', posting)); // ч.

}

viz_login = login; // Добавляется логин в переменную

posting_key = isPostingKey; // и ключ.

} else {

window.alert('Постинг ключ не соответствует пренадлежащему аккаунту.');
// Если в массиве ключей нашего public нет, выводится это сообщение.

}

} else {

window.alert('Постинг ключ имеет неверный формат. Пожалуйста, попробуйте
ещё раз.'); // Если формат неверен, выводится такое сообщение (относится
к resultIsPostingWif).

}

if (!viz_login && !posting_key) { // Если нет значений у переменных
логина и ключа

$('#delete_posting_key').css("display", "none"); // Скрывается блок с
кнопкой выхода.

$('#unblock_form').css("display", "block"); // Отображается блок с
формой входа.

} else {

$('#unblock_form').css("display", "none"); // иначе скрывается форма
входа

$('#delete_posting_key').css("display", "block"); // а ссылка выхода
отображается.

jQuery("#delete_posting_key").html('<p align="center"><a
onclick="localStorage.removeItem(\'login\'\);
localStorage.removeItem(\'PostingKey\'\);
location.reload();">Выйти</a></p>');// Также выводится в
соответствующем элементе ссылка выхода, удаляющая из localStorage
логин и ключ.

ajaxSend(localStorage.getItem('login')); // и вызывается функция
отправки ajax.

}

} // end userAuth

Всё

Благодарю за внимание. С вами был незрячий автор, программист и делегат @denis-skripnik. До встречи в новых постах.

1
581.113 GOLOS
На Golos с November 2017
Комментарии (3)
Сортировать по:
Сначала старые