]> git.mxchange.org Git - friendica.git/blob - addon/js_upload/js_upload.php
Merge pull request #137 from fabrixxm/master
[friendica.git] / addon / js_upload / js_upload.php
1 <?php
2
3 /**
4  * Name: JS Uploader
5  * Description: JavaScript photo/image uploader. Uses Valum 'qq' Uploader.
6  * Version: 1.0
7  * Author: Chris Case <http://friendika.openmindspace.org/profile/chris_case>
8  */
9
10 /**
11  *
12  * JavaScript Photo/Image Uploader
13  *
14  * Uses Valum 'qq' Uploader. 
15  * Module Author: Chris Case
16  *
17  * Prior to enabling, ensure that you have a directory 'uploads'
18  * which is writable by the web server.
19  *
20  */
21
22
23 function js_upload_install() {
24         register_hook('photo_upload_form', 'addon/js_upload/js_upload.php', 'js_upload_form');
25         register_hook('photo_post_init',   'addon/js_upload/js_upload.php', 'js_upload_post_init');
26         register_hook('photo_post_file',   'addon/js_upload/js_upload.php', 'js_upload_post_file');
27         register_hook('photo_post_end',    'addon/js_upload/js_upload.php', 'js_upload_post_end');
28 }
29
30
31 function js_upload_uninstall() {
32         unregister_hook('photo_upload_form', 'addon/js_upload/js_upload.php', 'js_upload_form');
33         unregister_hook('photo_post_init',   'addon/js_upload/js_upload.php', 'js_upload_post_init');
34         unregister_hook('photo_post_file',   'addon/js_upload/js_upload.php', 'js_upload_post_file');
35         unregister_hook('photo_post_end',    'addon/js_upload/js_upload.php', 'js_upload_post_end');
36 }
37
38
39 function js_upload_form(&$a,&$b) {
40
41         $b['default_upload'] = false;
42
43         $b['addon_text'] .= '<link href="' . $a->get_baseurl() . '/addon/js_upload/file-uploader/client/fileuploader.css" rel="stylesheet" type="text/css">';
44         $b['addon_text'] .= '<script src="' . $a->get_baseurl() . '/addon/js_upload/file-uploader/client/fileuploader.js" type="text/javascript"></script>';
45    
46         $upload_msg = t('Upload a file');
47         $drop_msg = t('Drop files here to upload');
48         $cancel = t('Cancel');
49         $failed = t('Failed');
50
51         $b['addon_text'] .= <<< EOT
52         
53  <div id="file-uploader-demo1">         
54   <noscript>                    
55    <p>Please enable JavaScript to use file uploader.</p>
56    <!-- or put a simple form for upload here -->
57   </noscript> 
58  </div>
59
60 <script type="text/javascript">
61 var uploader = null;       
62 function getSelected(opt) {
63             var selected = new Array();
64             var index = 0;
65             for (var intLoop = 0; intLoop < opt.length; intLoop++) {
66                if ((opt[intLoop].selected) ||
67                    (opt[intLoop].checked)) {
68                   index = selected.length;
69                   //selected[index] = new Object;
70                   selected[index] = opt[intLoop].value;
71                   //selected[index] = intLoop;
72                }
73             }
74             return selected;
75          } 
76 function createUploader() {
77         uploader = new qq.FileUploader({
78                 element: document.getElementById('file-uploader-demo1'),
79                 action: '{$b['post_url']}',
80
81         template: '<div class="qq-uploader">' + 
82                 '<div class="qq-upload-drop-area"><span>$drop_msg</span></div>' +
83                 '<div class="qq-upload-button">$upload_msg</div>' +
84                 '<ul class="qq-upload-list"></ul>' + 
85              '</div>',
86
87         // template for one item in file list
88         fileTemplate: '<li>' +
89                 '<span class="qq-upload-file"></span>' +
90                 '<span class="qq-upload-spinner"></span>' +
91                 '<span class="qq-upload-size"></span>' +
92                 '<a class="qq-upload-cancel" href="#">$cancel</a>' +
93                 '<span class="qq-upload-failed-text">$failed</span>' +
94             '</li>',        
95
96                 debug: true,
97                 onSubmit: function(id,filename) {
98
99                         uploader.setParams( {
100                                 newalbum                :       document.getElementById('photos-upload-newalbum').value,
101                                 album                   :       document.getElementById('photos-upload-album-select').value,
102                                 group_allow             :       getSelected(document.getElementById('group_allow')).join(','),
103                                 contact_allow   :       getSelected(document.getElementById('contact_allow')).join(','),
104                                 group_deny              :       getSelected(document.getElementById('group_deny')).join(','),
105                                 contact_deny    :       getSelected(document.getElementById('contact_deny')).join(',')
106                         });
107                 }
108         });           
109 }
110
111
112 // in your app create uploader as soon as the DOM is ready
113 // don't wait for the window to load  
114 window.onload = createUploader;     
115
116
117 </script>
118  
119 EOT;
120
121
122 }
123
124 function js_upload_post_init(&$a,&$b) {
125
126         // list of valid extensions, ex. array("jpeg", "xml", "bmp")
127
128         $allowedExtensions = array("jpeg","gif","png","jpg");
129
130         // max file size in bytes
131
132         $sizeLimit = get_config('system','maximagesize'); //6 * 1024 * 1024;
133
134         $uploader = new qqFileUploader($allowedExtensions, $sizeLimit);
135
136         $result = $uploader->handleUpload();
137
138
139         // to pass data through iframe you will need to encode all html tags
140         $a->data['upload_jsonresponse'] =  htmlspecialchars(json_encode($result), ENT_NOQUOTES);
141
142         if(isset($result['error'])) {
143                 logger('mod/photos.php: photos_post(): error uploading photo: ' . $result['error'] , 'LOGGER_DEBUG');
144                 echo json_encode($result);
145                 killme();
146         }
147
148         $a->data['upload_result'] = $result;
149
150 }
151
152 function js_upload_post_file(&$a,&$b) {
153
154         $result = $a->data['upload_result'];
155
156         $b['src']               = $result['path'];
157         $b['filename']  = $result['filename'];
158         $b['filesize']  = filesize($b['src']);
159
160 }
161
162
163 function js_upload_post_end(&$a,&$b) {
164
165 logger('upload_post_end');
166         if(x($a->data,'upload_jsonresponse')) {
167                 echo $a->data['upload_jsonresponse'];
168                 killme();
169         }
170
171 }
172
173
174 /**
175  * Handle file uploads via XMLHttpRequest
176  */
177 class qqUploadedFileXhr {
178
179         private $pathnm = '';
180
181     /**
182      * Save the file in the temp dir.
183      * @return boolean TRUE on success
184      */
185     function save() {    
186         $input = fopen("php://input", "r");
187         $this->pathnm = tempnam(sys_get_temp_dir(),'frn');
188                 $temp = fopen($this->pathnm,"w");
189         $realSize = stream_copy_to_stream($input, $temp);
190
191         fclose($input);
192                 fclose($temp);
193         
194         if ($realSize != $this->getSize()){            
195             return false;
196         }
197         return true;
198     }
199
200         function getPath() {
201                 return $this->pathnm;
202         }
203
204     function getName() {
205         return $_GET['qqfile'];
206     }
207
208     function getSize() {
209         if (isset($_SERVER["CONTENT_LENGTH"])){
210             return (int)$_SERVER["CONTENT_LENGTH"];            
211         } else {
212             throw new Exception('Getting content length is not supported.');
213         }      
214     }   
215 }
216
217 /**
218  * Handle file uploads via regular form post (uses the $_FILES array)
219  */
220
221 class qqUploadedFileForm {  
222
223
224     /**
225      * Save the file to the specified path
226      * @return boolean TRUE on success
227      */
228
229
230     function save() {
231         return true;
232     }
233
234         function getPath() {
235                 return $_FILES['qqfile']['tmp_name'];
236         }
237
238     function getName() {
239         return $_FILES['qqfile']['name'];
240     }
241     function getSize() {
242         return $_FILES['qqfile']['size'];
243     }
244 }
245
246 class qqFileUploader {
247     private $allowedExtensions = array();
248     private $sizeLimit = 10485760;
249     private $file;
250
251     function __construct(array $allowedExtensions = array(), $sizeLimit = 10485760){        
252         $allowedExtensions = array_map("strtolower", $allowedExtensions);
253             
254         $this->allowedExtensions = $allowedExtensions;        
255         $this->sizeLimit = $sizeLimit;
256         
257         $this->checkServerSettings();       
258
259         if (isset($_GET['qqfile'])) {
260             $this->file = new qqUploadedFileXhr();
261         } elseif (isset($_FILES['qqfile'])) {
262             $this->file = new qqUploadedFileForm();
263         } else {
264             $this->file = false; 
265         }
266
267     }
268     
269     private function checkServerSettings(){        
270         $postSize = $this->toBytes(ini_get('post_max_size'));
271         $uploadSize = $this->toBytes(ini_get('upload_max_filesize'));        
272                 logger('mod/photos.php: qqFileUploader(): upload_max_filesize=' . $uploadSize , 'LOGGER_DEBUG');
273         if ($postSize < $this->sizeLimit || $uploadSize < $this->sizeLimit){
274             $size = max(1, $this->sizeLimit / 1024 / 1024) . 'M';             
275             die("{'error':'increase post_max_size and upload_max_filesize to $size'}");    
276         }        
277     }
278     
279     private function toBytes($str){
280         $val = trim($str);
281         $last = strtolower($str[strlen($str)-1]);
282         switch($last) {
283             case 'g': $val *= 1024;
284             case 'm': $val *= 1024;
285             case 'k': $val *= 1024;        
286         }
287         return $val;
288     }
289     
290     /**
291      * Returns array('success'=>true) or array('error'=>'error message')
292      */
293     function handleUpload(){
294         
295         if (!$this->file){
296             return array('error' => t('No files were uploaded.'));
297         }
298         
299         $size = $this->file->getSize();
300         
301         if ($size == 0) {
302             return array('error' => t('Uploaded file is empty'));
303         }
304         
305         if ($size > $this->sizeLimit) {
306
307             return array('error' => t('Uploaded file is too large'));
308         }
309         
310
311                 $maximagesize = get_config('system','maximagesize');
312
313                 if(($maximagesize) && ($size > $maximagesize)) {
314                         return array('error' => t('Image exceeds size limit of ') . $maximagesize );
315
316                 }
317
318         $pathinfo = pathinfo($this->file->getName());
319         $filename = $pathinfo['filename'];
320
321         $ext = $pathinfo['extension'];
322
323         if($this->allowedExtensions && !in_array(strtolower($ext), $this->allowedExtensions)){
324             $these = implode(', ', $this->allowedExtensions);
325             return array('error' => t('File has an invalid extension, it should be one of ') . $these . '.');
326         }
327         
328         if ($this->file->save()){
329             return array(
330                                 'success'=>true,
331                                 'path' => $this->file->getPath(), 
332                                 'filename' => $filename . '.' . $ext
333                         );
334         } else {
335             return array(
336                                 'error'=> t('Upload was cancelled, or server error encountered'),
337                                 'path' => $this->file->getPath(), 
338                                 'filename' => $filename . '.' . $ext
339                         );
340         }
341         
342     }    
343 }