ファイルをサーバにアップロードする

macOS Swift

ファイルをサーバにアップロードする

macOS Mojava 10.15.7 / Xcode 11.3.1 / Swift 5.0
[file_upload2]
クライアントアプリケーションから、ローカルディスクのファイルをサーバーにアップロードする。ファイルは、画像データのようなバイナリデータを対象とする。アップロードする方法(プロトコル)は二つある。

データをBASE64形式の文字列に変換する

ひとつめは、バイナリデータを BASE64形式の文字列に変換して送信し、受信側はデータを逆変換する方法である。これは、送受信双方のアプリケーションが呼応してデータの変換を行うもので、HTTPの視点からすれば普通のテキストデータの送信と何ら変わるものでない。BASE64形式の変換はメソッド一つでできるので、実装は容易である。デメリットとしては、変換によってデータ量は元のデータの約1.3倍に増加する。
データは、ファイル名等の付属情報をサーバ側のアプリケーションに渡したいので Json形式のデータとして送信する。x-www-form-urlencoded形式のPOSTのパラメータとして送ることも当然できる。
バイナリデータを Base64形式の文字列に変換するには Dataクラスの base64EncodedStringメソッドを使用する。
クライアントアプリケーション
メッセージの送受信を行う sendRequestメソッドのコードは後述する
サーバ側の処理
upload_mime.php
PHPスクリプトで実装する。受信したPOSTパラメータは json_decode関数でデコードする。Base64形式のデータは base64_decode関数により元データに変換する。データはサーバ上の所定のディレクトリに受信したファイル名と同じ名前で出力する。

multipart/form-data方式

二つめは、バイナリデータをそのまま送る方法である。これは、multipart/form-data という HTTPプロトコルに定義された送信形式のひとつである。 ざっくり言うと、送信するデータの前後に、セパレータの働きをする文字列を挟んでデータを送信する。HTTPはその部分をバイナリ形式の送信データであると解釈する。 受信側は、境界文字列で挟まれたデータを所定の方式で読み込むことができる。
境界となる文字列は、RFCによれば、1文字から 70文字までの任意な文字列を設定することになっている。 主要なブラウザは40文字前後で実装しているようだ。
送信データを約束事に従って作成するのはかなり面倒で、実際、アプリケーションで実装するような場面はほとんど無いように思う。
(素朴な疑問だが、境界文字列と、データの中身が偶然同じになったらどうなるのか? 単純なテストだが、送信データの中に境界文字列を混ぜ込んでみたが、全く問題はなく送信できた。HTTPの方でうまいことやってくれてるようだ。)
クライアントアプリケーション
メッセージの送受信を行う sendRequestメソッドのコードは後述する
ランダム文字列の生成
Message Bodyの詳細
境界文字列は、30文字のランダムな文字列としている。文字列の先頭には、ハイフン(-)を二つ付ける。Bodyは、バイナリデータ本体と、MAX_FILE_SIZEの指定の二つのパーツから成る。Bodyの先頭と終わり、パーツの境界に境界文字列をセットする。境界文字列、改行コードの配置は厳密に決まっている。付加情報として、Content-Disposition、Content-Typeを指定する。パラメータの意味はよくわかっていないが、例題の通りにすれば動くということだけは確か。
サーバ側の処理
upload_multipart.php
リクエスト受信後、バイナリデータはサーバ上の一時ファイルに格納される。PHPの move_uploaded_file関数により、そのファイルを所定のディレクトリの下に、ファイル名を指定して移動する。必要な情報は $_FILE配列に格納されている。
$_FILE配列の内容
"tmp_name" が一時ファイル名である。クライアントプログラムの記述がサーバ側の連想配列の名前とどう対応付くのか、HTTPか PHPが内部的に行っていることなのでよくわからない。例えば filename=xxxxx が full_path=xxxx となるように。とにかくこういうものだと理解するしかない。

メッセージの送受信を行う sendRequestメソッド

サンプルアプリケーション

[upload1]
SelectFileボタンで Openパネルを開いてアップロードするファイルを選択する。アップロード方式を選択してボタンをクリックする。送信されたデータは、サーバのPHPスクリプトによりそれぞれの方式に従って所定のディレクトリに保存される。
ソースコード

送信ファイルサイズの上限を設定する

10Mバイトのファイルを送信するとする。PHPの設定ファイル(php.ini)の以下のパラメータを変更する。なお、multipart/form-data方式の場合、POSTパメータに MAX_FILE_SIZEの指定も必要である。
実行 php.iniファイルの場所を探すコンソールコマンド