Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
75.00% covered (warning)
75.00%
3 / 4
CRAP
92.42% covered (success)
92.42%
61 / 66
remote
0.00% covered (danger)
0.00%
0 / 1
75.00% covered (warning)
75.00%
3 / 4
21.19
92.42% covered (success)
92.42%
61 / 66
 __construct
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
7 / 7
 upload
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 remote_upload
0.00% covered (danger)
0.00%
0 / 1
13.27
88.37% covered (warning)
88.37%
38 / 43
 get_max_file_size
100.00% covered (success)
100.00%
1 / 1
6
100.00% covered (success)
100.00%
14 / 14
<?php
/**
 *
 * This file is part of the phpBB Forum Software package.
 *
 * @copyright (c) phpBB Limited <https://www.phpbb.com>
 * @license GNU General Public License, version 2 (GPL-2.0)
 *
 * For full copyright and license information, please see
 * the docs/CREDITS.txt file.
 *
 */
namespace phpbb\files\types;
use bantu\IniGetWrapper\IniGetWrapper;
use phpbb\config\config;
use phpbb\files\factory;
use phpbb\files\filespec;
use phpbb\language\language;
use phpbb\request\request_interface;
class remote extends base
{
    /** @var config phpBB config */
    protected $config;
    /** @var factory Files factory */
    protected $factory;
    /** @var language */
    protected $language;
    /** @var IniGetWrapper */
    protected $php_ini;
    /** @var request_interface */
    protected $request;
    /** @var \phpbb\files\upload */
    protected $upload;
    /** @var string phpBB root path */
    protected $phpbb_root_path;
    /**
     * Construct a form upload type
     *
     * @param config $config phpBB config
     * @param factory $factory Files factory
     * @param language $language Language class
     * @param IniGetWrapper $php_ini ini_get() wrapper
     * @param request_interface $request Request object
     * @param string $phpbb_root_path phpBB root path
     */
    public function __construct(config $config, factory $factory, language $language, IniGetWrapper $php_ini, request_interface $request, $phpbb_root_path)
    {
        $this->config = $config;
        $this->factory = $factory;
        $this->language = $language;
        $this->php_ini = $php_ini;
        $this->request = $request;
        $this->phpbb_root_path = $phpbb_root_path;
    }
    /**
     * {@inheritdoc}
     */
    public function upload()
    {
        $args = func_get_args();
        return $this->remote_upload($args[0]);
    }
    /**
     * Remote upload method
     * Uploads file from given url
     *
     * @param string $upload_url URL pointing to file to upload, for example http://www.foobar.com/example.gif
     * @return filespec $file Object "filespec" is returned, all further operations can be done with this object
     * @access public
     */
    protected function remote_upload($upload_url)
    {
        $upload_ary = array();
        $upload_ary['local_mode'] = true;
        if (!preg_match('#^(https?://).*?\.(' . implode('|', $this->upload->allowed_extensions) . ')$#i', $upload_url, $match))
        {
            return $this->factory->get('filespec')->set_error($this->language->lang($this->upload->error_prefix . 'URL_INVALID'));
        }
        $url = parse_url($upload_url);
        $upload_ary['type'] = 'application/octet-stream';
        $url['path'] = explode('.', $url['path']);
        $ext = array_pop($url['path']);
        $url['path'] = implode('', $url['path']);
        $upload_ary['name'] = utf8_basename($url['path']) . (($ext) ? '.' . $ext : '');
        $remote_max_filesize = $this->get_max_file_size();
        $guzzle_options = [
            'timeout'            => $this->upload->upload_timeout,
            'connect_timeout'    => $this->upload->upload_timeout,
            'verify'            => !empty($this->config['remote_upload_verify']) ? (bool) $this->config['remote_upload_verify'] : false,
        ];
        $client = new \GuzzleHttp\Client($guzzle_options);
        try
        {
            $response = $client->get($upload_url, $guzzle_options);
        }
        catch (\GuzzleHttp\Exception\ClientException $clientException)
        {
            return $this->factory->get('filespec')->set_error($this->upload->error_prefix . 'URL_NOT_FOUND');
        }
        catch (\GuzzleHttp\Exception\RequestException $requestException)
        {
            if (strpos($requestException->getMessage(), 'cURL error 28') !== false || preg_match('/408|504/', $requestException->getCode()))
            {
                return $this->factory->get('filespec')->set_error($this->upload->error_prefix . 'REMOTE_UPLOAD_TIMEOUT');
            }
            else
            {
                return $this->factory->get('filespec')->set_error($this->language->lang($this->upload->error_prefix . 'NOT_UPLOADED'));
            }
        }
        catch (\Exception $e)
        {
            return $this->factory->get('filespec')->set_error($this->language->lang($this->upload->error_prefix . 'NOT_UPLOADED'));
        }
        $content_length = $response->getBody()->getSize();
        if ($remote_max_filesize && $content_length > $remote_max_filesize)
        {
            $max_filesize = get_formatted_filesize($remote_max_filesize, false);
            return $this->factory->get('filespec')->set_error($this->language->lang($this->upload->error_prefix . 'WRONG_FILESIZE', $max_filesize['value'], $max_filesize['unit']));
        }
        if ($content_length == 0)
        {
            return $this->factory->get('filespec')->set_error($this->upload->error_prefix . 'EMPTY_REMOTE_DATA');
        }
        $data = $response->getBody();
        $filename = tempnam(sys_get_temp_dir(), unique_id() . '-');
        if (!($fp = @fopen($filename, 'wb')))
        {
            return $this->factory->get('filespec')->set_error($this->upload->error_prefix . 'NOT_UPLOADED');
        }
        $upload_ary['size'] = fwrite($fp, $data);
        fclose($fp);
        unset($data);
        $upload_ary['tmp_name'] = $filename;
        /** @var filespec $file */
        $file = $this->factory->get('filespec')
            ->set_upload_ary($upload_ary)
            ->set_upload_namespace($this->upload);
        $this->upload->common_checks($file);
        return $file;
    }
    /**
     * Get maximum file size for remote uploads
     *
     * @return int Maximum file size
     */
    protected function get_max_file_size()
    {
        $max_file_size = $this->upload->max_filesize;
        if (!$max_file_size)
        {
            $max_file_size = $this->php_ini->getString('upload_max_filesize');
            if (!empty($max_file_size))
            {
                $unit = strtolower(substr($max_file_size, -1, 1));
                $max_file_size = (int) $max_file_size;
                switch ($unit)
                {
                    case 'g':
                        $max_file_size *= 1024;
                    // no break
                    case 'm':
                        $max_file_size *= 1024;
                    // no break
                    case 'k':
                        $max_file_size *= 1024;
                    // no break
                }
            }
        }
        return $max_file_size;
    }
}