今日も適当ダイアリー

PHP や Javascript や Symfony、BEAR.Sunday などのWeb周りのことを中心に。それ以外のことも気まぐれに投稿します。

PHP で生データから POST/GET の全データを取得する

PHP で POST を取得するには、通常、$_POST 変数が使われるが、下記のような配列になっていない フォーム の場合、同じ変数に格納しようとするため、全データを取得することができません。

<form method="post">
  <input value="AAAAA" name="a" />
  <inpu value="BBBBB" name="a" />
  <input value="CCCCC" name="a" />
  <input value="CCCCC" name="a" />
  <input value="D&E" name="a" />

  <input type="submit" />
</form>

もちろん、下記のように HTML にて、PHP で取得時に配列に格納されるよう name 属性を変更すれば取得できます。

<form method="post">
  <input value="AAAAA" name="a[]" />
  <inpu value="BBBBB" name="a[]" />
  <input value="CCCCC" name="a[]" />
  <input value="CCCCC" name="a[]" />
  <input value="D&E" name="a[]" />

  <input type="submit" />
</form>

ただ、最近の案件で HTML を変更できないケースがあり、そのときに使った関数を忘れないようにメモ。

<?php
// array jGetInputData( [ string $type , [ string $str , [ bool $del_null_byte ] ] ] )
//   $type          : 'POST' / 'GET'(デフォルトは POST)
//   $str           : 生データを指定したい場合
//   $del_null_byte : ヌルバイトを削除するか(デフォルトは TRUE)
//   return         : POST / GET データを配列で返します。
function jGetInputData($type = 'post', $str = null, $del_null_byte = true) {
  if ($str === null) {
    switch (strtolower($type)) {
      case 'get': // GET の生データを取得
        $str = $_SERVER["QUERY_STRING"];
        break;
      case 'post': // POST の生データを取得
      default:
        $str = file_get_contents("php://input");
    }
  }

  if (!is_string($str)) return false;
  if (trim($str) === '') return array(); // 何もなし

  // 「&」が含まれていれば分解
  $datas = (strpos($str, '&') === false) ? array($str) : explode('&', $str);
  $rtn = array();

  foreach($datas as $data) {
    $name = null;
    $val = null;

    if (strpos($data, '=') === false) {
      $name = urldecode($data);
    } else {
      $_tmp = explode('=', $data, 2);
      $name = urldecode($_tmp[0]);
      $val = urldecode($_tmp[1]);
    }

    if (!isset($rtn[$name])) {
      // アイテム名が存在しなければそのまま代入
      $rtn[$name] = $val;
    } else {
      if (!is_array($rtn[$name])) {
        // アイテム名の変数が存在し、
        // アイテム名の配列が存在しなければ配列にする
        $rtn[$name] = array($rtn[$name]);
      }
      // 新しい値を配列に追加
      $rtn[$name][] = $val;
    }
  }

  if ($del_null_byte) {
    $rtn = jDelNullbyte($rtn);
  }

  return $rtn;
}

function jDelNullbyte($data) {
    if (is_array($data)) {
        return array_map('jDelNullbyte', $data);
    }

    return str_replace("\0", '', $data);
}

使う場合は

<?php
  $_POST = jGetInputData();

のような感じで。

<form method="post">
  <input value="AAAAA" name="a" />
  <inpu value="BBBBB" name="a" />
  <input value="CCCCC" name="a" />
  <input value="CCCCC" name="a" />
  <input value="D&E" name="a" />
  <input value="F" name="a.b" />
  <input value="G" name="あいう=えお" />
  <input value="H" name="" />
  <input value="" name="I" />
  <input value="JJJJJ" name="a[]" />

  <input type="submit" />
</form>

に対して

<?php
  var_dump(jGetInputData());

をすると、

array(6) {
  ["a"]=>
  array(4) {
    [0]=>
    string(5) "AAAAA"
    [1]=>
    string(5) "CCCCC"
    [2]=>
    string(5) "CCCCC"
    [3]=>
    string(3) "D&E"
  }
  ["a.b"]=>
  string(1) "F"
  ["あいう=えお"]=>
  string(1) "G"
  [""]=>
  string(1) "H"
  ["I"]=>
  string(0) ""
  ["a[]"]=>
  string(5) "JJJJJ"
}

のように返ります。

何らかの事情で HTML を変更できない、もしくは変更せずに PHP からその値を取得したい場合があれば、自由に改変して使っていただいて結構です。

なお、上記関数を使用した場合、name 属性で使用した文字列がそのまま配列のアイテム名になり、[]を使用しても配列として展開されないので注意。

間違いがありましたら、コメントください。