Master-X
Форум | Новости | Статьи
Главная » Форум » Программинг, Скрипты, Софт, Сервисы » 
Тема: Подскажите, как лучше реализовать на PHP.
цитата
15/12/16 в 22:18
 Lexikon
Нужно реализовать генерацию с определенным повторением имен, без БД, только файлы.
Нюанс в том, что генерация не разовая, а дергается по крону и затем имя пишется в файл, при всем при этом имена должны генерироваться рандомно, но учитывая % повторяемости
К примеру:
имя|% повторяемости
A|40
B|20
C|15
D|10
E|5
F|5
G|3
H|2
J|1
На основе подобного дампа всё и должно генерироваться, в данном примере только 9 имен, по факту их может быть до нескольких тысяч.
Как вариант, добавить еще один параметр в дамп (относительный %):
На начальной стадии относительный % = 0, у всех
имя|% повторяемости|относительный %
A|40|0
B|20|0
C|15|0
D|10|0
E|5|0
F|5|0
G|3|0
H|2|0
J|1|0
Затем после первой генерации, относительный процент у одного из имен (кторое сгенерировано первым) будет равен 100%, затем второй раз рандомно берем из дампа строку и сравниваем, если относительный процент меньше должного %-повторяемости, то генерим это имя, если больше, то берем другую строку дампа и также сравниваем, при этом вероятнее всего, нужно будет добавить еще один параметр, это число сгенерированных имен, чтоб можно было высчитывать относительны процент.
Надеюсь поймете мысль icon_smile.gif
Спасибо!

PS: возможно это было бы проще реализовать с использованием БД, но в них я ноль, хотя вещь полезная. Но меня у меня фобия того, что из-за незнания БД могут ломануть SQL инъекцией или чем-то подобным.
цитата
16/12/16 в 01:50
 rx
1. определись как с конечным результатом, так и с оптимальным алгоритмом того что ты хочешь реализовать. пока что тут слегка каша

2. если нужно много и часто и с хранением результатов - заранее посмотри в сторону redis/memcached

ну и про цепи маркова почитай, по ним уже много много лет существуют готовые алгоритмы - например для генерации текста древних дорвеев trollface.png
цитата
16/12/16 в 19:36
 Lexikon
Вот по сути рабочий вариант, написан на основе имеющихся знаний, я не волшебник, я только учусь icon_smile.gif icon_razz.gif .

<?php

function frequencyOfUse($pathToFileDump){

      

      if (!is_writable($pathToFileDump)) {
         exit();
      }

      

      $pathToTmpFileDump = $pathToFileDump.".tmp";

      file_put_contents($pathToTmpFileDump, "");

      if (!is_writable($pathToTmpFileDump)) {
         exit();
      }   


      $db = file($pathToFileDump, FILE_IGNORE_NEW_LINES);
      shuffle($db);

      foreach ($db as $keyStr => $strDb) {

            $strDb = trim($strDb);

            list($name, $pctFreqConst, $pctFreqRelat, $numbOfUses, $sumOfAllUses) = explode("|", $strDb);

               if (empty($pctFreqRelat)) {
                  $pctFreqRelat = 0;
               }

               if ($pctFreqConst >= $pctFreqRelat) {
                  
                     if (empty($numbOfUses)) {
                        $numbOfUses = 1;
                     }else{
                        $numbOfUses = $numbOfUses + 1;
                     }

                     if (empty($sumOfAllUses)) {
                        $sumOfAllUses = 1;
                     }else{
                        $sumOfAllUses = $sumOfAllUses + 1;
                     }   
                     
                     $pctFreqRelat = $numbOfUses * 100 / $sumOfAllUses;
                     $pctFreqRelat = floor($pctFreqRelat);

                  $result = $name;

                  break;

               }else{

                  continue;

               }
      }

      // Корректировка данных

      foreach ($db as $keyStrCorr => $strDbCorr) {

            list($nameCorr, $pctFreqConstCorr, $pctFreqRelatCorr, $numbOfUsesCorr, $sumOfAllUsesCorr) = explode("|", $strDbCorr);

            $sumOfAllUsesCorr = $sumOfAllUses;   

            if ($keyStrCorr == $keyStr) {
               $pctFreqRelatCorr = $pctFreqRelat;
               $numbOfUsesCorr = $numbOfUses;
            }else{
               $pctFreqRelatCorr = $numbOfUsesCorr * 100 / $sumOfAllUses;
               $pctFreqRelatCorr = floor($pctFreqRelatCorr);
            }

            $strDump = $nameCorr."|".$pctFreqConstCorr."|".$pctFreqRelatCorr."|".$numbOfUsesCorr."|".$sumOfAllUsesCorr;

         file_put_contents($pathToTmpFileDump, $strDump."\n", FILE_APPEND);

      }

      if (copy($pathToTmpFileDump, $pathToFileDump)){
         unlink($pathToTmpFileDump);
      }

      // Проверка результата

      if (!isset($result) AND empty($result)) {
            $result = NULL;
         }   

   return $result;


}


