Удобная работа с параметрами из URL и MODX. Я изобрёл велосипед?

Предыстория
Сидел себе спокойно, ни о чём подобном даже не думал… может быть показанное ниже тоже кого-то на что-то натолкнёт?
Брат у меня — творческая личность…

Показал как-то собственноручно созданный квест и спросил — можно ли такое сделать на чистом HTML (ну и показал первую страницу, сделанную на Construct)?

Что такое игра-квест (книга-игра, книга-квест)?

Открываете первую страницу. В конце — варианты перехода с указанием номера новой страницы, которую нужно открыть при наличии заклинаний или предметов… повторить до перехода на новую страницу.
Начиная новую игру, Вы, по сути, «читаете» новую книгу, с новыми сюжетными и поворотами и неожиданными приключениями.
В детстве у меня были книги Браславского, если что — погуглите :)

Ведь что такое переходы в странице? Это же ссылки на новые страницы, т.е. игра — обычный сайт с нужным набором страниц!
Но одно дело — просто переходить по ссылкам, а другое — обрабатывать наличие предметов и заклинаний, и предлагать их по необходимости и наличию.

Что нужно сделать?
Есть HTML-страница, в нужных местах нужно будет по условию (если его результат true — текст вставляется) вставить текст, рисунки, ссылки, формы и так далее.
Условие иногда может быть очень сложным, один параметр может зависеть кучи других, поэтому, я сразу сказал, что это сложно… и через день был ПЕРВЫЙ рабочий вариант.

Как это работает?
Состояние игры зависит от того, на какой странице ты находишься и какой набор параметров будет передан странице.

Параметры должны ВСЕГДА передаваться на следующую страницу, если они НЕ РАВНЫ НУЛЮ.

1. Параметры могут быть переданы при помощи GET или POST.
Я остановился на GET, все параметры будут передаваться в адресной строке браузера, т.е. типичная страница игры-квеста будет
www.site.com/knigi/put-geroya/stranica1/?par1=12&par2=34
(POST — скорее всего добавится чуть позже, для борьбы с читерами самое то. Ну и POST позволяет обойти ограничение в 2048 символов, хотя превысить этот лимит — надо постараться).

2. Любой «Текст» передается из формы опять же при помощи GET.
Ограничение на длину «текста» — не более 8 символов, и этого хватает практически для всего.

3. Все передаваемые параметры — числовые, даже текстовые (работать с числом проще и безопаснее) — они ВСЁ РАВНО будут представлены (перекодированы) в виде числа.
К пример, «ответ» — это 2428121528

Обработку параметров делал прямо в коде PHP, параметров было не слишком много (сначала).
Ринулся я сразу реализовывать хотя бы первые несколько страниц и подоф… удивился — каждый новый объект (предмет или заклинание) ведёт к прямому и долгому программированию в PHP.

Поэтому, чтобы брат не кодил лишнего (хотя чего греха таить — всё равно всю работу по переносу игры я дальше делал сам...), автоматизировал процесс объявления переменных в MODX.

Для себя определил, что есть обычные переменные, есть счётчики, есть игровые объекты со своими параметрами, есть переменные для ввода паролей и т.д. — и это ЗДОРОВО облегчило работу в дальнейшем, по сути я дальше прописывал ТОЛЬКО ЛОГИКУ игры, не копаясь бесконечно в коде.

К примеру, переменные «счётчики» автоматически уменьшались при переходе на новую страницу. Или значения параметров автоматически меняли значения.
Кроме того, при создании параметра в MODX можно было задать минимальное и максимальное значение, что ТАКЖЕ снимало с меня муторные проверки при изменении.

Как это работает?

1. При открытии страницы PHP обрабатывает только те параметры, которые прописаны в MODX (передаются в PHP из поля MIGX РОДИТЕЛЬСКОЙ страницы), на остальные — грубо говоря, плевать.
2. PHP обрабатывает параметры, уменьшает счётчики, изменяет значения, проверяет условия выхода за нижний и верхний пределы.
3. После обработки параметры ПОЛУЧЕНЫ (и проверены) и начинается процесс вывода HTML-блоков из поля MIGX ТЕКУЩЕЙ страницы.

По каждому блоку HTML проверяется условие вывода, если условие верно — блок выводится.

К примеру, у блока HTML может быть такое условие (в синтаксисе PHP)
$par1>10 && $par2>30
Если в браузерной строке страница была вида
www.site.com/knigi/put-geroya/stranica1/?par1=12&par2=34

— соответственно блок HTML-кода буде выведен ( par1 больше 10 И par2 больше 30)
Таких блоков конечно же может быть несколько.

К примеру, мне надо вывести ССЫЛКУ, которая на СЛЕДУЮЩЕЙ странице (можно указать и текущую) уменьшит параметр par1 на 5 (игрок отдаст 5 монет и купит предмет амуниции)

Создаю блок HTML с текстом
КУПИТЬ лопату на 5 монет

Прописываю условие (можно уменьшить только при наличии денег, т.е. par1 ДОЛЖЕН быть больше или равен 5)
$par1>=5
Прописываю то, что должно произойти при покупке — деньги отнимаются, предмет добавляется — в синтаксисе PHP
$par1inc=-5;
$par3inc=1;
Указываю ID страницы, которая откроется при нажатии по ссылке
stranica2

Т.к. условие верно, то в соответствующем месте в теле страницы HTML появится код
<a class="btn btn-default" href="stranica2/?par1=12&par2=34&par1inc=-5&par3inc=1"> КУПИТЬ лопату на 5 монет</a>

Обратите внимание — par1 НЕ МЕНЯЕТСЯ сразу и повторное открытие этой же страницы НИЧЕГО не изменит.

А вот при клике по данной ссылке будет открыта страница
www.site.com/knigi/put-geroya/stranica1/?par1=12&par2=34&par1inc=-5&par3inc=1

(
При открытии ЭТОЙ страницы АВТОМАТИЧЕСКИ, без написания кода, значение par1 будет уменьшено на 5, значение $par3 увеличено на 1, ВМЕСТЕ СО ВСЕМИ проверками на превышение по лимитам — ниже просто пример:

$par1=$par1+$par1inc;
if($par1<0)
{
$par1=0;
}

if($par1>50000)
{
$par1=50000;
}

$par3=$par3+$par3inc;
if($par3>1)
{
$par3=1;
}

if($par3<0)
{
$par3=0;
}
И уже на этой странице значение par1 станет равно 7, значение par3 станет равно 1
Эти же параметры будут проверяться при выводе HTML-блоков
)

