Вход Регистрация
Файл: concrete5.7.5.6/concrete/vendor/zendframework/zend-http/src/Client.php
Строк: 1349
<?php
/**
 * Zend Framework (http://framework.zend.com/)
 *
 * @link      http://github.com/zendframework/zf2 for the canonical source repository
 * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
 * @license   http://framework.zend.com/license/new-bsd New BSD License
 */

namespace ZendHttp;

use 
ArrayIterator;
use 
Traversable;
use 
ZendStdlib;
use 
ZendStdlibArrayUtils;
use 
ZendStdlibErrorHandler;
use 
ZendUriHttp;

/**
 * Http client
 */
class Client implements StdlibDispatchableInterface
{
    
/**
     * @const string Supported HTTP Authentication methods
     */
    
const AUTH_BASIC  'basic';
    const 
AUTH_DIGEST 'digest';  // not implemented yet

    /**
     * @const string POST data encoding methods
     */
    
const ENC_URLENCODED 'application/x-www-form-urlencoded';
    const 
ENC_FORMDATA   'multipart/form-data';

    
/**
     * @const string DIGEST Authentication
     */
    
const DIGEST_REALM  'realm';
    const 
DIGEST_QOP    'qop';
    const 
DIGEST_NONCE  'nonce';
    const 
DIGEST_OPAQUE 'opaque';
    const 
DIGEST_NC     'nc';
    const 
DIGEST_CNONCE 'cnonce';

    
/**
     * @var Response
     */
    
protected $response;

    
/**
     * @var Request
     */
    
protected $request;

    
/**
     * @var Client/Adapter
     */
    
protected $adapter;

    
/**
     * @var array
     */
    
protected $auth = array();

    
/**
     * @var string
     */
    
protected $streamName null;

    
/**
     * @var array of HeaderSetCookie
     */
    
protected $cookies = array();

    
/**
     * @var string
     */
    
protected $encType '';

    
/**
     * @var Request
     */
    
protected $lastRawRequest null;

    
/**
     * @var Response
     */
    
protected $lastRawResponse null;

    
/**
     * @var int
     */
    
protected $redirectCounter 0;

    
/**
     * Configuration array, set using the constructor or using ::setOptions()
     *
     * @var array
     */
    
protected $config = array(
        
'maxredirects'    => 5,
        
'strictredirects' => false,
        
'useragent'       => 'ZendHttpClient',
        
'timeout'         => 10,
        
'adapter'         => 'ZendHttpClientAdapterSocket',
        
'httpversion'     => Request::VERSION_11,
        
'storeresponse'   => true,
        
'keepalive'       => false,
        
'outputstream'    => false,
        
'encodecookies'   => true,
        
'argseparator'    => null,
        
'rfc3986strict'   => false
    
);

    
/**
     * Fileinfo magic database resource
     *
     * This variable is populated the first time _detectFileMimeType is called
     * and is then reused on every call to this method
     *
     * @var resource
     */
    
protected static $fileInfoDb null;

    
/**
     * Constructor
     *
     * @param string $uri
     * @param array|Traversable $options
     */
    
public function __construct($uri null$options null)
    {
        if (
$uri !== null) {
            
$this->setUri($uri);
        }
        if (
$options !== null) {
            
$this->setOptions($options);
        }
    }

    
/**
     * Set configuration parameters for this HTTP client
     *
     * @param  array|Traversable $options
     * @return Client
     * @throws ClientExceptionInvalidArgumentException
     */
    
public function setOptions($options = array())
    {
        if (
$options instanceof Traversable) {
            
$options ArrayUtils::iteratorToArray($options);
        }
        if (!
is_array($options)) {
            throw new 
ClientExceptionInvalidArgumentException('Config parameter is not valid');
        }

        
/** Config Key Normalization */
        
foreach ($options as $k => $v) {
            
$this->config[str_replace(array('-''_'' ''.'), ''strtolower($k))] = $v// replace w/ normalized
        
}

        
// Pass configuration options to the adapter if it exists
        
if ($this->adapter instanceof ClientAdapterAdapterInterface) {
            
$this->adapter->setOptions($options);
        }

        return 
$this;
    }

    
/**
     * Load the connection adapter
     *
     * While this method is not called more than one for a client, it is
     * separated from ->request() to preserve logic and readability
     *
     * @param  ClientAdapterAdapterInterface|string $adapter
     * @return Client
     * @throws ClientExceptionInvalidArgumentException
     */
    
public function setAdapter($adapter)
    {
        if (
is_string($adapter)) {
            if (!
class_exists($adapter)) {
                throw new 
ClientExceptionInvalidArgumentException('Unable to locate adapter class "' $adapter '"');
            }
            
$adapter = new $adapter;
        }

        if (! 
$adapter instanceof ClientAdapterAdapterInterface) {
            throw new 
ClientExceptionInvalidArgumentException('Passed adapter is not a HTTP connection adapter');
        }

        
$this->adapter $adapter;
        
$config $this->config;
        unset(
$config['adapter']);
        
$this->adapter->setOptions($config);
        return 
$this;
    }

    
/**
     * Load the connection adapter
     *
     * @return ClientAdapterAdapterInterface $adapter
     */
    
public function getAdapter()
    {
        if (! 
$this->adapter) {
            
$this->setAdapter($this->config['adapter']);
        }

        return 
$this->adapter;
    }

    
/**
     * Set request
     *
     * @param Request $request
     * @return Client
     */
    
public function setRequest(Request $request)
    {
        
$this->request $request;
        return 
$this;
    }

    
/**
     * Get Request
     *
     * @return Request
     */
    
public function getRequest()
    {
        if (empty(
$this->request)) {
            
$this->request = new Request();
        }
        return 
$this->request;
    }

    
/**
     * Set response
     *
     * @param Response $response
     * @return Client
     */
    
public function setResponse(Response $response)
    {
        
$this->response $response;
        return 
$this;
    }

    
/**
     * Get Response
     *
     * @return Response
     */
    
public function getResponse()
    {
        if (empty(
$this->response)) {
            
$this->response = new Response();
        }
        return 
$this->response;
    }


    
/**
     * Get the last request (as a string)
     *
     * @return string
     */
    
public function getLastRawRequest()
    {
        return 
$this->lastRawRequest;
    }

    
/**
     * Get the last response (as a string)
     *
     * @return string
     */
    
public function getLastRawResponse()
    {
        return 
$this->lastRawResponse;
    }

    
/**
     * Get the redirections count
     *
     * @return int
     */
    
public function getRedirectionsCount()
    {
        return 
$this->redirectCounter;
    }

    
/**
     * Set Uri (to the request)
     *
     * @param string|Http $uri
     * @return Client
     */
    
public function setUri($uri)
    {
        if (!empty(
$uri)) {
            
// remember host of last request
            
$lastHost $this->getRequest()->getUri()->getHost();
            
$this->getRequest()->setUri($uri);

            
// if host changed, the HTTP authentication should be cleared for security
            // reasons, see #4215 for a discussion - currently authentication is also
            // cleared for peer subdomains due to technical limits
            
$nextHost $this->getRequest()->getUri()->getHost();
            if (!
preg_match('/' preg_quote($lastHost'/') . '$/i'$nextHost)) {
                
$this->clearAuth();
            }

            
// Set auth if username and password has been specified in the uri
            
if ($this->getUri()->getUser() && $this->getUri()->getPassword()) {
                
$this->setAuth($this->getUri()->getUser(), $this->getUri()->getPassword());
            }

            
// We have no ports, set the defaults
            
if (! $this->getUri()->getPort()) {
                
$this->getUri()->setPort(($this->getUri()->getScheme() == 'https' 443 80));
            }
        }
        return 
$this;
    }

    
/**
     * Get uri (from the request)
     *
     * @return Http
     */
    
public function getUri()
    {
        return 
$this->getRequest()->getUri();
    }

    
/**
     * Set the HTTP method (to the request)
     *
     * @param string $method
     * @return Client
     */
    
public function setMethod($method)
    {
        
$method $this->getRequest()->setMethod($method)->getMethod();

        if ((
$method == Request::METHOD_POST || $method == Request::METHOD_PUT ||
             
$method == Request::METHOD_DELETE || $method == Request::METHOD_PATCH)
             && empty(
$this->encType)) {
            
$this->setEncType(self::ENC_URLENCODED);
        }

        return 
$this;
    }

    
/**
     * Get the HTTP method
     *
     * @return string
     */
    
public function getMethod()
    {
        return 
$this->getRequest()->getMethod();
    }

    
/**
     * Set the query string argument separator
     *
     * @param string $argSeparator
     * @return Client
     */
    
public function setArgSeparator($argSeparator)
    {
        
$this->setOptions(array("argseparator" => $argSeparator));
        return 
$this;
    }

    
/**
     * Get the query string argument separator
     *
     * @return string
     */
    
public function getArgSeparator()
    {
        
$argSeparator $this->config['argseparator'];
        if (empty(
$argSeparator)) {
            
$argSeparator ini_get('arg_separator.output');
            
$this->setArgSeparator($argSeparator);
        }
        return 
$argSeparator;
    }

    
/**
     * Set the encoding type and the boundary (if any)
     *
     * @param string $encType
     * @param string $boundary
     * @return Client
     */
    
public function setEncType($encType$boundary null)
    {
        if (!empty(
$encType)) {
            if (!empty(
$boundary)) {
                
$this->encType $encType "; boundary={$boundary}";
            } else {
                
$this->encType $encType;
            }
        }
        return 
$this;
    }

    
/**
     * Get the encoding type
     *
     * @return string
     */
    
public function getEncType()
    {
        return 
$this->encType;
    }

    
/**
     * Set raw body (for advanced use cases)
     *
     * @param string $body
     * @return Client
     */
    
public function setRawBody($body)
    {
        
$this->getRequest()->setContent($body);
        return 
$this;
    }

    
/**
     * Set the POST parameters
     *
     * @param array $post
     * @return Client
     */
    
public function setParameterPost(array $post)
    {
        
$this->getRequest()->getPost()->fromArray($post);
        return 
$this;
    }

    
/**
     * Set the GET parameters
     *
     * @param array $query
     * @return Client
     */
    
public function setParameterGet(array $query)
    {
        
$this->getRequest()->getQuery()->fromArray($query);
        return 
$this;
    }

    
/**
     * Reset all the HTTP parameters (request, response, etc)
     *
     * @param  bool   $clearCookies  Also clear all valid cookies? (defaults to false)
     * @param  bool   $clearAuth     Also clear http authentication? (defaults to true)
     * @return Client
     */
    
public function resetParameters($clearCookies false /*, $clearAuth = true */)
    {
        
$clearAuth true;
        if (
func_num_args() > 1) {
            
$clearAuth func_get_arg(1);
        }

        
$uri $this->getUri();

        
$this->streamName      null;
        
$this->encType         null;
        
$this->request         null;
        
$this->response        null;
        
$this->lastRawRequest  null;
        
$this->lastRawResponse null;

        
$this->setUri($uri);

        if (
$clearCookies) {
            
$this->clearCookies();
        }

        if (
$clearAuth) {
            
$this->clearAuth();
        }

        return 
$this;
    }

    
/**
     * Return the current cookies
     *
     * @return array
     */
    
public function getCookies()
    {
        return 
$this->cookies;
    }

    
/**
     * Get the cookie Id (name+domain+path)
     *
     * @param  HeaderSetCookie|HeaderCookie $cookie
     * @return string|bool
     */
    
protected function getCookieId($cookie)
    {
        if ((
$cookie instanceof HeaderSetCookie) || ($cookie instanceof HeaderCookie)) {
            return 
$cookie->getName() . $cookie->getDomain() . $cookie->getPath();
        }
        return 
false;
    }

    
/**
     * Add a cookie
     *
     * @param array|ArrayIterator|HeaderSetCookie|string $cookie
     * @param string  $value
     * @param string  $expire
     * @param string  $path
     * @param string  $domain
     * @param  bool $secure
     * @param  bool $httponly
     * @param string  $maxAge
     * @param string  $version
     * @throws ExceptionInvalidArgumentException
     * @return Client
     */
    
public function addCookie($cookie$value null$expire null$path null$domain null$secure false$httponly true$maxAge null$version null)
    {
        if (
is_array($cookie) || $cookie instanceof ArrayIterator) {
            foreach (
$cookie as $setCookie) {
                if (
$setCookie instanceof HeaderSetCookie) {
                    
$this->cookies[$this->getCookieId($setCookie)] = $setCookie;
                } else {
                    throw new 
ExceptionInvalidArgumentException('The cookie parameter is not a valid Set-Cookie type');
                }
            }
        } elseif (
is_string($cookie) && $value !== null) {
            
$setCookie = new HeaderSetCookie($cookie$value$expire$path$domain$secure$httponly$maxAge$version);
            
$this->cookies[$this->getCookieId($setCookie)] = $setCookie;
        } elseif (
$cookie instanceof HeaderSetCookie) {
            
$this->cookies[$this->getCookieId($cookie)] = $cookie;
        } else {
            throw new 
ExceptionInvalidArgumentException('Invalid parameter type passed as Cookie');
        }
        return 
$this;
    }

    
/**
     * Set an array of cookies
     *
     * @param  array $cookies
     * @throws ExceptionInvalidArgumentException
     * @return Client
     */
    
public function setCookies($cookies)
    {
        if (
is_array($cookies)) {
            
$this->clearCookies();
            foreach (
$cookies as $name => $value) {
                
$this->addCookie($name$value);
            }
        } else {
            throw new 
ExceptionInvalidArgumentException('Invalid cookies passed as parameter, it must be an array');
        }
        return 
$this;
    }

    
/**
     * Clear all the cookies
     */
    
public function clearCookies()
    {
        
$this->cookies = array();
    }

    
/**
     * Set the headers (for the request)
     *
     * @param  Headers|array $headers
     * @throws ExceptionInvalidArgumentException
     * @return Client
     */
    
public function setHeaders($headers)
    {
        if (
is_array($headers)) {
            
$newHeaders = new Headers();
            
$newHeaders->addHeaders($headers);
            
$this->getRequest()->setHeaders($newHeaders);
        } elseif (
$headers instanceof Headers) {
            
$this->getRequest()->setHeaders($headers);
        } else {
            throw new 
ExceptionInvalidArgumentException('Invalid parameter headers passed');
        }
        return 
$this;
    }

    
/**
     * Check if exists the header type specified
     *
     * @param  string $name
     * @return bool
     */
    
public function hasHeader($name)
    {
        
$headers $this->getRequest()->getHeaders();

        if (
$headers instanceof Headers) {
            return 
$headers->has($name);
        }

        return 
false;
    }

    
/**
     * Get the header value of the request
     *
     * @param  string $name
     * @return string|bool
     */
    
public function getHeader($name)
    {
        
$headers $this->getRequest()->getHeaders();

        if (
$headers instanceof Headers) {
            if (
$headers->get($name)) {
                return 
$headers->get($name)->getFieldValue();
            }
        }
        return 
false;
    }

    
/**
     * Set streaming for received data
     *
     * @param string|bool $streamfile Stream file, true for temp file, false/null for no streaming
     * @return ZendHttpClient
     */
    
public function setStream($streamfile true)
    {
        
$this->setOptions(array("outputstream" => $streamfile));
        return 
$this;
    }

    
/**
     * Get status of streaming for received data
     * @return bool|string
     */
    
public function getStream()
    {
        if (
null !== $this->streamName) {
            return 
$this->streamName;
        }

        return 
$this->config['outputstream'];
    }

    
/**
     * Create temporary stream
     *
     * @throws ExceptionRuntimeException
     * @return resource
     */
    
protected function openTempStream()
    {
        
$this->streamName $this->config['outputstream'];

        if (!
is_string($this->streamName)) {
            
// If name is not given, create temp name
            
$this->streamName tempnam(
                isset(
$this->config['streamtmpdir']) ? $this->config['streamtmpdir'] : sys_get_temp_dir(),
                
'ZendHttpClient'
            
);
        }

        
ErrorHandler::start();
        
$fp    fopen($this->streamName"w+b");
        
$error ErrorHandler::stop();
        if (
false === $fp) {
            if (
$this->adapter instanceof ClientAdapterAdapterInterface) {
                
$this->adapter->close();
            }
            throw new 
ExceptionRuntimeException("Could not open temp file {$this->streamName}"0$error);
        }

        return 
$fp;
    }

    
/**
     * Create a HTTP authentication "Authorization:" header according to the
     * specified user, password and authentication method.
     *
     * @param string $user
     * @param string $password
     * @param string $type
     * @throws ExceptionInvalidArgumentException
     * @return Client
     */
    
public function setAuth($user$password$type self::AUTH_BASIC)
    {
        if (!
defined('self::AUTH_' strtoupper($type))) {
            throw new 
ExceptionInvalidArgumentException("Invalid or not supported authentication type: '$type'");
        }
        if (empty(
$user)) {
            throw new 
ExceptionInvalidArgumentException("The username cannot be empty");
        }

        
$this->auth = array (
            
'user'     => $user,
            
'password' => $password,
            
'type'     => $type

        
);

        return 
$this;
    }

    
/**
     * Clear http authentication
     */
    
public function clearAuth()
    {
        
$this->auth = array();
    }

    
/**
     * Calculate the response value according to the HTTP authentication type
     *
     * @see http://www.faqs.org/rfcs/rfc2617.html
     * @param string $user
     * @param string $password
     * @param string $type
     * @param array $digest
     * @param null|string $entityBody
     * @throws ExceptionInvalidArgumentException
     * @return string|bool
     */
    
protected function calcAuthDigest($user$password$type self::AUTH_BASIC$digest = array(), $entityBody null)
    {
        if (!
defined('self::AUTH_' strtoupper($type))) {
            throw new 
ExceptionInvalidArgumentException("Invalid or not supported authentication type: '$type'");
        }
        
$response false;
        switch (
strtolower($type)) {
            case 
self::AUTH_BASIC :
                
// In basic authentication, the user name cannot contain ":"
                
if (strpos($user':') !== false) {
                    throw new 
ExceptionInvalidArgumentException("The user name cannot contain ':' in Basic HTTP authentication");
                }
                
$response base64_encode($user ':' $password);
                break;
            case 
self::AUTH_DIGEST :
                if (empty(
$digest)) {
                    throw new 
ExceptionInvalidArgumentException("The digest cannot be empty");
                }
                foreach (
$digest as $key => $value) {
                    if (!
defined('self::DIGEST_' strtoupper($key))) {
                        throw new 
ExceptionInvalidArgumentException("Invalid or not supported digest authentication parameter: '$key'");
                    }
                }
                
$ha1 md5($user ':' $digest['realm'] . ':' $password);
                if (empty(
$digest['qop']) || strtolower($digest['qop']) == 'auth') {
                    
$ha2 md5($this->getMethod() . ':' $this->getUri()->getPath());
                } elseif (
strtolower($digest['qop']) == 'auth-int') {
                     if (empty(
$entityBody)) {
                        throw new 
ExceptionInvalidArgumentException("I cannot use the auth-int digest authentication without the entity body");
                     }
                     
$ha2 md5($this->getMethod() . ':' $this->getUri()->getPath() . ':' md5($entityBody));
                }
                if (empty(
$digest['qop'])) {
                    
$response md5($ha1 ':' $digest['nonce'] . ':' $ha2);
                } else {
                    
$response md5($ha1 ':' $digest['nonce'] . ':' $digest['nc']
                                    . 
':' $digest['cnonce'] . ':' $digest['qoc'] . ':' $ha2);
                }
                break;
        }
        return 
$response;
    }

    
/**
     * Dispatch
     *
     * @param StdlibRequestInterface $request
     * @param StdlibResponseInterface $response
     * @return StdlibResponseInterface
     */
    
public function dispatch(StdlibRequestInterface $requestStdlibResponseInterface $response null)
    {
        
$response $this->send($request);
        return 
$response;
    }

    
/**
     * Send HTTP request
     *
     * @param  Request $request
     * @return Response
     * @throws ExceptionRuntimeException
     * @throws ClientExceptionRuntimeException
     */
    
public function send(Request $request null)
    {
        if (
$request !== null) {
            
$this->setRequest($request);
        }

        
$this->redirectCounter 0;
        
$response null;

        
$adapter $this->getAdapter();

        
// Send the first request. If redirected, continue.
        
do {
            
// uri
            
$uri $this->getUri();

            
// query
            
$query $this->getRequest()->getQuery();

            if (!empty(
$query)) {
                
$queryArray $query->toArray();

                if (!empty(
$queryArray)) {
                    
$newUri $uri->toString();
                    
$queryString http_build_query($querynull$this->getArgSeparator());

                    if (
$this->config['rfc3986strict']) {
                        
$queryString str_replace('+''%20'$queryString);
                    }

                    if (
strpos($newUri'?') !== false) {
                        
$newUri .= $this->getArgSeparator() . $queryString;
                    } else {
                        
$newUri .= '?' $queryString;
                    }

                    
$uri = new Http($newUri);
                }
            }
            
// If we have no ports, set the defaults
            
if (!$uri->getPort()) {
                
$uri->setPort($uri->getScheme() == 'https' 443 80);
            }

            
// method
            
$method $this->getRequest()->getMethod();

            
// body
            
$body $this->prepareBody();

            
// headers
            
$headers $this->prepareHeaders($body$uri);

            
$secure $uri->getScheme() == 'https';

            
// cookies
            
$cookie $this->prepareCookies($uri->getHost(), $uri->getPath(), $secure);
            if (
$cookie->getFieldValue()) {
                
$headers['Cookie'] = $cookie->getFieldValue();
            }

            
// check that adapter supports streaming before using it
            
if (is_resource($body) && !($adapter instanceof ClientAdapterStreamInterface)) {
                throw new 
ClientExceptionRuntimeException('Adapter does not support streaming');
            }

            
// calling protected method to allow extending classes
            // to wrap the interaction with the adapter
            
$response $this->doRequest($uri$method$secure$headers$body);

            if (! 
$response) {
                throw new 
ExceptionRuntimeException('Unable to read response, or response is empty');
            }

            if (
$this->config['storeresponse']) {
                
$this->lastRawResponse $response;
            } else {
                
$this->lastRawResponse null;
            }

            if (
$this->config['outputstream']) {
                
$stream $this->getStream();
                if (!
is_resource($stream) && is_string($stream)) {
                    
$stream fopen($stream'r');
                }
                
$streamMetaData stream_get_meta_data($stream);
                if (
$streamMetaData['seekable']) {
                    
rewind($stream);
                }
                
// cleanup the adapter
                
$adapter->setOutputStream(null);
                
$response ResponseStream::fromStream($response$stream);
                
$response->setStreamName($this->streamName);
                if (!
is_string($this->config['outputstream'])) {
                    
// we used temp name, will need to clean up
                    
$response->setCleanup(true);
                }
            } else {
                
$response $this->getResponse()->fromString($response);
            }

            
// Get the cookies from response (if any)
            
$setCookies $response->getCookie();
            if (!empty(
$setCookies)) {
                
$this->addCookie($setCookies);
            }

            
// If we got redirected, look for the Location header
            
if ($response->isRedirect() && ($response->getHeaders()->has('Location'))) {

                
// Avoid problems with buggy servers that add whitespace at the
                // end of some headers
                
$location trim($response->getHeaders()->get('Location')->getFieldValue());

                
// Check whether we send the exact same request again, or drop the parameters
                // and send a GET request
                
if ($response->getStatusCode() == 303 ||
                   ((! 
$this->config['strictredirects']) && ($response->getStatusCode() == 302 ||
                       
$response->getStatusCode() == 301))) {

                    
$this->resetParameters(falsefalse);
                    
$this->setMethod(Request::METHOD_GET);
                }


                
// If we got a well formed absolute URI
                
if (($scheme substr($location06)) &&
                        (
$scheme == 'http:/' || $scheme == 'https:')) {
                    
// setURI() clears parameters if host changed, see #4215
                    
$this->setUri($location);
                } else {

                    
// Split into path and query and set the query
                    
if (strpos($location'?') !== false) {
                        list(
$location$query) = explode('?'$location2);
                    } else {
                        
$query '';
                    }
                    
$this->getUri()->setQuery($query);

                    
// Else, if we got just an absolute path, set it
                    
if (strpos($location'/') === 0) {
                        
$this->getUri()->setPath($location);
                        
// Else, assume we have a relative path
                    
} else {
                        
// Get the current path directory, removing any trailing slashes
                        
$path $this->getUri()->getPath();
                        
$path rtrim(substr($path0strrpos($path'/')), "/");
                        
$this->getUri()->setPath($path '/' $location);
                    }
                }
                ++
$this->redirectCounter;

            } else {
                
// If we didn't get any location, stop redirecting
                
break;
            }

        } while (
$this->redirectCounter <= $this->config['maxredirects']);

        
$this->response $response;
        return 
$response;
    }

    
/**
     * Fully reset the HTTP client (auth, cookies, request, response, etc.)
     *
     * @return Client
     */
    
public function reset()
    {
       
$this->resetParameters();
       
$this->clearAuth();
       
$this->clearCookies();

       return 
$this;
    }

    
/**
     * Set a file to upload (using a POST request)
     *
     * Can be used in two ways:
     *
     * 1. $data is null (default): $filename is treated as the name if a local file which
     * will be read and sent. Will try to guess the content type using mime_content_type().
     * 2. $data is set - $filename is sent as the file name, but $data is sent as the file
     * contents and no file is read from the file system. In this case, you need to
     * manually set the Content-Type ($ctype) or it will default to
     * application/octet-stream.
     *
     * @param  string $filename Name of file to upload, or name to save as
     * @param  string $formname Name of form element to send as
     * @param  string $data Data to send (if null, $filename is read and sent)
     * @param  string $ctype Content type to use (if $data is set and $ctype is
     *                null, will be application/octet-stream)
     * @return Client
     * @throws ExceptionRuntimeException
     */
    
public function setFileUpload($filename$formname$data null$ctype null)
    {
        if (
$data === null) {
            
ErrorHandler::start();
            
$data  file_get_contents($filename);
            
$error ErrorHandler::stop();
            if (
$data === false) {
                throw new 
ExceptionRuntimeException("Unable to read file '{$filename}' for upload"0$error);
            }
            if (!
$ctype) {
                
$ctype $this->detectFileMimeType($filename);
            }
        }

        
$this->getRequest()->getFiles()->set($filename, array(
            
'formname' => $formname,
            
'filename' => basename($filename),
            
'ctype' => $ctype,
            
'data' => $data
        
));

        return 
$this;
    }

    
/**
     * Remove a file to upload
     *
     * @param  string $filename
     * @return bool
     */
    
public function removeFileUpload($filename)
    {
        
$file $this->getRequest()->getFiles()->get($filename);
        if (!empty(
$file)) {
            
$this->getRequest()->getFiles()->set($filenamenull);
            return 
true;
        }
        return 
false;
    }

    
/**
     * Prepare Cookies
     *
     * @param   string $domain
     * @param   string $path
     * @param   bool $secure
     * @return  HeaderCookie|bool
     */
    
protected function prepareCookies($domain$path$secure)
    {
        
$validCookies = array();

        if (!empty(
$this->cookies)) {
            foreach (
$this->cookies as $id => $cookie) {
                if (
$cookie->isExpired()) {
                    unset(
$this->cookies[$id]);
                    continue;
                }

                if (
$cookie->isValidForRequest($domain$path$secure)) {
                    
// OAM hack some domains try to set the cookie multiple times
                    
$validCookies[$cookie->getName()] = $cookie;
                }
            }
        }

        
$cookies HeaderCookie::fromSetCookieArray($validCookies);
        
$cookies->setEncodeValue($this->config['encodecookies']);

        return 
$cookies;
    }

    
/**
     * Prepare the request headers
     *
     * @param resource|string $body
     * @param Http $uri
     * @throws ExceptionRuntimeException
     * @return array
     */
    
protected function prepareHeaders($body$uri)
    {
        
$headers = array();

        
// Set the host header
        
if ($this->config['httpversion'] == Request::VERSION_11) {
            
$host $uri->getHost();
            
// If the port is not default, add it
            
if (!(($uri->getScheme() == 'http' && $uri->getPort() == 80) ||
                (
$uri->getScheme() == 'https' && $uri->getPort() == 443))) {
                
$host .= ':' $uri->getPort();
            }

            
$headers['Host'] = $host;
        }

        
// Set the connection header
        
if (!$this->getRequest()->getHeaders()->has('Connection')) {
            if (!
$this->config['keepalive']) {
                
$headers['Connection'] = 'close';
            }
        }

        
// Set the Accept-encoding header if not set - depending on whether
        // zlib is available or not.
        
if (!$this->getRequest()->getHeaders()->has('Accept-Encoding')) {
            if (
function_exists('gzinflate')) {
                
$headers['Accept-Encoding'] = 'gzip, deflate';
            } else {
                
$headers['Accept-Encoding'] = 'identity';
            }
        }


        
// Set the user agent header
        
if (!$this->getRequest()->getHeaders()->has('User-Agent') && isset($this->config['useragent'])) {
            
$headers['User-Agent'] = $this->config['useragent'];
        }

        
// Set HTTP authentication if needed
        
if (!empty($this->auth)) {
            switch (
$this->auth['type']) {
                case 
self::AUTH_BASIC :
                    
$auth $this->calcAuthDigest($this->auth['user'], $this->auth['password'], $this->auth['type']);
                    if (
$auth !== false) {
                        
$headers['Authorization'] = 'Basic ' $auth;
                    }
                    break;
                case 
self::AUTH_DIGEST :
                    throw new 
ExceptionRuntimeException("The digest authentication is not implemented yet");
            }
        }

        
// Content-type
        
$encType $this->getEncType();
        if (!empty(
$encType)) {
            
$headers['Content-Type'] = $encType;
        }

        if (!empty(
$body)) {
            if (
is_resource($body)) {
                
$fstat fstat($body);
                
$headers['Content-Length'] = $fstat['size'];
            } else {
                
$headers['Content-Length'] = strlen($body);
            }
        }

        
// Merge the headers of the request (if any)
        // here we need right 'http field' and not lowercase letters
        
$requestHeaders $this->getRequest()->getHeaders();
        foreach (
$requestHeaders as $requestHeaderElement) {
            
$headers[$requestHeaderElement->getFieldName()] = $requestHeaderElement->getFieldValue();
        }
        return 
$headers;
    }


    
/**
     * Prepare the request body (for PATCH, POST and PUT requests)
     *
     * @return string
     * @throws ZendHttpClientExceptionRuntimeException
     */
    
protected function prepareBody()
    {
        
// According to RFC2616, a TRACE request should not have a body.
        
if ($this->getRequest()->isTrace()) {
            return 
'';
        }

        
$rawBody $this->getRequest()->getContent();
        if (!empty(
$rawBody)) {
            return 
$rawBody;
        }

        
$body '';
        
$totalFiles 0;

        if (!
$this->getRequest()->getHeaders()->has('Content-Type')) {
            
$totalFiles count($this->getRequest()->getFiles()->toArray());
            
// If we have files to upload, force encType to multipart/form-data
            
if ($totalFiles 0) {
                
$this->setEncType(self::ENC_FORMDATA);
            }
        } else {
            
$this->setEncType($this->getHeader('Content-Type'));
        }

        
// If we have POST parameters or files, encode and add them to the body
        
if (count($this->getRequest()->getPost()->toArray()) > || $totalFiles 0) {
            if (
stripos($this->getEncType(), self::ENC_FORMDATA) === 0) {
                
$boundary '---ZENDHTTPCLIENT-' md5(microtime());
                
$this->setEncType(self::ENC_FORMDATA$boundary);

                
// Get POST parameters and encode them
                
$params self::flattenParametersArray($this->getRequest()->getPost()->toArray());
                foreach (
$params as $pp) {
                    
$body .= $this->encodeFormData($boundary$pp[0], $pp[1]);
                }

                
// Encode files
                
foreach ($this->getRequest()->getFiles()->toArray() as $file) {
                    
$fhead = array('Content-Type' => $file['ctype']);
                    
$body .= $this->encodeFormData($boundary$file['formname'], $file['data'], $file['filename'], $fhead);
                }
                
$body .= "--{$boundary}--rn";
            } elseif (
stripos($this->getEncType(), self::ENC_URLENCODED) === 0) {
                
// Encode body as application/x-www-form-urlencoded
                
$body http_build_query($this->getRequest()->getPost()->toArray());
            } else {
                throw new 
ClientExceptionRuntimeException("Cannot handle content type '{$this->encType}' automatically");
            }
        }

        return 
$body;
    }


    
/**
     * Attempt to detect the MIME type of a file using available extensions
     *
     * This method will try to detect the MIME type of a file. If the fileinfo
     * extension is available, it will be used. If not, the mime_magic
     * extension which is deprecated but is still available in many PHP setups
     * will be tried.
     *
     * If neither extension is available, the default application/octet-stream
     * MIME type will be returned
     *
     * @param string $file File path
     * @return string MIME type
     */
    
protected function detectFileMimeType($file)
    {
        
$type null;

        
// First try with fileinfo functions
        
if (function_exists('finfo_open')) {
            if (static::
$fileInfoDb === null) {
                
ErrorHandler::start();
                static::
$fileInfoDb finfo_open(FILEINFO_MIME);
                
ErrorHandler::stop();
            }

            if (static::
$fileInfoDb) {
                
$type finfo_file(static::$fileInfoDb$file);
            }

        } elseif (
function_exists('mime_content_type')) {
            
$type mime_content_type($file);
        }

        
// Fallback to the default application/octet-stream
        
if (! $type) {
            
$type 'application/octet-stream';
        }

        return 
$type;
    }

    
/**
     * Encode data to a multipart/form-data part suitable for a POST request.
     *
     * @param string $boundary
     * @param string $name
     * @param mixed $value
     * @param string $filename
     * @param array $headers Associative array of optional headers @example ("Content-Transfer-Encoding" => "binary")
     * @return string
     */
    
public function encodeFormData($boundary$name$value$filename null$headers = array())
    {
        
$ret "--{$boundary}rn" .
            
'Content-Disposition: form-data; name="' $name '"';

        if (
$filename) {
            
$ret .= '; filename="' $filename '"';
        }
        
$ret .= "rn";

        foreach (
$headers as $hname => $hvalue) {
            
$ret .= "{$hname}{$hvalue}rn";
        }
        
$ret .= "rn";
        
$ret .= "{$value}rn";

        return 
$ret;
    }

    
/**
     * Convert an array of parameters into a flat array of (key, value) pairs
     *
     * Will flatten a potentially multi-dimentional array of parameters (such
     * as POST parameters) into a flat array of (key, value) paris. In case
     * of multi-dimentional arrays, square brackets ([]) will be added to the
     * key to indicate an array.
     *
     * @since 1.9
     *
     * @param array $parray
     * @param string $prefix
     * @return array
     */
    
protected function flattenParametersArray($parray$prefix null)
    {
        if (!
is_array($parray)) {
            return 
$parray;
        }

        
$parameters = array();

        foreach (
$parray as $name => $value) {
            
// Calculate array key
            
if ($prefix) {
                if (
is_int($name)) {
                    
$key $prefix '[]';
                } else {
                    
$key $prefix "[$name]";
                }
            } else {
                
$key $name;
            }

            if (
is_array($value)) {
                
$parameters array_merge($parameters$this->flattenParametersArray($value$key));

            } else {
                
$parameters[] = array($key$value);
            }
        }

        return 
$parameters;
    }

    
/**
     * Separating this from send method allows subclasses to wrap
     * the interaction with the adapter
     *
     * @param Http $uri
     * @param string $method
     * @param  bool $secure
     * @param array $headers
     * @param string $body
     * @return string the raw response
     * @throws ExceptionRuntimeException
     */
    
protected function doRequest(Http $uri$method$secure false$headers = array(), $body '')
    {
        
// Open the connection, send the request and read the response
        
$this->adapter->connect($uri->getHost(), $uri->getPort(), $secure);

        if (
$this->config['outputstream']) {
            if (
$this->adapter instanceof ClientAdapterStreamInterface) {
                
$stream $this->openTempStream();
                
$this->adapter->setOutputStream($stream);
            } else {
                throw new 
ExceptionRuntimeException('Adapter does not support streaming');
            }
        }
        
// HTTP connection
        
$this->lastRawRequest $this->adapter->write($method,
            
$uri$this->config['httpversion'], $headers$body);

        return 
$this->adapter->read();
    }

    
/**
     * Create a HTTP authentication "Authorization:" header according to the
     * specified user, password and authentication method.
     *
     * @see http://www.faqs.org/rfcs/rfc2617.html
     * @param string $user
     * @param string $password
     * @param string $type
     * @return string
     * @throws ClientExceptionInvalidArgumentException
     */
    
public static function encodeAuthHeader($user$password$type self::AUTH_BASIC)
    {
        
$authHeader null;

        switch (
$type) {
            case 
self::AUTH_BASIC:
                
// In basic authentication, the user name cannot contain ":"
                
if (strpos($user':') !== false) {
                    throw new 
ClientExceptionInvalidArgumentException("The user name cannot contain ':' in 'Basic' HTTP authentication");
                }

                
$authHeader 'Basic ' base64_encode($user ':' $password);
                break;

            
//case self::AUTH_DIGEST:
                /**
                * @todo Implement digest authentication
                */
                //    break;

            
default:
                throw new 
ClientExceptionInvalidArgumentException("Not a supported HTTP authentication type: '$type'");

        }
        return 
$authHeader;
    }
}
Онлайн: 3
Реклама