-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathDownloadComponent.php
More file actions
256 lines (233 loc) · 8 KB
/
DownloadComponent.php
File metadata and controls
256 lines (233 loc) · 8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
<?php
/**
* DownloadComponent
*
* @author Ryuji AMANO <ryuji@ryus.co.jp>
* @link http://www.netcommons.org NetCommons Project
* @license http://www.netcommons.org/license.txt NetCommons License
*/
App::uses('Component', 'Controller');
/**
* Class DownloadComponent
*/
class DownloadComponent extends Component {
/**
* @var Controller コントローラ
*/
protected $_controller = null;
/**
* Called before the Controller::beforeFilter().
*
* @param Controller $controller Instantiating controller
* @return void
*/
public function initialize(Controller $controller) {
$this->_controller = $controller;
}
/**
* ダウンロード実行
*
* @param int $contentId コンテンツID
* @param array $options オプション field : ダウンロードのフィールド名, size: nullならオリジナル thumb, small, medium, big
* @return CakeResponse|null
* @throws ForbiddenException
*/
public function doDownload($contentId, $options = array()) {
if (isset($options['field'])) {
$fieldName = $options['field'];
unset($options['field']);
} else {
if (isset($this->_controller->request->params['field_name'])) {
$fieldName = $this->_controller->request->params['field_name'];
} elseif (isset($this->_controller->params['pass'][0])) {
$fieldName = $this->_controller->params['pass'][0];
} else {
$fieldName = null;
}
}
if (isset($options['size'])) {
$size = $options['size'];
unset($options['size']);
} else {
if (isset($this->_controller->request->params['size'])) {
$size = $this->_controller->request->params['size'];
} elseif (isset($this->_controller->params['pass'][1])) {
$size = $this->_controller->params['pass'][1];
} else {
$size = null;
}
}
// ファイル情報取得 plugin_keyとコンテンツID、フィールドの情報が必要
$UploadFile = ClassRegistry::init('Files.UploadFile');
$pluginKey = Inflector::underscore($this->_controller->plugin);
$file = $UploadFile->getFile($pluginKey, $contentId, $fieldName);
if (! $file) {
//データがない=リンク切れ。リンク切れの場合、ログアウトしないようにするため、メッセージを追加
throw new ForbiddenException('Not found file');
}
return $this->_downloadUploadFile($file, $size, $options);
}
/**
* UploadFileのID指定でのダウンロード実行
*
* @param int $uploadFileId UploadFile ID
* @param array $options オプション field : ダウンロードのフィールド名, size: nullならオリジナル thumb, small, medium, big
* @param string $pluginKey プラグインキー
* @return CakeResponse|null
* @throws ForbiddenException
*/
public function doDownloadByUploadFileId($uploadFileId, $options = [], $pluginKey = 'wysiwyg') {
if (isset($options['size'])) {
$size = $options['size'];
unset($options['size']);
} else {
if (isset($this->_controller->request->params['size'])) {
$size = $this->_controller->request->params['size'];
} elseif (isset($this->_controller->params['pass'][2])) {
$size = $this->_controller->params['pass'][2];
} else {
$size = null;
}
}
// ファイル情報取得 plugin_keyとコンテンツID、フィールドの情報が必要
$UploadFile = ClassRegistry::init('Files.UploadFile');
$file = $UploadFile->findById($uploadFileId);
if (! $file || $file['UploadFile']['plugin_key'] !== $pluginKey) {
//データがない=リンク切れ。リンク切れの場合、ログアウトしないようにするため、メッセージを追加
throw new ForbiddenException('Not found file');
}
return $this->_downloadUploadFile($file, $size, $options);
}
/**
* UploadFileのデータ指定でのダウンロード実行
*
* @param array $file UploadFile data
* @param array $options オプション field : ダウンロードのフィールド名, size: nullならオリジナル thumb, small, medium, big
* @return CakeResponse|null
* @throws ForbiddenException
*/
public function doDownloadByUploadFile($file, $options = []) {
if (isset($options['size'])) {
$size = $options['size'];
unset($options['size']);
} else {
if (isset($this->_controller->request->params['size'])) {
$size = $this->_controller->request->params['size'];
} else {
$size = null;
}
}
return $this->_downloadUploadFile($file, $size, $options);
}
/**
* ダウンロード処理
*
* @param array $file UploadFile data
* @param string $size サムネイル名
* @param array $options オプション
* @return CakeResponse|null
* @throws ForbiddenException
* @throws BadRequestException
* @throws NotFoundException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
protected function _downloadUploadFile($file, $size, $options) {
$UploadFile = ClassRegistry::init('Files.UploadFile');
// ルームチェック
if ($file['UploadFile']['room_id']) {
$roomId = Current::read('Room.id');
if ($file['UploadFile']['room_id'] != $roomId) {
throw new ForbiddenException('Not found file');
}
}
if ($file['UploadFile']['block_key']) {
// block_keyによるガード
$Block = ClassRegistry::init('Blocks.Block');
$uploadFileBlock = $Block->find('first',
[
'recursive' => -1,
'fields' => ['id', 'key', 'public_type', 'publish_start', 'publish_end'],
'conditions' => [
'key' => $file['UploadFile']['block_key']
]
]
);
// ブロック見えない & ブロック編集できないのは 403
if (!$uploadFileBlock ||
($Block->isVisible($uploadFileBlock) === false &&
!Current::permission('block_editable'))) {
throw new ForbiddenException('Not found file');
}
}
// size対応
$filename = $file['UploadFile']['real_file_name'];
if ($size) {
// $size = '../../'とかを排除するため!
if (strpos($size, '..') !== false) {
throw new BadRequestException();
}
$filename = $size . '_' . $filename;
}
$filePath = $UploadFile->uploadBasePath .
$file['UploadFile']['path'] . $file['UploadFile']['id'] . DS . $filename;
if (!file_exists($filePath)) {
return null;
}
try {
$downloadFileName = $file['UploadFile']['original_name'];
if (! empty($options['name'])) {
$downloadFileName = $options['name'];
}
$content = 'attachment;';
$content .= 'filename*=UTF-8\'\'' . rawurlencode($downloadFileName);
$this->_controller->response->header('Content-Disposition', $content);
// name, downloadが入っているとCake側処理により文字化けが発生する
unset($options['name']);
unset($options['download']);
$this->_controller->response->file(
$filePath,
$options
);
} catch (NotFoundException $ex) {
//データがない=リンク切れ。リンク切れの場合、ログアウトしないようにする
CakeLog::error($ex);
throw new NotFoundException('Not found file');
} catch (Exception $ex) {
CakeLog::error($ex);
throw $ex;
}
// Download カウントアップ
$pluginKey = $file['UploadFile']['plugin_key'] ?? null;
if ($pluginKey !== 'wysiwyg') {
$UploadFile->countUp($file);
}
return $this->_controller->response;
}
/**
* ファイルが存在するかのチェック
*
* @param array $modelRecord AttachmentBehaviorを利用してfindで取得してきたレコード
* $data['UploadFile'][フィールド名]にUploadFile情報がはいってる
* @param string $field Modelで指定しているattachmentのフィールド名
* @param string|null $size 画像等の別サイズ指定
* @return bool
*/
public function existsRealFileByModelRecord(
array $modelRecord,
string $field,
string $size = null
) : bool {
$UploadFile = ClassRegistry::init('Files.UploadFile');
$filePath = $UploadFile->uploadBasePath .
$modelRecord['UploadFile'][$field]['path'] .
$modelRecord['UploadFile'][$field]['id'] .
DS;
$filename = $modelRecord['UploadFile'][$field]['real_file_name'];
if ($size !== null) {
$filename = $size . '_' . $filename;
}
$filePath .= $filename;
return file_exists($filePath);
}
}