ВАЖНО

При формировании ссылки при переходе на новую страницу, передаются ТОЛЬКО НЕНУЛЕВЫЕ параметры.
Т.е. если параметр после изменения стал нулевым — в адресной строке его вообще не будет.

4. Кроме HTML-блоков текущей страницы (чем одна страница отличается от другой) нужно вывести малый Интерфейс игрока на экран -Записную книжку и Вещмешок.
Так как вывод интерфейса для всех страниц одинаков — проверяются и в соответствующем месте выводятся HTML-блоки РОДИТЕЛЬСКОЙ страницы.

К примеру, HTML блок для вывода лопаты будет такой
Лопата
Условие
$par3>0
5. Ещё есть БОЛЬШОЙ интерфейс — по клику там выведется возможность работы с лопатой.
Кроме того, есть возможность формирования «на лету» в HTML-аккордеонах и модальных окнах.

ЗАРАБОТАЛО ВСЁ ОТЛИЧНО, но
… появились жуткие тормоза, если HTML-блоков блоков уже больше 5, и это уже стало видно буквально на второй странице.

Почему?

Всё связано с тем, что при проверке каждого блока HTML (показывать его или нет на экране) все параметры должны загрузиться, инициализироваться (автоматически уменьшиться, провериться на превышения и т.д.), вывестись при срабатывании условия и обработаться (если есть кнопки, ссылки и формы).

Так вот загрузка и инициализация проводятся КАЖДЫЙ раз, при каждой проверке HTML-блока, а код их ОДИНАКОВ всегда.

Залез я в PHP… думал сделать всё через куки, нашёл другой вариант.

Решил отказаться от прямого формирования кода PHP из MODX (первоначально мне это казалось очень удобным).

Вместо этого, сделал так, что MODX формирует только одну константу (список переменных, превышений и т.д.) в виде массива, которая и передаётся в PHP для дальнейшей обработки.

Ниже — пример сформированной чанком константы (не весь текст).

