タスクは次のとおりです。 ファイルと写真をサーバーにアップロードするための便利なメカニズム(必要なチェックを含む)、写真のサムネイルの作成、ファイルをダウンロードするための
img
タグとリンクの自動生成が必要です。 拡張機能には何も見つかりませんでした。 最も近い意味はアップロード拡張機能ですが、多くの必要な機能を提供しません。 だから私は自分で書くことにしました。 記事を出版する直前に、私は偶然、同じようなアイデアを見るレシピを見ました。
コード例は参照用であり、作業中のプロジェクトから挿入しましたが、混乱する可能性があります。 作業コードが必要な場合は、記事の最後にプロジェクトへのリンクがあります。 どうぞ!
最初の反復。 標準機能を補完します。
Yiiは何を提供しますか? まず、 CUploadedFileクラス。ダウンロードしたファイルに関する情報を提供し、サーバーに保存することができます。 次に、ダウンロードされたファイルをチェックするCFileValidatorバリデーター。 公式ドキュメントがファイルのダウンロードを推奨する方法は次のとおりです。
// class MyModel extends CActiveRecord { public $image; public function rules(){ return array( array('image', 'file', 'types'=>'jpg, gif, png'), ); } } // class MyModelController extends CController { public function actionCreate(){ $modMyModel=new MyModel; if(isset($_POST['MyModel'])){ $modMyModel->attributes=$_POST['MyModel']; $modMyModel->id_image=CUploadedFile::getInstance($modMyModel,'image'); if($modMyModel->save()){ $modMyModel->id_image->saveAs('path/to/localFile'); // , // } } $this->render('create', array('model'=>$modMyModel)); } } // <?php echo CHtml::form('','post',array('enctype'=>'multipart/form-data')); ?> ... <?php echo CHtml::activeFileField($modMyModel, 'image'); ?> ... <?php echo CHtml::endForm(); ?>
このアプローチにはいくつかの欠点があります。
- フレームワークには、ファイルをダウンロードするための専用フォルダーがありません
- ファイルのアップロードは、コントローラーで毎回説明する必要があります
- 示されたアプローチは
actionUpdate()
転送できません。これは、呼び出しごとにファイルがロードされることを想定しているためです。 また、通常のプロパティと同様にファイルを操作すると便利です。モデルを作成するときに読み込み、必要に応じてモデルを変更するときに再起動します。 - ファイルへのその後のアクセスに関する推奨事項はありません。 ただし、
path/to/localFile
はモデルプロパティに保存できます。
もちろん、これらの欠点については、自分のプロジェクトのコンテキストでのみ話している。 そして、ここに私が提供したいものがあります。
まず、ファイルを保存する場所を決めましょう。 私の意見では、ディレクトリ
.../protected/data/files
保存に最適
.../protected/data/files
。 一般的に、作業中に作成されたファイルには、フォルダ
.../protected/runtime
があり
.../protected/runtime
が、意味では、
data
ディレクトリはこれらの目的により適しています。 ファイル名はランダムに生成され(
uniqid()
)、モデルプロパティ
$modMyModel->id_image
に保存されます。次の段落でその方法を説明します。 確かに、このアプローチには落とし穴が1つあり
data
。ブラウザからアクセスするために
data
ディレクトリが閉じられます。 これに対処する方法-少し後で。 今後は、
readfile()
を
readfile()
てファイルを動的にダウンロードし、
assets
フォルダーに画像(より正確には、画像のサムネイル
readfile()
を公開することをお勧めします。
フォルダとファイルの命名を整理しました。 次に、検証とロードを扱います。 フォームから始めましょう。 これをやってみましょう:
<?php echo $modMyModel->id_image ?> <?php echo CHtml::activeFileField($modMyModel, 'id_image_file'); ?>
そのため、ファイルがアップロードされているかどうかを確認します。 そして、ファイル自体は
id_image_file
という名前でロードされます。
echo $modMyModel->id_image
代わりに、ファイルまたはサムネイル画像をダウンロードするためのリンクを挿入できます。
今検証。 アイデアは次のとおりです。バリデーターは、
$_FILES
ダウンロードファイル
$_FILES
かどうかを確認する必要
$_FILES
ます。 その場合、
CUploadedFile
オブジェクトを作成し、それを
$modMyModel->id_image
ます。 次に
$modMyModel->id_image
標準的な方法
$modMyModel->id_image
検証します。 これを行うには、
DFileValidator
から継承した独自の
DFileValidator
バリデーターを作成します。 そしてすぐに別の
DImageValidator
から継承された
DFileValidator
、画像のデフォルトのファイルタイプを示します。
最後に、ファイルをロードしてモデルを保存します。 検証後、ダウンロードされたファイルは
$modMyModel->id_image
にあり、
CUploadedFile
の形式に
CUploadedFile
ます。 ロードが特定のプロパティに関連付けられないようにするには、モデルを保存する前に、そのプロパティのいずれかが
CUploadedFile
クラスのオブジェクトであるかどうかを確認する必要があります。 これで、モデルは次のようになります。
class MyModel extends DActiveRecord { public $id_image; public function rules(){ return array( array('id_image', 'DImageValidator'), ); } public function beforeSave() { foreach ($this->attributes as $key => $attribute) if ($attribute instanceof CUploadedFile) { $strSource = uniqid(); if ($attribute->saveAs(Yii::getPathOfAlias('application.data.files') . '/' . $strSource)) $this->$key = $strSource; } return parent::beforeSave(); } }
imageプロパティは、意図的にid_imageプロパティに置き換えられました。 さらに、その理由は明らかです。
小計を要約するには
- すべてのファイルは、フォルダ
.../protected/data/files
にランダムな名前で保存されます。 - ファイルのアップロードは、データベースに保存される前にモデルで実行されます。
- プロパティをファイルとしてマークするには、次のものが必要です。
-
rules()
モデルで、DFileValidator
バリデーターをこのプロパティに割り当てます。 - フォームで、このプロパティの入力に
'_file'
を'_file'
名前を変更します。
-
-
actionCreate()
およびactionUpdate()
メソッドは変更しないでおくことができます。
2回目の反復。 データベースを接続します。
ファイルをアップロードする方法を見つけました。 しかし、彼に連絡する方法は明確ではありませんが。
img
タグの
src
パラメーターに何を書くのですか? ダウンロード用のファイルを提供する方法は? 私の意見では、Yiiモデルの機能を使用してファイルを操作すると便利です。 実際、モデルがダウンロードされた各ファイルに対応する場合、ダウンロードを含むすべての低レベルの操作をそのファイルに委ねることができます。 そして、プロパティ
$modMyModel->id_image
にこのモデルの主キーを保存します(このプロパティの名前の本質は明確です)。 次に、
$modMyModel
に対して、適切な関係を決定し、たとえば次のように記述することができます。
// MyModel: public function relations() { return array( 'image' => array(self::BELONGS_TO, 'DImage', 'id_image'), ); } // : $modMyModel = new MyModel; echo $modMyModel->id_image->image($htmlOptions); // img echo $modMyModel->file->downloadLink(); //
さらに、モデルを使用すると、元のファイル名を保存する問題(保存すると失われます)が自動的に解決されます。
行こう
フィールド
id, source, name
tbl_files
テーブルを作成します。 このテーブルに関連付けられた
DFile
モデルを定義します。 静的な
upload
方法を定義します:
class DFile extends DActiveRecord { public $uploadPath; // public function init() { $this->uploadPath = Yii::getPathOfAlias('application.data.files'); } public static function upload($objFile) { $modFile = new DFile; $modFile->name = $objFile->name; $modFile->source = uniqid(); if ($objFile->saveAs($modFile->uploadPath . '/' . $modFile->source)) if ($modFile->save()) return $modFile; return null; } }
そしてすぐに空の
DImage extends DFile
作成し、
DImage extends DFile
ます。 後で必要になります。
次に、モデルを少し変更しましょう。 画像との約束された接続を定義し、
beforeSave()
メソッドを
beforeSave()
調整し
beforeSave()
:
class MyModel extends DActiveRecord { public $id_image; public function rules(){ return array( array('id_image', 'DImageValidator', 'allowEmpty' => true), ); } public function relations() { return array( 'image' => array(self::BELONGS_TO, 'DImage', 'id_image'), ); } public function beforeSave() { foreach ($this->attributes as $key => $attribute) if ($attribute instanceof CUploadedFile) { $modFile = DFile::upload($attribute); // DFile $this->$key = $modFile->id; } return parent::beforeSave(); } }
モデルの
$modMyModel
オブジェクトでは、
$modMyModel->image
介してファイルにアクセスできます。 それを有益に使用する方法-読んでください。
3回目の反復。 アップロードされたファイルへのアクセス。
この瞬間まで、私たちはファイルと写真をほとんど共有しませんでした。 実際、それらのダウンロードは同じです。 唯一の違いは、プリブートチェックです。 しかし、
DFileValidator
および
DImageValidator
バリデーターは
DFileValidator
うまく機能し、必要なすべてのルールを指定できます。
ダウンロードとは異なり、ダウンロードしたファイルや画像へのアクセス方法は異なります。 ファイルは、後でダウンロードできるようにロードされ、画像-それらを見るために。 ファイルから始めましょう。
ファイルを操作する
繰り返しますが、ファイルはダウンロードするためにダウンロードされます。 多くの場合、これにはアクセス権の確認が必要です。 合計で、2つのタスク、つまり、ダウンロードリンクの提供と、実際にはダウンロード用のファイルの発行を解決する必要があります。
リンク生成は
DFile
行うと便利
DFile
。 このようなもの:
class DFile extends DActiveRecord { public function downloadLink($htmlOptions = array()) { return CHtml::link($this->name, array('/files/file/download', 'id' => $this->id), $htmlOptions); } }
リンクは
FileController
コントローラーを
FileController
ます。 定義してください:
class FileController extends DcController { public function actionDownload($id) { $modFile = $this->loadModel($id); header("Content-Type: application/force-download"); header("Content-Type: application/octet-stream"); header("Content-Type: application/download"); header("Content-Disposition: attachment; filename=" . $modFile->name); header("Content-Transfer-Encoding: binary "); readfile($modFile->uploadPath . '/' . $modFile->source); } public function loadModel($id) { $modFile = DFile::model()->findByPk($id); if($modFile === null) throw new CHttpException(404,'The requested page does not exist.'); return $modFile; } }
ここではすべてが明確だと思います。
actionDownload()
メソッドは追加のチェックを行いませんが、必要に応じて含めることができます。 現在のモデルでは、対応する関係を決定したら、
$modMyModel->file->downloadLink()
記述できます。 もちろん、このアプローチはファイルへの直接リンクを発行するよりも生産性が低くなります。 パフォーマンスが重要な場合は、安全な
data
ディレクトリではなく、別の(開いている)ディレクトリでファイルを注文し、直接リンクを発行できます。
写真で作業する
写真では、状況はもう少し複雑です。 写真にはサムネイルが必要です。 さらに、写真では、ダイナミックリンクを作成する余裕はありません。 幸いなことに、Yiiは私たちの目的に使用できる便利なリソース公開メカニズムを提供します。 アイデアは次のとおりです。写真へのリンクを生成するときに、リソースとしてサムネイルを作成して公開します。 ただし、いくつかの問題があります。 まず、ソースイメージにアクセスする必要がある場合は、それを
assets
フォルダーにコピーする必要もあります。 第二に、標準のYiiツールを使用してパブリケーションを実装することはできません。 実際には、公開されたファイルごとに、Yiiは独自のフォルダーを作成しますが、これはブルートフォースになります。 はい。標準ツールを使用して、
assets
フォルダにすぐにサムネイルを作成することはできません。
最初の問題は、大量の写真がダウンロードされておらず、元の写真へのアクセスが必要ない場合は関係ありません。 元の写真は高解像度で保存され、上記のメカニズムを使用してダウンロードできます。また、画面に表示するのにサムネイルのみが使用されます。 そのような問題が発生した場合、オプションとして、ソースフォルダーを
assets
フォルダーにコピーすることはできませんが、リンクを作成できます(Yiiの標準公開メカニズムは、リンク作成を含む公開を提供します)。
2番目の問題については、出版物を自分で作成する必要があります。 しかし、それほど書くことはありません...
行きましょう。
DImage
から継承された
DFile
クラスが既にあります。 サムネイルの作成と公開について説明します。
class DImage extends DFile { public $assetsPath; // public $assetsUrl; // URL public $thumbs = array( 'min' => array('width' => 150, 'height' => 150), 'mid' => array('width' => 250), 'big' => array('width' => 600), ); // public function init() { $this->assetsUrl = Yii::app()->assetManager->baseUrl . '/files'; $this->assetsPath = Yii::app()->assetManager->basePath . '/files'; if (!is_dir($this->assetsPath)) mkdir($this->assetsPath); } // $this->assetsPath public function getIsPublished() { foreach ($this->thumbs as $kThumb => $vThumb) if (!is_file($this->assetsPath . '/' . $this->source . '_' . $kThumb)) return false; return true; } // public function publish() { if (!$this->isPublished) foreach ($this->thumbs as $kThumb => $vThumb) $this->createThumb($this->uploadPath . '/' . $this->source, $this->assetsPath . '/' . $this->source . '_' . $kThumb, $kThumb); return $this->assetsUrl . '/' . $this->source; } // function createThumb($strSrcFile, $strDstFile, $strThumb) { // $strSrcFile, $strDstFile } }
サムネイルを公開するには、
assets
フォルダーに
files
サブフォルダーを作成することをお勧めします。
assets
フォルダーを定期的にクリーニングすることをお勧めしますが、毎回
assets/files
フォルダーの存在を確認する必要があります。 必要に応じて作成します。 サムネイル名は、サムネイル名で補足された画像名と同じです。 すべてのサムネイルが配置されている場合、画像は公開されていると見なされます。 ダウンロードしたファイルは変更できないため、ソースファイルと公開ファイルの日付を確認することは意味がありません。
publish()
関数は、公開された画像のURLを返します(ただし、サムネイルは指定しません)。これは、Yiiでリソースを公開するという考え方と矛盾しません。
最後に、アップロードされた画像へのアクセスを検討します。
DImage
クラスに
image()
メソッドを
DImage
:
public function image($strThumb = 'min', $htmlOptions = array()) { return CHtml::image($this->publish() . '_' . $strThumb, $this->name, $htmlOptions); }
これで、ファイルとの類推により、モデルに
$modMyModel->image->image()
を書くことができます。 ちなみに、サムネイルのサイズを突然変更する必要がある場合、または新しいサムネイルを追加する必要がある場合(一度私に起こったことがあります)、すべてのファイルが既にアップロードされている場合は、設定のサイズを変更してアセットフォルダーをクリアするだけで十分です。
最後の仕上げ
すべてが機能します。 写真がアップロードされ、表示されます。 ファイルがアップロードおよびダウンロードされます。 コードを少しとかすことが残っています。 たとえば、beforeSave()メソッドをMyModelクラスからDActiveRecordクラスに削除すると、そこからすべてのモデルが継承されることがわかります。 さらに、ファイルおよび画像の入力の表示は、
DActiveForm extends CActiveForm
転送できます。 設定の保存は、
files
モジュールに割り当てることが
files
ます。
まあ、そして良い伝統によると、 作業プロジェクトをダウンロードするためのリンクです。 多数の依存関係があるため、個別のファイルをアップロードするのは問題があることが判明したため、プロジェクト全体を投稿します。 データベースダンプは、protected / data / dump.sqlにあります。 設定から-Yiiへのパスを指定し、データベースへのアクセスを登録します。 基本クラスとバリデーターはprotected / componentsフォルダーにあり、ファイルに関するすべてはfilesモジュールにあります。
おわりに
したがって、出力は次のとおりです。
- 一元化されたファイルのアップロードとストレージ管理
- モデルにファイルプロパティを作成するための使いやすいインターフェイス
- ファイルとIMGタグをダウンロードするための高レベルのリンク生成
アイデアを発展させることができます。 たとえば、ほとんどすべてのWYCIWYGエディターは、ファイルと画像をダウンロードするためのインターフェイスを提供します。 これを行うには、ダウンロードアドレスを指定するだけです。
FileController
ダウンロードハンドラーを含めることができます。 しかし、サムネイルを公開する方法は?
または、記事に記載されている提案を使用して、サーバーに画像を安全にアップロードできます。 パート1およびサーバーへの画像の安全なアップロード。 パート2 上記のアップロード拡張機能を補足できます。 機能を動作に移行できます。
つまり、提案されたソリューションの準備ができていると考えるのは時期尚早です。 しかし、説明したアイデアが有用であることが判明した場合、作業を完了し、対応する拡張機能を公開する準備ができています。 読んでくれた皆さん、ありがとう!