[MEDIA] ImageFile fromUpload method wasn't ensuring uploaded file was an image
This commit is contained in:
		@@ -1,34 +1,32 @@
 | 
				
			|||||||
<?php
 | 
					<?php
 | 
				
			||||||
 | 
					// This file is part of GNU social - https://www.gnu.org/software/social
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// GNU social is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					// it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					// the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					// (at your option) any later version.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// GNU social is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					// GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * StatusNet, the distributed open-source microblogging tool
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Upload an avatar
 | 
					 * Upload an avatar
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * PHP version 5
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * LICENCE: This program is free software: you can redistribute it and/or modify
 | 
					 | 
				
			||||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
					 | 
				
			||||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
					 | 
				
			||||||
 * (at your option) any later version.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This program is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 | 
				
			||||||
 * GNU Affero General Public License for more details.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * You should have received a copy of the GNU Affero General Public License
 | 
					 | 
				
			||||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @category  Settings
 | 
					 * @category  Settings
 | 
				
			||||||
 * @package   StatusNet
 | 
					 * @package   GNUsocial
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * @author    Evan Prodromou <evan@status.net>
 | 
					 * @author    Evan Prodromou <evan@status.net>
 | 
				
			||||||
 * @author    Zach Copley <zach@status.net>
 | 
					 * @author    Zach Copley <zach@status.net>
 | 
				
			||||||
 * @copyright 2008-2009 StatusNet, Inc.
 | 
					 * @author    Diogo Cordeiro <diogo@fc.up.pt>
 | 
				
			||||||
 | 
					 * @copyright 2008-2009, 2020 Free Software Foundation http://fsf.org
 | 
				
			||||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 | 
				
			||||||
 * @link      http://status.net/
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					defined('GNUSOCIAL') || die;
 | 
				
			||||||
if (!defined('GNUSOCIAL')) { exit(1); }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Upload an avatar
 | 
					 * Upload an avatar
 | 
				
			||||||
