]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - actions/avatarsettings.php
Merge remote branch 'gitorious/0.9.x' into 0.9.x
[quix0rs-gnu-social.git] / actions / avatarsettings.php
1 <?php
2 /**
3  * StatusNet, the distributed open-source microblogging tool
4  *
5  * Upload an avatar
6  *
7  * PHP version 5
8  *
9  * LICENCE: This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU Affero General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Affero General Public License for more details.
18  *
19  * You should have received a copy of the GNU Affero General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  * @category  Settings
23  * @package   StatusNet
24  * @author    Evan Prodromou <evan@status.net>
25  * @author    Zach Copley <zach@status.net>
26  * @copyright 2008-2009 StatusNet, Inc.
27  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
28  * @link      http://status.net/
29  */
30
31 if (!defined('STATUSNET') && !defined('LACONICA')) {
32     exit(1);
33 }
34
35 require_once INSTALLDIR.'/lib/accountsettingsaction.php';
36
37 define('MAX_ORIGINAL', 480);
38
39 /**
40  * Upload an avatar
41  *
42  * We use jCrop plugin for jQuery to crop the image after upload.
43  *
44  * @category Settings
45  * @package  StatusNet
46  * @author   Evan Prodromou <evan@status.net>
47  * @author   Zach Copley <zach@status.net>
48  * @author   Sarven Capadisli <csarven@status.net>
49  * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
50  * @link     http://status.net/
51  */
52
53 class AvatarsettingsAction extends AccountSettingsAction
54 {
55     var $mode = null;
56     var $imagefile = null;
57     var $filename = null;
58
59     /**
60      * Title of the page
61      *
62      * @return string Title of the page
63      */
64
65     function title()
66     {
67         return _('Avatar');
68     }
69
70     /**
71      * Instructions for use
72      *
73      * @return instructions for use
74      */
75
76     function getInstructions()
77     {
78         return sprintf(_('You can upload your personal avatar. The maximum file size is %s.'), ImageFile::maxFileSize());
79     }
80
81     /**
82      * Content area of the page
83      *
84      * Shows a form for uploading an avatar.
85      *
86      * @return void
87      */
88
89     function showContent()
90     {
91         if ($this->mode == 'crop') {
92             $this->showCropForm();
93         } else {
94             $this->showUploadForm();
95         }
96     }
97
98     function showUploadForm()
99     {
100         $user = common_current_user();
101
102         $profile = $user->getProfile();
103
104         if (!$profile) {
105             common_log_db_error($user, 'SELECT', __FILE__);
106             $this->serverError(_('User without matching profile.'));
107             return;
108         }
109
110         $original = $profile->getOriginalAvatar();
111
112         $this->elementStart('form', array('enctype' => 'multipart/form-data',
113                                           'method' => 'post',
114                                           'id' => 'form_settings_avatar',
115                                           'class' => 'form_settings',
116                                           'action' =>
117                                           common_local_url('avatarsettings')));
118         $this->elementStart('fieldset');
119         $this->element('legend', null, _('Avatar settings'));
120         $this->hidden('token', common_session_token());
121         
122         if (Event::handle('StartAvatarFormData', array($this))) {
123             $this->elementStart('ul', 'form_data');
124             if ($original) {
125                 $this->elementStart('li', array('id' => 'avatar_original',
126                                                 'class' => 'avatar_view'));
127                 $this->element('h2', null, _("Original"));
128                 $this->elementStart('div', array('id'=>'avatar_original_view'));
129                 $this->element('img', array('src' => $original->url,
130                                             'width' => $original->width,
131                                             'height' => $original->height,
132                                             'alt' => $user->nickname));
133                 $this->elementEnd('div');
134                 $this->elementEnd('li');
135             }
136
137             $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
138
139             if ($avatar) {
140                 $this->elementStart('li', array('id' => 'avatar_preview',
141                                                 'class' => 'avatar_view'));
142                 $this->element('h2', null, _("Preview"));
143                 $this->elementStart('div', array('id'=>'avatar_preview_view'));
144                 $this->element('img', array('src' => $original->url,
145                                             'width' => AVATAR_PROFILE_SIZE,
146                                             'height' => AVATAR_PROFILE_SIZE,
147                                             'alt' => $user->nickname));
148                 $this->elementEnd('div');
149                 $this->submit('delete', _('Delete'));
150                 $this->elementEnd('li');
151             }
152
153             $this->elementStart('li', array ('id' => 'settings_attach'));
154             $this->element('input', array('name' => 'avatarfile',
155                                           'type' => 'file',
156                                           'id' => 'avatarfile'));
157             $this->element('input', array('name' => 'MAX_FILE_SIZE',
158                                           'type' => 'hidden',
159                                           'id' => 'MAX_FILE_SIZE',
160                                           'value' => ImageFile::maxFileSizeInt()));
161             $this->elementEnd('li');
162             $this->elementEnd('ul');
163
164             $this->elementStart('ul', 'form_actions');
165             $this->elementStart('li');
166             $this->submit('upload', _('Upload'));
167             $this->elementEnd('li');
168             $this->elementEnd('ul');
169         }
170         Event::handle('EndAvatarFormData', array($this));
171
172         $this->elementEnd('fieldset');
173         $this->elementEnd('form');
174
175     }
176
177     function showCropForm()
178     {
179         $user = common_current_user();
180
181         $profile = $user->getProfile();
182
183         if (!$profile) {
184             common_log_db_error($user, 'SELECT', __FILE__);
185             $this->serverError(_('User without matching profile.'));
186             return;
187         }
188
189         $original = $profile->getOriginalAvatar();
190
191         $this->elementStart('form', array('method' => 'post',
192                                           'id' => 'form_settings_avatar',
193                                           'class' => 'form_settings',
194                                           'action' =>
195                                           common_local_url('avatarsettings')));
196         $this->elementStart('fieldset');
197         $this->element('legend', null, _('Avatar settings'));
198         $this->hidden('token', common_session_token());
199
200         $this->elementStart('ul', 'form_data');
201
202         $this->elementStart('li',
203                             array('id' => 'avatar_original',
204                                   'class' => 'avatar_view'));
205         $this->element('h2', null, _("Original"));
206         $this->elementStart('div', array('id'=>'avatar_original_view'));
207         $this->element('img', array('src' => Avatar::url($this->filedata['filename']),
208                                     'width' => $this->filedata['width'],
209                                     'height' => $this->filedata['height'],
210                                     'alt' => $user->nickname));
211         $this->elementEnd('div');
212         $this->elementEnd('li');
213
214         $this->elementStart('li',
215                             array('id' => 'avatar_preview',
216                                   'class' => 'avatar_view'));
217         $this->element('h2', null, _("Preview"));
218         $this->elementStart('div', array('id'=>'avatar_preview_view'));
219         $this->element('img', array('src' => Avatar::url($this->filedata['filename']),
220                                     'width' => AVATAR_PROFILE_SIZE,
221                                     'height' => AVATAR_PROFILE_SIZE,
222                                     'alt' => $user->nickname));
223         $this->elementEnd('div');
224
225         foreach (array('avatar_crop_x', 'avatar_crop_y',
226                        'avatar_crop_w', 'avatar_crop_h') as $crop_info) {
227             $this->element('input', array('name' => $crop_info,
228                                           'type' => 'hidden',
229                                           'id' => $crop_info));
230         }
231         $this->submit('crop', _('Crop'));
232
233         $this->elementEnd('li');
234         $this->elementEnd('ul');
235         $this->elementEnd('fieldset');
236         $this->elementEnd('form');
237
238     }
239
240     /**
241      * Handle a post
242      *
243      * We mux on the button name to figure out what the user actually wanted.
244      *
245      * @return void
246      */
247
248     function handlePost()
249     {
250         // Workaround for PHP returning empty $_POST and $_FILES when POST
251         // length > post_max_size in php.ini
252
253         if (empty($_FILES)
254             && empty($_POST)
255             && ($_SERVER['CONTENT_LENGTH'] > 0)
256         ) {
257             // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
258             // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
259             $msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
260                       'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
261                       intval($_SERVER['CONTENT_LENGTH']));
262             $this->showForm(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
263             return;
264         }
265
266         // CSRF protection
267
268         $token = $this->trimmed('token');
269         if (!$token || $token != common_session_token()) {
270             $this->showForm(_('There was a problem with your session token. '.
271                                'Try again, please.'));
272             return;
273         }
274         
275         if (Event::handle('StartAvatarSaveForm', array($this))) {
276             if ($this->arg('upload')) {
277                 $this->uploadAvatar();
278                 } else if ($this->arg('crop')) {
279                     $this->cropAvatar();
280                 } else if ($this->arg('delete')) {
281                     $this->deleteAvatar();
282                 } else {
283                     $this->showForm(_('Unexpected form submission.'));
284                 }
285             Event::handle('EndAvatarSaveForm', array($this));
286         }
287     }
288
289     /**
290      * Handle an image upload
291      *
292      * Does all the magic for handling an image upload, and crops the
293      * image by default.
294      *
295      * @return void
296      */
297
298     function uploadAvatar()
299     {
300         try {
301             $imagefile = ImageFile::fromUpload('avatarfile');
302         } catch (Exception $e) {
303             $this->showForm($e->getMessage());
304             return;
305         }
306         if ($imagefile === null) {
307             $this->showForm(_('No file uploaded.'));
308             return;
309         }
310
311         $cur = common_current_user();
312
313         $filename = Avatar::filename($cur->id,
314                                      image_type_to_extension($imagefile->type),
315                                      null,
316                                      'tmp'.common_timestamp());
317
318         $filepath = Avatar::path($filename);
319
320         move_uploaded_file($imagefile->filepath, $filepath);
321
322         $filedata = array('filename' => $filename,
323                           'filepath' => $filepath,
324                           'width' => $imagefile->width,
325                           'height' => $imagefile->height,
326                           'type' => $imagefile->type);
327
328         $_SESSION['FILEDATA'] = $filedata;
329
330         $this->filedata = $filedata;
331
332         $this->mode = 'crop';
333
334         $this->showForm(_('Pick a square area of the image to be your avatar'),
335                         true);
336     }
337
338     /**
339      * Handle the results of jcrop.
340      *
341      * @return void
342      */
343
344     function cropAvatar()
345     {
346         $filedata = $_SESSION['FILEDATA'];
347
348         if (!$filedata) {
349             $this->serverError(_('Lost our file data.'));
350             return;
351         }
352
353         $file_d = ($filedata['width'] > $filedata['height'])
354                      ? $filedata['height'] : $filedata['width'];
355
356         $dest_x = $this->arg('avatar_crop_x') ? $this->arg('avatar_crop_x'):0;
357         $dest_y = $this->arg('avatar_crop_y') ? $this->arg('avatar_crop_y'):0;
358         $dest_w = $this->arg('avatar_crop_w') ? $this->arg('avatar_crop_w'):$file_d;
359         $dest_h = $this->arg('avatar_crop_h') ? $this->arg('avatar_crop_h'):$file_d;
360         $size = min($dest_w, $dest_h, MAX_ORIGINAL);
361
362         $user = common_current_user();
363         $profile = $user->getProfile();
364
365         $imagefile = new ImageFile($user->id, $filedata['filepath']);
366         $filename = $imagefile->resize($size, $dest_x, $dest_y, $dest_w, $dest_h);
367
368         if ($profile->setOriginal($filename)) {
369             @unlink($filedata['filepath']);
370             unset($_SESSION['FILEDATA']);
371             $this->mode = 'upload';
372             $this->showForm(_('Avatar updated.'), true);
373             common_broadcast_profile($profile);
374         } else {
375             $this->showForm(_('Failed updating avatar.'));
376         }
377     }
378     
379     /**
380      * Get rid of the current avatar.
381      *
382      * @return void
383      */
384     
385     function deleteAvatar()
386     {
387         $user = common_current_user();
388         $profile = $user->getProfile();
389         
390         $avatar = $profile->getOriginalAvatar();
391         if($avatar) $avatar->delete();
392         $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
393         if($avatar) $avatar->delete();
394         $avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
395         if($avatar) $avatar->delete();
396         $avatar = $profile->getAvatar(AVATAR_MINI_SIZE);
397         if($avatar) $avatar->delete();
398
399         $this->showForm(_('Avatar deleted.'), true);
400     }
401
402     /**
403      * Add the jCrop stylesheet
404      *
405      * @return void
406      */
407
408     function showStylesheets()
409     {
410         parent::showStylesheets();
411         $this->cssLink('css/jquery.Jcrop.css','base','screen, projection, tv');
412     }
413
414     /**
415      * Add the jCrop scripts
416      *
417      * @return void
418      */
419
420     function showScripts()
421     {
422         parent::showScripts();
423
424         if ($this->mode == 'crop') {
425             $this->script('jcrop/jquery.Jcrop.min.js');
426             $this->script('jcrop/jquery.Jcrop.go.js');
427         }
428
429         $this->autofocus('avatarfile');
430     }
431 }