echo frequencyOfUse("dbFrequencyOfUse.dat");

?>



dbFrequencyOfUse.dat
X|1|1|3|220
J|4|3|7|220
P|2|1|4|220
T|1|1|4|220
C|9|7|17|220
A|10|10|22|220
Q|2|1|4|220
O|2|2|5|220
E|8|7|16|220
F|7|5|13|220
D|9|7|17|220
Z|1|0|2|220
G|6|6|14|220
N|2|2|5|220
L|3|2|6|220
V|1|1|3|220
U|1|1|4|220
I|4|5|11|220
M|3|3|8|220
K|3|3|8|220
B|10|9|21|220
S|2|1|4|220
Y|1|0|2|220
H|5|5|11|220
R|2|2|5|220
W|1|1|4|220


Всё работает. Но есть один момент. Если тупо зажать F5, т.е. исполняться код будет очень быстро, в конечном итоге данные в dbFrequencyOfUse.dat херятся и получается пустой файл.
В чем может быть причина?
цитата
16/12/16 в 19:57
 S_Flash
Lexikon писал:
В чем может быть причина?

Не в даваясь в подробности, скорее всего в парадигме. Что у тебя к файлу, который на какой-то момент производится запись появляется необходимость чтения или ещё одна запись в тот же файл. Если я попробую угадать, то в тестах у тебя всё хорошо, а в продакшене на сервере, в момент нагрузки - плохо, верно?
цитата
16/12/16 в 20:22
 Lexikon
S_Flash писал:
Если я попробую угадать, то в тестах у тебя всё хорошо, а в продакшене на сервере, в момент нагрузки - плохо, верно?

Нагрузку я создавал искусственно, без нагрузки, да, всё нормально. У меня тоже было такое предположение, что из за чтения и записи вот такая ня получается, ты как раз подтвердил мое предположение. Конечно если учесть, что данный скрипт будет дергаться по крону и не чаще чем 1 раз в минуту, всё это должно работать нормально. Но всё же, стало интересно, как то можно организовать это так, чтоб оно работало и на нагрузке?
цитата
16/12/16 в 22:25
 S_Flash
Lexikon писал:
Но всё же, стало интересно, как то можно организовать это так, чтоб оно работало и на нагрузке?

- Ну либо юзать вместо file_xxx_contents - fopen() в сочетании с flock() по старинке,
- либо посмотреть внимательнее мануал по file_put_contents, там вроде есть имитация лока в виде LOCK_EX.

Но это скорее спасёт от одновременной записи в один файл. Попробуй ещё опискать, нет ли в твоём коде такого сотояния, когда файл просто обнуляется хотябы на долисекунды для перезаписи и пофикси это. Короче, если у тебя чтение и запись с одного файла, то лучше раздели на 2 отдельных и копируй обновлённый, только когда тот готов и читай уже с него.
цитата
17/12/16 в 01:08
 Stek
Дались вам эти файлы. PDO->sqlite и куча проблем будет решена. Вон что хром, что фаерфокс - все куки, сессии, логины и т.п. пишут именно в sqlite.
цитата
17/12/16 в 01:17
 Mika
