Вход Регистрация
Файл: library/XenForo/ProxyOutput.php
Строк: 286
<?php

/**
 * This class is entirely self sufficient. It handles parsing the input,
 * getting the data, rendering it, and manipulating HTTP headers.
 *
 * @package XenForo_ProxyOutput
 */
class XenForo_ProxyOutput
{
    
/**
     * @var Zend_Controller_Response_Http
     */
    
protected $_response = null;

    
/**
     * @var XenForo_Dependencies_Abstract
     */
    
protected $_dependencies;

    protected 
$_mode = null;

    protected 
$_url = null;

    protected 
$_hash = null;

    
/**
     * Constructor.
     *
     * @param array $input Array of input (intended to normally be $_REQUEST)
     * @param XenForo_Dependencies_Abstract $dependencies
     */
    
public function __construct(array $input, XenForo_Dependencies_Abstract $dependencies)
    {
        
$this->_dependencies = $dependencies;
        
$this->_response = new Zend_Controller_Response_Http();

        if (!empty(
$input['image']))
        {
            
$this->_mode = 'image';
            
$this->_url = trim(strval($input['image']));
        }

        if (!empty(
$input['link']))
        {
            
$this->_mode = 'link';
            
$this->_url = trim(strval($input['link']));
        }

        if (!empty(
$input['hash']))
        {
            
$this->_hash = trim(strval($input['hash']));
        }
    }

    public function 
isValidRequest(&$error = null)
    {
        
$error = false;

        if (!
$this->_url || !preg_match('#^https?://#i', $this->_url))
        {
            
$error = 'invalid_url';
            return 
false;
        }

        
$urlParts = @parse_url($this->_url);
        if (!
$urlParts || empty($urlParts['host']))
        {
            
$error = 'invalid_url';
            return 
false;
        }

        
$hash = hash_hmac('md5', $this->_url,
            
XenForo_Application::getConfig()->globalSalt . XenForo_Application::getOptions()->imageLinkProxyKey
        
);
        if (
$hash !== $this->_hash)
        {
            
$error = 'invalid_hash';
            return 
false;
        }

        if (!
$this->isValidReferrer())
        {
            
$error = 'invalid_referrer';
            return 
false;
        }

        return 
true;
    }

    
/**
     * Attempts to determine whether the request is referred from the expected host.
     * By default, only supports the current host.
     *
     * @return boolean
     */
    
public function isValidReferrer()
    {
        if (!empty(
$_SERVER['HTTP_REFERER']) && $referer = $_SERVER['HTTP_REFERER'])
        {
            
$refererParts = @parse_url($referer);
            if (
$refererParts && !empty($refererParts['host']))
            {
                
$paths = XenForo_Application::get('requestPaths');
                
$requestParts = @parse_url($paths['fullUri']);

                if (
$requestParts && !empty($requestParts['host']))
                {
                    if (
$refererParts['host'] != $requestParts['host'])
                    {
                        
// referer is not the same as request host
                        
return false;
                    }
                }
            }
        }

        
// either we have the same host and referer, or we just don't know...
        
return true;
    }

    public function 
output()
    {
        
$isValidRequest = $this->isValidRequest($error);

        switch (
$this->_mode)
        {
            case 
'image':
                
$this->_outputImage($error);
                break;

            case 
'link':
                
$this->_outputLinkRedirect($error);
                break;

            default:
                
header('Content-Type: text/html; charset=utf-8', true, 500);
                die(
'Unknown proxy mode');
        }
    }

    
/**
     * Tells the browser that the data should be downloaded (rather than displayed)
     * using the specified file name.
     *
     * @param string $fileName
     * @param boolean $inline True if the attachment should be shown inline - use with caution!
     */
    
protected function _setDownloadFileName($fileName, $inline = false)
    {
        
$type = ($inline ? 'inline' : 'attachment');

        
$this->_response->setHeader('Content-Disposition',
            
$type . '; filename="' . str_replace('"', '', $fileName) . '"',
            
true
        
);
    }

