このすみノート

Webエンジニアが技術や趣味を書くブログです。

application/x-www-form-urlencoded で配列パラメータを受け渡す時のPHPとPythonの違い

Pythonで開発していて、フォームの配列パラメータを送信したら上手く受け取れず、原因が分からずはまりました。

配列パラメータを受け取れなかった原因

配列パラメータにブラケット()を付ける付けないの違いが原因です。

PHP

PHPだと、配列パラメータは ブラケット()を付けて送受信します。

names[]=1&names=2

Pytonh

これがPythonだと、ブラケット不要になります。

names=1&names=2

それぞれの違い

  • Python (Requests),key=a&key=b,キーを単に繰り返す (標準仕様に近い)
  • PHP,key=a&key=b,キーに [] を付与して繰り返す

他言語間の受け渡しでは、どちらかが違いを吸収する必要がある

例えばjQueryで実現するなら、何もしないとPHP型の配列パラメータになるため、専用オプション(traditional)を利用します。

$.ajax({
  url: '/api',
  method: 'POST',
  // Python (Flask/Django) や Java, .NET などの「キーをそのまま繰り返す形式」を好むサーバーに送る場合は、traditional: true というオプションを追加します。
  traditional: true,  // <--- これを追加!
  data: {
    tags: ['python', 'php']
  }
});
// 送信されるデータ: tags=python&tags=php

Gemini 3 による分類

ブラケットあり言語

言語 / フレームワーク,役割,解説
PHP,受信側,$_POSTがこの形式を期待しており、[]がないと配列として解釈されません。
Ruby on Rails,受信側,パラメータの自動解析(パーサー)がこの形式に基づいています。
Node.js (Express),受信側,qsライブラリ(Expressでよく使われる)がデフォルトで深いネストをサポートするため、ブラケット形式を好みます。
jQuery (Default),送信側,デフォルト設定 (traditional: false) がこのブラケット形式で送信します。

ブラケットなし言語

言語 / フレームワーク,役割,解説
Python (Django/Flask),受信側,request.form.getlist('key')など、重複したキーをリストとして取得するメソッドを使います。[] はキー名の一部として認識されます。
Java (Spring),受信側,"getParameterValues(""key"")や @RequestParam List<String> key などで、重複キーをそのままリストとしてバインドします。"
Go (net/http),受信側,"標準ライブラリの r.Form[""key""] などが重複キーを自動でスライス(配列)にします。"
C# (ASP.NET),受信側,モデルバインディングが重複キーをリスト型にマッピングします。
Python (Requests),送信側,デフォルトで配列をこのキー重複形式で送信します。
jQuery (traditional: true),送信側,このオプションを有効にすると、ブラケットなしのこの形式で送信します。

あとがき

プログラミング言語によって挙動が異なるため、フォーム内の配列パラメータの取り扱いは要注意であることが分かりました。

application/x-www-form-urlencoded を明確に意識することは今まで少なかったため、勉強になります。