Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Как превратить велосипед в фотонный звездолёт (https://javascript.ru/forum/events/64372-kak-prevratit-velosiped-v-fotonnyjj-zvezdoljot.html)

avalan4e 06.08.2016 13:19

Как превратить велосипед в фотонный звездолёт
 
Приветствую, уважаемые коллеги. Поставил себе задачу: считывать данные формы, как только будут внесены изменения, затем обработать их на сервере и вернуть на страничку результат. Нагородил семнадцати колесный велосипед с треугольным парусом. Надел треуголку, а велосипед хоть и едет, но со скрежетом, и команда грозит поднять бунт и отправить меня прогуляться по рее на корм рыбам.
Если вкратце, то я считываю данные формы в режиме полёта (без сабмита и пр.), отправляю расчитывать на сервер, пишу в файл результат расчетов, читаю из файла полученный результат и вывожу его в необходимом блоке. Короче говоря, если бы я повстречал дьявола, то он бы попросил оставить автограф на сиськах.
Очень надеюсь, что существует более элегантное решение этой, как мне кажется, весьма тривиальной задачи. Надеюсь на вашу помощь.
var days = 3;
$('#days').change(function() {
  days = $(this).val();
})

var model;
$('#models [name="optradio"]').change(function() {
  model = $(this).val();

  var formData = new FormData();
  formData.append("type", type);
  formData.append("model", model);
  formData.append("days", days);
  // отослать
  var xhr = new XMLHttpRequest();
  xhr.open("POST", "interactive.php");
  xhr.send(formData);
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (xhttp.readyState == 4 && xhttp.status == 200) {
      $('#vote_status').text(xhttp.responseText);
    }
    else {
      $('#vote_status').text('');
      req();
    }
  };

  function req() {
    if (xhttp.readyState == 4 && xhttp.status == 200) {
      $('#vote_status').text(xhttp.responseText);
    }
    else {
      $('#vote_status').text('');
      req();
    }
  } 
    
  xhttp.open("GET", "INTERACTIVE_PRICE/INTERACTIVE_PRICE.txt", true);
  xhttp.send();
})

var type = "standart";
$('#types [name="optradio"]').change(function() {
  type = $(this).val();
})

laimas 06.08.2016 15:40

Цитата:

Сообщение от avalan4e
читаю из файла полученный результат и вывожу его в необходимом блоке

Зачем читать из файла, если интерпретатор все расчеты имеет?

avalan4e 06.08.2016 17:13

laimas, как их извлечь? Может в каких-то глобальных переменных хранятся?

avalan4e 06.08.2016 17:17

Rise, хех, да уж. Собирал по сусекам сети варианты решения своей задачи. Вот такой коктейль (или скорее борщ) получился. Предложите вариант получше? Или может почитать что-то для более целостной картины восприятия посоветуете?

laimas 06.08.2016 17:23

Цитата:

Сообщение от avalan4e
как их извлечь?

Встречный вопрос - и кто же здесь отправляю расчитывать на сервер, пишу в файл результат расчетов считает? А если посчитал и записал в файл, то то что он пишет в файл разве нельзя вернуть и клиенту?

А насчет "винегрета из JS и JQ", так в в jQuery готовых методов Ajax хоть отбавляй.

avalan4e 06.08.2016 18:14

Rise,
Ради неё весь сыр-бор. Был вариант на jquery без привлечения внешних скриптов, который работал хорошо и быстро, но с одним недостатком -- view page source обнажает всю кухню.

avalan4e 06.08.2016 18:46

Rise, собственно вот оно:
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">


<h2>Выберите класс автомобиля</h2>
<form id="auto-class">
  <div class="checkbox">
    <label><input id="auto-class-econom" type="checkbox" value="econom-value" name="econom-checkbox">Эконом-класс</label>
  </div>
  <div class="checkbox auto-class-vip">
    <label><input id="auto-class-vip" type="checkbox" value="">Представительский класс (VIP)</label>
  </div>
</form>

<h2>Выберите тип аренды</h2>
<form name="chk" id="types">
  <div class="radio">
    <label><input id="standart" type="radio" name="optradio" value="standart" checked>Стандарт</label>
  </div>
  <div class="radio">
    <label><input id="wedding" type="radio" name="optradio" value="wedding">Автомобиль на свадьбу</label>
  </div>
</form>