const parametri = [ [ "", "1", "1", "0", "0", "1", "0", "0", "Череп", "7", "1", "0", "0", "0", "0", "0", "0" ], [ "", "1", "1", "0", "0", "1", "0", "0", "Кровь", "7", "2", "0", "0", "0", "0", "0", "0" ], [ "", "1", "1", "0", "0", "1", "0", "0", "Муха", "7", "3", "0", "0", "0", "0", "0", "0" ], [ "", "1", "1", "0", "0", "1", "0", "0", "Меч", "7", "4", "0", "0", "0", "0", "0", "0" ], [ "", "1", "1", "0", "0", "1", "0", "0", "Волк", "7", "5", "0", "0", "0", "0", "0", "0" ], [ "", "1", "1", "0", "0", "1", "0", "0", "Восток", "7", "6", "0", "0", "0", "0", "0", "0" ], [ "gld", "2", "1", "0", "0", "2", "50000", "50000", "0", "9", "0", "1", "0", "0", "1", "0", "0" ], [ "shag", "2", "2", "0", "0", "2", "11", "11", "0", "9", "0", "0", "0", "0", "0", "0", "0" ], [ "spicki", "2", "0", "0", "0", "0", "0", "0", "0", "9", "0", "0", "0", "0", "0", "0", "0" ], ;
Далее PHP из этой константы формирует ОДИН раз константы с ТЕКУЩИМИ значениями параметров, которые ВСЕГДА доступны для проверок как любым кодом PHP.
Параллельно автоматически формируется ОДИН раз код на PHP загрузки и инициализации и сразу выполняется.

Ниже — сформированный для ОДНОРАЗОВОГО выполнения код (не весь текст).

$gld=(int) $_GET["gld"];$gldinc=(int) $_GET["gldinc"];if($gldinc<-9999999999999999 || $gldinc>9999999999999999) {$gldinc=0; } $gld=$gld+$gldinc;if($gld<-9999999999999999) {$gld=0; } if($gld>50000) {$gld=50000; } $shag=(int) $_GET["shag"];$shaginc=(int) $_GET["shaginc"];if($shaginc<-9999999999999999 || $shaginc>9999999999999999) {$shaginc=0; } $shag=$shag+$shaginc;if($shag<0) {$shag=0; } if($shag>11) {$shag=11; } $spicki=(int) $_GET["spicki"];$spickiinc=(int) $_GET["spickiinc"];if($spickiinc<-9999999999999999 || $spickiinc>9999999999999999) {$spickiinc=0; } $spicki=$spicki+$spickiinc;if($spicki<-9999999999999999) {$spicki=0; } if($spicki>9999999999999999) {$spicki=0; }


Ниже — установка значений констант (уже обработанные значение параметров), которые будут доступны в любой момент времени — не весь текст.

define("igragld", "0");define("igragldinc", "0");define("igrashag", "0");define("igrashaginc", "0");define("igraspicki", "0");define("igraspickiinc", "0");define("igraprlparomcikid", "0");define("igraprlparomcikvidan", "0");define("igraotvetdan", "0");define("igrazklpolet", "0");define("igrazklpoletinc", "0");define("igrazklplav", "0");
Ниже — код константы (сформировано автоматически) для установки значений перед каждой проверкой HTML-блока — не весь текст. Назначение — простой перенос в переменную.

$gld=igragld;$gldinc=igragldinc;$shag=igrashag;$shaginc=igrashaginc;$spicki=igraspicki;$spickiinc=igraspickiinc;$prlparomcikid=igraprlparomcikid;$prlparomcikvidan=igraprlparomcikvidan;$otvetdan=igraotvetdan;$zklpolet=igrazklpolet;$zklpoletinc=igrazklpoletinc;$zklplav=igrazklplav;$zklplavinc=igrazklplavinc;$dveberez=igradveberez;$dveberezinc=igradveberezinc;
Ниже — код, который формирует строку с параметрами при наличии ссылок и кнопок (специальные HTML-блоки) — не весь текст
$sobitie_fsget="?";if($gld!=0) {$sobitie_fsget=$sobitie_fsget."&gld=".$gld;}if($gldinc!=0) {$sobitie_fsget=$sobitie_fsget."&gldinc=".$gldinc;}if($shag!=0) {$sobitie_fsget=$sobitie_fsget."&shag=".$shag;}if($shaginc!=0) {$sobitie_fsget=$sobitie_fsget."&shaginc=".$shaginc;}if($spicki!=0) {$sobitie_fsget=$sobitie_fsget."&spicki=".$spicki;}if($spickiinc!=0) {$sobitie_fsget=$sobitie_fsget."&spickiinc=".$spickiinc;}
Скорость обработки внезапно выросла в 10-15 раз, что теперь позволяет разместить в 10-15 раз больше HTML-блоков.
Загрузка и инициализация запускаются один раз в самом начале ДО того момента, когда надо выводить блоки HTML.

Константы в PHP — это нечто… Доступны ВСЕГДА, проверки можно проводить прямо в шаблонах MODX.

Сейчас задержки видны только при посещении таверн — там, где РЕАЛЬНО много товаров и проверок.
Процесс добавления новых игровых объектов — дело минуты, как и реакции на их наличие (использовать заклинание, попить из фляги и т.д.).

Работая уже с самим квестом, добавил события onInit и onLoad.

Ниже — код снипета для загрузки массива-константы и загрузки/инициализации.

<?php
$ustparr = $modx->getOption('ustparr', $scriptProperties, '');
$onloadmain = $modx->getOption('onloadmain', $scriptProperties, '');
$onloadpage = $modx->getOption('onloadpage', $scriptProperties, '');
$oninitpage = $modx->getOption('oninitpage', $scriptProperties, '');
$idpage = (int) $modx->getOption('idpage', $scriptProperties, '');

$titlepage="";

const stzam = [
        ["0", "90"],
        ["1", "91"],
        ["2", "92"],
        ["3", "93"],
        ["4", "94"],
        ["5", "95"],
        ["6", "96"],
        ["7", "97"],
        ["8", "98"],
        ["9", "99"],
        ["а", "10"],
        ["б", "11"],
        ["в", "12"],
        ["г", "13"],
        ["д", "14"],
        ["е", "15"],
        ["ё", "15"],
        ["ж", "16"],
        ["з", "17"],
        ["и", "18"],
        ["й", "19"],
        ["к", "20"],
        ["л", "21"],
        ["м", "22"],
        ["н", "23"],
        ["о", "24"],
        ["п", "25"],
        ["р", "26"],
        ["с", "27"],
        ["т", "28"],
        ["у", "29"],
        ["ф", "30"],
        ["х", "31"],
        ["ц", "32"],
        ["ч", "33"],
        ["ш", "34"],
        ["щ", "35"],
        ["ъ", "36"],
        ["ы", "37"],
        ["ь", "38"],
        ["э", "39"],
        ["ю", "40"],
        ["я", "41"],
        ["-", "42"],
        [" ",""],
];

eval ($ustparr);

################

$fs="";
foreach(parametri as $k => $values) 
{

if(parametri[$k][9]=="9")
{
$fs=$fs.'$'.parametri[$k][0].'=(int) $_GET["'.parametri[$k][0].'"];';

    if(parametri[$k][1]=='2' || parametri[$k][1]=='5' || parametri[$k][1]=='6')
    {
    $fs=$fs.'$'.parametri[$k][0].'inc=(int) $_GET["'.parametri[$k][0].'inc"];';
    $fs=$fs.'if($'.parametri[$k][0].'inc<-9999999999999999 || $'.parametri[$k][0].'inc>9999999999999999) {$'.parametri[$k][0].'inc=0; }     ';
    $fs=$fs.'$'.parametri[$k][0].'=$'.parametri[$k][0].'+$'.parametri[$k][0].'inc;';

    }

    if(parametri[$k][1]=='5')
    {

    $fs=$fs.'$'.parametri[$k][0].'zn=(int) $_GET["'.parametri[$k][0].'zn"];';
    $fs=$fs.'$'.parametri[$k][0].'zninc=(int) $_GET["'.parametri[$k][0].'zninc"];';
    $fs=$fs.'$'.parametri[$k][0].'zntip=(int) $_GET["'.parametri[$k][0].'zntip"];';
    $fs=$fs.'$'.parametri[$k][0].'znpar=(int) $_GET["'.parametri[$k][0].'znpar"];';
    $fs=$fs.'$'.parametri[$k][0].'zndesclong="";';
    $fs=$fs.'$'.parametri[$k][0].'zndescshort="";';

    $fs=$fs.'if($'.parametri[$k][0].'zninc<-9999999999999999 || $'.parametri[$k][0].'zninc>9999999999999999) {$'.parametri[$k][0].'zninc=0; }     ';
    $fs=$fs.'$'.parametri[$k][0].'zn=$'.parametri[$k][0].'zn+$'.parametri[$k][0].'zninc;';


        if(parametri[$k][11]=='2')
        {
        $fs=$fs.'if($'.parametri[$k][0].'zn<'.parametri[$k][12].') {$'.parametri[$k][0].'zn='.parametri[$k][13].'; }     ';
        }
        else
        {
        $fs=$fs.'if($'.parametri[$k][0].'zn<-9999999999999999) {$'.parametri[$k][0].'zn=0; }     ';
        }

        if(parametri[$k][14]=='2')
        {
        $fs=$fs.'if($'.parametri[$k][0].'zn>'.parametri[$k][15].') {$'.parametri[$k][0].'zn='.parametri[$k][16].'; }     ';        
        }
        else
        {
        $fs=$fs.'if($'.parametri[$k][0].'zn>9999999999999999) {$'.parametri[$k][0].'zn=0; }     ';
        }

    }


    if(parametri[$k][2]=='2')
    {
    $fs=$fs.'if($'.parametri[$k][0].'<'.parametri[$k][3].') {$'.parametri[$k][0].'='.parametri[$k][4].'; }     ';
    }
    else
    {
    $fs=$fs.'if($'.parametri[$k][0].'<-9999999999999999) {$'.parametri[$k][0].'=0; }     ';
    }

    if(parametri[$k][5]=='2')
    {
    $fs=$fs.'if($'.parametri[$k][0].'>'.parametri[$k][6].') {$'.parametri[$k][0].'='.parametri[$k][7].'; }     ';        
    }
    else
    {
    $fs=$fs.'if($'.parametri[$k][0].'>9999999999999999) {$'.parametri[$k][0].'=0; }     ';
    }
 
    
}
    
}

eval ($fs);
################

$fs="";
for ($ii = 1; $ii < 10; $ii++) 
{
    $fs=$fs.'$soobsenie'.$ii.'="";';
}

eval ($fs);

if($oninitpage!="")
{
eval ($oninitpage);    
}


if($onloadmain!="")
{
eval ($onloadmain);    
}

if($onloadpage!="")
{
eval ($onloadpage);    
}

################

$fs="";
foreach(parametri as $k => $values) 
{

if(parametri[$k][9]=="9")
{

    $fst='return $'.parametri[$k][0].';';
    $fstt=eval($fst);
    $fs=$fs.'define("igra'.parametri[$k][0].'", "'.$fstt.'");';


    if(parametri[$k][1]=='2' || parametri[$k][1]=='5'  || parametri[$k][1]=='6')
    {

        $fstinc='return $'.parametri[$k][0].'inc;';
        $fsttinc=eval($fstinc);
        $fs=$fs.'define("igra'.parametri[$k][0].'inc", "'.$fsttinc.'");';

    }

    if(parametri[$k][1]=='5')
    {
        $fstinc='return $'.parametri[$k][0].'zn;';
        $fsttinc=eval($fstinc);
        $fs=$fs.'define("igra'.parametri[$k][0].'zn", "'.$fsttinc.'");';

        $fstinc='return $'.parametri[$k][0].'zninc;';
        $fsttinc=eval($fstinc);
        $fs=$fs.'define("igra'.parametri[$k][0].'zninc", "'.$fsttinc.'");';

        $fstinc='return $'.parametri[$k][0].'zntip;';
        $fsttinc=eval($fstinc);
        $fs=$fs.'define("igra'.parametri[$k][0].'zntip", "'.$fsttinc.'");';

        $fstinc='return $'.parametri[$k][0].'znpar;';
        $fsttinc=eval($fstinc);
        $fs=$fs.'define("igra'.parametri[$k][0].'znpar", "'.$fsttinc.'");';

        $fstinc='return $'.parametri[$k][0].'zndesclong;';
        $fsttinc=eval($fstinc);
        $fs=$fs.'define("igra'.parametri[$k][0].'zndesclong", "'.$fsttinc.'");';

        $fstinc='return $'.parametri[$k][0].'zndescshort;';
        $fsttinc=eval($fstinc);
        $fs=$fs.'define("igra'.parametri[$k][0].'zndescshort", "'.$fsttinc.'");';

    }

}
}


for ($ii = 1; $ii < 10; $ii++) 
{
$fstinc='return $soobsenie'.$ii.';';
$fsttinc=eval($fstinc);
$fs=$fs.'define("igrasoobsenie'.$ii.'", "'.$fsttinc.'");';
}

$fs=$fs.'define("igraidpage", "'.$idpage.'");';
$fs=$fs.'define("igratitlepage", "'.$titlepage.'");';
eval ($fs);

$fs="";
foreach(parametri as $k => $values) 
{
if(parametri[$k][9]=="9" && parametri[$k][1]=="4")
{

    $fst='return $'.parametri[$k][0].';';
    $fstt=eval($fst);


foreach(parametri as $kk => $values) 
{
if(parametri[$kk][9]=="7" && parametri[$kk][10]==$fstt)
{

    $fs=$fs.'define("igra'.parametri[$k][0].'dsh", "'.parametri[$kk][8].'");';

#######
$sborka="";
$vvodtexta=parametri[$kk][8];
$vvodtexta=mb_strtolower($vvodtexta);
$vvodtexta=mb_substr($vvodtexta,0, 8);
for ($i = 0; $i < mb_strlen($vvodtexta); $i++) {
for ($ii = 0; $ii < 45; $ii++) {
  if(mb_substr($vvodtexta,$i,1)==stzam[$ii][0])
  {
  $sborka=$sborka.stzam[$ii][1];    
  }
}
}
#######

    $fs=$fs.'define("igra'.parametri[$k][0].'sh", "'.$sborka.'");';
    
}
}

}
}

eval ($fs);

$fs="";
foreach(parametri as $k => $values) 
{

if(parametri[$k][9]=="9")
{

$fs=$fs.'$'.parametri[$k][0].'=igra'.parametri[$k][0].';';

    if(parametri[$k][1]=='2' || parametri[$k][1]=='5'  || parametri[$k][1]=='6')
    {
    $fs=$fs.'$'.parametri[$k][0].'inc=igra'.parametri[$k][0].'inc;';
    }

    if(parametri[$k][1]=='4')
    {
    $fs=$fs.'$'.parametri[$k][0].'sh=igra'.parametri[$k][0].'sh;';
    $fs=$fs.'$'.parametri[$k][0].'dsh=igra'.parametri[$k][0].'dsh;';

    }
    
    if(parametri[$k][1]=='5')
    {
    $fs=$fs.'$'.parametri[$k][0].'zn=igra'.parametri[$k][0].'zn;';
    $fs=$fs.'$'.parametri[$k][0].'zninc=igra'.parametri[$k][0].'zninc;';
    $fs=$fs.'$'.parametri[$k][0].'zntip=igra'.parametri[$k][0].'zntip;';
    $fs=$fs.'$'.parametri[$k][0].'znpar=igra'.parametri[$k][0].'znpar;';
    }
    
}    
}


define("igrasetupparam", $fs);

###################
###################
###################

$sobitie_get='$sobitie_fsget="?";';
$sobitie_post='';

foreach(parametri as $k => $values) 
{

    if(parametri[$k][9]=="9")
    {
        $slov=parametri[$k][0];
        $otvett='if($'.$slov.'!=0'.') {$sobitie_fsget=$sobitie_fsget."&'.$slov.'=".$'.$slov.';}';
        $sobitie_get=$sobitie_get.$otvett;

        if(parametri[$k][1]==2 || parametri[$k][1]==5  || parametri[$k][1]==6)
        {
        $otvett='if($'.$slov.'inc!=0'.') {$sobitie_fsget=$sobitie_fsget."&'.$slov.'inc=".$'.$slov.'inc;}';
        $sobitie_get=$sobitie_get.$otvett;
        }

        if(parametri[$k][1]==5)
        {

        $otvett='if($'.$slov.'zn!=0'.') {$sobitie_fsget=$sobitie_fsget."&'.$slov.'zn=".$'.$slov.'zn;}';
        $sobitie_get=$sobitie_get.$otvett;


        $otvett='if($'.$slov.'zninc!=0'.') {$sobitie_fsget=$sobitie_fsget."&'.$slov.'zninc=".$'.$slov.'zninc;}';
        $sobitie_get=$sobitie_get.$otvett;


        $otvett='if($'.$slov.'zntip!=0'.') {$sobitie_fsget=$sobitie_fsget."&'.$slov.'zntip=".$'.$slov.'zntip;}';
        $sobitie_get=$sobitie_get.$otvett;

        $otvett='if($'.$slov.'znpar!=0'.') {$sobitie_fsget=$sobitie_fsget."&'.$slov.'znpar=".$'.$slov.'znpar;}';
        $sobitie_get=$sobitie_get.$otvett;
        }

    }    
}

###################
###################
###################


define("igragetparam", $sobitie_get);

return '';

Ниже — код для вывода HTML-блоков

<?php
$sobitie_html = $modx->getOption('sobitie_html', $scriptProperties, '');
$sobitie_this_text = $modx->getOption('sobitie_this_text', $scriptProperties, '');
$sobitie_text = $modx->getOption('sobitie_text', $scriptProperties, '');
$sobitie_obrabotka = $modx->getOption('sobitie_obrabotka', $scriptProperties, '');
$sobitie_stranica = $modx->getOption('sobitie_stranica', $scriptProperties, '');
$sobitie_ssilkatip = $modx->getOption('sobitie_ssilkatip', $scriptProperties, '');

$sobitie_kod = $modx->getOption('sobitie_kod', $scriptProperties, '');
$sobitie_uslovie_true = $modx->getOption('sobitie_uslovie_true', $scriptProperties, '');
$sobitie_uslovie_false = $modx->getOption('sobitie_uslovie_false', $scriptProperties, '');
$sobitie_obrabotka_true = $modx->getOption('sobitie_obrabotka_true', $scriptProperties, '');
$sobitie_obrabotka_false = $modx->getOption('sobitie_obrabotka_false', $scriptProperties, '');
$imachunk = $modx->getOption('imachunk', $scriptProperties, '');
$imiapar = $modx->getOption('imiapar', $scriptProperties, '');
$ustpar= $modx->getOption('ustpar', $scriptProperties, ''); # массив возможных переменных
$sobitie_dtext_ssilki= $modx->getOption('sobitie_dtext_ssilki', $scriptProperties, '');
$sobitie_dtext_ssilki = str_replace(' ', '', $sobitie_dtext_ssilki);


$idpage=igraidpage;
$titlepage=igratitlepage;


if($sobitie_this_text=='1')
{
    $sobitie_th=$sobitie_text;
}
else
{
    $sobitie_th=$sobitie_html;    
}

$formirtu='';

if($uslovieprov=='')
{
$uslovieprov='0==0';
$formirtu='1';
}

#####
if($nomerknigi=="")
{
    $nomerknigi=0;
}
else
{
    $nomerknigi=(int) $nomerknigi;
}

eval (igrasetupparam);

$otvett='if(('.$uslovieprov.')==true) {return "1";} else {return "";}';
#return $otvett;

if(eval($otvett)=="")
{
 $formirtu='';
}
else
{
$formirtu='1';
}
#####
 
if($sobitie_stranica!='')
{

$fs="";
foreach(parametri as $k => $values) 
{

if(parametri[$k][9]=="9")
{

    switch (parametri[$k][1]) {
    case "2":
        $fs=$fs.'$'.parametri[$k][0].'inc=0;';
        break;
    case "3":
        $fs=$fs.'$'.parametri[$k][0].'=0;';
        break;
    case "5":
        $fs=$fs.'$'.parametri[$k][0].'inc=0;';
        $fs=$fs.'$'.parametri[$k][0].'zninc=0;';
        break;
    case "6":

$fs=$fs.'$'.parametri[$k][0].'inc=0;';

$fst='return $'.parametri[$k][0].';';
$fstt=eval($fst);
if($fstt!=0)
{
$fs=$fs.'$'.parametri[$k][0].'='.'$'.parametri[$k][0].'-1'.';';    
}

        break;

    
}
    
}
}

if($fs!='')
{
eval ($fs);    
}

if($sobitie_obrabotka!='')
{
eval($sobitie_obrabotka);

    if($sobitie_dtext_ssilki!='')
        {
        $sobitie_th=eval($sobitie_dtext_ssilki);
        }
}

$sobitie_fs='';
if($sobitie_ssilkatip!=4)
{


##
$sobitie_fs='';
$sobitie_get="";
eval(igragetparam);
$sobitie_fs=$sobitie_fsget;
##

}
else
{
foreach(parametri as $k => $values) 
{
 ##########
 ##########
 ##########
if(parametri[$k][9]=="9")
{
        $fs='$'.parametri[$k][0].'!=0';
        $otvett='if(('.$fs.')==true) {return "1";} else {return "";}';

        if(eval($otvett)!="")
        {
            $fst='return $'.parametri[$k][0].';';
            $fstt=eval($fst);
            $sobitie_fs=$sobitie_fs.'<input type="hidden" name="'.parametri[$k][0].'"  value="'.$fstt.'"/>';
        }

        if(parametri[$k][1]==2 || parametri[$k][1]==5 || parametri[$k][1]==6)
        {
            $fs='$'.parametri[$k][0].'inc!=0';
            $otvett='if(('.$fs.')==true) {return "1";} else {return "";}';
            if(eval($otvett)!="")
            {
            $fst='return $'.parametri[$k][0].'inc;';
            $fstt=eval($fst);
            $sobitie_fs=$sobitie_fs.'<input type="hidden" name="'.parametri[$k][0].'inc"  value="'.$fstt.'"/>';
            }
        }


        if(parametri[$k][1]==5)
        {
            $fs='$'.parametri[$k][0].'zn!=0';
            $otvett='if(('.$fs.')==true) {return "1";} else {return "";}';
            if(eval($otvett)!="")
            {
            $fst='return $'.parametri[$k][0].'zn;';
            $fstt=eval($fst);
            $sobitie_fs=$sobitie_fs.'<input type="hidden" name="'.parametri[$k][0].'zn"  value="'.$fstt.'"/>';
            }

            $fs='$'.parametri[$k][0].'zninc!=0';
            $otvett='if(('.$fs.')==true) {return "1";} else {return "";}';
            if(eval($otvett)!="")
            {
            $fst='return $'.parametri[$k][0].'zninc;';
            $fstt=eval($fst);
            $sobitie_fs=$sobitie_fs.'<input type="hidden" name="'.parametri[$k][0].'zninc"  value="'.$fstt.'"/>';
            }

            $fs='$'.parametri[$k][0].'zntip!=0';
            $otvett='if(('.$fs.')==true) {return "1";} else {return "";}';
            if(eval($otvett)!="")
            {
            $fst='return $'.parametri[$k][0].'zntip;';
            $fstt=eval($fst);
            $sobitie_fs=$sobitie_fs.'<input type="hidden" name="'.parametri[$k][0].'zntip"  value="'.$fstt.'"/>';
            }

            $fs='$'.parametri[$k][0].'znpar!=0';
            $otvett='if(('.$fs.')==true) {return "1";} else {return "";}';
            if(eval($otvett)!="")
            {
            $fst='return $'.parametri[$k][0].'znpar;';
            $fstt=eval($fst);
            $sobitie_fs=$sobitie_fs.'<input type="hidden" name="'.parametri[$k][0].'znpar"  value="'.$fstt.'"/>';
            }

        }

}
}
 ##########
 ##########
 ########## 
 
}

}

//возвращаем чанк с установленными плейсхолдерами
$output = $modx->getChunk($imachunk,array('formirtu' => $formirtu,
'sobitie_th' => $sobitie_th,
'sobitie_fs' => $sobitie_fs,
'sobitie_stranica' => $sobitie_stranica,
'sobitie_ssilkatip' => $sobitie_ssilkatip,
'sobitie_kod' => $sobitie_kod,
'sobitie_uslovie_true' => $sobitie_uslovie_true,
'sobitie_uslovie_false' => $sobitie_uslovie_false,
'sobitie_obrabotka_true' => $sobitie_obrabotka_true,
'sobitie_obrabotka_false' => $sobitie_obrabotka_false,
'imiapar' => $imiapar,
'nomerknigi' => $nomerknigi

));
//возвращаем результат

return $output;
— События позволяют работать с переданными параметрами сразу после загрузки/инициализации. В них можно задавать параметры по умолчанию или разместить код, который будет выполняться на ВСЕХ страницах — удобно для формирования интерфейсов игрока.
Порядок выполнения последователен — onInit текущей страницы, onLoad РОДИТЕЛЬСКОЙ страницы, onLoad текущей страницы.

К примеру onLoad РОДИТЕЛЬСКОЙ страницы (событие запустится после onInit текущей страницы) под спойлером такой.

$soobsenie2="";
$soobsenie4="";
if($sdl>0)
{
$soobsenie4=$soobsenie4."Сделка успешно совершена!
";
}

#фляга
if($flg==1 && $flgzntip==1 && $flgzn<3)
{
$flgzn=3;
$soobsenie4=$soobsenie4."Фляга чудесным образом наполнилась
";
}
else
{
if($flgzninc>0)
{
$soobsenie4=$soobsenie4."Фляга наполнена
";
}
}

if($flg==1)
{
  if($flgzn>$flgznpar)
  {
  $flgzn=$flgznpar;
  }
}

$flgzndescshort="";

if($flgznpar!=0)
{
if($flgzn==$flgznpar)
{
$flgzndescshort="- заполнена";
}
else
{
$prc=floatval( $flgzn/$flgznpar);
if($prc>0.5)
{
$flgzndescshort="- больше половины";
}
if($prc<0.5)
{
$flgzndescshort="- меньше половины";

if($prc>0.3)
{
$flgzndescshort=$flgzndescshort.", чуть больше трети";
}
}
}
}

#лопата
if($lptinc==1)
{
$soobsenie4=$soobsenie4."Лопата получена
";
}

if($lptinc==-1)
{
$soobsenie4=$soobsenie4."Лопата потеряна
";
}

#кошелёк
if($ksl==1)
{

if($kslzn>$kslznpar)
{
$kslzninc=$kslznpar-$kslzn;
$kslzn=$kslzn+$kslzninc;
$soobsenie4=$soobsenie4."Слишком маленький кошелёк, часть денег потерялось
";
}

}
else
{

if($kslzn>5)
{
$kslzninc=5-$kslzn;
$kslzn=$kslzn+$kslzninc;
$soobsenie4=$soobsenie4."Нет кошелька - нет денег, почти всё потерялось
";
}
}

#усталость
if($ustinc>0)
{
$soobsenie4=$soobsenie4."Усталость отступила
";
}

if($ustinc<0)
{
$soobsenie4=$soobsenie4."Вы подустали больше, чем обычно...
";
}

if($ust<600)
{

if($ust<300)
{
$soobsenie2=$soobsenie2."Вы <font color='RED'><b>ОЧЕНЬ</b></font> устали
";

if($ust<100)
{
$soobsenie4=$soobsenie4."Вам <font color=red><b>очень СИЛЬНО устали</b></font>. Сделайте что-нибудь!
";
}

}
else
{
$soobsenie2=$soobsenie2."Вы устали
";
}

}
else
{

if($ust==1000 && $ustinc>0)
{
$soobsenie4=$soobsenie4."Вы максимально бодры
";
}

}

#амулет-звезда
if($amlzvzinc>0)
{
$soobsenie4=$soobsenie4."Добавлен амулет со звездой
";
}

if($amlzvzinc<0)
{
$soobsenie4=$soobsenie4."Убран амулет со звездой
";
}

#клубок
if($klbinc>0)
{
$soobsenie4=$soobsenie4."Добавлен клубок - он покажет Вам <b>правильный</b> путь
";
}

if($klbinc<0)
{
$soobsenie4=$soobsenie4."Убран клубок
";
}

#заклятие огня
if($zklogninc>0)
{
$soobsenie4=$soobsenie4."Добавлено заклинание огня 
";
}

if($zklogninc<0)
{
$soobsenie4=$soobsenie4."Заклинание огня удалено
";
}

if($zklplavinc<0)
{
$soobsenie4=$soobsenie4."Заклинание плавания удалено
";
}

if($zklpoletinc<0)
{
$soobsenie4=$soobsenie4."Заклинание полёта удалено
";
}

#кольцо
if($klcinc>0)
{
$soobsenie4=$soobsenie4."Добавлено кольцо
";
}

if($klcinc<0)
{
$soobsenie4=$soobsenie4."Кольцо удалено
";
}


#пузырёк с зельем
if($pzkinc>0)
{
$soobsenie4=$soobsenie4."Добавлен пузырёк с зельем
";
}

if($pzkinc<0)
{
$soobsenie4=$soobsenie4."Зелье использовано или удалено
";

}

#заклятие молота
if($zklmolotinc>0)
{
$soobsenie4=$soobsenie4."Добавлено заклинание молота 
";
}

if($zklmolotinc<0)
{
$soobsenie4=$soobsenie4."Заклинание молота удалено
";
}
Ниже — ТИПИЧНЫЙ пример, все HTML-блоки страницы «Несчастный торговец».


На этой странице, кстати, реализованы ДВЕ страницы: одна при первоначальном открытии, и вторая — после того, как Вы даёте флягу разбойнику.
При первоначальном открытии shag равен 0 и показываются блоки при $shag==0, отстёгиваете флягу — и переменная стала равна 1, следовательно, будут показаны блоки с $shag==1

Я так понимаю, отказ от MODX ещё больше увеличит скорость работы :), но я к этому пока не готов.

