/** * Get an instance of a Transporter. * * See HPCloud::Transport::CURLTransport and HPCloud::Transport::PHPStreamTransport * for implementations of an HPCloud::Transport::Transporter. * * To set the transport, the suggested method is this: * * @code * <?php * // Set the 'transport' config option. * $settings = array( * // Make sure you use the entire namespace, and that * // your classloader can find this namespace. * 'transport' => '\HPCloud\Transport\CURLTransport', * ); * * // Merge $settings into existing configuration. * \HPCloud\Bootstrap::setConfiguration($settings); * ?> * @endcode * * @retval HPCloud::Transport::Transporter * @return \HPCloud\Transport\Transporter * An initialized transporter. */ public static function instance() { if (empty(self::$inst)) { $klass = \HPCloud\Bootstrap::config('transport'); self::$inst = new $klass(); } return self::$inst; }
/** * Testing the account options separately since they are only in HP Helion * Public Cloud and may be skipped. * * @depends testAuthenticateAsAccount */ function testBootstrapAsAccount() { $reset = Bootstrap::$config; // Test authenticating as an account. $settings = array('account' => self::conf('hpcloud.identity.account'), 'secret' => self::conf('hpcloud.identity.secret'), 'endpoint' => self::conf('hpcloud.identity.url'), 'tenantid' => self::conf('hpcloud.identity.tenantId')); Bootstrap::setConfiguration($settings); $is = Bootstrap::identity(TRUE); $this->assertInstanceOf('\\HPCloud\\Services\\IdentityServices', $is); Bootstrap::$config = $reset; // Test with tenant name $settings = array('account' => self::conf('hpcloud.identity.account'), 'secret' => self::conf('hpcloud.identity.secret'), 'endpoint' => self::conf('hpcloud.identity.url'), 'tenantname' => self::conf('hpcloud.identity.tenantName')); Bootstrap::setConfiguration($settings); $is = Bootstrap::identity(TRUE); $this->assertInstanceOf('\\HPCloud\\Services\\IdentityServices', $is); }
/** * Build the stream context for a request. * * All of the HTTP transport data is passed into PHP's stream wrapper via a * stream context. This builds the context. */ protected function buildStreamContext($method, $headers, $body) { // Construct the stream options. $headers['Connection'] = 'close'; $config = array('http' => array('protocol_version' => $this->httpVersion, 'method' => strtoupper($method), 'header' => $this->smashHeaders($headers), 'user_agent' => Transporter::HTTP_USER_AGENT . self::HTTP_USER_AGENT_SUFFIX)); if (!empty($body)) { $config['http']['content'] = $body; } if (\HPCloud\Bootstrap::hasConfig('transport.timeout')) { $config['http']['timeout'] = (double) \HPCloud\Bootstrap::config('transport.timeout'); } // Set the params. (Currently there is only one.) $params = array(); if (!empty($this->notificationCallback)) { $params['notification'] = $this->notificationCallback; } elseif (\HPCloud\Bootstrap::hasConfig('transport.debug') && \HPCloud\Bootstrap::config('transport.debug')) { //fwrite(STDOUT, "Sending debug messages to STDOUT\n"); $params['notification'] = array($this, 'printNotifications'); } // Build the context. $context = stream_context_create($config, $params); return $context; }
/** * Get an item out of the context. * * @todo Should there be an option to NOT query the Bootstrap::conf()? * * @param string $name * The name to look up. First look it up in the context, then look * it up in the Bootstrap config. * @param mixed $default * The default value to return if no config param was found. * @retval mixed * The discovered result, or $default if specified, or NULL if * no $default is specified. */ protected function cxt($name, $default = NULL) { // Lazilly populate the context array. if (is_resource($this->context) && empty($this->contextArray)) { $cxt = stream_context_get_options($this->context); // If a custom scheme name has been set, use that. if (!empty($cxt[$this->schemeName])) { $this->contextArray = $cxt[$this->schemeName]; } elseif (!empty($cxt[self::DEFAULT_SCHEME])) { $this->contextArray = $cxt[self::DEFAULT_SCHEME]; } } // Should this be array_key_exists()? if (isset($this->contextArray[$name])) { return $this->contextArray[$name]; } // Check to see if the value can be gotten from // \HPCloud\Bootstrap. $val = \HPCloud\Bootstrap::config($name, NULL); if (isset($val)) { return $val; } return $default; }
/** * Internal workhorse. */ protected function handleDoRequest($uri, $method, $headers, $in = NULL) { // XXX: I don't like this, but I'm getting bug reports that mistakenly // assume this library is broken, when in fact CURL is not installed. if (!function_exists('curl_init')) { throw new \HPCloud\Exception('The CURL library is not available.'); } // A majority of curl users suggest allowing curl to automatically calculate // the content-length header. Ensure that the header is not set in code. // http://stackoverflow.com/questions/9152165/php-curl-content-length-und-content-type-wrong if (!empty($headers['Content-Length'])) { unset($headers['Content-Length']); } //syslog(LOG_WARNING, "Real Operation: $method $uri"); //$urlParts = parse_url($uri); $opts = array(CURLOPT_USERAGENT => self::HTTP_USER_AGENT . self::HTTP_USER_AGENT_SUFFIX); // Write to in-mem handle backed by a temp file. $out = fopen('php://temp', 'wb+'); $headerFile = fopen('php://temp', 'w+'); $curl = curl_init($uri); // Set method $this->determineMethod($curl, $method); // Set the upload $copy = NULL; // If we get a string, we send the string data. if (is_string($in)) { $opts[CURLOPT_POSTFIELDS] = $in; } elseif (is_resource($in)) { $opts[CURLOPT_INFILE] = $in; } // Set headers. $this->setHeaders($curl, $headers); // Get the output. $opts[CURLOPT_FILE] = $out; // We need to capture the headers, too. $opts[CURLOPT_WRITEHEADER] = $headerFile; if (Bootstrap::hasConfig('transport.debug')) { $debug = Bootstrap::config('transport.debug', NULL); $opts[CURLOPT_VERBOSE] = (int) $debug; } if (Bootstrap::hasConfig('transport.timeout')) { $opts[CURLOPT_TIMEOUT] = (int) Bootstrap::config('transport.timeout'); } if (Bootstrap::hasConfig('transport.ssl.verify')) { $validate = (bool) Bootstrap::config('transport.ssl.verify', TRUE); $opts[CURLOPT_SSL_VERIFYPEER] = $validate; } // PROXY settings $proxyMap = array('proxy' => CURLOPT_PROXY, 'proxy.tunnel' => CURLOPT_HTTPPROXYTUNNEL, 'proxy.auth' => CURLOPT_PROXYAUTH, 'proxy.port' => CURLOPT_PROXYPORT, 'proxy.type' => CURLOPT_PROXYTYPE, 'proxy.userpwd' => CURLOPT_PROXYUSERPWD); foreach ($proxyMap as $conf => $opt) { if (Bootstrap::hasConfig($conf)) { $val = Bootstrap::config($conf); $opts[$opt] = $val; } } // Set all of the curl opts and then execute. curl_setopt_array($curl, $opts); $ret = $this->execCurl($curl); $info = curl_getinfo($curl); $status = $info['http_code']; rewind($headerFile); $responseHeaders = $this->fetchHeaders($headerFile); fclose($headerFile); if (!$ret || $status < 200 || $status > 299) { if (empty($responseHeaders)) { $err = 'Unknown (non-HTTP) error: ' . $status; } else { $err = $responseHeaders[0]; } //rewind($out); //fwrite(STDERR, stream_get_contents($out)); Response::failure($status, $err, $info['url'], $method, $info); } rewind($out); // Now we need to build a response. $resp = new Response($out, $info, $responseHeaders); //curl_close($curl); if (is_resource($copy)) { fclose($copy); } return $resp; }
/** * Internal workhorse. */ protected function handleDoRequest($uri, $method, $headers, $in = NULL) { // XXX: I don't like this, but I'm getting bug reports that mistakenly // assume this library is broken, when in fact CURL is not installed. if (!function_exists('curl_init')) { throw new \HPCloud\Exception('The CURL library is not available.'); } //syslog(LOG_WARNING, "Real Operation: $method $uri"); //$urlParts = parse_url($uri); $opts = array(CURLOPT_USERAGENT => self::HTTP_USER_AGENT . self::HTTP_USER_AGENT_SUFFIX); $uri = str_replace(" ", "%20", $uri); // Write to in-mem handle backed by a temp file. $out = fopen('php://temp', 'wb+'); $headerFile = fopen('php://temp', 'w+'); $curl = curl_init($uri); //$curl = $this->curl($uri); // Set method $this->determineMethod($curl, $method); // Set the upload $copy = NULL; // If we get a string, we send the string // data. if (is_string($in)) { //curl_setopt($curl, CURLOPT_POSTFIELDS, $in); $opts[CURLOPT_POSTFIELDS] = $in; if (!isset($headers['Content-Length'])) { $headers['Content-Length'] = strlen($in); } } elseif (is_resource($in)) { //curl_setopt($curl, CURLOPT_INFILE, $in); $opts[CURLOPT_INFILE] = $in; // Tell CURL about the content length if we know it. if (!empty($headers['Content-Length'])) { //curl_setopt($curl, CURLOPT_INFILESIZE, $headers['Content-Length']); $opts[CURLOPT_INFILESIZE] = $headers['Content-Length']; unset($headers['Content-Length']); } } // Set headers. $this->setHeaders($curl, $headers); // Get the output. //curl_setopt($curl, CURLOPT_FILE, $out); $opts[CURLOPT_FILE] = $out; //curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // We need to capture the headers, too. //curl_setopt($curl, CURLOPT_WRITEHEADER, $headerFile); $opts[CURLOPT_WRITEHEADER] = $headerFile; if (Bootstrap::hasConfig('transport.debug')) { $debug = Bootstrap::config('transport.debug', NULL); //curl_setopt($curl, CURLOPT_VERBOSE, (int) $debug); $opts[CURLOPT_VERBOSE] = (int) $debug; } if (Bootstrap::hasConfig('transport.timeout')) { //curl_setopt($curl, CURLOPT_TIMEOUT, (int) Bootstrap::config('transport.timeout')); $opts[CURLOPT_TIMEOUT] = (int) Bootstrap::config('transport.timeout'); } if (Bootstrap::hasConfig('transport.ssl.verify')) { $validate = (bool) Bootstrap::config('transport.ssl.verify', TRUE); //curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $validate); $opts[CURLOPT_SSL_VERIFYPEER] = $validate; } // Set all of the curl opts and then execute. curl_setopt_array($curl, $opts); $ret = curl_exec($curl); \AJXP_Logger::debug("CURL {$method} " . $uri); //$ret = $this->execCurl($curl); $info = curl_getinfo($curl); //var_dump($info); $status = $info['http_code']; //var_dump(fstat($headerFile)); rewind($headerFile); $responseHeaders = $this->fetchHeaders($headerFile); fclose($headerFile); //var_dump($responseHeaders); if (!$ret || $status < 200 || $status > 299 || empty($responseHeaders)) { if (empty($responseHeaders)) { $err = 'Unknown (non-HTTP) error: ' . $status; } else { $err = $responseHeaders[0]; } //rewind($out); //fwrite(STDERR, stream_get_contents($out)); Response::failure($status, $err, $info['url'], $method, $info); } rewind($out); // Now we need to build a response. $resp = new Response($out, $info, $responseHeaders); //curl_close($curl); if (is_resource($copy)) { fclose($copy); } return $resp; }
/** * @depends testStream */ public function testCaching() { $container = $this->containerFixture(); $obj = $container->remoteObject(self::FNAME); $this->assertFalse($obj->isCaching()); // This is a roundabout way of testing. We know that if caching is // turned on, then we can get a local copy of the file instead of a // remote, and the best way to find this out is by grabbing a // stream. The local copy will be in a php://temp stream. // // The CURL, though, backs its up with a temp file wrapped in a PHP // stream. Other backends are likely to do the same. So this test // is weakened for CURL backends. $transport = \HPCloud\Bootstrap::config('transport'); if ($transport == '\\HPCloud\\Transport\\PHPStreamTransport') { $expect = 'http'; } else { $expect = 'PHP'; } $content = $obj->content(); $res1 = $obj->stream(); $md = stream_get_meta_data($res1); $this->assertEquals($expect, $md['wrapper_type']); fclose($res1); // Enable caching and retest. $obj->setCaching(TRUE); $this->assertTrue($obj->isCaching()); // This will cache the content. $content = $obj->content(); $res2 = $obj->stream(); $md = stream_get_meta_data($res2); // If this is using the PHP version, it built content from the // cached version. $this->assertEquals('PHP', $md['wrapper_type']); fclose($res2); }