Lexikon:
Что по-твоему делает вот эта строчка?
      if (copy($pathToTmpFileDump, $pathToFileDump)){

Stek писал:
PDO->sqlite и куча проблем будет решена.

И появится куча других, если основ не понимать.
цитата
17/12/16 в 03:03
 Stek
Mika писал:
И появится куча других

Каких именно ?
цитата
17/12/16 в 06:55
 Lexikon
Вот этот вопрос мне адресован?
Mika писал:
Lexikon:
Что по-твоему делает вот эта строчка?
Код: [свернуть]
      if (copy($pathToTmpFileDump, $pathToFileDump)){

Или это к:
S_Flash писал:
то лучше раздели на 2 отдельных и копируй обновлённый, только когда тот готов и читай уже с него.



Stek писал:
Дались вам эти файлы. PDO->sqlite и куча проблем будет решена. Вон что хром, что фаерфокс - все куки, сессии, логины и т.п. пишут именно в sqlite.

Изучу, что это такое. Спасибо.
цитата
17/12/16 в 10:19
 S_Flash
Кстати, кто-то знает file_put_contents - атомарна по отношению к чтению из этого же файла или можно поймать запись на середине заполнения файла и прочитать только тот кусок, что учпел записаться на данный момент?
цитата
17/12/16 в 10:50
 Ailk
не атомарна. Развернутый ответ:

http://stackoverflow.com/questions/4899737/should-lock-ex-on-both-r…1&lq=1
цитата
17/12/16 в 11:02
 S_Flash
тогда хуййознает, как читатать только "готовый файл" в многозадачных системах и стоит ли юзать тут именно файловую систему.
цитата
17/12/16 в 11:20
 Ailk
Для таких целей обычно семафоры используют. (сам не юзал, тока теорию читал =))
цитата
17/12/16 в 11:27
 Ailk
или как вариант юзать бдшные транзации и всякие лок тейблы для хранения.
У редиса также все операции атомарны, т.к. работают в 1 потоке + есть транзакции. Тож можно юзать.
цитата
18/12/16 в 19:19
 Doctor
помимо всего вышесказанного, такие обнуления могут быть (по крайней мере было у меня) из-за постоянной высокой нагрузки на серверный диск... посмотри, нет ли перманентно забитой очереди на запись... ну и процент использования диска тож глянь...
цитата
19/12/16 в 19:35
 Lexikon
Скрипт который обращается к файлу запускается по крону и во время работы скрипта его больше ни кто не беспокоит.
Проблема в принципе раскрыта в этом топике, множественные обращение, которые так же происходят во время записи и перезаписи файла, соответственно в какой то момент получается, что одно перекрывается другим, и в конечном итоге всё херится.
Проблему решил достаточно просто:
Код:

$pathToStatusFile = "status.dat";
      if (!is_writable($pathToFileDump)) {
         exit();
      }

      if (!is_writable($pathToStatusFile) OR file_get_contents($pathToStatusFile) == 1) {
         exit();
      }else{

         file_put_contents($pathToStatusFile, 1);
# тут основной код
         file_put_contents($pathToStatusFile, 0);   
      }      

   return $result;


Смысл в том, что пока выполняется скрипт, в дополнительном файле status.dat ставим метку, в данном случае это 0, типа ЗАНЯТО! icon_smile.gif и при попытке обратиться во время исполнения скрипта вторым запросом, получаем выход из скрипта exit() и всё. Статус же меняется по окончанию выполнения и после этого уже можно обращаться. Пока писал этот пост, подумал, что примерно так же можно вместо exit() запускать цикл, но он скорее всего будет полезен только том случае, если не нужно выходить из скрипта.
цитата
19/12/16 в 20:10
 Ailk
вместо метки можно работать с файлом в режиме лока на запись.
Т.е. пока какой-то скрипт работает на запись, никто другой к нему не лезет.
http://php.net/manual/ru/function.flock.php

Код:

if (is_file($pathToFileDump) && !is_writable($pathToFileDump)) {
   exit();
}


Этого должно быть достаточно, и убрать файловый семафор ;D

П.С.
Хотя там в примерах есть годные функции по работе с залоченым файлом без искусственных проверок на запись.
цитата
20/12/16 в 16:15
 rickdeckard
Stek писал:
PDO->sqlite и куча проблем будет решена


лучше mysql - он есть на всех хостингах. а sqlite - не всегда доступен.
цитата
20/12/16 в 16:17
 rickdeckard
Lexikon писал:
возможно это было бы проще реализовать с использованием БД, но в них я ноль, хотя вещь полезная. Но меня у меня фобия того, что из-за незнания БД могут ломануть SQL инъекцией или чем-то подобным.


экранируй весь пользовательский ввод mysqli_real_escape_string
http://php.net/manual/ru/mysqli.real-escape-string.php

или используй prepared statement
http://php.net/manual/ru/mysqli.quickstart.prepared-statements.php
цитата
20/12/16 в 18:37
 Lexikon
rickdeckard писал:
лучше mysql - он есть на всех хостингах. а sqlite - не всегда доступен.

Вчера в качестве вечернего просмотра организовал себе просмотр видоса по sqlite, как я понял sqlite идет в PHP 5. У меня WAMP установлен, там тоже есть icon_smile.gif
цитата
20/12/16 в 18:44
 Lexikon
rickdeckard писал:
экранируй весь пользовательский ввод mysqli_real_escape_string
http://php.net/manual/ru/mysqli.real-escape-string.php

или используй prepared statement
http://php.net/manual/ru/mysqli.quickstart.prepared-statements.php

Благодарю!
Это да, но вот всё же, меня не покидает мысль, что как-то относительно просто ломают базы, х.з. может всё так изначально криво пишут, чтоб специально ломать. Знаю существуют большие базы с SQL запросами инъекций и ими хуярят различные форумы и сайты. Разве те, кто писал код сайта, не в курсе что да как? Может я что-то не понимаю, касаемо этого. icon_confused.gif
Вот уже наверное года 3-4 использую ПХП, но всё организовывал на файлах, наверное всё таки фобия smail101.gif
цитата
20/12/16 в 19:27
 Ailk
Движки форумов и сайтов ооочень древние, никто не апгрейдит их и не переписывает. Ибо нахуя? Работает - не трожь. =)
Вот. А еще в сети мегатонны старых манов, где все примерны на старых мускульных функциях, и всякие новички пишут по ним свои велосипеды. А потом удивляются как это все ломается весело и задорно.