@@ -37,24 +35,26 @@ if (!defined('GNUSOCIAL')) { exit(1); }
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * @category Settings
 | 
					 * @category Settings
 | 
				
			||||||
 * @package  StatusNet
 | 
					 * @package  StatusNet
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * @author   Evan Prodromou <evan@status.net>
 | 
					 * @author   Evan Prodromou <evan@status.net>
 | 
				
			||||||
 * @author   Zach Copley <zach@status.net>
 | 
					 * @author   Zach Copley <zach@status.net>
 | 
				
			||||||
 * @author   Sarven Capadisli <csarven@status.net>
 | 
					 * @author   Sarven Capadisli <csarven@status.net>
 | 
				
			||||||
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 | 
					 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 | 
				
			||||||
 * @link     http://status.net/
 | 
					 *
 | 
				
			||||||
 | 
					 * @see     http://status.net/
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
class AvatarsettingsAction extends SettingsAction
 | 
					class AvatarsettingsAction extends SettingsAction
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    var $mode = null;
 | 
					    public $mode;
 | 
				
			||||||
    var $imagefile = null;
 | 
					    public $imagefile;
 | 
				
			||||||
    var $filename = null;
 | 
					    public $filename;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function prepare(array $args=array())
 | 
					    public function prepare(array $args = [])
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $avatarpath = Avatar::path('');
 | 
					        $avatarpath = Avatar::path('');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!is_writable($avatarpath)) {
 | 
					        if (!is_writable($avatarpath)) {
 | 
				
			||||||
            throw new Exception(_("The administrator of your site needs to
 | 
					            throw new Exception(_m("The administrator of your site needs to
 | 
				
			||||||
                add write permissions on the avatar upload folder before
 | 
					                add write permissions on the avatar upload folder before
 | 
				
			||||||
                you're able to set one."));
 | 
					                you're able to set one."));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -67,24 +67,30 @@ class AvatarsettingsAction extends SettingsAction
 | 
				
			|||||||
     * Title of the page
 | 
					     * Title of the page
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return string Title of the page
 | 
					     * @return string Title of the page
 | 
				
			||||||
 | 
					     * @throws Exception
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    function title()
 | 
					    public function title()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // TRANS: Title for avatar upload page.
 | 
					        // TRANS: Title for avatar upload page.
 | 
				
			||||||
        return _('Avatar');
 | 
					        return _m('Avatar');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Instructions for use
 | 
					     * Instructions for use
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return instructions for use
 | 
					     * @return string instructions for use
 | 
				
			||||||
 | 
					     * @throws Exception
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    function getInstructions()
 | 
					    public function getInstructions()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // TRANS: Instruction for avatar upload page.
 | 
					        // TRANS: Instruction for avatar upload page.
 | 
				
			||||||
        // TRANS: %s is the maximum file size, for example "500b", "10kB" or "2MB".
 | 
					        // TRANS: %s is the maximum file size, for example "500b", "10kB" or "2MB".
 | 
				
			||||||
        return sprintf(_('You can upload your personal avatar. The maximum file size is %s.'),
 | 
					        return sprintf(
 | 
				
			||||||
                       ImageFile::maxFileSize());
 | 
					            _m('You can upload your personal avatar. The maximum file size is %s.'),
 | 
				
			||||||
 | 
					            ImageFile::maxFileSize()
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -95,7 +101,7 @@ class AvatarsettingsAction extends SettingsAction
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return void
 | 
					     * @return void
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    function showContent()
 | 
					    public function showContent()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ($this->mode == 'crop') {
 | 
					        if ($this->mode == 'crop') {
 | 
				
			||||||
            $this->showCropForm();
 | 
					            $this->showCropForm();
 | 
				
			||||||
@@ -104,33 +110,32 @@ class AvatarsettingsAction extends SettingsAction
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function showUploadForm()
 | 
					    public function showUploadForm()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->elementStart('form', array('enctype' => 'multipart/form-data',
 | 
					        $this->elementStart('form', ['enctype' => 'multipart/form-data',
 | 
				
			||||||
            'method' => 'post',
 | 
					            'method' => 'post',
 | 
				
			||||||
            'id' => 'form_settings_avatar',
 | 
					            'id' => 'form_settings_avatar',
 | 
				
			||||||
            'class' => 'form_settings',
 | 
					            'class' => 'form_settings',
 | 
				
			||||||
                                          'action' =>
 | 
					            'action' => common_local_url('avatarsettings'),]);
 | 
				
			||||||
                                          common_local_url('avatarsettings')));
 | 
					 | 
				
			||||||
        $this->elementStart('fieldset');
 | 
					        $this->elementStart('fieldset');
 | 
				
			||||||
        // TRANS: Avatar upload page form legend.
 | 
					        // TRANS: Avatar upload page form legend.
 | 
				
			||||||
        $this->element('legend', null, _('Avatar settings'));
 | 
					        $this->element('legend', null, _m('Avatar settings'));
 | 
				
			||||||
        $this->hidden('token', common_session_token());
 | 
					        $this->hidden('token', common_session_token());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (Event::handle('StartAvatarFormData', array($this))) {
 | 
					        if (Event::handle('StartAvatarFormData', [$this])) {
 | 
				
			||||||
            $this->elementStart('ul', 'form_data');
 | 
					            $this->elementStart('ul', 'form_data');
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                $original = Avatar::getUploaded($this->scoped);
 | 
					                $original = Avatar::getUploaded($this->scoped);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                $this->elementStart('li', array('id' => 'avatar_original',
 | 
					                $this->elementStart('li', ['id' => 'avatar_original',
 | 
				
			||||||
                                                'class' => 'avatar_view'));
 | 
					                    'class' => 'avatar_view',]);
 | 
				
			||||||
                // TRANS: Header on avatar upload page for thumbnail of originally uploaded avatar (h2).
 | 
					                // TRANS: Header on avatar upload page for thumbnail of originally uploaded avatar (h2).
 | 
				
			||||||
                $this->element('h2', null, _("Original"));
 | 
					                $this->element('h2', null, _m('Original'));
 | 
				
			||||||
                $this->elementStart('div', array('id'=>'avatar_original_view'));
 | 
					                $this->elementStart('div', ['id' => 'avatar_original_view']);
 | 
				
			||||||
                $this->element('img', array('src' => $original->displayUrl(),
 | 
					                $this->element('img', ['src' => $original->displayUrl(),
 | 
				
			||||||
                    'width' => $original->width,
 | 
					                    'width' => $original->width,
 | 
				
			||||||
                    'height' => $original->height,
 | 
					                    'height' => $original->height,
 | 
				
			||||||
                                            'alt' => $this->scoped->getNickname()));
 | 
					                    'alt' => $this->scoped->getNickname(),]);
 | 
				
			||||||
                $this->elementEnd('div');
 | 
					                $this->elementEnd('div');
 | 
				
			||||||
                $this->elementEnd('li');
 | 
					                $this->elementEnd('li');
 | 
				
			||||||
            } catch (NoAvatarException $e) {
 | 
					            } catch (NoAvatarException $e) {
 | 
				
			||||||
@@ -139,97 +144,100 @@ class AvatarsettingsAction extends SettingsAction
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                $avatar = $this->scoped->getAvatar(AVATAR_PROFILE_SIZE);
 | 
					                $avatar = $this->scoped->getAvatar(AVATAR_PROFILE_SIZE);
 | 
				
			||||||
                $this->elementStart('li', array('id' => 'avatar_preview',
 | 
					                $this->elementStart('li', ['id' => 'avatar_preview',
 | 
				
			||||||
                                                'class' => 'avatar_view'));
 | 
					                    'class' => 'avatar_view',]);
 | 
				
			||||||
                // TRANS: Header on avatar upload page for thumbnail of to be used rendition of uploaded avatar (h2).
 | 
					                // TRANS: Header on avatar upload page for thumbnail of to be used rendition of uploaded avatar (h2).
 | 
				
			||||||
                $this->element('h2', null, _("Preview"));
 | 
					                $this->element('h2', null, _m('Preview'));
 | 
				
			||||||
                $this->elementStart('div', array('id'=>'avatar_preview_view'));
 | 
					                $this->elementStart('div', ['id' => 'avatar_preview_view']);
 | 
				
			||||||
                $this->element('img', array('src' => $avatar->displayUrl(),
 | 
					                $this->element('img', ['src' => $avatar->displayUrl(),
 | 
				
			||||||
                    'width' => AVATAR_PROFILE_SIZE,
 | 
					                    'width' => AVATAR_PROFILE_SIZE,
 | 
				
			||||||
                    'height' => AVATAR_PROFILE_SIZE,
 | 
					                    'height' => AVATAR_PROFILE_SIZE,
 | 
				
			||||||
                                            'alt' => $this->scoped->getNickname()));
 | 
					                    'alt' => $this->scoped->getNickname(),]);
 | 
				
			||||||
                $this->elementEnd('div');
 | 
					                $this->elementEnd('div');
 | 
				
			||||||
                if (!empty($avatar->filename)) {
 | 
					                if (!empty($avatar->filename)) {
 | 
				
			||||||
                    // TRANS: Button on avatar upload page to delete current avatar.
 | 
					                    // TRANS: Button on avatar upload page to delete current avatar.
 | 
				
			||||||
                    $this->submit('delete', _m('BUTTON','Delete'));
 | 
					                    $this->submit('delete', _m('BUTTON', 'Delete'));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                $this->elementEnd('li');
 | 
					                $this->elementEnd('li');
 | 
				
			||||||
            } catch (NoAvatarException $e) {
 | 
					            } catch (NoAvatarException $e) {
 | 
				
			||||||
                // No previously uploaded avatar to preview.
 | 
					                // No previously uploaded avatar to preview.
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            $this->elementStart('li', array ('id' => 'settings_attach'));
 | 
					            $this->elementStart('li', ['id' => 'settings_attach']);
 | 
				
			||||||
            $this->element('input', array('name' => 'MAX_FILE_SIZE',
 | 
					            $this->element('input', ['name' => 'MAX_FILE_SIZE',
 | 
				
			||||||
                'type' => 'hidden',
 | 
					                'type' => 'hidden',
 | 
				
			||||||
                'id' => 'MAX_FILE_SIZE',
 | 
					                'id' => 'MAX_FILE_SIZE',
 | 
				
			||||||
                                          'value' => ImageFile::maxFileSizeInt()));
 | 
					                'value' => ImageFile::maxFileSizeInt(),]);
 | 
				
			||||||
            $this->element('input', array('name' => 'avatarfile',
 | 
					            $this->element('input', ['name' => 'avatarfile',
 | 
				
			||||||
                'type' => 'file',
 | 
					                'type' => 'file',
 | 
				
			||||||
                                          'id' => 'avatarfile'));
 | 
					                'id' => 'avatarfile',]);
 | 
				
			||||||
            $this->elementEnd('li');
 | 
					            $this->elementEnd('li');
 | 
				
			||||||
            $this->elementEnd('ul');
 | 
					            $this->elementEnd('ul');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            $this->elementStart('ul', 'form_actions');
 | 
					            $this->elementStart('ul', 'form_actions');
 | 
				
			||||||
            $this->elementStart('li');
 | 
					            $this->elementStart('li');
 | 
				
			||||||
            // TRANS: Button on avatar upload page to upload an avatar.
 | 
					            // TRANS: Button on avatar upload page to upload an avatar.
 | 
				
			||||||
            $this->submit('upload', _m('BUTTON','Upload'));
 | 
					            $this->submit('upload', _m('BUTTON', 'Upload'));
 | 
				
			||||||
            $this->elementEnd('li');
 | 
					            $this->elementEnd('li');
 | 
				
			||||||
            $this->elementEnd('ul');
 | 
					            $this->elementEnd('ul');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Event::handle('EndAvatarFormData', array($this));
 | 
					        Event::handle('EndAvatarFormData', [$this]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->elementEnd('fieldset');
 | 
					        $this->elementEnd('fieldset');
 | 
				
			||||||
        $this->elementEnd('form');
 | 
					        $this->elementEnd('form');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function showCropForm()
 | 
					    public function showCropForm()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->elementStart('form', array('method' => 'post',
 | 
					        $this->elementStart('form', ['method' => 'post',
 | 
				
			||||||
            'id' => 'form_settings_avatar',
 | 
					            'id' => 'form_settings_avatar',
 | 
				
			||||||
            'class' => 'form_settings',
 | 
					            'class' => 'form_settings',
 | 
				
			||||||
                                          'action' =>
 | 
					            'action' => common_local_url('avatarsettings'),]);
 | 
				
			||||||
                                          common_local_url('avatarsettings')));
 | 
					 | 
				
			||||||
        $this->elementStart('fieldset');
 | 
					        $this->elementStart('fieldset');
 | 
				
			||||||
        // TRANS: Avatar upload page crop form legend.
 | 
					        // TRANS: Avatar upload page crop form legend.
 | 
				
			||||||
        $this->element('legend', null, _('Avatar settings'));
 | 
					        $this->element('legend', null, _m('Avatar settings'));
 | 
				
			||||||
        $this->hidden('token', common_session_token());
 | 
					        $this->hidden('token', common_session_token());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->elementStart('ul', 'form_data');
 | 
					        $this->elementStart('ul', 'form_data');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->elementStart('li',
 | 
					        $this->elementStart(
 | 
				
			||||||
                            array('id' => 'avatar_original',
 | 
					            'li',
 | 
				
			||||||
                                  'class' => 'avatar_view'));
 | 
					            ['id' => 'avatar_original',
 | 
				
			||||||
 | 
					                'class' => 'avatar_view',]
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        // TRANS: Header on avatar upload crop form for thumbnail of originally uploaded avatar (h2).
 | 
					        // TRANS: Header on avatar upload crop form for thumbnail of originally uploaded avatar (h2).
 | 
				
			||||||
        $this->element('h2', null, _('Original'));
 | 
					        $this->element('h2', null, _m('Original'));
 | 
				
			||||||
        $this->elementStart('div', array('id'=>'avatar_original_view'));
 | 
					        $this->elementStart('div', ['id' => 'avatar_original_view']);
 | 
				
			||||||
        $this->element('img', array('src' => Avatar::url($this->filedata['filename']),
 | 
					        $this->element('img', ['src' => Avatar::url($this->filedata['filename']),
 | 
				
			||||||
            'width' => $this->filedata['width'],
 | 
					            'width' => $this->filedata['width'],
 | 
				
			||||||
            'height' => $this->filedata['height'],
 | 
					            'height' => $this->filedata['height'],
 | 
				
			||||||
                                    'alt' => $this->scoped->getNickname()));
 | 
					            'alt' => $this->scoped->getNickname(),]);
 | 
				
			||||||
        $this->elementEnd('div');
 | 
					        $this->elementEnd('div');
 | 
				
			||||||
        $this->elementEnd('li');
 | 
					        $this->elementEnd('li');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->elementStart('li',
 | 
					        $this->elementStart(
 | 
				
			||||||
                            array('id' => 'avatar_preview',
 | 
					            'li',
 | 
				
			||||||
                                  'class' => 'avatar_view'));
 | 
					            ['id' => 'avatar_preview',
 | 
				
			||||||
 | 
					                'class' => 'avatar_view',]
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        // TRANS: Header on avatar upload crop form for thumbnail of to be used rendition of uploaded avatar (h2).
 | 
					        // TRANS: Header on avatar upload crop form for thumbnail of to be used rendition of uploaded avatar (h2).
 | 
				
			||||||
        $this->element('h2', null, _('Preview'));
 | 
					        $this->element('h2', null, _m('Preview'));
 | 
				
			||||||
        $this->elementStart('div', array('id'=>'avatar_preview_view'));
 | 
					        $this->elementStart('div', ['id' => 'avatar_preview_view']);
 | 
				
			||||||
        $this->element('img', array('src' => Avatar::url($this->filedata['filename']),
 | 
					        $this->element('img', ['src' => Avatar::url($this->filedata['filename']),
 | 
				
			||||||
            'width' => AVATAR_PROFILE_SIZE,
 | 
					            'width' => AVATAR_PROFILE_SIZE,
 | 
				
			||||||
            'height' => AVATAR_PROFILE_SIZE,
 | 
					            'height' => AVATAR_PROFILE_SIZE,
 | 
				
			||||||
                                    'alt' => $this->scoped->getNickname()));
 | 
					            'alt' => $this->scoped->getNickname(),]);
 | 
				
			||||||
        $this->elementEnd('div');
 | 
					        $this->elementEnd('div');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        foreach (array('avatar_crop_x', 'avatar_crop_y',
 | 
					        foreach (['avatar_crop_x', 'avatar_crop_y',
 | 
				
			||||||
                       'avatar_crop_w', 'avatar_crop_h') as $crop_info) {
 | 
					                     'avatar_crop_w', 'avatar_crop_h',] as $crop_info) {
 | 
				
			||||||
            $this->element('input', array('name' => $crop_info,
 | 
					            $this->element('input', ['name' => $crop_info,
 | 
				
			||||||
                'type' => 'hidden',
 | 
					                'type' => 'hidden',
 | 
				
			||||||
                                          'id' => $crop_info));
 | 
					                'id' => $crop_info,]);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // TRANS: Button on avatar upload crop form to confirm a selected crop as avatar.
 | 
					        // TRANS: Button on avatar upload crop form to confirm a selected crop as avatar.
 | 
				
			||||||
        $this->submit('crop', _m('BUTTON','Crop'));
 | 
					        $this->submit('crop', _m('BUTTON', 'Crop'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->elementEnd('li');
 | 
					        $this->elementEnd('li');
 | 
				
			||||||
        $this->elementEnd('ul');
 | 
					        $this->elementEnd('ul');
 | 
				
			||||||
@@ -237,20 +245,31 @@ class AvatarsettingsAction extends SettingsAction
 | 
				
			|||||||
        $this->elementEnd('form');
 | 
					        $this->elementEnd('form');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return string
 | 
				
			||||||
 | 
					     * @throws NoResultException
 | 
				
			||||||
 | 
					     * @throws NoUploadedMediaException
 | 
				
			||||||
 | 
					     * @throws ServerException
 | 
				
			||||||
 | 
					     * @throws UnsupportedMediaException
 | 
				
			||||||
 | 
					     * @throws UseFileAsThumbnailException
 | 
				
			||||||
 | 
					     * @throws Exception
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @throws ClientException
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    protected function doPost()
 | 
					    protected function doPost()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (Event::handle('StartAvatarSaveForm', array($this))) {
 | 
					        if (Event::handle('StartAvatarSaveForm', [$this])) {
 | 
				
			||||||
            if ($this->trimmed('upload')) {
 | 
					            if ($this->trimmed('upload')) {
 | 
				
			||||||
                return $this->uploadAvatar();
 | 
					                return $this->uploadAvatar();
 | 
				
			||||||
            } else if ($this->trimmed('crop')) {
 | 
					            } elseif ($this->trimmed('crop')) {
 | 
				
			||||||
                return $this->cropAvatar();
 | 
					                return $this->cropAvatar();
 | 
				
			||||||
            } else if ($this->trimmed('delete')) {
 | 
					            } elseif ($this->trimmed('delete')) {
 | 
				
			||||||
                return $this->deleteAvatar();
 | 
					                return $this->deleteAvatar();
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                // TRANS: Unexpected validation error on avatar upload form.
 | 
					                // TRANS: Unexpected validation error on avatar upload form.
 | 
				
			||||||
                throw new ClientException(_('Unexpected form submission.'));
 | 
					                throw new ClientException(_m('Unexpected form submission.'));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Event::handle('EndAvatarSaveForm', array($this));
 | 
					            Event::handle('EndAvatarSaveForm', [$this]);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -260,28 +279,39 @@ class AvatarsettingsAction extends SettingsAction
 | 
				
			|||||||
     * Does all the magic for handling an image upload, and crops the
 | 
					     * Does all the magic for handling an image upload, and crops the
 | 
				
			||||||
     * image by default.
 | 
					     * image by default.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return void
 | 
					     * @return string
 | 
				
			||||||
 | 
					     * @throws NoResultException
 | 
				
			||||||
 | 
					     * @throws NoUploadedMediaException
 | 
				
			||||||
 | 
					     * @throws ServerException
 | 
				
			||||||
 | 
					     * @throws UnsupportedMediaException
 | 
				
			||||||
 | 
					     * @throws UseFileAsThumbnailException
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @throws ClientException
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    function uploadAvatar()
 | 
					    public function uploadAvatar(): string
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // ImageFile throws exception if something goes wrong, which we'll
 | 
					        // ImageFile throws exception if something goes wrong, which we'll
 | 
				
			||||||
        // pick up and show as an error message above the form.
 | 
					        // pick up and show as an error message above the form.
 | 
				
			||||||
        $imagefile = ImageFile::fromUpload('avatarfile');
 | 
					        $imagefile = ImageFile::fromUpload('avatarfile');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $type = $imagefile->preferredType();
 | 
					        $type = $imagefile->preferredType();
 | 
				
			||||||
        $filename = Avatar::filename($this->scoped->getID(),
 | 
					        $filename = Avatar::filename(
 | 
				
			||||||
 | 
					            $this->scoped->getID(),
 | 
				
			||||||
            image_type_to_extension($type),
 | 
					            image_type_to_extension($type),
 | 
				
			||||||
            null,
 | 
					            null,
 | 
				
			||||||
                                     'tmp'.common_timestamp());
 | 
					            'tmp' . common_timestamp()
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $filepath = Avatar::path($filename);
 | 
					        $filepath = Avatar::path($filename);
 | 
				
			||||||
        $imagefile = $imagefile->copyTo($filepath);
 | 
					        $imagefile = $imagefile->copyTo($filepath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $filedata = array('filename' => $filename,
 | 
					        $filedata = [
 | 
				
			||||||
 | 
					            'filename' => $filename,
 | 
				
			||||||
            'filepath' => $filepath,
 | 
					            'filepath' => $filepath,
 | 
				
			||||||
            'width' => $imagefile->width,
 | 
					            'width' => $imagefile->width,
 | 
				
			||||||
            'height' => $imagefile->height,
 | 
					            'height' => $imagefile->height,
 | 
				
			||||||
                          'type' => $type);
 | 
					            'type' => $type,
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $_SESSION['FILEDATA'] = $filedata;
 | 
					        $_SESSION['FILEDATA'] = $filedata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -290,13 +320,18 @@ class AvatarsettingsAction extends SettingsAction
 | 
				
			|||||||
        $this->mode = 'crop';
 | 
					        $this->mode = 'crop';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // TRANS: Avatar upload form instruction after uploading a file.
 | 
					        // TRANS: Avatar upload form instruction after uploading a file.
 | 
				
			||||||
        return _('Pick a square area of the image to be your avatar.');
 | 
					        return _m('Pick a square area of the image to be your avatar.');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Handle the results of jcrop.
 | 
					     * Handle the results of jcrop.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return void
 | 
					     * @return string
 | 
				
			||||||
 | 
					     * @throws NoResultException
 | 
				
			||||||
 | 
					     * @throws ServerException
 | 
				
			||||||
 | 
					     * @throws UnsupportedMediaException
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @throws ClientException
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function cropAvatar()
 | 
					    public function cropAvatar()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -304,30 +339,34 @@ class AvatarsettingsAction extends SettingsAction
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if (empty($filedata)) {
 | 
					        if (empty($filedata)) {
 | 
				
			||||||
            // TRANS: Server error displayed if an avatar upload went wrong somehow server side.
 | 
					            // TRANS: Server error displayed if an avatar upload went wrong somehow server side.
 | 
				
			||||||
            throw new ServerException(_('Lost our file data.'));
 | 
					            throw new ServerException(_m('Lost our file data.'));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $file_d = min($filedata['width'], $filedata['height']);
 | 
					        $file_d = min($filedata['width'], $filedata['height']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $dest_x = $this->arg('avatar_crop_x') ? $this->arg('avatar_crop_x'):0;
 | 
					        $dest_x = $this->arg('avatar_crop_x') ? $this->arg('avatar_crop_x') : 0;
 | 
				
			||||||
        $dest_y = $this->arg('avatar_crop_y') ? $this->arg('avatar_crop_y'):0;
 | 
					        $dest_y = $this->arg('avatar_crop_y') ? $this->arg('avatar_crop_y') : 0;
 | 
				
			||||||
        $dest_w = $this->arg('avatar_crop_w') ? $this->arg('avatar_crop_w'):$file_d;
 | 
					        $dest_w = $this->arg('avatar_crop_w') ? $this->arg('avatar_crop_w') : $file_d;
 | 
				
			||||||
        $dest_h = $this->arg('avatar_crop_h') ? $this->arg('avatar_crop_h'):$file_d;
 | 
					        $dest_h = $this->arg('avatar_crop_h') ? $this->arg('avatar_crop_h') : $file_d;
 | 
				
			||||||
        $size = intval(min($dest_w, $dest_h, common_config('avatar', 'maxsize')));
 | 
					        $size = (int)(min($dest_w, $dest_h, common_config('avatar', 'maxsize')));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $box = array('width' => $size, 'height' => $size,
 | 
					        $box = ['width' => $size, 'height' => $size,
 | 
				
			||||||
            'x' => $dest_x, 'y' => $dest_y,
 | 
					            'x' => $dest_x, 'y' => $dest_y,
 | 
				
			||||||
                     'w' => $dest_w,   'h' => $dest_h);
 | 
					            'w' => $dest_w, 'h' => $dest_h,];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $imagefile = new ImageFile(null, $filedata['filepath']);
 | 
					        $imagefile = new ImageFile(null, $filedata['filepath']);
 | 
				
			||||||
        $filename = Avatar::filename($this->scoped->getID(), image_type_to_extension($imagefile->preferredType()),
 | 
					        $filename = Avatar::filename(
 | 
				
			||||||
                                     $size, common_timestamp());
 | 
					            $this->scoped->getID(),
 | 
				
			||||||
 | 
					            image_type_to_extension($imagefile->preferredType()),
 | 
				
			||||||
 | 
					            $size,
 | 
				
			||||||
 | 
					            common_timestamp()
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            $imagefile->resizeTo(Avatar::path($filename), $box);
 | 
					            $imagefile->resizeTo(Avatar::path($filename), $box);
 | 
				
			||||||
        } catch (UseFileAsThumbnailException $e) {
 | 
					        } catch (UseFileAsThumbnailException $e) {
 | 
				
			||||||
            common_debug('Using uploaded avatar directly without resizing, copying it to: '.$filename);
 | 
					            common_debug('Using uploaded avatar directly without resizing, copying it to: ' . $filename);
 | 
				
			||||||
            if (!copy($filedata['filepath'], Avatar::path($filename))) {
 | 
					            if (!copy($filedata['filepath'], Avatar::path($filename))) {
 | 
				
			||||||
                common_debug('Tried to copy image file '.$filedata['filepath'].' to destination '.Avatar::path($filename));
 | 
					                common_debug('Tried to copy image file ' . $filedata['filepath'] . ' to destination ' . Avatar::path($filename));
 | 
				
			||||||
                throw new ServerException('Could not copy file to destination.');
 | 
					                throw new ServerException('Could not copy file to destination.');
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -337,24 +376,26 @@ class AvatarsettingsAction extends SettingsAction
 | 
				
			|||||||
            unset($_SESSION['FILEDATA']);
 | 
					            unset($_SESSION['FILEDATA']);
 | 
				
			||||||
            $this->mode = 'upload';
 | 
					            $this->mode = 'upload';
 | 
				
			||||||
            // TRANS: Success message for having updated a user avatar.
 | 
					            // TRANS: Success message for having updated a user avatar.
 | 
				
			||||||
            return _('Avatar updated.');
 | 
					            return _m('Avatar updated.');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // TRANS: Error displayed on the avatar upload page if the avatar could not be updated for an unknown reason.
 | 
					        // TRANS: Error displayed on the avatar upload page if the avatar could not be updated for an unknown reason.
 | 
				
			||||||
        throw new ServerException(_('Failed updating avatar.'));
 | 
					        throw new ServerException(_m('Failed updating avatar.'));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Get rid of the current avatar.
 | 
					     * Get rid of the current avatar.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return void
 | 
					     * @return string
 | 
				
			||||||
 | 
					     * @throws Exception
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    function deleteAvatar()
 | 
					    public function deleteAvatar()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Avatar::deleteFromProfile($this->scoped);
 | 
					        Avatar::deleteFromProfile($this->scoped);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // TRANS: Success message for deleting a user avatar.
 | 
					        // TRANS: Success message for deleting a user avatar.
 | 
				
			||||||
        return _('Avatar deleted.');
 | 
					        return _m('Avatar deleted.');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -362,11 +403,10 @@ class AvatarsettingsAction extends SettingsAction
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return void
 | 
					     * @return void
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 | 
					    public function showStylesheets()
 | 
				
			||||||
    function showStylesheets()
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        parent::showStylesheets();
 | 
					        parent::showStylesheets();
 | 
				
			||||||
        $this->cssLink('js/extlib/jquery-jcrop/css/jcrop.css','base','screen, projection, tv');
 | 
					        $this->cssLink('js/extlib/jquery-jcrop/css/jcrop.css', 'base', 'screen, projection, tv');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -374,7 +414,7 @@ class AvatarsettingsAction extends SettingsAction
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return void
 | 
					     * @return void
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    function showScripts()
 | 
					    public function showScripts()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        parent::showScripts();
 | 
					        parent::showScripts();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,10 +24,9 @@
 | 
				
			|||||||
 * @author    Zach Copley <zach@status.net>
 | 
					 * @author    Zach Copley <zach@status.net>
 | 
				
			||||||
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 | 
					 * @author    Mikael Nordfeldth <mmn@hethane.se>
 | 
				
			||||||
 * @author    Miguel Dantas <biodantasgs@gmail.com>
 | 
					 * @author    Miguel Dantas <biodantasgs@gmail.com>
 | 
				
			||||||
 * @copyright 2008, 2019 Free Software Foundation http://fsf.org
 | 
					 * @author    Diogo Cordeiro <diogo@fc.up.pt>
 | 
				
			||||||
 | 
					 * @copyright 2008, 2019-2020 Free Software Foundation http://fsf.org
 | 
				
			||||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @see       https://www.gnu.org/software/social/
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
defined('GNUSOCIAL') || die();
 | 
					defined('GNUSOCIAL') || die();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -40,6 +39,7 @@ use Intervention\Image\ImageManagerStatic as Image;
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * @category Image
 | 
					 * @category Image
 | 
				
			||||||
 * @package  GNUsocial
 | 
					 * @package  GNUsocial
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 | 
					 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 | 
				
			||||||
 * @author   Evan Prodromou <evan@status.net>
 | 
					 * @author   Evan Prodromou <evan@status.net>
 | 
				
			||||||
 * @author   Zach Copley <zach@status.net>
 | 
					 * @author   Zach Copley <zach@status.net>
 | 
				
			||||||
@@ -52,8 +52,8 @@ class ImageFile extends MediaFile
 | 
				
			|||||||
    public $height;
 | 
					    public $height;
 | 
				
			||||||
    public $width;
 | 
					    public $width;
 | 
				
			||||||
    public $rotate = 0;    // degrees to rotate for properly oriented image (extrapolated from EXIF etc.)
 | 
					    public $rotate = 0;    // degrees to rotate for properly oriented image (extrapolated from EXIF etc.)
 | 
				
			||||||
    public $animated = null; // Animated image? (has more than 1 frame). null means untested
 | 
					    public $animated; // Animated image? (has more than 1 frame). null means untested
 | 
				
			||||||
    public $mimetype = null; // The _ImageFile_ mimetype, _not_ the originating File object
 | 
					    public $mimetype; // The _ImageFile_ mimetype, _not_ the originating File object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function __construct($id, string $filepath)
 | 
					    public function __construct($id, string $filepath)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -74,12 +74,7 @@ class ImageFile extends MediaFile
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        if (!(($cmp($this, IMAGETYPE_GIF)  && function_exists('imagecreatefromgif'))  ||
 | 
					        if (!(($cmp($this, IMAGETYPE_GIF) && function_exists('imagecreatefromgif')) || ($cmp($this, IMAGETYPE_JPEG) && function_exists('imagecreatefromjpeg')) || ($cmp($this, IMAGETYPE_BMP) && function_exists('imagecreatefrombmp')) || ($cmp($this, IMAGETYPE_WBMP) && function_exists('imagecreatefromwbmp')) || ($cmp($this, IMAGETYPE_XBM) && function_exists('imagecreatefromxbm')) || ($cmp($this, IMAGETYPE_PNG) && function_exists('imagecreatefrompng')))) {
 | 
				
			||||||
              ($cmp($this, IMAGETYPE_JPEG) && function_exists('imagecreatefromjpeg')) ||
 | 
					 | 
				
			||||||
              ($cmp($this, IMAGETYPE_BMP)  && function_exists('imagecreatefrombmp'))  ||
 | 
					 | 
				
			||||||
              ($cmp($this, IMAGETYPE_WBMP) && function_exists('imagecreatefromwbmp')) ||
 | 
					 | 
				
			||||||
              ($cmp($this, IMAGETYPE_XBM)  && function_exists('imagecreatefromxbm'))  ||
 | 
					 | 
				
			||||||
              ($cmp($this, IMAGETYPE_PNG)  && function_exists('imagecreatefrompng')))) {
 | 
					 | 
				
			||||||
            common_debug("Mimetype '{$this->mimetype}' was not recognized as a supported format");
 | 
					            common_debug("Mimetype '{$this->mimetype}' was not recognized as a supported format");
 | 
				
			||||||
            // TRANS: Exception thrown when trying to upload an unsupported image file format.
 | 
					            // TRANS: Exception thrown when trying to upload an unsupported image file format.
 | 
				
			||||||
            throw new UnsupportedMediaException(_m('Unsupported image format.'), $this->filepath);
 | 
					            throw new UnsupportedMediaException(_m('Unsupported image format.'), $this->filepath);
 | 
				
			||||||
@@ -99,7 +94,7 @@ class ImageFile extends MediaFile
 | 
				
			|||||||
            // Orientation value to rotate thumbnails properly
 | 
					            // Orientation value to rotate thumbnails properly
 | 
				
			||||||
            $exif = @$img->exif();
 | 
					            $exif = @$img->exif();
 | 
				
			||||||
            if (is_array($exif) && isset($exif['Orientation'])) {
 | 
					            if (is_array($exif) && isset($exif['Orientation'])) {
 | 
				
			||||||
                switch ((int) ($exif['Orientation'])) {
 | 
					                switch ((int)($exif['Orientation'])) {
 | 
				
			||||||
                    case 1: // top is top
 | 
					                    case 1: // top is top
 | 
				
			||||||
                        $this->rotate = 0;
 | 
					                        $this->rotate = 0;
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
@@ -198,24 +193,34 @@ class ImageFile extends MediaFile
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Process a file upload
 | 
					     * Process a file upload
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * Uses MediaFile's `fromUpload` to do the majority of the work and reencodes the image,
 | 
					     * Uses MediaFile's `fromUpload` to do the majority of the work
 | 
				
			||||||
     * to mitigate injection attacks.
 | 
					     * and ensures the uploaded file is in fact an image.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param string $param
 | 
					     * @param string $param
 | 
				
			||||||
     * @param null|Profile $scoped
 | 
					     * @param null|Profile $scoped
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @throws ClientException
 | 
					     * @return ImageFile
 | 
				
			||||||
     * @throws NoResultException
 | 
					     * @throws NoResultException
 | 
				
			||||||
     * @throws NoUploadedMediaException
 | 
					     * @throws NoUploadedMediaException
 | 
				
			||||||
     * @throws ServerException
 | 
					     * @throws ServerException
 | 
				
			||||||
     * @throws UnsupportedMediaException
 | 
					     * @throws UnsupportedMediaException
 | 
				
			||||||
     * @throws UseFileAsThumbnailException
 | 
					     * @throws UseFileAsThumbnailException
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return ImageFile|MediaFile
 | 
					     * @throws ClientException
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static function fromUpload(string $param = 'upload', Profile $scoped = null)
 | 
					    public static function fromUpload(string $param = 'upload', ?Profile $scoped = null): self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return parent::fromUpload($param, $scoped);
 | 
					        $mediafile = parent::fromUpload($param, $scoped);
 | 
				
			||||||
 | 
					        if ($mediafile instanceof self) {
 | 
				
			||||||
 | 
					            return $mediafile;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // We can conclude that we have failed to get the MIME type
 | 
				
			||||||
 | 
					            // TRANS: Client exception thrown trying to upload an invalid image type.
 | 
				
			||||||
 | 
					            // TRANS: %s is the file type that was denied
 | 
				
			||||||
 | 
					            $hint = sprintf(_m('"%s" is not a supported file type on this server. ' .
 | 
				
			||||||
 | 
					                'Try using another image format.'), $mediafile->mimetype);
 | 
				
			||||||
 | 
					            throw new ClientException($hint);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -227,7 +232,7 @@ class ImageFile extends MediaFile
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function preferredType()
 | 
					    public function preferredType()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // Keep only JPEG and GIF in their orignal format
 | 
					        // Keep only JPEG and GIF in their original format
 | 
				
			||||||
        if ($this->type === IMAGETYPE_JPEG || $this->type === IMAGETYPE_GIF) {
 | 
					        if ($this->type === IMAGETYPE_JPEG || $this->type === IMAGETYPE_GIF) {
 | 
				
			||||||
            return $this->type;
 | 
					            return $this->type;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -245,13 +250,13 @@ class ImageFile extends MediaFile
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param string $outpath
 | 
					     * @param string $outpath
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @throws ClientException
 | 
					     * @return ImageFile the image stored at target path
 | 
				
			||||||
     * @throws NoResultException
 | 
					     * @throws NoResultException
 | 
				
			||||||
     * @throws ServerException
 | 
					     * @throws ServerException
 | 
				
			||||||
     * @throws UnsupportedMediaException
 | 
					     * @throws UnsupportedMediaException
 | 
				
			||||||
     * @throws UseFileAsThumbnailException
 | 
					     * @throws UseFileAsThumbnailException
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return ImageFile the image stored at target path
 | 
					     * @throws ClientException
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function copyTo($outpath)
 | 
					    public function copyTo($outpath)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -263,20 +268,21 @@ class ImageFile extends MediaFile
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param string $outpath
 | 
					     * @param string $outpath
 | 
				
			||||||
     * @param array $box width, height, boundary box (x,y,w,h) defaults to full image
 | 
					     * @param array $box width, height, boundary box (x,y,w,h) defaults to full image
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return string full local filesystem filename
 | 
				
			||||||
     * @return string full local filesystem filename
 | 
					     * @return string full local filesystem filename
 | 
				
			||||||
     * @throws UnsupportedMediaException
 | 
					     * @throws UnsupportedMediaException
 | 
				
			||||||
     * @throws UseFileAsThumbnailException
 | 
					     * @throws UseFileAsThumbnailException
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return string full local filesystem filename
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function resizeTo($outpath, array $box = [])
 | 
					    public function resizeTo($outpath, array $box = [])
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $box['width']  = isset($box['width'])  ? intval($box['width'])  : $this->width;
 | 
					        $box['width'] = isset($box['width']) ? (int)($box['width']) : $this->width;
 | 
				
			||||||
        $box['height'] = isset($box['height']) ? intval($box['height']) : $this->height;
 | 
					        $box['height'] = isset($box['height']) ? (int)($box['height']) : $this->height;
 | 
				
			||||||
        $box['x']      = isset($box['x'])      ? intval($box['x'])      : 0;
 | 
					        $box['x'] = isset($box['x']) ? (int)($box['x']) : 0;
 | 
				
			||||||
        $box['y']      = isset($box['y'])      ? intval($box['y'])      : 0;
 | 
					        $box['y'] = isset($box['y']) ? (int)($box['y']) : 0;
 | 
				
			||||||
        $box['w']      = isset($box['w'])      ? intval($box['w'])      : $this->width;
 | 
					        $box['w'] = isset($box['w']) ? (int)($box['w']) : $this->width;
 | 
				
			||||||
        $box['h']      = isset($box['h'])      ? intval($box['h'])      : $this->height;
 | 
					        $box['h'] = isset($box['h']) ? (int)($box['h']) : $this->height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!file_exists($this->filepath)) {
 | 
					        if (!file_exists($this->filepath)) {
 | 
				
			||||||
            // TRANS: Exception thrown during resize when image has been registered as present,
 | 
					            // TRANS: Exception thrown during resize when image has been registered as present,
 | 
				
			||||||
@@ -346,7 +352,7 @@ class ImageFile extends MediaFile
 | 
				
			|||||||
        try {
 | 
					        try {
 | 
				
			||||||
            $img = Image::make($this->filepath);
 | 
					            $img = Image::make($this->filepath);
 | 
				
			||||||
        } catch (Exception $e) {
 | 
					        } catch (Exception $e) {
 | 
				
			||||||
            common_log(LOG_ERR, __METHOD__ . ' ecountered exception: ' . print_r($e, true));
 | 
					            common_log(LOG_ERR, __METHOD__ . ' encountered exception: ' . print_r($e, true));
 | 
				
			||||||
            // TRANS: Exception thrown when trying to resize an unknown file type.
 | 
					            // TRANS: Exception thrown when trying to resize an unknown file type.
 | 
				
			||||||
            throw new Exception(_m('Unknown file type'));
 | 
					            throw new Exception(_m('Unknown file type'));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -359,7 +365,9 @@ class ImageFile extends MediaFile
 | 
				
			|||||||
            $img = $img->orientate();
 | 
					            $img = $img->orientate();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $img->fit($box['width'], $box['height'],
 | 
					        $img->fit(
 | 
				
			||||||
 | 
					            $box['width'],
 | 
				
			||||||
 | 
					            $box['height'],
 | 
				
			||||||
            function ($constraint) {
 | 
					            function ($constraint) {
 | 
				
			||||||
                if (common_config('attachments', 'upscale') !== true) {
 | 
					                if (common_config('attachments', 'upscale') !== true) {
 | 
				
			||||||
                    $constraint->upsize(); // Prevent upscaling
 | 
					                    $constraint->upsize(); // Prevent upscaling
 | 
				
			||||||
@@ -421,9 +429,9 @@ class ImageFile extends MediaFile
 | 
				
			|||||||
     * @param $crop     int Crop to the size (not preserving aspect ratio)
 | 
					     * @param $crop     int Crop to the size (not preserving aspect ratio)
 | 
				
			||||||
     * @param int $rotate
 | 
					     * @param int $rotate
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
					     * @return array
 | 
				
			||||||
     * @throws ServerException
 | 
					     * @throws ServerException
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return array
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static function getScalingValues(
 | 
					    public static function getScalingValues(
 | 
				
			||||||
        $width,
 | 
					        $width,
 | 
				
			||||||
@@ -484,10 +492,10 @@ class ImageFile extends MediaFile
 | 
				
			|||||||
                $rw = ceil($width * $rh / $height);
 | 
					                $rw = ceil($width * $rh / $height);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return array(intval($rw), intval($rh),
 | 
					        return [(int)$rw, (int)$rh,
 | 
				
			||||||
                     intval($cx), intval($cy),
 | 
					            (int)$cx, (int)$cy,
 | 
				
			||||||
                     is_null($cw) ? $width : intval($cw),
 | 
					            is_null($cw) ? $width : (int)$cw,
 | 
				
			||||||
                     is_null($ch) ? $height : intval($ch));
 | 
					            is_null($ch) ? $height : (int)$ch,];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -588,7 +596,8 @@ class ImageFile extends MediaFile
 | 
				
			|||||||
        ];
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $outpath = File_thumbnail::path(
 | 
					        $outpath = File_thumbnail::path(
 | 
				
			||||||
            "thumb-{$this->fileRecord->id}-{$box['width']}x{$box['height']}-{$outfilename}");
 | 
					            "thumb-{$this->fileRecord->id}-{$box['width']}x{$box['height']}-{$outfilename}"
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Doublecheck that parameters are sane and integers.
 | 
					        // Doublecheck that parameters are sane and integers.
 | 
				
			||||||
        if ($box['width'] < 1 || $box['width'] > common_config('thumbnail', 'maxsize')
 | 
					        if ($box['width'] < 1 || $box['width'] > common_config('thumbnail', 'maxsize')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,33 +1,33 @@
 | 
				
			|||||||
<?php
 | 
					<?php
 | 
				
			||||||
 | 
					// This file is part of GNU social - https://www.gnu.org/software/social
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// GNU social is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					// it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					// the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					// (at your option) any later version.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// GNU social is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					// GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * GNU social - a federating social network
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Abstraction for media files
 | 
					 * Abstraction for media files
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * LICENCE: This program is free software: you can redistribute it and/or modify
 | 
					 | 
				
			||||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
					 | 
				
			||||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
					 | 
				
			||||||
 * (at your option) any later version.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This program is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 | 
				
			||||||
 * GNU Affero General Public License for more details.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * You should have received a copy of the GNU Affero General Public License
 | 
					 | 
				
			||||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @category  Media
 | 
					 * @category  Media
 | 
				
			||||||
 * @package   GNUsocial
 | 
					 * @package   GNUsocial
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * @author    Robin Millette <robin@millette.info>
 | 
					 * @author    Robin Millette <robin@millette.info>
 | 
				
			||||||
 * @author    Miguel Dantas <biodantas@gmail.com>
 | 
					 * @author    Miguel Dantas <biodantas@gmail.com>
 | 
				
			||||||
 * @author    Zach Copley <zach@status.net>
 | 
					 * @author    Zach Copley <zach@status.net>
 | 
				
			||||||
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 | 
					 * @author    Mikael Nordfeldth <mmn@hethane.se>
 | 
				
			||||||
 * @copyright 2008-2009, 2019 Free Software Foundation http://fsf.org
 | 
					 * @author    Diogo Cordeiro <diogo@fc.up.pt>
 | 
				
			||||||
 | 
					 * @copyright 2008-2009, 2019-2020 Free Software Foundation http://fsf.org
 | 
				
			||||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 | 
					 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 | 
				
			||||||
 * @link      https://www.gnu.org/software/social/
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					 | 
				
			||||||
defined('GNUSOCIAL') || die();
 | 
					defined('GNUSOCIAL') || die();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -35,21 +35,22 @@ defined('GNUSOCIAL') || die();
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
class MediaFile
 | 
					class MediaFile
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public $id            = null;
 | 
					    public $id;
 | 
				
			||||||
    public $filepath      = null;
 | 
					    public $filepath;
 | 
				
			||||||
    public $filename      = null;
 | 
					    public $filename;
 | 
				
			||||||
    public $fileRecord    = null;
 | 
					    public $fileRecord;
 | 
				
			||||||
    public $fileurl       = null;
 | 
					    public $fileurl;
 | 
				
			||||||
    public $short_fileurl = null;
 | 
					    public $short_fileurl;
 | 
				
			||||||
    public $mimetype      = null;
 | 
					    public $mimetype;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @param string $filepath The path of the file this media refers to. Required
 | 
					     * @param string $filepath The path of the file this media refers to. Required
 | 
				
			||||||
     * @param string $mimetype The mimetype of the file. Required
 | 
					     * @param string $mimetype The mimetype of the file. Required
 | 
				
			||||||
     * @param $filehash        The hash of the file, if known. Optional
 | 
					     * @param string $filehash The hash of the file, if known. Optional
 | 
				
			||||||
     * @param int|null $id     The DB id of the file. Int if known, null if not.
 | 
					     * @param null|int $id The DB id of the file. Int if known, null if not.
 | 
				
			||||||
     *                     If null, it searches for it. If -1, it skips all DB
 | 
					     *                     If null, it searches for it. If -1, it skips all DB
 | 
				
			||||||
     *                     interactions (useful for temporary objects)
 | 
					     *                     interactions (useful for temporary objects)
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @throws ClientException
 | 
					     * @throws ClientException
 | 
				
			||||||
     * @throws NoResultException
 | 
					     * @throws NoResultException
 | 
				
			||||||
     * @throws ServerException
 | 
					     * @throws ServerException
 | 
				
			||||||
@@ -80,7 +81,7 @@ class MediaFile
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            $this->fileurl = common_local_url(
 | 
					            $this->fileurl = common_local_url(
 | 
				
			||||||
                'attachment',
 | 
					                'attachment',
 | 
				
			||||||
                array('attachment' => $this->fileRecord->id)
 | 
					                ['attachment' => $this->fileRecord->id]
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            $this->short_fileurl = common_shorten_url($this->fileurl);
 | 
					            $this->short_fileurl = common_shorten_url($this->fileurl);
 | 
				
			||||||
@@ -125,14 +126,17 @@ class MediaFile
 | 
				
			|||||||
     * Calculate the hash of a file.
 | 
					     * Calculate the hash of a file.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * This won't work for files >2GiB because PHP uses only 32bit.
 | 
					     * This won't work for files >2GiB because PHP uses only 32bit.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param string $filepath
 | 
					     * @param string $filepath
 | 
				
			||||||
     * @param string|null $filehash
 | 
					     * @param null|string $filehash
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @return string
 | 
					     * @return string
 | 
				
			||||||
     * @throws ServerException
 | 
					     * @throws ServerException
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static function getHashOfFile(string $filepath, $filehash = null)
 | 
					    public static function getHashOfFile(string $filepath, $filehash = null)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        assert(!empty($filepath), __METHOD__ . ": filepath cannot be null");
 | 
					        assert(!empty($filepath), __METHOD__ . ': filepath cannot be null');
 | 
				
			||||||
        if ($filehash === null) {
 | 
					        if ($filehash === null) {
 | 
				
			||||||
            // Calculate if we have an older upload method somewhere (Qvitter) that
 | 
					            // Calculate if we have an older upload method somewhere (Qvitter) that
 | 
				
			||||||
            // doesn't do this before calling new MediaFile on its local files...
 | 
					            // doesn't do this before calling new MediaFile on its local files...
 | 
				
			||||||
@@ -148,8 +152,9 @@ class MediaFile
 | 
				
			|||||||
     * Retrieve or insert as a file in the DB
 | 
					     * Retrieve or insert as a file in the DB
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return object File
 | 
					     * @return object File
 | 
				
			||||||
     * @throws ClientException
 | 
					 | 
				
			||||||
     * @throws ServerException
 | 
					     * @throws ServerException
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @throws ClientException
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    protected function storeFile()
 | 
					    protected function storeFile()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -161,7 +166,7 @@ class MediaFile
 | 
				
			|||||||
            // Well, let's just continue below.
 | 
					            // Well, let's just continue below.
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $fileurl = common_local_url('attachment_view', array('filehash' => $this->filehash));
 | 
					        $fileurl = common_local_url('attachment_view', ['filehash' => $this->filehash]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $file = new File;
 | 
					        $file = new File;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -178,8 +183,8 @@ class MediaFile
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        $file_id = $file->insert();
 | 
					        $file_id = $file->insert();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ($file_id===false) {
 | 
					        if ($file_id === false) {
 | 
				
			||||||
            common_log_db_error($file, "INSERT", __FILE__);
 | 
					            common_log_db_error($file, 'INSERT', __FILE__);
 | 
				
			||||||
            // TRANS: Client exception thrown when a database error was thrown during a file upload operation.
 | 
					            // TRANS: Client exception thrown when a database error was thrown during a file upload operation.
 | 
				
			||||||
            throw new ClientException(_m('There was a database error while saving your file. Please try again.'));
 | 
					            throw new ClientException(_m('There was a database error while saving your file. Please try again.'));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -187,7 +192,7 @@ class MediaFile
 | 
				
			|||||||
        // Set file geometrical properties if available
 | 
					        // Set file geometrical properties if available
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            $image = ImageFile::fromFileObject($file);
 | 
					            $image = ImageFile::fromFileObject($file);
 | 
				
			||||||
            $orig = clone($file);
 | 
					            $orig = clone $file;
 | 
				
			||||||
            $file->width = $image->width;
 | 
					            $file->width = $image->width;
 | 
				
			||||||
            $file->height = $image->height;
 | 
					            $file->height = $image->height;
 | 
				
			||||||
            $file->update($orig);
 | 
					            $file->update($orig);
 | 
				
			||||||
@@ -215,11 +220,11 @@ class MediaFile
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        $value = self::maxFileSizeInt();
 | 
					        $value = self::maxFileSizeInt();
 | 
				
			||||||
        if ($value > 1024 * 1024) {
 | 
					        if ($value > 1024 * 1024) {
 | 
				
			||||||
            $value = $value/(1024*1024);
 | 
					            $value = $value / (1024 * 1024);
 | 
				
			||||||
            // TRANS: Number of megabytes. %d is the number.
 | 
					            // TRANS: Number of megabytes. %d is the number.
 | 
				
			||||||
            return sprintf(_m('%dMB', '%dMB', $value), $value);
 | 
					            return sprintf(_m('%dMB', '%dMB', $value), $value);
 | 
				
			||||||
        } elseif ($value > 1024) {
 | 
					        } elseif ($value > 1024) {
 | 
				
			||||||
            $value = $value/1024;
 | 
					            $value = $value / 1024;
 | 
				
			||||||
            // TRANS: Number of kilobytes. %d is the number.
 | 
					            // TRANS: Number of kilobytes. %d is the number.
 | 
				
			||||||
            return sprintf(_m('%dkB', '%dkB', $value), $value);
 | 
					            return sprintf(_m('%dkB', '%dkB', $value), $value);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
@@ -231,7 +236,7 @@ class MediaFile
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The maximum allowed file size, as an int
 | 
					     * The maximum allowed file size, as an int
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static function maxFileSizeInt() : int
 | 
					    public static function maxFileSizeInt(): int
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return common_config('attachments', 'file_quota');
 | 
					        return common_config('attachments', 'file_quota');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -239,9 +244,13 @@ class MediaFile
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Encodes a file name and a file hash in the new file format, which is used to avoid
 | 
					     * Encodes a file name and a file hash in the new file format, which is used to avoid
 | 
				
			||||||
     * having an extension in the file, removing trust in extensions, while keeping the original name
 | 
					     * having an extension in the file, removing trust in extensions, while keeping the original name
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param mixed $original_name
 | 
				
			||||||
 | 
					     * @param null|mixed $ext
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @throws ClientException
 | 
					     * @throws ClientException
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static function encodeFilename($original_name, string $filehash, $ext = null) : string
 | 
					    public static function encodeFilename($original_name, string $filehash, $ext = null): string
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (empty($original_name)) {
 | 
					        if (empty($original_name)) {
 | 
				
			||||||
            $original_name = _m('Untitled attachment');
 | 
					            $original_name = _m('Untitled attachment');
 | 
				
			||||||
@@ -268,6 +277,7 @@ class MediaFile
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Decode the new filename format
 | 
					     * Decode the new filename format
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @return false | null | string on failure, no match (old format) or original file name, respectively
 | 
					     * @return false | null | string on failure, no match (old format) or original file name, respectively
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static function decodeFilename(string $encoded_filename)
 | 
					    public static function decodeFilename(string $encoded_filename)
 | 
				
			||||||
@@ -319,19 +329,21 @@ class MediaFile
 | 
				
			|||||||
     * format ("{$hash}.{$ext}")
 | 
					     * format ("{$hash}.{$ext}")
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param string $param Form name
 | 
					     * @param string $param Form name
 | 
				
			||||||
     * @param Profile|null $scoped
 | 
					     * @param null|Profile $scoped
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @return ImageFile|MediaFile
 | 
					     * @return ImageFile|MediaFile
 | 
				
			||||||
     * @throws ClientException
 | 
					 | 
				
			||||||
     * @throws NoResultException
 | 
					     * @throws NoResultException
 | 
				
			||||||
     * @throws NoUploadedMediaException
 | 
					     * @throws NoUploadedMediaException
 | 
				
			||||||
     * @throws ServerException
 | 
					     * @throws ServerException
 | 
				
			||||||
     * @throws UnsupportedMediaException
 | 
					     * @throws UnsupportedMediaException
 | 
				
			||||||
     * @throws UseFileAsThumbnailException
 | 
					     * @throws UseFileAsThumbnailException
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @throws ClientException
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static function fromUpload(string $param='media', Profile $scoped=null)
 | 
					    public static function fromUpload(string $param = 'media', Profile $scoped = null)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // The existence of the "error" element means PHP has processed it properly even if it was ok.
 | 
					        // The existence of the "error" element means PHP has processed it properly even if it was ok.
 | 
				
			||||||
        if (!(isset($_FILES[$param]) && isset($_FILES[$param]['error']))) {
 | 
					        if (!(isset($_FILES[$param], $_FILES[$param]['error']))) {
 | 
				
			||||||
            throw new NoUploadedMediaException($param);
 | 
					            throw new NoUploadedMediaException($param);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -363,7 +375,7 @@ class MediaFile
 | 
				
			|||||||
                // TRANS: Client exception thrown when a file upload operation has been stopped by an extension.
 | 
					                // TRANS: Client exception thrown when a file upload operation has been stopped by an extension.
 | 
				
			||||||
                throw new ClientException(_m('File upload stopped by extension.'));
 | 
					                throw new ClientException(_m('File upload stopped by extension.'));
 | 
				
			||||||
            default:
 | 
					            default:
 | 
				
			||||||
                common_log(LOG_ERR, __METHOD__ . ": Unknown upload error " . $_FILES[$param]['error']);
 | 
					                common_log(LOG_ERR, __METHOD__ . ': Unknown upload error ' . $_FILES[$param]['error']);
 | 
				
			||||||
                // TRANS: Client exception thrown when a file upload operation has failed with an unknown reason.
 | 
					                // TRANS: Client exception thrown when a file upload operation has failed with an unknown reason.
 | 
				
			||||||
                throw new ClientException(_m('System error uploading file.'));
 | 
					                throw new ClientException(_m('System error uploading file.'));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -417,10 +429,10 @@ class MediaFile
 | 
				
			|||||||
                return new ImageFile(null, $filepath);
 | 
					                return new ImageFile(null, $filepath);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return new MediaFile($filepath, $mimetype, $filehash);
 | 
					        return new self($filepath, $mimetype, $filehash);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static function fromFilehandle($fh, Profile $scoped=null)
 | 
					    public static function fromFilehandle($fh, Profile $scoped = null)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $stream = stream_get_meta_data($fh);
 | 
					        $stream = stream_get_meta_data($fh);
 | 
				
			||||||
        // So far we're only handling filehandles originating from tmpfile(),
 | 
					        // So far we're only handling filehandles originating from tmpfile(),
 | 
				
			||||||
@@ -449,7 +461,7 @@ class MediaFile
 | 
				
			|||||||
                throw new ClientException(_m('File could not be moved to destination directory.'));
 | 
					                throw new ClientException(_m('File could not be moved to destination directory.'));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (!chmod($e->path, 0664)) {
 | 
					            if (!chmod($e->path, 0664)) {
 | 
				
			||||||
                common_log(LOG_ERR, 'Could not chmod uploaded file: '._ve($e->path));
 | 
					                common_log(LOG_ERR, 'Could not chmod uploaded file: ' . _ve($e->path));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            $filename = basename($file->getPath());
 | 
					            $filename = basename($file->getPath());
 | 
				
			||||||
@@ -467,14 +479,14 @@ class MediaFile
 | 
				
			|||||||
            $result = copy($stream['uri'], $filepath) && chmod($filepath, 0664);
 | 
					            $result = copy($stream['uri'], $filepath) && chmod($filepath, 0664);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!$result) {
 | 
					            if (!$result) {
 | 
				
			||||||
                common_log(LOG_ERR, 'File could not be moved (or chmodded) from '._ve($stream['uri']) . ' to ' . _ve($filepath));
 | 
					                common_log(LOG_ERR, 'File could not be moved (or chmodded) from ' . _ve($stream['uri']) . ' to ' . _ve($filepath));
 | 
				
			||||||
                // TRANS: Client exception thrown when a file upload operation fails because the file could
 | 
					                // TRANS: Client exception thrown when a file upload operation fails because the file could
 | 
				
			||||||
                // TRANS: not be moved from the temporary folder to the permanent file location.
 | 
					                // TRANS: not be moved from the temporary folder to the permanent file location.
 | 
				
			||||||
                throw new ClientException(_m('File could not be moved to destination directory.'));
 | 
					                throw new ClientException(_m('File could not be moved to destination directory.'));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return new MediaFile($filename, $mimetype, $filehash);
 | 
					        return new self($filename, $mimetype, $filehash);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -482,14 +494,16 @@ class MediaFile
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param string $filepath filesystem path as string (file must exist)
 | 
					     * @param string $filepath filesystem path as string (file must exist)
 | 
				
			||||||
     * @param bool $originalFilename (optional) for extension-based detection
 | 
					     * @param bool $originalFilename (optional) for extension-based detection
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @return string
 | 
					     * @return string
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @throws ClientException if type is known, but not supported for local uploads
 | 
					 | 
				
			||||||
     * @throws ServerException
 | 
					 | 
				
			||||||
     * @fixme this seems to tie a front-end error message in, kinda confusing
 | 
					     * @fixme this seems to tie a front-end error message in, kinda confusing
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
					     * @throws ServerException
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @throws ClientException if type is known, but not supported for local uploads
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static function getUploadedMimeType(string $filepath, $originalFilename=false)
 | 
					    public static function getUploadedMimeType(string $filepath, $originalFilename = false)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // We only accept filenames to existing files
 | 
					        // We only accept filenames to existing files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -534,7 +548,7 @@ class MediaFile
 | 
				
			|||||||
         *    due to security concerns, hence the function_usable() checks
 | 
					         *    due to security concerns, hence the function_usable() checks
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        if (DIRECTORY_SEPARATOR !== '\\') {
 | 
					        if (DIRECTORY_SEPARATOR !== '\\') {
 | 
				
			||||||
            $cmd = 'file --brief --mime '.escapeshellarg($filepath).' 2>&1';
 | 
					            $cmd = 'file --brief --mime ' . escapeshellarg($filepath) . ' 2>&1';
 | 
				
			||||||
            if (empty($mimetype) && function_exists('exec')) {
 | 
					            if (empty($mimetype) && function_exists('exec')) {
 | 
				
			||||||
                /* This might look confusing, as $mime is being populated with all of the output
 | 
					                /* This might look confusing, as $mime is being populated with all of the output
 | 
				
			||||||
                 * when set in the second parameter. However, we only need the last line, which is
 | 
					                 * when set in the second parameter. However, we only need the last line, which is
 | 
				
			||||||
@@ -581,13 +595,13 @@ class MediaFile
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Unclear types are such that we can't really tell by the auto
 | 
					        // Unclear types are such that we can't really tell by the auto
 | 
				
			||||||
        // detect what they are (.bin, .exe etc. are just "octet-stream")
 | 
					        // detect what they are (.bin, .exe etc. are just "octet-stream")
 | 
				
			||||||
        $unclearTypes = array('application/octet-stream',
 | 
					        $unclearTypes = ['application/octet-stream',
 | 
				
			||||||
            'application/vnd.ms-office',
 | 
					            'application/vnd.ms-office',
 | 
				
			||||||
            'application/zip',
 | 
					            'application/zip',
 | 
				
			||||||
            'text/plain',
 | 
					            'text/plain',
 | 
				
			||||||
            'text/html',  // Ironically, Wikimedia Commons' SVG_logo.svg is identified as text/html
 | 
					            'text/html',  // Ironically, Wikimedia Commons' SVG_logo.svg is identified as text/html
 | 
				
			||||||
            // TODO: for XML we could do better content-based sniffing too
 | 
					            // TODO: for XML we could do better content-based sniffing too
 | 
				
			||||||
                              'text/xml');
 | 
					            'text/xml',];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $supported = common_config('attachments', 'supported');
 | 
					        $supported = common_config('attachments', 'supported');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -630,10 +644,12 @@ class MediaFile
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Title for a file, to display in the interface (if there's no better title) and
 | 
					     * Title for a file, to display in the interface (if there's no better title) and
 | 
				
			||||||
     * for download filenames
 | 
					     * for download filenames
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param $file File object
 | 
					     * @param $file File object
 | 
				
			||||||
     * @returns string
 | 
					     * @returns string
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static function getDisplayName(File $file) : string {
 | 
					    public static function getDisplayName(File $file): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        if (empty($file->filename)) {
 | 
					        if (empty($file->filename)) {
 | 
				
			||||||
            return _m('Untitled attachment');
 | 
					            return _m('Untitled attachment');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user