<?
  $pricelist = array();
  $handle = @fopen("pricelist.txt", "r");
  if ($handle) {
      while (($buffer = fgets($handle, 4096)) !== false) {
        list($id, $auto, $price, $class) = explode(":", $buffer);
        $pricelist[$id] = array('class' => $class, 'price' => $price, 'auto' => $auto);
      }
      echo '<form name="tt" id="models">';
      foreach ($pricelist as $id => $value) {
        echo '<div class="radio '.$value["class"].' hidden">'.'
              <label><input type="radio" name="optradio" value="'.$id.'">';
              echo $value["auto"];
              echo " - ";
              echo $value["price"];
              echo " - ";
              echo $value["class"];
              echo '</label>
            </div>    
        ';
      }
      echo '</form>';
      if (!feof($handle)) {
          echo "Error: unexpected fgets() fail\n";
      }
      fclose($handle);
  }
?>
<input id="days" type="number" name="days" min="3" value="3"><br>
<button id="test-button"></button>

<div id="vote_status"></div>

Да, и по большому счету мне не столько нужна секретность формулы расчета, сколько относительная безопасность от внесения изменений в процессе выполнения. В вопросах безопасности я, конечно, полный профан, но что-то мне подсказывает, если оставить всю кухню на виду, то жди беды.

laimas 07.08.2016 00:37

Цитата:

Сообщение от avalan4e
не столько нужна секретность формулы расчета, сколько относительная безопасность от внесения изменений в процессе выполнения

Клиент может считать у себя в браузере, в тетрадке в клеточку, хоть на доске мелом, и это не несет опасности если серверу все эти расчеты побоку. А у нормального сервера так и должно быть - клиентский скрипт, это сервис, серверный скрипт, это контроль.

Есть менеджер и машины для прогулок описанные в базе (не файлах), и серверный скрипт.

Клиент выбрал машину А - получает в свой клиентский калькулятор цену проката за один час. Выбирает 3 часа покататься - клиентский калькулятор просчитал стоимость катания. Клиент удовлетворен и жмет Заказать - серверу приходят данные: фейс клиента, идентификатор выбранной машины и время проката. А чего там насчитал клиентский калькулятор серверу глубоко "все равно", этого ему не надо.

Полученные данные пишутся в базу (не файл) в таблицу заказов также под своим идентификатором. Из базы данных по идентификатору выбранной машины получаем цену проката за час, умножаем на выбранное время и эти расчеты шлем заказчику на почту/телефон/пейджер/etc и менеджеру почту/телефон/админку сообщение о новом заказе.

Менеджер оторванная от макияжа присланным сообщением заходит в админку, видит новый заказ, который опять таки рассчитывается - по ID машины узнаем ее цену, множим на 3, что и отображается менеджеру как Итого.

Вариант 2. Ваша фирма/контора/артель/etc из 1 кг железа производит 20 кг золота. Клиент хочет получить у вас 50 кг, при этом он имеет возможность только отправлять запрос, без сервиса, так как формула получения золота "делим 1 кг железа на 5, возводим в квадрат части и складываем их вместе" является большим се6кретом, держится исключительно на сервере и своем, и защищенном от любых атак и взломов, что при таком способе добычи желтого металла может и возможно организовать.

А машины, время, это не есть секрет и проблемы надуманные, у вас просто не верно поставлены взаимоотношения клеиент-сервер, да и хранение выбрано не лучшее.

avalan4e 07.08.2016 13:01

Rise,
По сути, только расчет. Количество машин не ограничено. Но могу предположить, что автопарк всё же может насчитывать до 20-50 автомобилей. С учетом всех замечаний передал следующим образом:
var days = 3;
$('#days').change(function() {
  days = $(this).val();
  $('#vote_status').text(countPrice(type_val, model_val, days));
})

var model_val = -1;
var model;
$('#models [name="optradio"]').change(function() {
  model = $(this).attr("id");
  model_val = $(this).val();
  $('#vote_status').text(countPrice(type_val, model_val, days));
})

var type_val = 1;
var type = "standart";
$('#types [name="optradio"]').change(function() {
  type = $(this).attr("id");
  type_val = $(this).val();
  $('#vote_status').text(countPrice(type_val, model_val, days));
})

function countPrice(t,m,d) {
  if (m > 0 && d > 2 && t > 0) return t * m * d;
  else if (d < 3) return "Выберите количество часов не меньше 3-х";
  else return "Error: обратитесь к тех. поддержке";
}

