Permalink
Browse files

Release 0.1.1.

  • Loading branch information...
2 parents b573699 + 4b303c2 commit cac3fee8e8112e0128fd89ea22a1be29fcde801e @davidfstr davidfstr committed Sep 19, 2012
View
@@ -1,5 +1,11 @@
# Splunk PHP SDK Changelog
+## 0.1.1 (preview)
+
+* Improve HTTPS reliability in PHP 5.2.11 - 5.3.6.
+ * Streaming support for large result sets is no longer available for this
+ range of PHP versions. Please upgrade to PHP 5.3.7+ if you require this.
+
## 0.1.0 (preview)
* Initial PHP SDK release
View
@@ -27,6 +27,10 @@ PHP 5.3.7+ is highly recommended.
OpenSSL support for PHP is required to access Splunk over `https://` URLs.
+If using PHP < 5.3.7, the cURL extension is required as well.
+Under this configuration the SDK will not support streaming large results
+when accessing Splunk over `https://` URLs.
+
Tested PHP versions:
* PHP 5.4.x
@@ -45,12 +49,8 @@ Tested PHP versions:
* PHP 5.2.7 - Recalled due to security flaw.
Earliest PHP supported by PHPUnit 3.6.
-&dagger; Suffers from [bug 54137] which interferes with HTTPS communication,
-especially to a Splunk server on localhost. If you see the error message
-`SSL: Connection reset by peer`, you are probably triggering this bug.
-A possible workaround is to run your PHP script on a different server than
-the Splunk indexer server, although this does not always resolve the issue.
-The SDK team is developing a better workaround for the next release.
+&dagger; Suffers from [bug 54137]. The SDK's workaround for this prevents
+streaming of large result sets when accessing Splunk over `https://` URLs.
[bug 45092]: https://bugs.php.net/bug.php?id=45092
[bug 48182]: https://bugs.php.net/bug.php?id=48182
@@ -500,11 +500,9 @@ provided below.
### Support
-1. You will be granted support if you or your company are already covered under an existing maintenance/support agreement. Send an email to support@splunk.com and please include the SDK you are referring to in the subject.
-2. If you are not covered under an existing maintenance/support agreement you can find help through the broader community at:
-<br>Splunk answers - http://splunk-base.splunk.com/answers/ Specific tags (SDK, java, python, javascript) are available to identify your questions
-<br>Splunk dev google group - http://groups.google.com/group/splunkdev
-3. Splunk will NOT provide support for SDKs if the core library (this is the code in the Splunk directory) has been modified. If you modify an SDK and want support, you can find help through the broader community and Splunk answers (see above). We also want to know about why you modified the core library. You can send feedback to: devinfo@splunk.com
+* SDKs in Preview will not be Splunk supported. Once the PHP SDK moves to an Open Beta we will provide more detail on support.
+
+* Issues should be filed here: [https://github.com/splunk/splunk-sdk-php/issues](https://github.com/splunk/splunk-sdk-php/issues)
### Contact Us
View
@@ -75,13 +75,22 @@ private function requestWithParams(
public function request(
$method, $url, $requestHeaders=array(), $requestBody='')
{
- if ((substr($url, 0, strlen('http:')) !== 'http:') &&
- (substr($url, 0, strlen('https:')) !== 'https:'))
+ $isHttp = (substr($url, 0, strlen('http:')) === 'http:');
+ $isHttps = (substr($url, 0, strlen('https:')) === 'https:');
+
+ if (!$isHttp && !$isHttps)
{
throw new InvalidArgumentException(
'URL scheme must be either HTTP or HTTPS.');
}
+ // The HTTP stream wrapper in PHP < 5.3.7 has a bug which
+ // injects junk at the end of HTTP requests, which breaks
+ // SSL connections. Fallback to cURL-based requests.
+ if ($isHttps && (version_compare(PHP_VERSION, '5.3.7') < 0))
+ return $this->requestWithCurl(
+ $method, $url, $requestHeaders, $requestBody);
+
$requestHeaderLines = array();
foreach ($requestHeaders as $k => $v)
$requestHeaderLines[] = "{$k}: {$v}";
@@ -108,6 +117,7 @@ public function request(
throw new Splunk_ConnectException($errmsg, $errno);
}
+ $headers = array();
$headerLines = $http_response_header;
$statusLine = array_shift($headerLines);
foreach ($headerLines as $line)
@@ -135,4 +145,79 @@ public function request(
else
return $response;
}
+
+ private function requestWithCurl(
+ $method, $url, $requestHeaders=array(), $requestBody='')
+ {
+ $opts = array(
+ CURLOPT_URL => $url,
+ CURLOPT_TIMEOUT => 60, // secs
+ CURLOPT_RETURNTRANSFER => TRUE,
+ CURLOPT_HEADER => TRUE,
+ // disable SSL certificate validation
+ CURLOPT_SSL_VERIFYPEER => FALSE,
+ );
+
+ foreach ($requestHeaders as $k => $v)
+ $opts[CURLOPT_HTTPHEADER][] = "$k: $v";
+
+ switch ($method)
+ {
+ case 'get':
+ $opts[CURLOPT_HTTPGET] = TRUE;
+ break;
+ case 'post':
+ $opts[CURLOPT_POST] = TRUE;
+ $opts[CURLOPT_POSTFIELDS] = $requestBody;
+ break;
+ default:
+ $opts[CURLOPT_CUSTOMREQUEST] = strtoupper($method);
+ break;
+ }
+
+ if (!($curl = curl_init()))
+ throw new Splunk_ConnectException('Unable to initialize cURL.');
+ if (!(curl_setopt_array($curl, $opts)))
+ throw new Splunk_ConnectException(curl_error($curl));
+ // NOTE: The entire HTTP response is read into memory here,
+ // which could be very large. Unfortunately the cURL
+ // interface does not provide a streaming alternative.
+ // To avoid this problem, use PHP 5.3.7+, which doesn't
+ // need cURL to perform HTTP requests.
+ if (!($response = curl_exec($curl)))
+ throw new Splunk_ConnectException(curl_error($curl));
+
+ $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
+
+ $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
+ $headerText = substr($response, 0, $headerSize);
+ $body = (strlen($response) == $headerSize)
+ ? ''
+ : substr($response, $headerSize);
+
+ $headers = array();
+ $headerLines = explode("\r\n", trim($headerText));
+ $statusLine = array_shift($headerLines);
+ foreach ($headerLines as $line)
+ {
+ list($key, $value) = explode(':', $line, 2);
+ $headers[$key] = trim($value);
+ }
+
+ $statusLineComponents = explode(' ', $statusLine, 3);
+ $httpVersion = $statusLineComponents[0];
+ $reason = count($statusLineComponents) == 3 ? $statusLineComponents[2] : '';
+
+ $response = new Splunk_HttpResponse(array(
+ 'status' => $status,
+ 'reason' => $reason,
+ 'headers' => $headers,
+ 'body' => $body,
+ ));
+
+ if ($status >= 400)
+ throw new Splunk_HttpException($response);
+ else
+ return $response;
+ }
}
View
@@ -34,12 +34,14 @@
class Splunk_HttpResponse
{
private $state;
- private $body; // lazy
+ private $body; // lazy
+ private $bodyStream; // lazy
public function __construct($state)
{
$this->state = $state;
$this->body = NULL;
+ $this->bodyStream = NULL;
}
// === Accessors ===
@@ -48,14 +50,42 @@ public function __get($key)
{
if ($key === 'body')
return $this->getBody();
+ else if ($key === 'bodyStream')
+ return $this->getBodyStream();
else
return $this->state[$key];
}
private function getBody()
{
+ if (array_key_exists('body', $this->state))
+ return $this->state['body'];
+
if ($this->body === NULL)
- $this->body = Splunk_Util::stream_get_contents($this->bodyStream);
+ {
+ if (!array_key_exists('bodyStream', $this->state))
+ throw new Splunk_UnsupportedOperationException(
+ 'Response object does not contain body stream.');
+
+ $this->body = Splunk_Util::stream_get_contents(
+ $this->state['bodyStream']);
+ }
return $this->body;
}
+
+ private function getBodyStream()
+ {
+ if (array_key_exists('bodyStream', $this->state))
+ return $this->state['bodyStream'];
+
+ if ($this->bodyStream === NULL)
+ {
+ if (!array_key_exists('body', $this->state))
+ throw new Splunk_UnsupportedOperationException(
+ 'Response object does not contain body.');
+
+ $this->bodyStream = Splunk_StringStream::create($this->state['body']);
+ }
+ return $this->bodyStream;
+ }
}
View
@@ -22,13 +22,18 @@
*/
class Splunk_StringStream
{
+ /** (Prevent construction.) **/
+ private function __construct()
+ {
+ }
+
/**
* @return resource A stream that reads from the specified byte string.
*/
public static function create($string)
{
$stream = fopen('php://memory', 'rwb');
- fwrite($stream, $string);
+ Splunk_Util::fwriteall($stream, $string);
fseek($stream, 0);
/*
View
@@ -65,7 +65,12 @@ public static function fwriteall($stream, $data)
{
$numBytesWritten = fwrite($stream, $data);
if ($numBytesWritten === FALSE)
- throw new Splunk_IOException();
+ {
+ $errorInfo = error_get_last();
+ $errmsg = $errorInfo['message'];
+ $errno = $errorInfo['type'];
+ throw new Splunk_IOException($errmsg, $errno);
+ }
if ($numBytesWritten == strlen($data))
return;
$data = substr($data, $numBytesWritten);
View
@@ -146,21 +146,52 @@ public function testValidResultsForNormalJob()
'No rows were reported in the job results.');
}
- /**
- * @expectedException Splunk_JobNotDoneException
- */
public function testResultsNotDone()
{
$service = $this->loginToRealService();
- // (This search is installed by default on Splunk 4.x.)
- $ss = $service->getSavedSearches()->get('Top five sourcetypes');
- $job = $ss->dispatch();
+ $job = $service->getJobs()->create('search index=_internal');
$this->assertFalse($job->isDone(),
'Job completed too fast. Please rewrite this unit test to avoid timing issues.');
- $job->getResultsPage();
+ try
+ {
+ $job->getResultsPage();
+
+ $job->delete();
+ $this->fail('Expected Splunk_JobNotDoneException.');
+ }
+ catch (Splunk_JobNotDoneException $e)
+ {
+ // Good
+ $job->delete();
+ }
+ }
+
+ public function testResultsEmpty()
+ {
+ $SEARCHES = array(
+ 'search index=_internal x NOT x',
+ 'search index=_does_not_exist',
+ );
+
+ $service = $this->loginToRealService();
+
+ foreach ($SEARCHES as $search)
+ {
+ $job = $service->getJobs()->create('search index=_internal x NOT x', array(
+ 'exec_mode' => 'blocking'
+ ));
+
+ $results = new Splunk_ResultsReader($job->getResultsPage());
+ $hasResults = FALSE;
+ foreach ($results as $result)
+ {
+ $hasResults = TRUE;
+ }
+ $this->assertFalse($hasResults);
+ }
}
public function testResultsPageInNamespace()
View
@@ -3,6 +3,12 @@
require "./boxes.rb"
+def _compare_versions(v1, v2)
+ v1 = v1.split(".").map {|x| x.to_i }
+ v2 = v2.split(".").map {|x| x.to_i }
+ v1 <=> v2
+end
+
Vagrant::Config.run do |config|
PHP_VERSIONS.each do |php_version|
box_name = "php-" + php_version
@@ -24,6 +30,10 @@ Vagrant::Config.run do |config|
config.vm.provision :shell, :path => "provision/libxml-latest.sh"
# openssl (required by PHP for https:// URL support)
config.vm.provision :shell, :path => "provision/openssl-latest.sh"
+ # libcurl (required by SDK when PHP < 5.3.7)
+ if _compare_versions(php_version, "5.3.7") < 0
+ config.vm.provision :shell, :path => "provision/libcurl-latest.sh"
+ end
# PHP
config.vm.provision :shell, :path => "provision/php-" + php_version + ".sh"
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+sudo apt-get update
+sudo apt-get install -y libcurl4-openssl-dev
@@ -6,7 +6,7 @@ cd /tmp
wget http://museum.php.net/php5/php-5.2.10.tar.gz
tar xzf php-5.2.10.tar.gz
cd php-5.2.10/
-./configure --with-openssl
+./configure --with-openssl --with-curl=/usr
make
sudo make install
sudo cp php.ini-recommended /usr/local/lib/php.ini
@@ -6,7 +6,7 @@ cd /tmp
wget http://museum.php.net/php5/php-5.2.11.tar.gz
tar xzf php-5.2.11.tar.gz
cd php-5.2.11/
-./configure --with-openssl
+./configure --with-openssl --with-curl=/usr
make
sudo make install
sudo cp php.ini-recommended /usr/local/lib/php.ini
@@ -6,7 +6,7 @@ cd /tmp
wget http://museum.php.net/php5/php-5.2.17.tar.gz
tar xzf php-5.2.17.tar.gz
cd php-5.2.17/
-./configure --with-openssl
+./configure --with-openssl --with-curl=/usr
make
sudo make install
sudo cp php.ini-recommended /usr/local/lib/php.ini
@@ -6,7 +6,7 @@ cd /tmp
wget http://museum.php.net/php5/php-5.2.9.tar.gz
tar xzf php-5.2.9.tar.gz
cd php-5.2.9/
-./configure --with-openssl
+./configure --with-openssl --with-curl=/usr
make
sudo make install
sudo cp php.ini-recommended /usr/local/lib/php.ini
@@ -6,7 +6,7 @@ cd /tmp
wget http://museum.php.net/php5/php-5.3.0.tar.gz
tar xzf php-5.3.0.tar.gz
cd php-5.3.0/
-./configure --with-openssl
+./configure --with-openssl --with-curl=/usr
make
sudo make install
sudo cp php.ini-development /usr/local/lib/php.ini
Oops, something went wrong.

0 comments on commit cac3fee

Please sign in to comment.