Я знаю, что ЕСТЬ инструменты для генерации таких книг, но зато тут есть ПОЛНЫЙ контроль за всем, чем хочешь.
Теперь надо бы заняться изучением javascript и jQuery — исчезающие блоки, всплывающие окна, реакции на кнопки, спецэффекты — всё постепенно реализуется и дополняется.
Ещё хотелось бы попробовать сделать всё с Ajax, но пока знаний маловато.

Минусы — «только» от НЕбезопасного использования EVAL в кнопках/ссылках/формах.
Весь формируемый код выполняется при помощи eval, но, по моему, по другому и не получится (огромный плюс — код формируется на основе заданных переменных/параметров в MODX, PHP в дальнейшем работает ТОЛЬКО с ними).
Условие в HTML-блоке — тоже через eval (плюс — можно сдклать ЛЮБОЕ условие, например
$par1>=5 && $par3==0 || $par2>0
)
Через eval — и действия при формировании ссылок/кнопок/форм (плюс — можно применить любую функцию PHP, например код ниже добавит случайное количество монет от 15 до 27, и кошелёк вместимостью в 50 монет

$par1zninc=mt_rand(15, 27);
$par1inc=1;
$par1znpar=50;
).

Ещё из плюсов
При первоначальном задании переменных (тип переменной, ограничение вверх/вниз) можно заниматься только логикой, «программирования», как такового, НЕТ.