    protected function 
_isLocalHost($host)
    {
        return (
            
preg_match('#^(127.|192.168.|10.|172.(1[6789]|2|3[01])|169.254.)#', $host)
            || 
preg_match('#^localhost(.localdomain)?$#i', $host)
        );
    }

    
/**
     * Intercept a request for a cached image from the proxy and output it
     *
     * @param string|bool $error If non-false, an error that occurred when validating the request
     */
    
protected function _outputImage($error)
    {
        if (empty(
XenForo_Application::getOptions()->imageLinkProxy['images']))
        {
            
$error = 'disabled';
        }

        
/* @var $proxyModel XenForo_Model_ImageProxy */
        
$proxyModel = XenForo_Model::create('XenForo_Model_ImageProxy');

        
$image = false;

        if (!
$error)
        {
            
$urlParts = parse_url($this->_url);
            if (
$this->_isLocalHost($urlParts['host'])
                && (empty(
$_SERVER['SERVER_NAME']) || !$this->_isLocalHost($_SERVER['SERVER_NAME']))
            )
            {
                
$error = 'local_url';
            }
        }

        if (!
$error)
        {
            
$image = $proxyModel->getImage($this->_url);
            if (
$image)
            {
                
$image = $proxyModel->prepareImage($image);
                if (
$image['use_file'])
                {
                    
$proxyModel->logImageView($image);

                    
$eTag = !empty($_SERVER['HTTP_IF_NONE_MATCH']) ? $_SERVER['HTTP_IF_NONE_MATCH'] : null;
                    if (
$eTag && $eTag == '"' . $image['fetch_date'] . '"')
                    {
                        
$this->_response->setHttpResponseCode(304);
                        
$this->_response->clearHeader('Last-Modified');
                        
$this->_response->sendHeaders();
                        return;
                    }
                }
                else
                {
                    
$image = false;
                    
$error = 'retrieve_failed';
                }
            }
        }

        if (!
$image)
        {
            
$image = $proxyModel->getPlaceHolderImage();
        }

        
$imageTypes = array(
            
'image/gif',
            
'image/jpeg',
            
'image/pjpeg',
            
'image/png'
        
);

        if (
in_array($image['mime_type'], $imageTypes))
        {
            
$this->_response->setHeader('Content-type', $image['mime_type'], true);
            
$this->_setDownloadFileName($image['file_name'], true);
        }
        else
        {
            
$this->_response->setHeader('Content-type', 'application/octet-stream', true);
            
$this->_setDownloadFileName($image['file_name']);
        }

        
$this->_response->setHeader('ETag', '"' . $image['fetch_date'] . '"', true);
        if (
$image['file_size'])
        {
            
$this->_response->setHeader('Content-Length', $image['file_size'], true);
        }
        
$this->_response->setHeader('X-Content-Type-Options', 'nosniff');

        if (
$error)
        {
            
$this->_response->setHeader('X-Proxy-Error', $error);
        }

        
$this->_response->sendHeaders();

        
$imageData = new XenForo_FileOutput($image['file_path']);
        
$imageData->output();
    }

    
/**
     * Intercept a request for a link redirect
     *
     * @param string|bool $error If non-false, an error that occurred when validating the request
     */
    
protected function _outputLinkRedirect($error)
    {
        if (
$error === 'invalid_url')
        {
            
header('Content-Type: text/html; utf-8', true, 500);
            die(
'Invalid URL');
        }

        if (empty(
XenForo_Application::getOptions()->imageLinkProxy['links']))
        {
            
$error = 'disabled';
        }

        if (!
$error)
        {
            
/* @var $proxyModel XenForo_Model_LinkProxy */
            
$proxyModel = XenForo_Model::create('XenForo_Model_LinkProxy');
            
$proxyModel->logVisit($this->_url);

            
header('Location: ' . $this->_url, true, 302);
            exit;
        }

        
$request = new Zend_Controller_Request_Http();

        
XenForo_Session::startPublicSession($request);

        
$this->_dependencies->preRenderView();

        if (!
preg_match('#^https?://#i', $this->_url))
        {
            throw new 
Exception('Unsafe proxy URL: ' . $this->_url);
        }

        
$printable = urldecode($this->_url);
        if (!
preg_match('/./u', $printable))
        {
            
$printable = $this->_url;
        }

        
$renderer = new XenForo_ViewRenderer_HtmlPublic($this->_dependencies, $this->_response, $request);
        
$contents = $renderer->createTemplateObject('link_redirect', array(
            
'url' => $this->_url,
            
'printable' => $printable,
            
'parts' => parse_url($this->_url)
        ));
        
$containerParams = $this->_dependencies->getEffectiveContainerParams(array(), $request);

        
$output = $renderer->renderContainer($contents, $containerParams);

        
$extraHeaders = XenForo_Application::gzipContentIfSupported($output);
        foreach (
$extraHeaders AS $extraHeader)
        {
            
$this->_response->setHeader($extraHeader[0], $extraHeader[1], $extraHeader[2]);
        }

        
$this->_response->setHeader('X-Proxy-Error', $error);

        
$this->_response->sendHeaders();
        echo 
$output;
    }

    
/**
     * Static helper to execute a full request for proxy output
     */
    
public static function run()
    {
        
$dependencies = new XenForo_Dependencies_Public();
        
$dependencies->preLoadData();

        
$class = XenForo_Application::resolveDynamicClass(__CLASS__);

        
$proxyOutput = new $class($_REQUEST, $dependencies);
        
$proxyOutput->output();
    }
}
Онлайн: 2
Реклама