За последние 24 часа нас посетили 21658 программистов и 1053 робота. Сейчас ищут 660 программистов ...

pjax мать его! Как обновить правильно токен?

Тема в разделе "PHP для новичков", создана пользователем AlexProg, 11 апр 2019.

Метки:
  1. AlexProg

    AlexProg Активный пользователь

    С нами с:
    13 май 2014
    Сообщения:
    320
    Симпатии:
    7
    Всем добра!

    Парни, есть pjax. Как обновить токен после отправки формы? На странице несколько форм срабатывает только одна любая форма, потом все недоступны. Обновил страницу и все по кругу.

    PHP:
    1. <input type="hidden" name="_tocken" value="fyvrt568b7456765">
     
  2. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    Странно, не сталкивался. Правда, обычно я и не пользую pjax. Ты в Yii2 его применяешь или отдельно?
     
    AlexProg нравится это.
  3. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.825
    Симпатии:
    738
    Адрес:
    Татарстан
    имхо токен должен меняться только после перезагрузки страницы, если отсылаешь ajax то вроде тот же должен оставаться
    может дело в корректности написания имени?
    не
    Код (Text):
    1. name="_token"
    ?
     
    AlexProg нравится это.
  4. AlexProg

    AlexProg Активный пользователь

    С нами с:
    13 май 2014
    Сообщения:
    320
    Симпатии:
    7
    Отдельно. Свой мини MVC.
    --- Добавлено ---
    Разницы нет. Хоть qwerty, но потом qwerty и чекаем.

    Ну pjax и так обновляет страницу и токен в форме меняется.

    Пока столкнулся с такой проблемой... Первый раз форма отправляется нормально, второй раз получаю abord

    Код (Javascript):
    1.     $('html').on('pjax:error', function(event, xhr, textStatus, errorThrown, options) {
    2.         options.success(xhr.responseText, textStatus, xhr);
    3.         console.log(xhr.responseText);
    4.         console.log(textStatus); //  <- тут abord
    5.         console.log(xhr);
    6.         return false;
    7.     });
     
  5. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.825
    Симпатии:
    738
    Адрес:
    Татарстан
    покажи код чекания? Может ты в нем сразу новый токен генеришь?
     
    AlexProg нравится это.
  6. AlexProg

    AlexProg Активный пользователь

    С нами с:
    13 май 2014
    Сообщения:
    320
    Симпатии:
    7
    Это в контроллере. Если false, то выводим ошибку.

    PHP:
    1. if (NoCSRF::check( '_token', $_POST, false, 60, false ) == false) {
    2.     $errors = $langerrors['s'];
    3. }
    PHP:
    1. <?php
    2. /**
    3. * NoCSRF, an anti CSRF token generation/checking class.
    4. *
    5. * Copyright (c) 2011 Thibaut Despoulain <http://bkcore.com/blog/code/nocsrf-php-class.html>
    6. * Licensed under the MIT license <http://www.opensource.org/licenses/mit-license.php>
    7. *
    8. * @author Thibaut Despoulain <http://bkcore.com>
    9. * @version 1.0
    10. */
    11. class NoCSRF
    12. {
    13.  
    14.     protected static $doOriginCheck = false;
    15.  
    16.     /**
    17.      * Check CSRF tokens match between session and $origin.
    18.      * Make sure you generated a token in the form before checking it.
    19.      *
    20.      * @param String $key The session and $origin key where to find the token.
    21.      * @param Mixed $origin The object/associative array to retreive the token data from (usually $_POST).
    22.      * @param Boolean $throwException (Facultative) TRUE to throw exception on check fail, FALSE or default to return false.
    23.      * @param Integer $timespan (Facultative) Makes the token expire after $timespan seconds. (null = never)
    24.     * @param Boolean $multiple (Facultative) Makes the token reusable and not one-time. (Useful for ajax-heavy requests).
    25.      *
    26.      * @return Boolean Returns FALSE if a CSRF attack is detected, TRUE otherwise.
    27.      */
    28.     public static function check( $key, $origin, $throwException=false, $timespan=null, $multiple=false )
    29.     {
    30.         if ( !isset( $_SESSION[ 'csrf_' . $key ] ) )
    31.             if($throwException)
    32.                 throw new Exception( 'Missing CSRF session token.' );
    33.             else
    34.                 return false;
    35.          
    36.         if ( !isset( $origin[ $key ] ) )
    37.             if($throwException)
    38.                 throw new Exception( 'Missing CSRF form token.' );
    39.             else
    40.                 return false;
    41.  
    42.         // Get valid token from session
    43.         $hash = $_SESSION[ 'csrf_' . $key ];
    44.      
    45.         // Free up session token for one-time CSRF token usage.
    46.         if(!$multiple)
    47.             $_SESSION[ 'csrf_' . $key ] = null;
    48.  
    49.         // Origin checks
    50.         if( self::$doOriginCheck && sha1( $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] ) != substr( base64_decode( $hash ), 10, 40 ) )
    51.         {
    52.             if($throwException)
    53.                 throw new Exception( 'Form origin does not match token origin.' );
    54.             else
    55.                 return false;
    56.         }
    57.      
    58.         // Check if session token matches form token
    59.         if ( $origin[ $key ] != $hash )
    60.             if($throwException)
    61.                 #throw new Exception( 'Invalid CSRF token. <br>'.$origin[ $key ].'<br>='.$hash );
    62.                throw new Exception( 'Invalid CSRF token.');
    63.             else
    64.                 return false;
    65.  
    66.         // Check for token expiration
    67.         if ( $timespan != null && is_int( $timespan ) && intval( substr( base64_decode( $hash ), 0, 10 ) ) + $timespan < time() )
    68.             if($throwException)
    69.                 throw new Exception( 'CSRF token has expired.' );
    70.             else
    71.                 return false;
    72.  
    73.         return true;
    74.     }
    75.  
    76.     /**
    77.      * Adds extra useragent and remote_addr checks to CSRF protections.
    78.      */
    79.     public static function enableOriginCheck()
    80.     {
    81.         self::$doOriginCheck = true;
    82.     }
    83.  
    84.     /**
    85.      * CSRF token generation method. After generating the token, put it inside a hidden form field named $key.
    86.      *
    87.      * @param String $key The session key where the token will be stored. (Will also be the name of the hidden field name)
    88.      * @return String The generated, base64 encoded token.
    89.      */
    90.     public static function generate( $key )
    91.     {
    92.         $extra = self::$doOriginCheck ? sha1( $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] ) : '';
    93.         // token generation (basically base64_encode any random complex string, time() is used for token expiration)
    94.         $token = base64_encode( time() . $extra . self::randomString( 32 ) );
    95.         // store the one-time token in session
    96.         $_SESSION[ 'csrf_' . $key ] = $token;
    97.  
    98.         return $token;
    99.     }
    100.  
    101.     /**
    102.      * Generates a random string of given $length.
    103.      *
    104.      * @param Integer $length The string length.
    105.      * @return String The randomly generated string.
    106.      */
    107.     protected static function randomString( $length )
    108.     {
    109.         $seed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijqlmnopqrtsuvwxyz0123456789';
    110.         $max = strlen( $seed ) - 1;
    111.  
    112.         $string = '';
    113.         for ( $i = 0; $i < $length; ++$i )
    114.             $string .= $seed{intval( mt_rand( 0.0, $max ) )};
    115.  
    116.         return $string;
    117.     }
    118.  
    119. }
    120. ?>
    --- Добавлено ---
    UPDATE:
    генерится так

    PHP:
    1. NoCSRF::generate( '_token' )
     
  7. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.825
    Симпатии:
    738
    Адрес:
    Татарстан
    ну а сама check что делает посмотреть?
    --- Добавлено ---
    ну дык видно ж даже по описанию
    а у тебя false, поставь true
     
    AlexProg нравится это.
  8. AlexProg

    AlexProg Активный пользователь

    С нами с:
    13 май 2014
    Сообщения:
    320
    Симпатии:
    7
    Пробовал уже, не помогло. Сейчас еще раз проверил - ни как. Тупо обновляется страница и все (при отправке еще одной формы).
     
  9. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.825
    Симпатии:
    738
    Адрес:
    Татарстан
    обновление страницы то где происходит - во фронте? Покажи код где идет обновление
     
    AlexProg нравится это.
  10. AlexProg

    AlexProg Активный пользователь

    С нами с:
    13 май 2014
    Сообщения:
    320
    Симпатии:
    7
    Обычная форма:

    Код (Text):
    1.             <form action="/shop" method="POST" class="shopcard" data-pjax>
    2.  
    3.                         <input type="hidden" name="_token_shop_<?=$plan['id']; ?>" value="<?=NoCSRF::generate( '_token_shop_'.$plan['id'] ); ?>">
    4.                         <input type="hidden" name="buy" value="1">
    5.                         <input type="hidden" name="plan" value="<?=$plan['id']; ?>">
    6.                         <div class="shopcard__btn">
    7.                             <button type="submit" name="buy" class="btn btn-primary">Купить</button>
    8.                         </div>
    9.                     </form>
    JS код

    Код (Javascript):
    1.     $('html').on('submit', 'form[data-pjax]', function(event) {
    2.         $.pjax.submit(event, '#pjax-container', {fragment: '#pjax-container', type: 'post', scrollTo: 0, timeout: 10000}); //asnyc: false, push: true, enablePushState: true
    3.         //console.log("gooo"+event);
    4.     });
    Страница обернута <div id="pjax-container">
    --- Добавлено ---
    UPDATE:

    Токен у каждой формы свой. Мб в этом трабл?
    Типо _token_shop_1
    _token_shop_2
    _token_shop_3 и т.д.
     
  11. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.825
    Симпатии:
    738
    Адрес:
    Татарстан
    а зачем свой то? в беке то один проверяется
     
    AlexProg нравится это.
  12. AlexProg

    AlexProg Активный пользователь

    С нами с:
    13 май 2014
    Сообщения:
    320
    Симпатии:
    7
    Нет, тоже разные.

    PHP:
    1.     if (NoCSRF::check( '_token_shop_'.$plan['id'], $_POST, false, 60, true ) == false) {
    2.                 $errors = $langerrors['s'];
    3.             }
    --- Добавлено ---
    Что делать? Куда копать? Почему abort?

    Есть еще вот такая шляпа:

    Код (Javascript):
    1.     $(document).on('pjax:end', function () {
    2.         contentLoaded();
    3.         $('html, body').animate({
    4.             scrollTop: $(".section").offset().top
    5.         }, 0);
    6.     });
    Вот contentLoaded()

    Код (Javascript):
    1. "use strict";function contentLoaded(){document.getElementById("preloader").classList.add("loaded");var t=document.getElementsByClassName("js-youtube"),e=t.length;function a(){var t=document.createElement("iframe"),e="https://www.youtube.com/embed/"+this.id+"?autoplay=1&autohide=1";this.getAttribute("data-params")&&(e+="&"+this.getAttribute("data-params")),t.setAttribute("src",e),t.setAttribute("frameborder","0"),t.setAttribute("allowfullscreen","1"),t.setAttribute("width","100%"),t.setAttribute("height","100%"),this.innerHTML="",this.appendChild(t),this.removeEventListener("click",a)}for(var s=0;s<e;s++){t[s].getAttribute("data-background")&&(t[s].style.backgroundImage="url(https://i.ytimg.com/vi/"+t[s].id+"/sddefault.jpg)");var i=document.createElement("div");i.setAttribute("class","play"),t[s].appendChild(i),t[s].addEventListener("click",a)}!function(){var t=document.getElementsByClassName("section"),e=document.getElementById("block-content");if(t.length){var a=t[0],s=parseInt(a.clientHeight),i=Math.floor((s-100)/418);i<1?e.setAttribute("class","x1"):15<i?e.setAttribute("class","x15"):e.setAttribute("class","x"+i)}}()}document.addEventListener("DOMContentLoaded",contentLoaded);
    2. //# sourceMappingURL=common.js.map
     
  13. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.825
    Симпатии:
    738
    Адрес:
    Татарстан
    а у тебя contentLoaded(); не перезагружает ли всю страницу?
     
    AlexProg нравится это.
  14. AlexProg

    AlexProg Активный пользователь

    С нами с:
    13 май 2014
    Сообщения:
    320
    Симпатии:
    7
    Затрудняюсь ответить. В JS не особо силен... Пытался по строкам разложить и понять не смог :(
    --- Добавлено ---
    Убрал contentLoaded() и все что с этим связано. Без изменений.

    Получается так: первый раз отправляем любую форму - все ок. Второй раз эту же или любую другую, то уже все не отправляется тупо обновление страницы и все.
    Типо не видит форму? Токен меняется.
     
  15. muzmmuz

    muzmmuz Новичок

    С нами с:
    8 апр 2019
    Сообщения:
    41
    Симпатии:
    1
    Адрес:
    Россия, Москва
    Обновлять вместе с формой когда данные отослал или отдельно. Вот отослал ты запрос, если успешно выполнился он то с бакенда формируй новый и отбавай его в success и затем через js изменяй в инпуте.
     
    AlexProg нравится это.
  16. AlexProg

    AlexProg Активный пользователь

    С нами с:
    13 май 2014
    Сообщения:
    320
    Симпатии:
    7
    Можно подробней? Чутка кода добавить, схематично.