1 <?php
2
3 4 5 6 7 8 9 10
11
12 namespace Icybee\Modules\Files;
13
14 use ICanBoogie\HTTP\Request;
15 use ICanBoogie\strip_root;
16
17 18 19 20 21
22 class SaveOperation extends \Icybee\Modules\Nodes\SaveOperation
23 {
24 25 26 27 28
29 const USERFILE = 'path';
30
31 32 33
34 protected $file;
35
36 protected function get_file()
37 {
38 return $this->file;
39 }
40
41 42 43
44 protected $accept;
45
46 47 48 49 50
51 protected function lazy_get_properties()
52 {
53 $properties = parent::lazy_get_properties() + [
54
55 'description' => ''
56
57 ];
58
59
60
61
62
63
64
65 if (isset($properties[File::PATH]) && $properties[File::PATH] === true)
66 {
67 unset($properties[File::PATH]);
68 }
69
70 if ($this->file)
71 {
72 $properties[File::HTTP_FILE] = $this->file;
73 }
74
75 return $properties;
76 }
77
78 79 80
81 public function __invoke(Request $request)
82 {
83 $this->module->clean_temporary_files();
84
85 return parent::__invoke($request);
86 }
87
88 89 90 91 92 93 94 95 96 97 98 99
100 protected function control(array $controls)
101 {
102 global $core;
103
104 $request = $this->request;
105
106 $path = $request[File::PATH];
107 $file = null;
108
109
110
111 $file = $request->files[self::USERFILE];
112
113 if ($file && $file->is_valid)
114 {
115 $filename = strtr(uniqid(null, true), '.', '-') . $file->extension;
116 $pathname = \ICanBoogie\REPOSITORY . 'tmp' . DIRECTORY_SEPARATOR . $filename;
117
118 $file->move($pathname);
119 }
120 else if ($path && strpos($path, \ICanBoogie\strip_root(\ICanBoogie\REPOSITORY . "files")) !== 0)
121 {
122 $file = $this->resolve_request_file_from_pathname($path);
123
124 if (!$file)
125 {
126 $this->response->errors[File::PATH] = $this->response->errors->format("Invalid or delete file: %pathname", [ 'pathname' => $path ]);
127 }
128 }
129
130 unset($request[File::PATH]);
131 unset($request[File::MIME]);
132 unset($request[File::SIZE]);
133
134 $this->file = $file;
135
136 if ($file)
137 {
138
139
140
141
142 $request[File::PATH] = true;
143 }
144
145 return parent::control($controls);
146 }
147
148 149 150
151 protected function validate(\ICanboogie\Errors $errors)
152 {
153 global $core;
154
155 $file = $this->file;
156
157 if ($file)
158 {
159 $error_message = $file->error_message;
160
161 $max_file_size = $core->registry["{$this->module->flat_id}.max_file_size"];
162
163 if ($max_file_size && $max_file_size < $file->size)
164 {
165 $error_message = $errors->format("Maximum file size is :size Mb", [ ':size' => round($max_file_size / 1024) ]);
166 }
167
168 if ($this->accept && !$file->match($this->accept))
169 {
170 $error_message = $errors->format("Only the following file types are accepted: %accepted.", [ '%accepted' => implode(', ', $this->accept) ]);
171 }
172
173 if ($error_message)
174 {
175 $errors[File::PATH] = $errors->format('Unable to upload file %file: :message.', [
176
177 '%file' => $file->name,
178 ':message' => $error_message
179
180 ]);
181 }
182 }
183 else if (!$this->key)
184 {
185 $errors[File::PATH] = $errors->format("File is required.");
186 }
187
188 return parent::validate($errors);
189 }
190
191 192 193
194 protected function process()
195 {
196 $record = $this->record;
197 $oldpath = $record ? $record->path : null;
198
199 $rc = parent::process();
200
201 if ($oldpath)
202 {
203 $newpath = $this->module->model
204 ->select('path')
205 ->filter_by_nid($rc['key'])
206 ->rc;
207
208 if ($oldpath != $newpath)
209 {
210 new File\MoveEvent($record, $oldpath, $newpath);
211 }
212 }
213
214 return $rc;
215 }
216
217 protected function resolve_request_file_from_pathname($pathname)
218 {
219 $filename = basename($pathname);
220 $info_pathname = \ICanBoogie\REPOSITORY . 'tmp' . DIRECTORY_SEPARATOR . $filename . '.info';
221
222 if (!file_exists($info_pathname))
223 {
224 return;
225 }
226
227 $properties = json_decode(file_get_contents($info_pathname), true);
228
229 if (!$properties)
230 {
231 return;
232 }
233
234 return \ICanBoogie\HTTP\File::from($properties);
235 }
236 }
237
238 namespace Icybee\Modules\Files\File;
239
240 241 242
243 class MoveEvent extends \ICanBoogie\Event
244 {
245 246 247 248 249
250 public $from;
251
252 253 254 255 256
257 public $to;
258
259 260 261 262 263 264 265
266 public function __construct(\Icybee\Modules\Files\File $target, $from, $to)
267 {
268 $this->from = $from;
269 $this->to = $to;
270
271 parent::__construct($target, 'move');
272 }
273 }