Rokのソリューションを見た後、以下の私の回答、上記のcrb、およびRokのソリューションの制限に対処するバージョンを考え出しました。私の改良版をご覧ください。
上記の@crbの回答は良いスタートですが、いくつかの問題があります。
- すべてを再処理しますが、これはやり過ぎです。「。」を含むフィールドのみ。名前で再処理する必要があります。
- たとえば、"foo.bar[]" のようなキーの場合、ネイティブ PHP 処理と同じ方法で配列を処理できません。
以下の解決策は、現在これらの問題の両方に対処しています (最初に投稿されてから更新されていることに注意してください)。これは、私のテストでは上記の回答よりも約 50% 高速ですが、データが同じキー (または同じように抽出されるキー、たとえば foo.bar と foo_bar の両方が foo_bar として抽出される) を持つ状況を処理しません。
<?php
public function fix2(&$target, $source, $keep = false) {
if (!$source) {
return;
}
preg_match_all(
'/
# Match at start of string or &
(?:^|(?<=&))
# Exclude cases where the period is in brackets, e.g. foo[bar.blarg]
[^=&\[]*
# Affected cases: periods and spaces
(?:\.|%20)
# Keep matching until assignment, next variable, end of string or
# start of an array
[^=&\[]*
/x',
$source,
$matches
);
foreach (current($matches) as $key) {
$key = urldecode($key);
$badKey = preg_replace('/(\.| )/', '_', $key);
if (isset($target[$badKey])) {
// Duplicate values may have already unset this
$target[$key] = $target[$badKey];
if (!$keep) {
unset($target[$badKey]);
}
}
}
}