Вот к примеру яркий пример: https://toster.ru/q/381480
Просто первый попавшийся кликнул на тематику пхп+мускул =)

Может и не сильно будет понятно с первого раза, но когда въедешь во всю эту кухню, поймешь какой это пездец. Если в краце, то у чувака вообще никаких проверок и экранирования, уже молчу про использование prepareStatement.
цитата
20/12/16 в 19:56
 Lexikon
Ailk писал:
Движки форумов и сайтов ооочень древние, никто не апгрейдит их и не переписывает. Ибо нахуя? Работает - не трожь. =)
Вот. А еще в сети мегатонны старых манов, где все примерны на старых мускульных функциях, и всякие новички пишут по ним свои велосипеды. А потом удивляются как это все ломается весело и задорно.

Вот к примеру яркий пример: https://toster.ru/q/381480
Просто первый попавшийся кликнул на тематику пхп+мускул =)

Может и не сильно будет понятно с первого раза, но когда въедешь во всю эту кухню, поймешь какой это пездец. Если в краце, то у чувака вообще никаких проверок и экранирования, уже молчу про использование prepareStatement.

Ясно. Благодарю! icon_smile.gif
цитата
20/12/16 в 20:05
 Lexikon
Кстати, тут задался таким вопросом, а как правильно проверить существование файла, встречал варианты проверок: is_file() и file_exists(), но и опять же, бывает такой вариант, что файл то существует, но вот для чтения и записи не доступен, т.е. тут нужны функции is_readable(), is_writable().
Как правило для создания и чтения файлов использую file_put_contents() и file_get_contents().
Стр. 1, 2  >  последняя »


Эта страница в полной версии