jsupload addon DE translation updated
[friendica-addons.git/.git] / js_upload / js_upload.php
1 <?php
2 /**
3  * Name: JS Uploader
4  * Description: JavaScript photo/image uploader. Helpful for uploading multiple files at once. Uses Valum 'qq' Uploader.
5  * Version: 1.1
6  * Author: Chris Case <http://friendika.openmindspace.org/profile/chris_case>
7  * Maintainer: Hypolite Petovan <https://friendica.mrpetovan.com/profile/hypolite>
8  */
9
10 use Friendica\App;
11 use Friendica\Core\Hook;
12 use Friendica\Core\Logger;
13 use Friendica\Core\Renderer;
14 use Friendica\DI;
15 use Friendica\Util\Strings;
16
17 function js_upload_install()
18 {
19         Hook::register('photo_upload_form', __FILE__, 'js_upload_form');
20         Hook::register('photo_post_init', __FILE__, 'js_upload_post_init');
21         Hook::register('photo_post_file', __FILE__, 'js_upload_post_file');
22         Hook::register('photo_post_end', __FILE__, 'js_upload_post_end');
23 }
24
25 function js_upload_form(App $a, array &$b)
26 {
27         $b['default_upload'] = false;
28
29         DI::page()->registerStylesheet('addon/js_upload/file-uploader/client/fileuploader.css');
30         DI::page()->registerFooterScript('addon/js_upload/file-uploader/client/fileuploader.js');
31
32         $tpl = Renderer::getMarkupTemplate('js_upload.tpl', 'addon/js_upload');
33         $b['addon_text'] .= Renderer::replaceMacros($tpl, [
34                 '$upload_msg' => DI::l10n()->t('Select files for upload'),
35                 '$drop_msg' => DI::l10n()->t('Drop files here to upload'),
36                 '$cancel' => DI::l10n()->t('Cancel'),
37                 '$failed' => DI::l10n()->t('Failed'),
38                 '$post_url' => $b['post_url'],
39                 '$maximagesize' => intval(DI::config()->get('system', 'maximagesize')),
40         ]);
41 }
42
43 function js_upload_post_init(App $a, &$b)
44 {
45         // list of valid extensions
46         $allowedExtensions = ['jpeg', 'gif', 'png', 'jpg'];
47
48         // max file size in bytes
49         $sizeLimit = DI::config()->get('system', 'maximagesize');
50
51         $uploader = new qqFileUploader($allowedExtensions, $sizeLimit);
52
53         $result = $uploader->handleUpload();
54
55         // to pass data through iframe you will need to encode all html tags
56         $a->data['upload_jsonresponse'] = htmlspecialchars(json_encode($result), ENT_NOQUOTES);
57
58         if (isset($result['error'])) {
59                 Logger::log('mod/photos.php: photos_post(): error uploading photo: ' . $result['error'], Logger::DEBUG);
60                 echo json_encode($result);
61                 exit();
62         }
63
64         $a->data['upload_result'] = $result;
65 }
66
67 function js_upload_post_file(App $a, &$b)
68 {
69         $result = $a->data['upload_result'];
70
71         $b['src'] = $result['path'];
72         $b['filename'] = $result['filename'];
73         $b['filesize'] = filesize($b['src']);
74
75 }
76
77 function js_upload_post_end(App $a, &$b)
78 {
79         Logger::log('upload_post_end');
80         if (!empty($a->data['upload_jsonresponse'])) {
81                 echo $a->data['upload_jsonresponse'];
82                 exit();
83         }
84 }
85
86 /**
87  * Handle file uploads via XMLHttpRequest
88  */
89 class qqUploadedFileXhr
90 {
91         private $pathnm = '';
92
93         /**
94          * Save the file in the temp dir.
95          *
96          * @return boolean TRUE on success
97          */
98         function save()
99         {
100                 $input = fopen('php://input', 'r');
101
102                 $upload_dir = DI::config()->get('system', 'tempdir');
103                 if (!$upload_dir)
104                         $upload_dir = sys_get_temp_dir();
105
106                 $this->pathnm = tempnam($upload_dir, 'frn');
107
108                 $temp = fopen($this->pathnm, 'w');
109                 $realSize = stream_copy_to_stream($input, $temp);
110
111                 fclose($input);
112                 fclose($temp);
113
114                 if ($realSize != $this->getSize()) {
115                         return false;
116                 }
117                 return true;
118         }
119
120         function getPath()
121         {
122                 return $this->pathnm;
123         }
124
125         function getName()
126         {
127                 return $_GET['qqfile'];
128         }
129
130         function getSize()
131         {
132                 if (isset($_SERVER['CONTENT_LENGTH'])) {
133                         return (int)$_SERVER['CONTENT_LENGTH'];
134                 } else {
135                         throw new Exception('Getting content length is not supported.');
136                 }
137         }
138 }
139
140 /**
141  * Handle file uploads via regular form post (uses the $_FILES array)
142  */
143 class qqUploadedFileForm
144 {
145         /**
146          * Save the file to the specified path
147          *
148          * @return boolean TRUE on success
149          */
150         function save()
151         {
152                 return true;
153         }
154
155         function getPath()
156         {
157                 return $_FILES['qqfile']['tmp_name'];
158         }
159
160         function getName()
161         {
162                 return $_FILES['qqfile']['name'];
163         }
164
165         function getSize()
166         {
167                 return $_FILES['qqfile']['size'];
168         }
169 }
170
171 class qqFileUploader
172 {
173         private $allowedExtensions = [];
174         private $sizeLimit = 10485760;
175         private $file;
176
177         function __construct(array $allowedExtensions = [], $sizeLimit = 10485760)
178         {
179                 $allowedExtensions = array_map('strtolower', $allowedExtensions);
180
181                 $this->allowedExtensions = $allowedExtensions;
182                 $this->sizeLimit = $sizeLimit;
183
184                 if (isset($_GET['qqfile'])) {
185                         $this->file = new qqUploadedFileXhr();
186                 } elseif (isset($_FILES['qqfile'])) {
187                         $this->file = new qqUploadedFileForm();
188                 } else {
189                         $this->file = false;
190                 }
191
192         }
193
194         private function toBytes($str)
195         {
196                 $val = trim($str);
197                 $last = strtolower($str[strlen($str) - 1]);
198                 switch ($last) {
199                         case 'g':
200                                 $val *= 1024;
201                         case 'm':
202                                 $val *= 1024;
203                         case 'k':
204                                 $val *= 1024;
205                 }
206                 return $val;
207         }
208
209         /**
210          * Returns array('success'=>true) or array('error'=>'error message')
211          */
212         function handleUpload()
213         {
214                 if (!$this->file) {
215                         return ['error' => DI::l10n()->t('No files were uploaded.')];
216                 }
217
218                 $size = $this->file->getSize();
219
220                 if ($size == 0) {
221                         return ['error' => DI::l10n()->t('Uploaded file is empty')];
222                 }
223
224 //              if ($size > $this->sizeLimit) {
225
226 //                      return array('error' => DI::l10n()->t('Uploaded file is too large'));
227 //              }
228
229
230                 $maximagesize = DI::config()->get('system', 'maximagesize');
231
232                 if (($maximagesize) && ($size > $maximagesize)) {
233                         return ['error' => DI::l10n()->t('Image exceeds size limit of %s', Strings::formatBytes($maximagesize))];
234                 }
235
236                 $pathinfo = pathinfo($this->file->getName());
237                 $filename = $pathinfo['filename'];
238
239                 if (!isset($pathinfo['extension'])) {
240                         Logger::warning('extension isn\'t set.', ['filename' => $filename]);
241                 }
242                 $ext = $pathinfo['extension'] ?? '';
243
244                 if ($this->allowedExtensions && !in_array(strtolower($ext), $this->allowedExtensions)) {
245                         return ['error' => DI::l10n()->t('File has an invalid extension, it should be one of %s.', implode(', ', $this->allowedExtensions))];
246                 }
247
248                 if ($this->file->save()) {
249                         return [
250                                 'success' => true,
251                                 'path' => $this->file->getPath(),
252                                 'filename' => $filename . '.' . $ext
253                         ];
254                 } else {
255                         return [
256                                 'error' => DI::l10n()->t('Upload was cancelled, or server error encountered'),
257                                 'path' => $this->file->getPath(),
258                                 'filename' => $filename . '.' . $ext
259                         ];
260                 }
261         }
262 }