Не пробовал предложенный вами вариант т. к. придется менять разметку. Но он гораздо практичнее, так что, устранив остальные проблемы, отредактирую разметку и воспользуюсь им.
Пока что все работает хорошо. Только происходит существенная задержка при прокликивании в скоростном режиме нескольких часов аренды кряду. Если увеличивать/уменьшать количество на стрелках клавиатуры или забивать числа в поле вручную, то никакой задержки. Тестировал на подобных сайтах эту фишку, и у них все работает гладко в этом отношении. В чем может быть проблема?

avalan4e 07.08.2016 13:28

laimas,
Предположим, что база заказов не нужна. Как Вы оцениваете вариант, если на серверной части создать массив прайслиста и использовать полученные из $_POST идентификаторы для доступа к соответствующему элементу? Массив в любом случае не грозит разрастись до астрономических размеров, так что это не грозит потерей производительности.
По поводу второго варианта. Как все таки реализовать его без прославления сатаны написанием кода, подобного тому, что я представил в старте темы? Может есть на примете что-то стоящее покурить на эту тему? Если так, то я с удовольствием принимаюсь разжигать уголек для трубки.

laimas 07.08.2016 13:58

Цитата:

Сообщение от avalan4e
Как Вы оцениваете вариант, если на серверной части создать массив прайслиста и использовать полученные из $_POST идентификаторы для доступа к соответствующему элементу?

Массив нельзя хранить в файле, это раз. Второе, это безопасность которая вас беспокоит - клиент пусть считает что угодно и как угодно, серверу на это должно быть наплевать. Сервер должен получить в итоге выбор клиента - выбранную машину и время. И вот тут, чтобы знать обманывают вас или нет, нужно проверить есть ли такая машина. Если массив описывающий их первичными ключами содержит идентификатор машины и клиент его отдает в качестве выбора, то да, это практически тоже что и проверить в базе.
Вот только в файле в данном случае нужно содержать JSON, а не читать текстовый файл

$pricelist = array();
$handle = @fopen("pricelist.txt", "r");

$price = json_decode(file_get_contents("pricelist.txt"), 1);


И если так мало данных выгружать этот JSON клиенту (идентификатор машины=>[описание машины, цена, и прочее необходимое]), а готовя список в качестве значений опций указывать идентификатор машины. Выбор в списке будет означать - получить из объекта данные этого авто и рассчитать.

Вот только если сервер должен и хранить выбор пользователей (заказы), то писать их в файл, это неудачное решение.

warren buffet 08.08.2016 11:55

Цитата:

Сообщение от laimas
Массив нельзя хранить в файле

А вот у меня есть массив в файле

<?php return array (
  12 => 
  array (
    'id' => '12',
    'pid' => '0',
    'path' => 'stl',
    'title' => 'Стиль',
    'text' => 'Общая характеристика по стилю',
    'show' => '1',
    'c' => 
    array (
      13 => 
/* and so */


Что мне за это будет?

---

ТС, ты превратил банальную задачу клиент-серверного интерактивного обмена в какую-то историю О. Отправляешь по вводу - ну отправляй, получай, рендери и все как обычно. Просто у тебя получится вот что: на 1 байт глупых данных из формы, ты будешь поднимать мегабайты хлама на сервере и ради чего?

Передавай модель в браузер и не парься. Критические значения типа сколько осталось на складе или сколько свободно - это можно запросить и заблокировать, а все остальное делается в браузере. Никому нахер твои модели не нужны, а кому будут нужны - те и так все узнают по ответам сервера.

laimas 08.08.2016 12:00

Цитата:

Сообщение от warren buffet
А вот у меня есть массив в файле

Ты совсем больной или что?

warren buffet 08.08.2016 12:12

laimas, мне еще интересно, как клиент может обмануть сервер? Ну, скажем заказать несуществующий товар в несусветном количестве.

laimas 08.08.2016 12:47

А причем тут массив? Нельзя непосредственно тип данных Array, Oject записать в файл, нужна либо сериализация, либо JSON, либо свой велосипед изобретать. И уж коли вместо базы использовать массив, то выгоднее не просто текстовый файл, а необходимая структура данных в нем.

Тех кто слепо веруют, что форма/данные пришедшие извне есть истина, тех не только легко обмануть, но и взломать. А как это делается, читать на haker.ru.

warren buffet 08.08.2016 22:38

Нет, вот пришел id товара которого нет в бд. Как ты его вообще оформишь?


Часовой пояс GMT +3, время: 03:10.