ある意味で、この質問はこの質問の延長として見ることができます。
大規模な本番Webサイトのテーブルに格納されているセッションデータの逆シリアル化とシリアル化を処理するクラスをリリースして、任意のセッションデータを編集できるようにすることを検討しています。
問題は、デコードされた配列を返さずにsession_decode()
現在の配列を設定し、特定の配列をエンコードしないことです(現在のセッションのシリアル化された文字列のみを返します)。$_SESSION
session_encode()
デフォルトのPHPセッションシリアル化ハンドラーは単にserialize()
セッションのエンコードに使用するわけではないため、セッションのエンコードとデコードの同じ機能を取得する唯一の方法は、グローバル$_SESSION
変数を移動することです(つまり、セッションに保存し、データを取得して復元します)。 )または、実行する内容の実装を再現しようとすることによってsession.serialize_handler
。
あまり邪魔にならないように見えるので、後者の複製アプローチを選択しました。ドキュメントのsession_encodeとsession_decodeのコメントセクションで、この複製が何度も試みられています。最も信頼できると思われるものを2つ選び、それらを適用しました。デコード方法は非常に堅牢に見えますが、エンコード方法は機能しますが、5年以上前に投稿されました
これらのメソッドが機能しなくなる原因となる目に見えないエッジケースがある可能性があるという理由だけで、まだ展開することには消極的です。
最終的に、私は探しています:
- 以下の方法を破る例、または
- これらの方法が本番環境で使用されており、壊れないという安心感
- おそらく、本番環境で試され、テストされた代替案ですか?
よろしくお願いします!
コード:
class Session extends BaseSession
{
/**
* Taken from http://www.php.net/manual/en/function.session-decode.php#108037
*/
public function unserialized() {
$session_data = $this->content;
$method = ini_get("session.serialize_handler");
switch ($method) {
case "php":
return self::unserialize_php($session_data);
break;
case "php_binary":
return self::unserialize_phpbinary($session_data);
break;
default:
throw new Exception("Unsupported session.serialize_handler: " . $method . ". Supported: php, php_binary");
}
}
/**
* Taken from http://www.php.net/manual/en/function.session-encode.php#76425
*/
public function serialize($array, $safe = true) {
// the session is passed as refernece, even if you dont want it to
if( $safe ) $array = unserialize(serialize( $array )) ;
$raw = '' ;
$line = 0 ;
$keys = array_keys( $array ) ;
foreach( $keys as $key ) {
$value = $array[ $key ] ;
$line ++ ;
$raw .= $key .'|' ;
if( is_array( $value ) && isset( $value['huge_recursion_blocker_we_hope'] )) {
$raw .= 'R:'. $value['huge_recursion_blocker_we_hope'] . ';' ;
} else {
$raw .= serialize( $value ) ;
}
$array[$key] = Array( 'huge_recursion_blocker_we_hope' => $line ) ;
}
$this->content = $raw;
$this->save();
}
private static function unserialize_php($session_data) {
$return_data = array();
$offset = 0;
while ($offset < strlen($session_data)) {
if (!strstr(substr($session_data, $offset), "|")) {
throw new Exception("invalid data, remaining: " . substr($session_data, $offset));
}
$pos = strpos($session_data, "|", $offset);
$num = $pos - $offset;
$varname = substr($session_data, $offset, $num);
$offset += $num + 1;
$data = unserialize(substr($session_data, $offset));
$return_data[$varname] = $data;
$offset += strlen(serialize($data));
}
return $return_data;
}
private static function unserialize_phpbinary($session_data) {
$return_data = array();
$offset = 0;
while ($offset < strlen($session_data)) {
$num = ord($session_data[$offset]);
$offset += 1;
$varname = substr($session_data, $offset, $num);
$offset += $num;
$data = unserialize(substr($session_data, $offset));
$return_data[$varname] = $data;
$offset += strlen(serialize($data));
}
return $return_data;
}
}