Вход Регистрация
Файл: 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 $inputXenForo_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'true500);
                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'true500);
            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->_urltrue302);
            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();
    }
}
Онлайн: 1
Реклама