Merge pull request #8669 from yiijan/docs-ja-0605

docs/guide-ja/input-file-upload.md updated [ci skip]
This commit is contained in:
Paul Klimov
2015-06-05 15:50:33 +03:00
2 changed files with 98 additions and 139 deletions

View File

@@ -1,15 +1,16 @@
ファイルをアップロードする
==========================
Yii におけるファイルのアップロードは、フォームモデル、その検証規則、そして、いくらかのコントローラコードによって行われます。
アップロードを適切に処理するために何が必要とされるのか、見ていきましよう
Yii におけるファイルのアップロードは、通常、アップロードされる個々のファイルを `UploadedFile` としてカプセル化する [[yii\web\UploadedFile]] の助けを借りて実行されます。
これを [[yii\widgets\ActiveForm]] および [モデル](structure-models.md) と組み合わせることで、安全なファイルアップロードメカニズムを簡単に実装することが出来ます
一つのファイルをアップロードする
--------------------------------
## モデルを作成する <span id="creating-models"></span>
プレーンなテキストインプットを扱うのと同じように、一つのファイルをアップロードするためには、モデルクラスを作成して、そのモデルの一つの属性を使ってアップロードされるファイルのインスタンスを保持します。
また、ファイルのアップロードを検証するために、検証規則も宣言しなければなりません。
例えば、
まず最初に、ファイルのアップロードを処理するモデルを作成する必要があります。
次の内容を持つ `models/UploadForm.php` を作成してください。
```php
namespace app\models;
@@ -17,34 +18,49 @@ namespace app\models;
use yii\base\Model;
use yii\web\UploadedFile;
/**
* UploadForm : アップロードのフォームの背後にあるモデル
*/
class UploadForm extends Model
{
/**
* @var UploadedFile file 属性
* @var UploadedFile
*/
public $file;
public $imageFile;
/**
* @return array 検証規則
*/
public function rules()
{
return [
[['file'], 'file'],
[['imageFile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg'],
];
}
public function upload()
{
if ($this->validate()) {
$this->imageFile->saveAs('uploads/' . $this->imageFile->baseName . '.' . $this->imageFile->extension);
return true;
} else {
return false;
}
}
}
```
上記のコードにおいては、`imageFile` 属性がアップロードされたファイルのインスタンスを保持するのに使われます。
この属性が関連付けられている `file` 検証規則は、[[yii\validators\FileValidator]] を使って、`png` または `jpg` の拡張子を持つファイルがアップロードされることを保証しています。
`upload()` メソッドは検証を実行して、アップロードされたファイルをサーバに保存します。
`file` バリデータによって、ファイル拡張子、サイズ、MIME タイプなどをチェックすることが出来ます。
詳細については、[コアバリデータ](tutorial-core-validators.md#file) の節を参照してください。
> Tip|ヒント: 画像をアップロードしようとする場合は、`image` バリデータを代りに使うことを考慮しても構いません。
`image` バリデータは [[yii\validators\ImageValidator]] によって実装されており、属性が有効な画像、すなわち、保存したり [Imagine エクステンション](https://github.com/yiisoft/yii2-imagine) を使って処理したりすることが可能な有効な画像を、受け取ったかどうかを検証します。
上記のコードにおいて作成した `UploadForm` というモデルは、HTML フォームで `<input type="file">` となる `$file` という属性を持ちます。
この属性は [[yii\validators\FileValidator|FileValidator]] を使用する `file` という検証規則を持ちます。
###ォームのビュー
## ファイルインプットをレンダリングする <span id="rendering-file-input"></span>
次に、フォームを表示するビューを作成します。
次に、ビューでファイルインプットを作成します。
```php
<?php
@@ -53,19 +69,20 @@ use yii\widgets\ActiveForm;
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'file')->fileInput() ?>
<?= $form->field($model, 'imageFile')->fileInput() ?>
<button>送信</button>
<button>送信</button>
<?php ActiveForm::end() ?>
```
ファイルアップロードを可能にする `'enctype' => 'multipart/form-data'` は不可欠です。
`fileInput()` がフォームの入力フィールドを表します。
ファイルが正しくアップロードされるように、フォームに `enctype` オプションを追加することを憶えておくのは重要なことです。
`fileInput()` を呼ぶと `<input type="file">` のタグがレンダリングされて、ユーザがアップロードするファイルを選ぶことが出来るようになります。
### コントローラ
そして、フォームとモデルを結び付けるコントローラを作成します。
## 繋ぎ合せる <span id="wiring-up"></span>
そして、コントローラアクションの中で、モデルとビューを繋ぎ合せるコードを書いて、ファイルのアップロードを実装します。
```php
namespace app\controllers;
@@ -82,10 +99,10 @@ class SiteController extends Controller
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$model->file = UploadedFile::getInstance($model, 'file');
if ($model->file && $model->validate()) {
$model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
$model->imageFile = UploadedFile::getInstance($model, 'imageFile');
if ($model->upload()) {
// ファイルのアップロードが成功
return;
}
}
@@ -94,134 +111,68 @@ class SiteController extends Controller
}
```
`model->load(...)` の代りに `UploadedFile::getInstance(...)` を使っています。
[[\yii\web\UploadedFile|UploadedFile]] はモデルの検証を実行せず、アップロードされたファイルに関する情報を提供するだけです。
そのため、`$model->validate()` を手作業で実行して、[[yii\validators\FileValidator|FileValidator]] を起動する必要があります。
[[yii\validators\FileValidator|FileValidator]] は、下記のコアコードが示しているように、属性がファイルであることを要求します。
上記のコードでは、フォームが送信されると [[yii\web\UploadedFile::getInstance()]] メソッドが呼ばれて、アップロードされたファイルが `UploadedFile` のインスタンスとして表現されます。
そして、次に、モデルの検証によってアップロードされたファイルが有効なものであることを確かめ、サーバにファイルを保存します。
## 複数のファイルをアップロードする <span id="uploading-multiple-files"></span>
ここまでの項で示したコードに若干の修正を加えれば、複数のファイルを一度にアップロードすることも出来ます。
最初に、モデルクラスを修正して、`file` 検証規則に `maxFiles` オプションを追加して、アップロードを許可されるファイルの最大数を制限しなければなりません。
`upload()` メソッドも、アップロードされた複数のファイルを一つずつ保存するように修正しなければなりません。
```php
if (!$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE) {
return [$this->uploadRequired, []]; // "ファイルをアップロードしてください。" というエラーメッセージ
}
```
namespace app\models;
検証が成功したら、ファイルを保存します。
use yii\base\Model;
use yii\web\UploadedFile;
```php
$model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
```
「ベーシック」プロジェクトテンプレートを使っている場合は、`uploads` フォルダを `web` の下に作成しなければなりません。
以上です。ページをロードして、アップロードを試して見てください。ファイルは `basic/web/uploads` にアップロードされます。
検証
----
たいていの場合、検証規則を調整して、特定のファイルだけを受け取るようにしたり、アップロードを必須としたりする必要があります。
下記で、よく使われる規則の構成を見てみましよう。
### Required
ファイルのアップロードを必須とする必要がある場合は、次のように `skipOnEmpty``false` に設定します。
```php
public function rules()
{
return [
[['file'], 'file', 'skipOnEmpty' => false],
];
}
```
### MIME タイプ
アップロードされるファイルのタイプを検証することは賢明なことです。
`FileValidator` はこの目的のための `extensions` プロパティを持っています。
```php
public function rules()
{
return [
[['file'], 'file', 'extensions' => 'gif, jpg'],
];
}
```
デフォルトでは、ファイルのコンテントの MIME タイプが指定された拡張子に対応するものであるかどうかが検証されます。
例えば、`gif` に対しては `image/gif``jpg` に対しては `image/jpeg` であるかどうかが検証されます。
MIME タイプの中には、`file` バリデータによって使われている PHP fileinfo 拡張では適切に検知することが出来ないものがあることに注意してください。
例えば、`csv` ファイルは `text/csv` ではなく `text/plain` として検知されます。
このような振る舞いを避けるために、`checkExtensionByMimeType``false` に設定して、MIME タイプを手動で指定することが出来ます。
```php
public function rules()
{
return [
[['file'], 'file', 'checkExtensionByMimeType' => false, 'extensions' => 'csv', 'mimeTypes' => 'text/plain'],
];
}
```
[一般的なメディアタイプの一覧表](http://en.wikipedia.org/wiki/Internet_media_type#List_of_common_media_types)
### 画像のプロパティ
画像をアップロードするときは、[[yii\validators\ImageValidator|ImageValidator]] が重宝するでしょう。
このバリデータは、属性が有効な画像を受け取ったか否かを検証します。
画像は、保存するか、または、[Imagine エクステンション](https://github.com/yiisoft/yii2-imagine) によって処理することが出来ます。
複数のファイルをアップロードする
--------------------------------
複数のファイルを一度にアップロードする必要がある場合は、少し修正が必要になります。
モデル:
```php
class UploadForm extends Model
{
/**
* @var UploadedFile|Null ファイル属性
* @var UploadedFile[]
*/
public $file;
public $imageFiles;
/**
* @return array 検証規則
*/
public function rules()
{
return [
[['file'], 'file', 'maxFiles' => 10], // <--- ここ !
[['imageFiles'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg', 'maxFiles' => 4],
];
}
public function upload()
{
if ($this->validate()) {
foreach ($this->imageFiles as $file) {
$file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
}
return true;
} else {
return false;
}
}
}
```
ビュー:
ビューファイルでは、`fileInput()` の呼び出しに `multiple` オプションを追加して、ファイルアップロードのフィールドが複数のファイルを受け取ることが出来るようにしなければなりません。
```php
<?php
use yii\widgets\ActiveForm;
$form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]);
?>
<?= $form->field($model, 'file[]')->fileInput(['multiple' => true]) ?>
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'imageFiles[]')->fileInput(['multiple' => true, 'accept' => 'image/*']) ?>
<button>送信</button>
<?php ActiveForm::end(); ?>
<?php ActiveForm::end() ?>
```
違いがあるのは、次の行です
```php
<?= $form->field($model, 'file[]')->fileInput(['multiple' => true]) ?>
```
コントローラ:
そして、最後に、コントローラアクションの中では、`UploadedFile::getInstance()` の代りに `UploadedFile::getInstances()` を呼んで、`UploadedFile` インスタンスの配列を `UploadForm::imageFiles` に代入しなければなりません
```php
namespace app\controllers;
@@ -238,12 +189,10 @@ class SiteController extends Controller
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$model->file = UploadedFile::getInstances($model, 'file');
if ($model->file && $model->validate()) {
foreach ($model->file as $file) {
$file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
}
$model->imageFiles = UploadedFile::getInstances($model, 'imageFiles');
if ($model->upload()) {
// ファイルのアップロードが成功
return;
}
}
@@ -251,8 +200,3 @@ class SiteController extends Controller
}
}
```
単一のファイルのアップロードとは、二つの点で異なります。
最初の違いは、`UploadedFile::getInstance($model, 'file');` の代りに `UploadedFile::getInstances($model, 'file');` が使用されることです。
前者が一つのインスタンスを返すだけなのに対して、後者はアップロードされた **全ての** ファイルのインスタンスを返します。
第二の違いは、`foreach` によって、全てのファイルをそれぞれ保存している点です。

View File

@@ -12,7 +12,17 @@ Yii2 は [`Codeception`](https://github.com/Codeception/Codeception) テスト
これら三つのタイプのテスト全てについて、Yii は、[`yii2-basic`](https://github.com/yiisoft/yii2-app-basic) と [`yii2-advanced`](https://github.com/yiisoft/yii2-app-advanced) の両方のプロジェクトテンプレートで、そのまま使えるテストセットを提供しています。
テストを走らせるためには、[Codeception](https://github.com/Codeception/Codeception) をインストールする必要があります。
インストールするのに良い方法は次のとおりです。
Codeception は、特定のプロジェクトのためだけにローカルにインストールするか、開発マシンのためにグローバルにインストールするかを選ぶことが出来ます。
ローカルのインストールのためには、次のコマンドを使います。
```
composer require "codeception/codeception=2.0.*"
composer require "codeception/specify=*"
composer require "codeception/verify=*"
```
グローバルのインストールのためには、`global` 命令を使う必要があります。
```
composer global require "codeception/codeception=2.0.*"
@@ -29,3 +39,8 @@ Changed current directory to <directory>
そうしたら、`<directory>/vendor/bin` をあなたの `PATH` 環境変数に追加してください。
これでコマンドラインから `codecept` をグローバルに使うことが出来ます。
> Note|注意: グローバルにインストールすると、あなたの開発環境で扱っている全てのプロジェクトに対して Codeception を使うことが出来るようになります。
パスを指定せずに `codecept` シェルコマンドをグローバルに走らせることが可能になります。
しかしながら、例えば、二つのプロジェクトが異なるバージョンの Codeception のインストールを要求している場合など、この方法が不適切なこともあり得ます。
話を単純にするために、このガイドで実行しているテストに関するシェルコマンドは、全て、Codeception がグローバルにインストールされていることを前提にしています。