Где это может понадобиться?
Для создания игр-квестов, конечно же!
Ну и для создания тестов любой сложности (да ещё и с перелачей параметров POST, со временем).

Самое главное — для работы движка нужны всего один чанк для формирования константы-массива переменных (для передачи в снипет) и ДВА снипета:
Все остальные снипеты и чанки нужны только для удобства!

Игра-квест «Тёмный лес» состоит из 92 страниц, примерно половина из которых — сложные, т.е. одна и таже страница может кардинально меняться в зависимости от заданных параметров в строке браузера (во многих случаях гораздо проще и ЛОГИЧНЕЕ работать с одной страницей вместо того, чтобы добавлять ПЯТЬ отдельных).

Ссылка на сайт с квестом:
maple4.ru/knigi/put-geroya/

P.S.
Было бы здорово сделать компонент MODX, но ранее этим вообще не занимался.
Игорь
05 июля 2022, 15:03
modx.pro
244
0

Комментарии: 8

Артур
05 июля 2022, 22:38
0
.А зачем из этого делать компонент?
    Игорь
    06 июля 2022, 00:02
    0
    Представим ситуацию — я НЕ хочу (или не могу) напрямую работать с параметрами (да и самим PHP), тем более, начиная проект, я ещё НЕ ЗНАЮ, какие параметры мне понадобятся.

    Я знаю, что HTML страница, уже как ИГРОВОЙ элемент, состоит из, собственно, самой страницы ПЛЮС параметры.

    Сама страница — это просто шаблон.
    Я же в MODX (поле MIGX) размещаю HTML-блоки, условия их показа на странице и отработку кликов (нажатий) по ссылкам/кнопкам/формам, НЕ КОДИРУЯ в PHP напрямую — в рисунке ВЫШЕ был пример — рекомендую открыть в новом окне.

    Нужен мне какой-то параметр — в РОДИТЕЛЬСКОЙ странице (поле MIGX в MODX) его добавляю, а потом использую там, где НАДО (при помощи условий, опять же в поле MIGX в MODX).

    Ну и самое главное — параметры при переходе на новую страницу не «теряются», если они НЕ РАВНЫ нулю.
    Павел Бигель
    05 июля 2022, 22:56
    +1
    Отличительная особенность MODX сообщества заключается в том, что ребята изобретают такие велосипеды, от которых волосы на голове начинают выпадать.

    Откинем вообще код, архитектурные «особенности» проекта и т.д т.п

    Возьмем первоначальную задачу — «удобная работа с URL параметрами из под MODX»

    Преположим, что логика работы игры вынесена в сервисы и остается только работать с URL параметрами.

    Я просто оставлю этот тут
    www.php.net/manual/en/function.parse-str.php
      Игорь
      05 июля 2022, 23:36
      0
      Делая квест я НЕ ЗНАЛ, чем он закончится, какие параметры мне понадобятся и т.д.

      Открывая новую страницу, бумажную версию квеста, вижу «Вы находите амулет со звездой, если понадобится — добавьте 5 к номеру страницы».

      Ок, ТУТ же, в MODX, добавляю ИГРОВОЙ объект amlzvz

      В MODX добавляю реакцию на получение амулета и его потерю (а вдруг его отберут?), отображение в малом интерфейсе на главном экране и в модальном окне — НЕ ЗАНИМАЯСЬ напрямую непосредственно кодированием кода PHP, прописывая только условия отображения на экране или том же модальном окне.
      Мне это НЕ ИНТЕРЕСНО, у меня есть HTML-код, который я должен вывести.
      И «забываю» об амулете.

      Потом, в процессе прохождения квеста (точнее — последовательного переноса каждой бумажной страницы в электронный вариант), я вижу такое:

      «Вы заходите в комнату с изображением звезды»

      Ок, я понимаю, что должен «воспользоваться» амулетом, поэтому в Вещмешке добавляю ИМЕННО НА ЭТОЙ странице добавляю кнопку «Использовать амулет звезды» — опять же, в MODX, никакого кодирования напрямую в PHP — и для кнопки задаю действие — что должно произойти при использовании амулета (скорее всего — переход на новую страницу с новыми параметрами).

      ВСЁ. Я НЕ РАБОТАЮ напрямую с параметрами из строки браузера, не объявляю переменных PHP, я всего лишь проверяю условия срабатывания и изменение при использовании.

      Могу ради интереса прямо сейчас добавить куда-то объект и реакцию на его использование :)
      Артур
      06 июля 2022, 00:27
      0
      Допустим сохранять состояние можно в куки, в сессию или local storage. Что касается программирования, то если известен алгоритм, можно написать универсальный скрипт, который будет уметь работать с любыми параметрами, а migx, как и в твоём варианте, будет просто интерфейсом редактирования. Я думаю, что нужно оптимизировать, пока, лично для меня, логика работы до конца не ясна. Ещё не хватает описания практического применения. Только текстовые квесты? А на них есть спрос?
        Игорь
        06 июля 2022, 07:16
        0
        «сохранять состояние можно в куки, в сессию или local storage» — зачем?
        Все необходимые для работы программы параметры передаются в браузерной строке при переходе на следующую страницу.

        «migx, как и в твоём варианте, будет просто интерфейсом редактирования» — да, просто интерфейс редактирования.

        «не хватает описания практического применения» — квест является примером реализации.
        Конечно же, есть определённые чанки для вывода HTML-блоков, которые размещаются в шаблоне (у меня — в одном шаблоне для всего квеста).

        При размещении в шаблоне MODX при помощи formirfrommigx выведет HTML-блоки для основного экрана

        [[*content]]
        [[$formirfrommigx?&tipokna=`1`&nomerknigi=`0`]]
        В окне для записной книжки

        <!-- HTML-код модального окна -->
        <div id="myModalzapis" class="modal fade">
          <div class="modal-dialog">
            <div class="modal-content">
              <!-- Заголовок модального окна -->
              <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">X</button>
                <h4 class="modal-title">Записная книжка</h4>
              </div>
              <!-- Основное содержимое модального окна -->
              <div class="modal-body">
        [[$formirfrommigx?&tipokna=`3`&nomerknigi=`0`]]
        [[$formirfrommigxinterf?&tipokna=`3`&tipinter=`3`&nomerknigi=`0`]]
            <hr>
              </div>
              <!-- Футер модального окна -->
              <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Закрыть</button>
              </div>
            </div>
          </div>
        </div>
        [[$formirfrommigx?&tipokna=`3`&nomerknigi=`0`]] — вывести HTML-блоки для ЗАПИСНОЙ книжки именно на этой странице — в самом верху
        [[$formirfrommigxinterf?&tipokna=`3`&tipinter=`3`&nomerknigi=`0`]] — вывести HTML-блоки для ЗАПИСНОЙ книжки для ВСЕХ страниц — глобальный интерфейс

        чанк formirfrommigx

        [[getImageList?
            &tvname=`sobit`
            &tpl=`formirscenariotpl`
            &where=`{"sobitie_tip:=":"[[+tipokna]]","sobitie_tip_int:<":"2"}`
            &prmnomerknigi=`[[+nomerknigi]]`
        ]]
        tpl formirscenariotpl

        [[!newformirpostuslovienew?&nomerknigi=`[[+property.prmnomerknigi]]`&imachunk=`formirscenariotc[[+sobitie_ssilkatip]]`&uslovieprov=`[[+sobitie_uslovie]]`
        &sobitie_html=`[[+sobitie_html]]`
        &sobitie_text=`[[+sobitie_text]]`
        &sobitie_this_text=`[[+sobitie_this_text]]`
        &sobitie_obrabotka=`[[+sobitie_obrabotka]]`
        &sobitie_stranica=`[[+sobitie_stranica:is=`0`:then=`[[*id]]`:else=`[[!getmoiparamphp?&mp=`[[+sobitie_stranica]]`]]`]]`
        &sobitie_ssilkatip=`[[+sobitie_ssilkatip]]`
        &sobitie_kod=`[[+sobitie_kod]]`
        &sobitie_uslovie_true=`[[+sobitie_uslovie_true]]`
        &sobitie_uslovie_false=`[[+sobitie_uslovie_false]]`
        &sobitie_obrabotka_true=`[[+sobitie_obrabotka_true]]`
        &sobitie_obrabotka_false=`[[+sobitie_obrabotka_false]]`
        &imiapar=`[[+imiapar]]`
        &sobitie_dtext_ssilki=`[[+sobitie_dtext_ssilki:is=``:then=``:else=`[[+sobitie_dtext_ssilki]]`]]`
        ]]

        «Только текстовые квесты?» — применяется там, где вывод страницы зависит от наличия (состояния значений) параметров.

        Вместо текста — любой HTML-код (или я что-то не так понял?).

        Пример с кучей параметров (пока игрок подошёл к дракону, он успел получить два заклинания, подсказку о наличии клада, волшебную флягу в три порции воды, кошелёк вместимостью в 50 монет, деньги — 35 золотых, почти бодрый и с «флагами» о прохождении определённых шагов — n1=1 — загадка короля решена — при встрече с единорогом это обыгрывается, n2=1 — игрок раскопал клад — в слухах в это обыгрывается)

        maple4.ru/knigi/put-geroya/452-tryoxgolovyij-drakon/?&zklpolet=1&zklplav=1&dveberez=1&flg=1&flgzn=3&flgzntip=1&flgznpar=3&ksl=1&kslzn=35&kslznpar=50&ust=997&n1=1&n2=1

        Можно открыть записную книжку или вещмешок для доп действий

        ну, и без параметров
        maple4.ru/knigi/put-geroya/452-tryoxgolovyij-drakon/
          Артур
          06 июля 2022, 08:46
          0
          применяется там, где вывод страницы зависит от наличия (состояния значений) параметров.
          Я делал мультилэндинг на migx, где параметром была utm метка. У этого был практический смысл и привязка с парпметрам URL вполне оправдана. Ты говоришь что параметров может быть куча и предлагаешь хранить их в адресной строке, а зачем? Это квест, где, как ты сам писал, читерства быть не должно, убрав параметры из урла ты пресечешь читерство.
            Игорь
            06 июля 2022, 10:48
            0
            Есть ещё передача параметров POST (в будущем) — я как бы сразу написал…
            Думаю, что замена (int) $_GET[ на (int) $_POST[ в PHP и ссылок на формы с кнопками с передачей POST снимет эту проблему.
        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
        8