코드 점화기 세션이 Ajax 호출로 버그가 발생함
내 CodeIgniter 앱은 세션 라이브러리를 사용하고 데이터를 DB에 저장합니다.
특정 아약스 호출 후 빈 세션이 생성되는 문제가 발생했습니다.
조사해보니, 세션 검증이 필요한 두 개의 동시 함수 호출이 있었던 것 같습니다.하나는 실패하고 다른 하나는 괜찮을 것입니다.
동시에 발사하지 않음으로써 이 문제를 해결할 수 있었습니다.하지만 저는 여전히 왜 실패하는지 이해할 수 없습니다.한 통화가 사용자 쿠키를 업데이트하고 두 번째 통화가 무효화하는 것과 관련이 있습니까?아니면 DB를 읽을 때 어떻게든 죽을까요?
세션 코어 클래스를 조금 살펴보았지만 원인에 대한 단서를 찾지 못했습니다.
만약 누군가가 이전에 같은 문제를 가지고 있었다면 디버깅 방법이나 원인이 무엇인지에 대한 조언을 해주시면 감사하겠습니다.
감사합니다!
편집:
저는 원래 408 상태 리턴이 있다고 말했습니다.그것은 관련이 없는 사건이었습니다.
MyVar.refresh()를 병렬로 실행하는 기능은 다음과 같습니다.
function (event)
{
var self$ = this.a$;
var uid = this.b$.val();
var tid = this.c$.val();
var jqxhr = $.post('/controller1/index',{'uid':uid,'tid':tid,'action':true},function(re)
{
if(re.message != 'success')
{
MyVar.alert('<span class="msg_error sprite"></span>' + re.error);
MyVar.refresh();
}
},'json');
MyVar.refresh();
return stopDefault(event);
};
가능한 솔루션:
다음을 찾았습니다: http://codeigniter.com/forums/viewthread/102456/
분명히 그것은 아약스와 잘 어울리지 않습니다.한 가지 해결책은 Ajax 호출일 경우 세션 업데이트를 허용하지 않는 것입니다. 유일한 문제는 우리 사이트가 대부분 Ajax로 구축되어 있다는 것입니다.
또한 sess_time_to_update를 매우 빈번한 것으로 낮추었고 Ajax는 잘 지내고 있었습니다.또한 브라우저를 새로 고쳤으며 시간이 초과되지 않았습니다.Ajax 호출 시 세션 ID가 이미 변경되었고 브라우저 쿠키가 업데이트되지 않은 이유를 알 수 없습니다.
사용해 보세요.
<?php
/**
* ------------------------------------------------------------------------
* CI Session Class Extension for AJAX calls.
* ------------------------------------------------------------------------
*
* ====- Save as application/libraries/MY_Session.php -====
*/
class MY_Session extends CI_Session {
// --------------------------------------------------------------------
/**
* sess_update()
*
* Do not update an existing session on ajax or xajax calls
*
* @access public
* @return void
*/
public function sess_update()
{
$CI = get_instance();
if ( ! $CI->input->is_ajax_request())
{
parent::sess_update();
}
}
}
// ------------------------------------------------------------------------
/* End of file MY_Session.php */
/* Location: ./application/libraries/MY_Session.php */
이 문제는 세션 클래스의 sess_update 함수에서 X초 후에 새 session_id를 생성합니다.모든 페이지에는 session_id가 있으며, Ajax 호출 전에 session_id가 만료되면 해당 호출이 실패합니다.
이름이 MY_Session(또는 설정한 접두사)인 /application/libraries/에 php 파일을 만들고 이 코드를 붙여넣으면 그게 전부입니다.이 함수는 세션 클래스의 sess_update 함수를 재정의하여 모든 요청이 Ajax에 의해 수행되었는지 확인하고 sess_update 함수를 건너뜁니다.
sess_expiration을 더 높은 값으로 설정하는 것은 좋지 않습니다.이 기능은 세션 히잡으로부터 사용자를 보호하는 보안 기능입니다.
PD: 저는 영어를 잘 하지 못합니다. 이해가 안 되면 말씀해 주세요.
안정적인 분기에 병합될 때까지 솔루션(최종적으로!)은 데이터베이스 스키마와 결합된 Areson의 commit 245bef5를 사용하는 것입니다.
CREATE TABLE IF NOT EXISTS `ci_sessions` (
session_id varchar(40) DEFAULT '0' NOT NULL,
ip_address varchar(45) DEFAULT '0' NOT NULL,
user_agent varchar(120) NOT NULL,
last_activity int(10) unsigned DEFAULT 0 NOT NULL,
user_data text NOT NULL,
prevent_update int(10) DEFAULT NULL,
PRIMARY KEY (session_id),
KEY `last_activity_idx` (`last_activity`)
);
자세한 내용은 1283개의 댓글을 위에서 아래로 당기십시오.
이 문제는 config.php의 sess_time_to_update 매개 변수 때문에 발생했습니다.CI를 사용하여 세션 ID를 새 ID로 업데이트합니다.Ajax 호출에서 변경 사항이 발생하면 CI는 브라우저에 새 세션 ID를 알리기 위해 새 쿠키를 보냅니다.안타깝게도 브라우저는 이 쿠키를 무시하고 이전 세션 ID를 유지하는 것 같습니다.
구성에서 sess_time_to_update를 sess_expiration으로 설정하여 수정했습니다.
$config['sess_time_to_update'] = $config['sess_expiration'];
다음 구성을 사용할 때 코드 점화기 버전 2.1.3에서도 이 문제가 발생했습니다.
$config['sess_use_database'] = TRUE;
$config['sess_time_to_update'] = 300;
나는 그것이 아약스 요청과 관련이 없고 오히려 코드 점화기의 버그와 관련이 있다고 생각합니다.
세션을 데이터베이스에 저장하면 300초 후에 로그아웃이 강제로 실행되는 것 같습니다.3시간 동안 검색하고 분석한 결과, 코드에서 명확한 버그와 불분명한 버그를 발견했고, 다음과 같이 버그를 해결했습니다.
새 파일 MY_Session을 만듭니다.php가 응용 프로그램/디버깅 폴더에 있습니다.
다음 코드를 추가합니다.
<?php
// fixed by sirderno 2013
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Session extends CI_Session
{
public function __construct()
{
parent::__construct();
}
/**
* Update an existing session
*
* @access public
* @return void
*/
public function sess_update()
{
// We only update the session every five minutes by default
if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
{
return;
}
// Save the old session id so we know which record to
// update in the database if we need it
$old_sessid = $this->userdata['session_id'];
$new_sessid = '';
while (strlen($new_sessid) < 32)
{
$new_sessid .= mt_rand(0, mt_getrandmax());
}
// To make the session ID even more secure we'll combine it with the user's IP
$new_sessid .= $this->CI->input->ip_address();
// Turn it into a hash
$new_sessid = md5(uniqid($new_sessid, TRUE));
// Update the session data in the session data array
$this->userdata['session_id'] = $new_sessid;
$this->userdata['last_activity'] = $this->now;
// _set_cookie() will handle this for us if we aren't using database sessions
// by pushing all userdata to the cookie.
$cookie_data = NULL;
// Update the session ID and last_activity field in the DB if needed
if ($this->sess_use_database === TRUE)
{
// set cookie explicitly to only have our session data
$cookie_data = array();
foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
{
$cookie_data[$val] = $this->userdata[$val];
}
$cookie_data['session_id'] = $new_sessid; // added to solve bug
//added to solve bug
if (!empty($this->userdata['user_data']))
$cookie_data['user_data'] = $this->userdata['user_data'];
$this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));
}
// Write the cookie
$this->_set_cookie($cookie_data);
}
/**
* Write the session cookie
*
* @access public
* @return void
*/
public function _set_cookie($cookie_data = NULL)
{
if (is_null($cookie_data))
{
$cookie_data = $this->userdata;
}
// Serialize the userdata for the cookie
$cookie_data = $this->_serialize($cookie_data);
if ($this->sess_encrypt_cookie == TRUE)
{
$cookie_data = $this->CI->encrypt->encode($cookie_data);
}
else
{
// if encryption is not used, we provide an md5 hash to prevent userside tampering
$cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
}
$_COOKIE[ $this->sess_cookie_name ] = $cookie_data; // added to solve bug
$expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();
// Set the cookie
setcookie(
$this->sess_cookie_name,
$cookie_data,
$expire,
$this->cookie_path,
$this->cookie_domain,
$this->cookie_secure
);
}
}
?>
분명한 버그는 업데이트된 쿠키에 'user_data'를 저장하지 않았다는 것입니다.명확하지 않은 버그는 Session 파일에서 sess_read() 함수를 실행한다는 것입니다.php는 새로운 세션 ID를 업데이트한 후에 왜 이런 일이 일어나는지 모르겠습니다. 왜냐하면 저는 그것이 Session.php의 생성자에 쓰여진 것처럼 업데이트 전이 아니라 업데이트 전에 실행될 것이라고 예상했기 때문입니다.sess_read() 함수는 오래된 쿠키 정보를 오래된 세션 ID로 읽기 시작하고 데이터베이스의 세션 ID와 비교하려고 하지만 session_id 업데이트 후에는 더 이상 데이터베이스에 존재하지 않으므로 로그아웃이 발생합니다.
Session.php 파일의 functionsess_read에 있는 이 코드 행은 오래된 쿠키 정보를 읽습니다.
$session = $this->CI->input->cookie($this->sess_cookie_name);
그래서 MY_Session의 _set_cookie 함수에서.php i는 서버의 오래된 쿠키 정보를 새로운 것으로 업데이트하기 위해 이 코드 라인을 추가했습니다.
$_COOKIE[ $this->sess_cookie_name ] = $cookie_data; // added to solve bug
이 수정 프로그램을 사용하면 'ss_time_to_update'와 'ss_use_database'를 함께 사용하면 됩니다.이것은 간단하고 간단한 버그 수정입니다.
나는 아약스로 이미지를 업로드할 때 정확히 같은 문제를 겪었고, 나는 그것을 설정했습니다.sess_expiration
구성 시:
$config['sess_expiration'] = time()+10000000;
그리고 그것이 제 문제를 해결했습니다.
좋은 해결책이 여기 있습니다. sess_time_to_update 등으로 무엇이든 하십시오. 아래 해결책을 시도해 보십시오.
- https://degreesofzero.com/article/fixing-the-expiring-session-problem-in-codeigniter.html
- http://ellislab.com/forums/viewthread/138823/ #725078
솔루션 번호 "1"에 대해 스크립트를 조금 더 업데이트합니다. CI와 많이 충돌한 후 CI 세션이 손실되는 두 가지 이유가 있습니다. 하나는 잘못된 Ajax 호출이 세션을 업데이트하고 세션이 손실되는 경우입니다. 두 번째는 잘못된 Ajax 호출이 CI의 SESSION 라이브러리에서 sess_destroy 함수에 영향을 미치는 경우입니다. 그래서 조금 만들었습니다."1." 솔루션의 변경
/*add this code to MY_Session.php*/
function sess_destroy()
{
// Do NOT update an existing session on AJAX calls.
if (!$this->CI->input->is_ajax_request())
{
return parent::sess_destroy();
}
/* WHEN USER HIS/HER SELF DO A LOGOUT AND ALSO IF PROGRAMMER SET TO LOGOUT USING AJAX CALLS*/
$firsturlseg = $this->CI->security->xss_clean( $this->CI->uri->segment(1) );
$securlseg = $this->CI->security->xss_clean( $this->CI->uri->segment(2) );
if((string)$firsturlseg==(string)'put ur controller name which u are using for login' && (string)$securlseg==(string)'put url controler function for logout')
{
return parent::sess_destroy();
}
}
이것들이 사람들에게도 도움이 되기를 바랍니다.
코어 CI 세션 클래스 처리 세션에 결함이 있는 것 같습니다.
매력적으로 작동하는 대체 세션 라이브러리를 찾았습니다.
코어 CI_Session 클래스를 교체하는 것보다 확장하는 것이 좋습니다.
확장하려면 파일을 만듭니다.MY_Session.php
에application/libraries
대체 라이브러리의 내용을 붙여넣고 바꾸기class CI_Session
로.class MY_Session extends CI_Session
.
보호된 항목 제거_flashdata_mark()
,_flashdata_sweep()
,_get_time()
,_set_cookie()
,_serialize()
,_unserialize()
,_sess_gc()
기능들.
도움이 되길 바랍니다.
아직도 오래된 CI 버전이 많이 사용되고 있는 것 같습니다. 이 스레드가 오래되었음에도 불구하고 2센트를 추가하고 싶었습니다.저는 코드 이그니터에서 AJAX 호출 문제를 해결하는 데 며칠을 보냈으며, 주요 문제를 다루는 솔루션이 있지만 일부 솔루션은 '훌륭하지' 않습니다.제가 (아직) 사용하고 있는 CI 버전은2.1.3
내 애플리케이션에서는 유효한 세션을 유지하기 위해 AJAX 호출이 last_activity 필드를 업데이트해야 하므로 AJAX 호출에 대한 세션 업데이트를 포기하는 것만으로는 충분하지 않습니다.
이 CI 버전에서는 sess_update 및 sess_read에 대한 오류 검사가 부적절합니다(최근 버전은 조사하지 않았습니다). 많은 문제가 여기서 시작됩니다.
1부:sess_update()
여러 AJAX 호출은 경합 조건을 생성하여 이후 호출에 대해 데이터베이스를 잠급니다.업데이트 쿼리를 실행하려고 하지만 데이터베이스가 잠겨 있으면 오류가 발생하고 쿼리가 false를 반환하지만 쿠키가 여전히 새 데이터로 업데이트되어 있습니까?... BAD!또한 모든 Ajax 호출에 대해 새로운 session_id가 필요하지 않습니다.우리는 last_activity만 업데이트하면 됩니다.사용해 보십시오.
function sess_update()
{
// We only update the session every five minutes by default
if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
{
return;
}
// Save the old session id so we know which record to
// update in the database if we need it
$old_sessid = $this->userdata['session_id'];
//Assume this is an AJAX call... keep the same session_id
$new_sessid = $old_sessid;
if( !$this->CI->input->is_ajax_request() ){
//Then create a new session id
while (strlen($new_sessid) < 32)
{
$new_sessid .= mt_rand(0, mt_getrandmax());
}
// To make the session ID even more secure we'll combine it with the user's IP
$new_sessid .= $this->CI->input->ip_address();
// Turn it into a hash
$new_sessid = md5(uniqid($new_sessid, TRUE));
}
// _set_cookie() will handle this for us if we aren't using database sessions
// by pushing all userdata to the cookie.
$cookie_data = NULL;
// Update the session ID and last_activity field in the DB if needed
if ($this->sess_use_database === TRUE)
{
//TRY THE QUERY FIRST!
//Multiple simultaneous AJAX calls will not be able to update because the Database will be locked. ( Race Conditions )
//Besides... We don't want to update the cookie if the database didn't update
$query = $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));
if( $query ){
// Update the session data in the session data array
$this->userdata['session_id'] = $new_sessid;
$this->userdata['last_activity'] = $this->now;
// set cookie explicitly to only have our session data
$cookie_data = array();
foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
{
$cookie_data[$val] = $this->userdata[$val];
}
// Write the cookie
$this->_set_cookie($cookie_data);
}else{
//do nothing... we don't care, we still have an active retreivable session and the update didn't work
//debug: error_log( "ERROR::" . $this->CI->db->_error_message() ); //Shows locked session database
}
}else{
// Update the session data in the session data array
$this->userdata['session_id'] = $new_sessid;
$this->userdata['last_activity'] = $this->now;
// Write the cookie
$this->_set_cookie($cookie_data);
}
}
2: 파트 2:sess_read()
여기서 아주 비슷한 문제가...쿼리 중에 데이터베이스가 잠기는 경우가 있습니다.이번에는 오류를 무시할 수 없다는 것만 빼면요.세션이 있는지 확인하기 위해 세션을 읽는 중입니다.따라서 데이터베이스 오류가 잠길 경우 오류를 확인하고 다시 시도할 수 있습니다(필요한 경우 몇 번).테스트에서는 에서 2번 이상 시도하지 않았습니다.또한 당신에 대해서는 잘 모르겠지만, 저는 php가 잘못된 쿼리 결과를 확인하지 않음으로써 치명적인 오류로 실패하는 것을 원하지 않습니다.이 코드를 직접 시도하려면 session.php 파일의 맨 위에 이 정보가 있어야 합니다.
var $sess_query_attempts = 5;
참로고전, 은가아다닙니체이것▁entire다아'의 전체가 아닙니다.sess_read
를 수행
$query = $this->CI->db->get($this->sess_table_name);
//Multiple AJAX calls checking
//But adding add a loop to check a couple more times has stopped premature session breaking
$counter = 0;
while( !$query && $counter < $this->sess_query_attempts ){
usleep(100000);//wait a tenth of a second
$this->CI->db->where('session_id', $session['session_id']);
if ($this->sess_match_ip == TRUE)
{
$this->CI->db->where('ip_address', $session['ip_address']);
}
if ($this->sess_match_useragent == TRUE)
{
$this->CI->db->where('user_agent', $session['user_agent']);
}
$query = $this->CI->db->get($this->sess_table_name);
$counter++;
}
if ( !$query || $query->num_rows() == 0)
{
$this->CI->db->where('session_id', $session['session_id']);
$query = $this->CI->db->get( $this->sess_table_name );
$this->sess_destroy();
return FALSE;
}
어쨌든, 나는 이 문제에 대한 완전한 답이 없고 나처럼 AJAX를 많이 사용하는 사이트에서 아직도 초기 세션 타임아웃을 경험하고 있을 수 있는 사람들과 내 연구 결과를 공유해야 한다고 느꼈습니다.
글을 쓰다session_start()
언급URL : https://stackoverflow.com/questions/7980193/codeigniter-session-bugging-out-with-ajax-calls
'programing' 카테고리의 다른 글
PIL을 사용하여 이미지에 텍스트 추가 (0) | 2023.07.24 |
---|---|
Python SQL 쿼리 문자열 형식 지정 (0) | 2023.07.24 |
String(값) 대 value.to String()의 차이점은 무엇입니까? (0) | 2023.07.24 |
제출하기 전에 어떻게 해야 합니까? (0) | 2023.07.24 |
Oracle(PL/)SQL의 문자열 형식 (0) | 2023.07.24 |